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