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