|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that the above copyright notice and this paragraph are
7: * duplicated in all such forms and that any documentation,
8: * advertising materials, and other materials related to such
9: * distribution and use acknowledge that the software was developed
10: * by the University of California, Berkeley. The name of the
11: * University may not be used to endorse or promote products derived
12: * from this software without specific prior written permission.
13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16: */
17:
18: #ifndef lint
19: char copyright[] =
20: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
21: All rights reserved.\n";
22: #endif /* not lint */
23:
24: #ifndef lint
25: static char sccsid[] = "@(#)edquota.c 5.6 (Berkeley) 6/18/88";
26: #endif /* not lint */
27:
28: /*
29: * Disk quota editor.
30: */
31: #include <stdio.h>
32: #include <signal.h>
33: #include <errno.h>
34: #include <pwd.h>
35: #include <ctype.h>
36: #include <fstab.h>
37:
38: #include <sys/param.h>
39: #include <sys/stat.h>
40: #include <sys/file.h>
41: #include <sys/quota.h>
42:
43: #define DEFEDITOR "/usr/ucb/vi"
44:
45: struct dquot dq[NMOUNT];
46: struct dquot odq[NMOUNT];
47: char dqf[NMOUNT][MAXPATHLEN + 1];
48: char odqf[NMOUNT][MAXPATHLEN + 1];
49:
50: char tmpfil[] = "/tmp/EdP.aXXXXX";
51: char *qfname = "quotas";
52: char *getenv();
53:
54: main(argc, argv)
55: char **argv;
56: {
57: int uid;
58: char *arg0;
59:
60: mktemp(tmpfil);
61: close(creat(tmpfil, 0600));
62: chown(tmpfil, getuid(), getgid());
63: arg0 = *argv++;
64: if (argc < 2) {
65: fprintf(stderr, "Usage: %s [-p username] username ...\n", arg0);
66: unlink(tmpfil);
67: exit(1);
68: }
69: --argc;
70: if (getuid()) {
71: fprintf(stderr, "%s: permission denied\n", arg0);
72: unlink(tmpfil);
73: exit(1);
74: }
75: if (argc > 2 && strcmp(*argv, "-p") == 0) {
76: argc--, argv++;
77: uid = getentry(*argv++);
78: if (uid < 0) {
79: unlink(tmpfil);
80: exit(1);
81: }
82: getprivs(uid);
83: argc--;
84: while (argc-- > 0) {
85: uid = getentry(*argv++);
86: if (uid < 0)
87: continue;
88: getdiscq(uid, odq, odqf);
89: putprivs(uid);
90: }
91: unlink(tmpfil);
92: exit(0);
93: }
94: while (--argc >= 0) {
95: uid = getentry(*argv++);
96: if (uid < 0)
97: continue;
98: getprivs(uid);
99: if (editit())
100: putprivs(uid);
101: }
102: unlink(tmpfil);
103: exit(0);
104: }
105:
106: getentry(name)
107: char *name;
108: {
109: struct passwd *pw;
110: int uid;
111:
112: if (alldigits(name))
113: uid = atoi(name);
114: else if (pw = getpwnam(name))
115: uid = pw->pw_uid;
116: else {
117: fprintf(stderr, "%s: no such user\n", name);
118: sleep(1);
119: return (-1);
120: }
121: return (uid);
122: }
123:
124: editit()
125: {
126: register int pid, xpid;
127: long omask;
128: int stat;
129:
130: omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
131: top:
132: if ((pid = fork()) < 0) {
133: extern errno;
134:
135: if (errno == EPROCLIM) {
136: fprintf(stderr, "You have too many processes\n");
137: return(0);
138: }
139: if (errno == EAGAIN) {
140: sleep(1);
141: goto top;
142: }
143: perror("fork");
144: return (0);
145: }
146: if (pid == 0) {
147: register char *ed;
148:
149: sigsetmask(omask);
150: setgid(getgid());
151: setuid(getuid());
152: if ((ed = getenv("EDITOR")) == (char *)0)
153: ed = DEFEDITOR;
154: execlp(ed, ed, tmpfil, 0);
155: perror(ed);
156: exit(1);
157: }
158: while ((xpid = wait(&stat)) >= 0)
159: if (xpid == pid)
160: break;
161: sigsetmask(omask);
162: return (!stat);
163: }
164:
165: getprivs(uid)
166: register uid;
167: {
168: register i;
169: FILE *fd;
170:
171: getdiscq(uid, dq, dqf);
172: for (i = 0; i < NMOUNT; i++) {
173: odq[i] = dq[i];
174: strcpy(odqf[i], dqf[i]);
175: }
176: if ((fd = fopen(tmpfil, "w")) == NULL) {
177: fprintf(stderr, "edquota: ");
178: perror(tmpfil);
179: exit(1);
180: }
181: for (i = 0; i < NMOUNT; i++) {
182: if (*dqf[i] == '\0')
183: continue;
184: fprintf(fd,
185: "fs %s blocks (soft = %d, hard = %d) inodes (soft = %d, hard = %d)\n"
186: , dqf[i]
187: , dbtob(dq[i].dq_bsoftlimit) / 1024
188: , dbtob(dq[i].dq_bhardlimit) / 1024
189: , dq[i].dq_isoftlimit
190: , dq[i].dq_ihardlimit
191: );
192: }
193: fclose(fd);
194: }
195:
196: putprivs(uid)
197: register uid;
198: {
199: register i, j;
200: int n;
201: FILE *fd;
202: char line[BUFSIZ];
203:
204: fd = fopen(tmpfil, "r");
205: if (fd == NULL) {
206: fprintf(stderr, "Can't re-read temp file!!\n");
207: return;
208: }
209: for (i = 0; i < NMOUNT; i++) {
210: char *cp, *dp, *next();
211:
212: if (fgets(line, sizeof (line), fd) == NULL)
213: break;
214: cp = next(line, " \t");
215: if (cp == NULL)
216: break;
217: *cp++ = '\0';
218: while (*cp && *cp == '\t' && *cp == ' ')
219: cp++;
220: dp = cp, cp = next(cp, " \t");
221: if (cp == NULL)
222: break;
223: *cp++ = '\0';
224: while (*cp && *cp == '\t' && *cp == ' ')
225: cp++;
226: strcpy(dqf[i], dp);
227: n = sscanf(cp,
228: "blocks (soft = %d, hard = %d) inodes (soft = %hd, hard = %hd)\n"
229: , &dq[i].dq_bsoftlimit
230: , &dq[i].dq_bhardlimit
231: , &dq[i].dq_isoftlimit
232: , &dq[i].dq_ihardlimit
233: );
234: if (n != 4) {
235: fprintf(stderr, "%s: bad format\n", cp);
236: continue;
237: }
238: dq[i].dq_bsoftlimit = btodb(dq[i].dq_bsoftlimit * 1024);
239: dq[i].dq_bhardlimit = btodb(dq[i].dq_bhardlimit * 1024);
240: }
241: fclose(fd);
242: n = i;
243: for (i = 0; i < n; i++) {
244: if (*dqf[i] == '\0')
245: break;
246: for (j = 0; j < NMOUNT; j++) {
247: if (strcmp(dqf[i], odqf[j]) == 0)
248: break;
249: }
250: if (j >= NMOUNT)
251: continue;
252: *odqf[j] = '\0';
253: /*
254: * This isn't really good enough, it is quite likely
255: * to have changed while we have been away editing,
256: * but it's not important enough to worry about at
257: * the minute.
258: */
259: dq[i].dq_curblocks = odq[j].dq_curblocks;
260: dq[i].dq_curinodes = odq[j].dq_curinodes;
261: /*
262: * If we've upped the inode or disk block limits
263: * and the guy is out of warnings, reinitialize.
264: */
265: if (dq[i].dq_bsoftlimit > odq[j].dq_bsoftlimit &&
266: dq[i].dq_bwarn == 0)
267: dq[i].dq_bwarn = MAX_DQ_WARN;
268: if (dq[i].dq_isoftlimit > odq[j].dq_isoftlimit &&
269: dq[i].dq_iwarn == 0)
270: dq[i].dq_iwarn = MAX_IQ_WARN;
271: }
272: if (i < NMOUNT) {
273: for (j = 0; j < NMOUNT; j++) {
274: if (*odqf[j] == '\0')
275: continue;
276: strcpy(dqf[i], odqf[j]);
277: dq[i].dq_isoftlimit = 0;
278: dq[i].dq_ihardlimit = 0;
279: dq[i].dq_bsoftlimit = 0;
280: dq[i].dq_bhardlimit = 0;
281: /*
282: * Same applies as just above
283: * but matters not at all, as we are just
284: * turning quota'ing off for this filesys.
285: */
286: dq[i].dq_curblocks = odq[j].dq_curblocks;
287: dq[i].dq_curinodes = odq[j].dq_curinodes;
288: if (++i >= NMOUNT)
289: break;
290: }
291: }
292: if (*dqf[0])
293: putdiscq(uid, dq, dqf);
294: }
295:
296: char *
297: next(cp, match)
298: register char *cp;
299: char *match;
300: {
301: register char *dp;
302:
303: while (cp && *cp) {
304: for (dp = match; dp && *dp; dp++)
305: if (*dp == *cp)
306: return (cp);
307: cp++;
308: }
309: return ((char *)0);
310: }
311:
312: alldigits(s)
313: register char *s;
314: {
315: register c;
316:
317: c = *s++;
318: do {
319: if (!isdigit(c))
320: return (0);
321: } while (c = *s++);
322: return (1);
323: }
324:
325: getdiscq(uid, dq, dqf)
326: register uid;
327: register struct dquot *dq;
328: register char (*dqf)[MAXPATHLEN + 1];
329: {
330: register struct fstab *fs;
331: char qfilename[MAXPATHLEN + 1];
332: struct stat statb;
333: struct dqblk dqblk;
334: dev_t fsdev;
335: int fd;
336: static int warned = 0;
337: extern int errno;
338:
339: setfsent();
340: while (fs = getfsent()) {
341: if (stat(fs->fs_spec, &statb) < 0)
342: continue;
343: fsdev = statb.st_rdev;
344: sprintf(qfilename, "%s/%s", fs->fs_file, qfname);
345: if (stat(qfilename, &statb) < 0 || statb.st_dev != fsdev)
346: continue;
347: if (quota(Q_GETDLIM, uid, fsdev, &dqblk) != 0) {
348: if (errno == EINVAL && !warned) {
349: warned++;
350: fprintf(stderr, "Warning: %s\n",
351: "Quotas are not compiled into this kernel");
352: sleep(3);
353: }
354: fd = open(qfilename, O_RDONLY);
355: if (fd < 0)
356: continue;
357: lseek(fd, (long)(uid * sizeof dqblk), L_SET);
358: switch (read(fd, &dqblk, sizeof dqblk)) {
359: case 0: /* EOF */
360: /*
361: * Convert implicit 0 quota (EOF)
362: * into an explicit one (zero'ed dqblk)
363: */
364: bzero((caddr_t)&dqblk, sizeof dqblk);
365: break;
366:
367: case sizeof dqblk: /* OK */
368: break;
369:
370: default: /* ERROR */
371: fprintf(stderr, "edquota: read error in ");
372: perror(qfilename);
373: close(fd);
374: continue;
375: }
376: close(fd);
377: }
378: dq->dq_dqb = dqblk;
379: dq->dq_dev = fsdev;
380: strcpy(*dqf, fs->fs_file);
381: dq++, dqf++;
382: }
383: endfsent();
384: **dqf = '\0';
385: }
386:
387: putdiscq(uid, dq, dqf)
388: register uid;
389: register struct dquot *dq;
390: register char (*dqf)[MAXPATHLEN + 1];
391: {
392: register fd, cnt;
393: struct stat sb;
394: struct fstab *fs;
395:
396: cnt = 0;
397: for (cnt = 0; ++cnt <= NMOUNT && **dqf; dq++, dqf++) {
398: fs = getfsfile(*dqf);
399: if (fs == NULL) {
400: fprintf(stderr, "%s: not in /etc/fstab\n", *dqf);
401: continue;
402: }
403: strcat(*dqf, "/");
404: strcat(*dqf, qfname);
405: if (stat(*dqf, &sb) >= 0)
406: quota(Q_SETDLIM, uid, sb.st_dev, &dq->dq_dqb);
407: if ((fd = open(*dqf, 1)) < 0) {
408: perror(*dqf);
409: } else {
410: lseek(fd, (long)uid * (long)sizeof (struct dqblk), 0);
411: if (write(fd, &dq->dq_dqb, sizeof (struct dqblk)) !=
412: sizeof (struct dqblk)) {
413: fprintf(stderr, "edquota: ");
414: perror(*dqf);
415: }
416: close(fd);
417: }
418: }
419: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.