Commit | Line | Data |
---|---|---|
311ea057 | 1 | #ifndef lint |
1cfb1c19 | 2 | static char sccsid[] = "@(#)edquota.c 4.2 (Berkeley, from Melbourne) %G%"; |
311ea057 KM |
3 | #endif |
4 | ||
5 | /* | |
6 | * Disk quota editor. | |
7 | */ | |
8 | #include <stdio.h> | |
9 | #include <signal.h> | |
10 | #include <errno.h> | |
11 | #include <pwd.h> | |
12 | #include <ctype.h> | |
13 | #include <fstab.h> | |
14 | ||
15 | #include <sys/param.h> | |
1cfb1c19 | 16 | #define QUOTA |
311ea057 KM |
17 | #include <sys/quota.h> |
18 | #include <sys/stat.h> | |
19 | #include <sys/file.h> | |
20 | ||
311ea057 | 21 | #define DEFEDITOR "/usr/ucb/vi" |
311ea057 KM |
22 | |
23 | struct dquot dq[NMOUNT]; | |
24 | struct dquot odq[NMOUNT]; | |
25 | char dqf[NMOUNT][MAXPATHLEN + 1]; | |
26 | char odqf[NMOUNT][MAXPATHLEN + 1]; | |
27 | ||
28 | char tmpfil[] = "/tmp/EdP.aXXXXX"; | |
1cfb1c19 | 29 | char *qfname = "quotas"; |
311ea057 KM |
30 | char *arg0; |
31 | char *getenv(); | |
32 | ||
33 | main(argc, argv) | |
34 | char **argv; | |
35 | { | |
36 | ||
37 | mktemp(tmpfil); | |
38 | close(creat(tmpfil, 0600)); | |
39 | chown(tmpfil, getuid(), getgid()); | |
40 | arg0 = *argv++; | |
41 | if (argc < 2) { | |
42 | fprintf(stderr, "Usage: %s username ...\n", arg0); | |
43 | unlink(tmpfil); | |
44 | exit(1); | |
45 | } | |
46 | --argc; | |
47 | if (getuid()) { | |
48 | fprintf(stderr, "%s: permission denied\n", arg0); | |
49 | unlink(tmpfil); | |
50 | exit(1); | |
51 | } | |
52 | while (--argc >= 0) | |
53 | doedit(*argv++); | |
54 | unlink(tmpfil); | |
55 | exit(0); | |
56 | } | |
57 | ||
58 | doedit(name) | |
59 | register char *name; | |
60 | { | |
61 | register uid; | |
62 | register struct passwd *pw; | |
63 | ||
64 | if (alldigits(name)) | |
65 | uid = atoi(name); | |
66 | else if (pw = getpwnam(name)) | |
67 | uid = pw->pw_uid; | |
68 | else { | |
69 | fprintf(stderr, "%s: no such user\n"); | |
70 | sleep(1); | |
71 | return; | |
72 | } | |
73 | getprivs(uid); | |
74 | if (editit()) | |
75 | putprivs(uid); | |
76 | } | |
77 | ||
78 | editit() | |
79 | { | |
80 | register pid, xpid; | |
81 | int stat; | |
82 | ||
83 | sighold(SIGINT); | |
84 | sighold(SIGQUIT); | |
85 | sighold(SIGHUP); | |
86 | ||
87 | top: | |
88 | if ((pid = fork()) < 0) { | |
89 | extern errno; | |
90 | ||
91 | if (errno == EPROCLIM) { | |
92 | fprintf(stderr, "You have too many processes\n"); | |
93 | return(0); | |
94 | } | |
95 | if (errno == EAGAIN) { | |
96 | sleep(1); | |
97 | goto top; | |
98 | } | |
99 | perror("fork"); | |
100 | return (0); | |
101 | } | |
102 | if (pid == 0) { | |
103 | register char *ed; | |
104 | ||
105 | sigrelse(SIGINT); | |
106 | sigrelse(SIGQUIT); | |
107 | sigrelse(SIGHUP); | |
108 | setgid(getgid()); | |
109 | setuid(getuid()); | |
110 | ||
111 | if ((ed = getenv("EDITOR")) == (char *)0) | |
112 | ed = DEFEDITOR; | |
113 | execlp(ed, ed, tmpfil, 0); | |
114 | perror(ed); | |
115 | exit(1); | |
116 | } | |
117 | while ((xpid = wait(&stat)) >= 0) | |
118 | if (xpid == pid) | |
119 | break; | |
120 | sigrelse(SIGINT); | |
121 | sigrelse(SIGQUIT); | |
122 | sigrelse(SIGHUP); | |
123 | return (!stat); | |
124 | } | |
125 | ||
126 | getprivs(uid) | |
127 | register uid; | |
128 | { | |
129 | register i; | |
130 | FILE *fd; | |
131 | ||
132 | getdiscq(uid, dq, dqf); | |
133 | for (i = 0; i < NMOUNT; i++) { | |
134 | odq[i] = dq[i]; | |
135 | strcpy(odqf[i], dqf[i]); | |
136 | } | |
137 | if ((fd = fopen(tmpfil, "w")) == NULL) { | |
138 | fprintf(stderr, "edquota: "); | |
139 | perror(tmpfil); | |
140 | exit(1); | |
141 | } | |
142 | for (i = 0; i < NMOUNT; i++) { | |
143 | if (*dqf[i] == '\0') | |
144 | continue; | |
145 | fprintf(fd, | |
146 | "fs %s blocks (soft = %d, hard = %d) inodes (soft = %d, hard = %d)\n" | |
147 | , dqf[i] | |
1cfb1c19 KM |
148 | , dq[i].dq_bsoftlimit / btodb(1024) |
149 | , dq[i].dq_bhardlimit / btodb(1024) | |
311ea057 KM |
150 | , dq[i].dq_isoftlimit |
151 | , dq[i].dq_ihardlimit | |
152 | ); | |
153 | } | |
154 | fclose(fd); | |
155 | } | |
156 | ||
157 | putprivs(uid) | |
158 | register uid; | |
159 | { | |
160 | register i, j; | |
161 | int n; | |
162 | FILE *fd; | |
163 | char line[BUFSIZ]; | |
164 | ||
165 | fd = fopen(tmpfil, "r"); | |
166 | if (fd == NULL) { | |
167 | fprintf(stderr, "Can't re-read temp file!!\n"); | |
168 | return; | |
169 | } | |
170 | for (i = 0; i < NMOUNT; i++) { | |
171 | char *cp, *dp, *next(); | |
172 | ||
173 | if (fgets(line, sizeof (line), fd) == NULL) | |
174 | break; | |
175 | cp = next(line, " \t"); | |
176 | if (cp == NULL) | |
177 | break; | |
178 | *cp++ = '\0'; | |
179 | while (*cp && *cp == '\t' && *cp == ' ') | |
180 | cp++; | |
181 | dp = cp, cp = next(cp, " \t"); | |
182 | if (cp == NULL) | |
183 | break; | |
184 | *cp++ = '\0'; | |
185 | while (*cp && *cp == '\t' && *cp == ' ') | |
186 | cp++; | |
187 | strcpy(dqf[i], dp); | |
188 | n = sscanf(cp, | |
189 | "blocks (soft = %d, hard = %d) inodes (soft = %hd, hard = %hd)\n" | |
190 | , &dq[i].dq_bsoftlimit | |
191 | , &dq[i].dq_bhardlimit | |
192 | , &dq[i].dq_isoftlimit | |
193 | , &dq[i].dq_ihardlimit | |
194 | ); | |
1cfb1c19 KM |
195 | if (n != 4) { |
196 | fprintf(stderr, "%s: bad format\n", cp); | |
197 | continue; | |
198 | } | |
199 | dq[i].dq_bsoftlimit *= btodb(1024); | |
200 | dq[i].dq_bhardlimit *= btodb(1024); | |
311ea057 KM |
201 | } |
202 | fclose(fd); | |
203 | n = i; | |
204 | for (i = 0; i < n; i++) { | |
205 | if (*dqf[i] == '\0') | |
206 | break; | |
207 | for (j = 0; j < NMOUNT; j++) { | |
208 | if (strcmp(dqf[i], odqf[j]) == 0) | |
209 | break; | |
210 | } | |
211 | if (j >= NMOUNT) | |
212 | continue; | |
213 | *odqf[j] = '\0'; | |
214 | if (dq[i].dq_isoftlimit == odq[j].dq_isoftlimit && | |
215 | dq[i].dq_ihardlimit == odq[j].dq_ihardlimit && | |
216 | dq[i].dq_bsoftlimit == odq[j].dq_bsoftlimit && | |
217 | dq[i].dq_bhardlimit == odq[j].dq_bhardlimit) { | |
1cfb1c19 | 218 | for (j = i; j < NMOUNT; j++) { |
311ea057 KM |
219 | dq[j] = dq[j+1]; |
220 | strcpy(dqf[j], dqf[j+1]); | |
221 | } | |
222 | *dqf[j] = '\0'; | |
223 | i--; | |
224 | continue; | |
225 | } | |
226 | /* | |
227 | * This isn't really good enough, it is quite likely | |
228 | * to have changed while we have been away editing, | |
229 | * but it's not important enough to worry about at | |
230 | * the minute. | |
231 | */ | |
232 | dq[i].dq_curblocks = odq[j].dq_curblocks; | |
233 | dq[i].dq_curinodes = odq[j].dq_curinodes; | |
234 | /* | |
235 | * If we've upped the inode or disk block limits | |
236 | * and the guy is out of warnings, reinitialize. | |
237 | */ | |
238 | if (dq[i].dq_bsoftlimit > odq[j].dq_bsoftlimit && | |
239 | dq[i].dq_bwarn == 0) | |
240 | dq[i].dq_bwarn = MAX_DQ_WARN; | |
241 | if (dq[i].dq_isoftlimit > odq[j].dq_isoftlimit && | |
242 | dq[i].dq_iwarn == 0) | |
243 | dq[i].dq_iwarn = MAX_IQ_WARN; | |
244 | } | |
245 | if (i < NMOUNT) { | |
246 | for (j = 0; j < NMOUNT; j++) { | |
247 | if (*odqf[j] == '\0') | |
248 | continue; | |
249 | strcpy(dqf[i], odqf[j]); | |
250 | dq[i].dq_isoftlimit = 0; | |
251 | dq[i].dq_ihardlimit = 0; | |
252 | dq[i].dq_bsoftlimit = 0; | |
253 | dq[i].dq_bhardlimit = 0; | |
254 | /* | |
255 | * Same applies as just above | |
256 | * but matters not at all, as we are just | |
257 | * turning quota'ing off for this filesys. | |
258 | */ | |
259 | dq[i].dq_curblocks = odq[j].dq_curblocks; | |
260 | dq[i].dq_curinodes = odq[j].dq_curinodes; | |
261 | if (++i >= NMOUNT) | |
262 | break; | |
263 | } | |
264 | } | |
265 | if (*dqf[0]) | |
266 | putdiscq(uid, dq, dqf); | |
267 | } | |
268 | ||
269 | char * | |
270 | next(cp, match) | |
271 | register char *cp; | |
272 | char *match; | |
273 | { | |
274 | register char *dp; | |
275 | ||
276 | while (cp && *cp) { | |
277 | for (dp = match; dp && *dp; dp++) | |
278 | if (*dp == *cp) | |
279 | return (cp); | |
280 | cp++; | |
281 | } | |
282 | return ((char *)0); | |
283 | } | |
284 | ||
285 | alldigits(s) | |
286 | register char *s; | |
287 | { | |
288 | register c; | |
289 | ||
290 | c = *s++; | |
291 | do { | |
292 | if (!isdigit(c)) | |
293 | return (0); | |
294 | } while (c = *s++); | |
295 | return (1); | |
296 | } | |
297 | ||
298 | getdiscq(uid, dq, dqf) | |
299 | register uid; | |
300 | register struct dquot *dq; | |
301 | register char (*dqf)[MAXPATHLEN + 1]; | |
302 | { | |
303 | register struct fstab *fs; | |
1cfb1c19 | 304 | char qfilename[MAXPATHLEN + 1]; |
311ea057 KM |
305 | |
306 | setfsent(); | |
307 | while (fs = getfsent()) { | |
308 | struct stat statb; | |
309 | struct dqblk dqblk; | |
310 | dev_t fsdev; | |
311 | ||
312 | if (stat(fs->fs_spec, &statb) < 0) | |
313 | continue; | |
314 | fsdev = statb.st_rdev; | |
1cfb1c19 KM |
315 | sprintf(qfilename, "%s/%s", fs->fs_file, qfname); |
316 | if (stat(qfilename, &statb) < 0 || statb.st_dev != fsdev) | |
311ea057 KM |
317 | continue; |
318 | if (quota(Q_GETDLIM, uid, fsdev, &dqblk) != 0) { | |
1cfb1c19 | 319 | register fd = open(qfilename, FRDONLY); |
311ea057 KM |
320 | |
321 | if (fd < 0) | |
322 | continue; | |
323 | lseek(fd, (long)(uid * sizeof dqblk), FSEEK_ABSOLUTE); | |
324 | if (read(fd, &dqblk, sizeof dqblk) != sizeof (dqblk)) { | |
325 | close(fd); | |
326 | continue; | |
327 | } | |
328 | close(fd); | |
311ea057 KM |
329 | } |
330 | dq->dq_dqb = dqblk; | |
331 | dq->dq_dev = fsdev; | |
332 | strcpy(*dqf, fs->fs_file); | |
333 | dq++, dqf++; | |
334 | } | |
335 | endfsent(); | |
336 | **dqf = '\0'; | |
337 | } | |
338 | ||
339 | putdiscq(uid, dq, dqf) | |
340 | register uid; | |
341 | register struct dquot *dq; | |
342 | register char (*dqf)[MAXPATHLEN + 1]; | |
343 | { | |
344 | register fd, cnt; | |
345 | struct stat sb; | |
346 | struct fstab *fs; | |
347 | ||
348 | cnt = 0; | |
349 | for (cnt = 0; ++cnt <= NMOUNT && **dqf; dq++, dqf++) { | |
350 | fs = getfsfile(*dqf); | |
1cfb1c19 KM |
351 | if (fs == NULL) { |
352 | fprintf(stderr, "%s: not in /etc/fstab\n", *dqf); | |
353 | continue; | |
354 | } | |
355 | strcat(*dqf, "/"); | |
356 | strcat(*dqf, qfname); | |
357 | if (stat(*dqf, &sb) >= 0) | |
358 | quota(Q_SETDLIM, uid, sb.st_dev, &dq->dq_dqb); | |
359 | if ((fd = open(*dqf, 1)) < 0) { | |
360 | perror(*dqf); | |
361 | } else { | |
311ea057 KM |
362 | lseek(fd, (long)uid * (long)sizeof (struct dqblk), 0); |
363 | if (write(fd, &dq->dq_dqb, sizeof (struct dqblk)) != | |
364 | sizeof (struct dqblk)) { | |
365 | fprintf(stderr, "edquota: "); | |
366 | perror(*dqf); | |
367 | } | |
368 | close(fd); | |
369 | } | |
311ea057 KM |
370 | } |
371 | } |