|
|
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[] = "@(#)quotacheck.c 5.6 (Berkeley) 11/3/85";
15: #endif not lint
16:
17: /*
18: * Fix up / report on disc quotas & usage
19: */
20: #include <stdio.h>
21: #include <ctype.h>
22: #include <signal.h>
23: #include <errno.h>
24: #include <sys/param.h>
25: #include <sys/inode.h>
26: #include <sys/fs.h>
27: #include <sys/quota.h>
28: #include <sys/stat.h>
29: #include <sys/wait.h>
30: #include <fstab.h>
31: #include <pwd.h>
32:
33: union {
34: struct fs sblk;
35: char dummy[MAXBSIZE];
36: } un;
37: #define sblock un.sblk
38:
39: #define ITABSZ 256
40: struct dinode itab[ITABSZ];
41: struct dinode *dp;
42:
43: #define LOGINNAMESIZE 8
44: struct fileusage {
45: struct fileusage *fu_next;
46: struct dqusage fu_usage;
47: u_short fu_uid;
48: char fu_name[LOGINNAMESIZE + 1];
49: };
50: #define FUHASH 997
51: struct fileusage *fuhead[FUHASH];
52: struct fileusage *lookup();
53: struct fileusage *adduid();
54: int highuid;
55:
56: int fi;
57: ino_t ino;
58: long done;
59: struct passwd *getpwent();
60: struct dinode *ginode();
61: char *malloc(), *makerawname();
62:
63: int vflag; /* verbose */
64: int aflag; /* all file systems */
65: int pflag; /* fsck like parallel check */
66:
67: char *qfname = "quotas";
68: char quotafile[MAXPATHLEN + 1];
69: struct dqblk zerodqbuf;
70: struct fileusage zerofileusage;
71:
72: main(argc, argv)
73: int argc;
74: char **argv;
75: {
76: register struct fstab *fs;
77: register struct fileusage *fup;
78: register struct passwd *pw;
79: int i, errs = 0;
80:
81: again:
82: argc--, argv++;
83: if (argc > 0 && strcmp(*argv, "-v") == 0) {
84: vflag++;
85: goto again;
86: }
87: if (argc > 0 && strcmp(*argv, "-a") == 0) {
88: aflag++;
89: goto again;
90: }
91: if (argc > 0 && strcmp(*argv, "-p") == 0) {
92: pflag++;
93: goto again;
94: }
95: if (argc <= 0 && !aflag) {
96: fprintf(stderr, "Usage:\n\t%s\n\t%s\n",
97: "quotacheck [-v] [-p] -a",
98: "quotacheck [-v] [-p] filesys ...");
99: exit(1);
100: }
101:
102: setpwent();
103: while ((pw = getpwent()) != 0) {
104: fup = lookup(pw->pw_uid);
105: if (fup == 0) {
106: fup = adduid(pw->pw_uid);
107: strncpy(fup->fu_name, pw->pw_name,
108: sizeof(fup->fu_name));
109: }
110: }
111: endpwent();
112:
113: if (pflag)
114: errs = preen(argc, argv);
115: else {
116: if (setfsent() == 0) {
117: fprintf(stderr, "Can't open ");
118: perror(FSTAB);
119: exit(8);
120: }
121: while ((fs = getfsent()) != NULL) {
122: if (aflag &&
123: (fs->fs_type == 0 ||
124: strcmp(fs->fs_type, FSTAB_RQ) != 0))
125: continue;
126: if (!aflag &&
127: !(oneof(fs->fs_file, argv, argc) ||
128: oneof(fs->fs_spec, argv, argc)))
129: continue;
130: (void) sprintf(quotafile, "%s/%s", fs->fs_file, qfname);
131: errs += chkquota(fs->fs_spec, fs->fs_file, quotafile);
132: }
133: endfsent();
134: }
135:
136: for (i = 0; i < argc; i++)
137: if ((done & (1 << i)) == 0)
138: fprintf(stderr, "%s not found in %s\n",
139: argv[i], FSTAB);
140: exit(errs);
141: }
142:
143: preen(argc, argv)
144: int argc;
145: char **argv;
146: {
147: register struct fstab *fs;
148: register int passno, anygtr;
149: register int errs;
150: union wait status;
151:
152: passno = 1;
153: errs = 0;
154: do {
155: anygtr = 0;
156:
157: if (setfsent() == 0) {
158: fprintf(stderr, "Can't open ");
159: perror(FSTAB);
160: exit(8);
161: }
162:
163: while ((fs = getfsent()) != NULL) {
164: if (fs->fs_passno > passno)
165: anygtr = 1;
166:
167: if (aflag &&
168: (fs->fs_type == 0 ||
169: strcmp(fs->fs_type, FSTAB_RQ) != 0))
170: continue;
171:
172: if (!aflag &&
173: !(oneof(fs->fs_file, argv, argc) ||
174: oneof(fs->fs_spec, argv, argc)))
175: continue;
176:
177: if (fs->fs_passno != passno)
178: continue;
179:
180: switch (fork()) {
181: case -1:
182: perror("fork");
183: exit(8);
184: break;
185:
186: case 0:
187: sprintf(quotafile, "%s/%s",
188: fs->fs_file, qfname);
189: exit(chkquota(fs->fs_spec,
190: fs->fs_file, quotafile));
191: }
192: }
193:
194: while (wait(&status) != -1)
195: errs += status.w_retcode;
196:
197: passno++;
198: } while (anygtr);
199:
200: return (errs);
201: }
202:
203: chkquota(fsdev, fsfile, qffile)
204: char *fsdev;
205: char *fsfile;
206: char *qffile;
207: {
208: register struct fileusage *fup;
209: dev_t quotadev;
210: register FILE *qfi, *qfo;
211: u_short uid;
212: int cg, i, fdo;
213: char *rawdisk;
214: struct stat statb;
215: struct dqblk dqbuf;
216: static int warned = 0;
217: extern int errno;
218:
219: rawdisk = makerawname(fsdev);
220: if (vflag)
221: fprintf(stdout, "*** Checking quotas for %s (%s)\n", rawdisk, fsfile);
222: fi = open(rawdisk, 0);
223: if (fi < 0) {
224: perror(rawdisk);
225: return (1);
226: }
227: qfi = fopen(qffile, "r");
228: if (qfi == NULL) {
229: perror(qffile);
230: close(fi);
231: return (1);
232: }
233: if (fstat(fileno(qfi), &statb) < 0) {
234: perror(qffile);
235: fclose(qfi);
236: close(fi);
237: return (1);
238: }
239: quotadev = statb.st_dev;
240: if (stat(fsdev, &statb) < 0) {
241: perror(fsdev);
242: fclose(qfi);
243: close(fi);
244: return (1);
245: }
246: if (quotadev != statb.st_rdev) {
247: fprintf(stderr, "%s dev (0x%x) mismatch %s dev (0x%x)\n",
248: qffile, quotadev, fsdev, statb.st_rdev);
249: fclose(qfi);
250: close(fi);
251: return (1);
252: }
253: /*
254: * Must do fdopen(open(qffile, 1), "w") instead of fopen(qffile, "w")
255: * because fopen(qffile, "w") would truncate the quota file.
256: */
257: fdo = open(qffile, 1);
258: if (fdo < 0 || (qfo = fdopen(fdo, "w")) == NULL) {
259: perror(qffile);
260: if (fdo >= 0)
261: close(fdo);
262: fclose(qfi);
263: close(fi);
264: return (1);
265: }
266: if (quota(Q_SYNC, 0, quotadev, (caddr_t)0) < 0 &&
267: errno == EINVAL && !warned && vflag) {
268: warned++;
269: fprintf(stdout,
270: "*** Warning: Quotas are not compiled into this kernel\n");
271: }
272: sync();
273: bread(SBLOCK, (char *)&sblock, SBSIZE);
274: ino = 0;
275: for (cg = 0; cg < sblock.fs_ncg; cg++) {
276: dp = NULL;
277: for (i = 0; i < sblock.fs_ipg; i++)
278: acct(ginode());
279: }
280: for (uid = 0; uid <= highuid; uid++) {
281: i = fread(&dqbuf, sizeof(struct dqblk), 1, qfi);
282: if (i == 0)
283: dqbuf = zerodqbuf;
284: fup = lookup(uid);
285: if (fup == 0)
286: fup = &zerofileusage;
287: if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes &&
288: dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) {
289: fup->fu_usage.du_curinodes = 0;
290: fup->fu_usage.du_curblocks = 0;
291: fseek(qfo, (long)sizeof(struct dqblk), 1);
292: continue;
293: }
294: if (vflag) {
295: if (pflag)
296: printf("%s: ", rawdisk);
297: if (fup->fu_name[0] != '\0')
298: printf("%-8s fixed:", fup->fu_name);
299: else
300: printf("#%-7d fixed:", uid);
301: if (dqbuf.dqb_curinodes != fup->fu_usage.du_curinodes)
302: fprintf(stdout, "\tinodes %d -> %d",
303: dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes);
304: if (dqbuf.dqb_curblocks != fup->fu_usage.du_curblocks)
305: fprintf(stdout, "\tblocks %d -> %d",
306: dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks);
307: fprintf(stdout, "\n");
308: }
309: dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes;
310: dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks;
311: fwrite(&dqbuf, sizeof(struct dqblk), 1, qfo);
312: quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage);
313: fup->fu_usage.du_curinodes = 0;
314: fup->fu_usage.du_curblocks = 0;
315: }
316: fflush(qfo);
317: ftruncate(fileno(qfo), (off_t)((highuid + 1) * sizeof(struct dqblk)));
318: fclose(qfi);
319: fclose(qfo);
320: close(fi);
321: return (0);
322: }
323:
324: acct(ip)
325: register struct dinode *ip;
326: {
327: register struct fileusage *fup;
328:
329: if (ip == NULL)
330: return;
331: if (ip->di_mode == 0)
332: return;
333: fup = adduid(ip->di_uid);
334: fup->fu_usage.du_curinodes++;
335: if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK)
336: return;
337: fup->fu_usage.du_curblocks += ip->di_blocks;
338: }
339:
340: oneof(target, list, n)
341: char *target, *list[];
342: register int n;
343: {
344: register int i;
345:
346: for (i = 0; i < n; i++)
347: if (strcmp(target, list[i]) == 0) {
348: done |= 1 << i;
349: return (1);
350: }
351: return (0);
352: }
353:
354: struct dinode *
355: ginode()
356: {
357: register unsigned long iblk;
358:
359: if (dp == NULL || ++dp >= &itab[ITABSZ]) {
360: iblk = itod(&sblock, ino);
361: bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab);
362: dp = &itab[ino % INOPB(&sblock)];
363: }
364: if (ino++ < ROOTINO)
365: return(NULL);
366: return(dp);
367: }
368:
369: bread(bno, buf, cnt)
370: long unsigned bno;
371: char *buf;
372: {
373: extern off_t lseek();
374: register off_t pos;
375:
376: pos = (off_t)dbtob(bno);
377: if (lseek(fi, pos, 0) != pos) {
378: perror("lseek");
379: exit(1);
380: }
381:
382: if (read(fi, buf, cnt) != cnt) {
383: perror("read");
384: exit(1);
385: }
386: }
387:
388: struct fileusage *
389: lookup(uid)
390: u_short uid;
391: {
392: register struct fileusage *fup;
393:
394: for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next)
395: if (fup->fu_uid == uid)
396: return (fup);
397: return ((struct fileusage *)0);
398: }
399:
400: struct fileusage *
401: adduid(uid)
402: u_short uid;
403: {
404: struct fileusage *fup, **fhp;
405: extern char *calloc();
406:
407: fup = lookup(uid);
408: if (fup != 0)
409: return (fup);
410: fup = (struct fileusage *)calloc(1, sizeof(struct fileusage));
411: if (fup == 0) {
412: fprintf(stderr, "out of memory for fileusage structures\n");
413: exit(1);
414: }
415: fhp = &fuhead[uid % FUHASH];
416: fup->fu_next = *fhp;
417: *fhp = fup;
418: fup->fu_uid = uid;
419: if (uid > highuid)
420: highuid = uid;
421: return (fup);
422: }
423:
424: char *
425: makerawname(name)
426: char *name;
427: {
428: register char *cp;
429: char tmp, ch, *rindex();
430: static char rawname[MAXPATHLEN];
431:
432: strcpy(rawname, name);
433: cp = rindex(rawname, '/');
434: if (cp == NULL)
435: return (name);
436: else
437: cp++;
438: for (ch = 'r'; *cp != '\0'; ) {
439: tmp = *cp;
440: *cp++ = ch;
441: ch = tmp;
442: }
443: *cp++ = ch;
444: *cp = '\0';
445: return (rawname);
446: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.