|
|
1.1 root 1: /*
2: * Copyright (c) 1980, 1990 Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Robert Elz at The University of Melbourne.
7: *
8: * Redistribution and use in source and binary forms are permitted provided
9: * that: (1) source distributions retain this entire copyright notice and
10: * comment, and (2) distributions including binaries display the following
11: * acknowledgement: ``This product includes software developed by the
12: * University of California, Berkeley and its contributors'' in the
13: * documentation or other materials provided with the distribution and in
14: * all advertising materials mentioning features or use of this software.
15: * Neither the name of the University nor the names of its contributors may
16: * be used to endorse or promote products derived from this software without
17: * specific prior written permission.
18: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
19: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
20: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21: */
22:
23: #ifndef lint
24: char copyright[] =
25: "@(#) Copyright (c) 1980, 1990 Regents of the University of California.\n\
26: All rights reserved.\n";
27: #endif /* not lint */
28:
29: #ifndef lint
30: static char sccsid[] = "@(#)quota.c 5.11 (Berkeley) 6/1/90";
31: #endif /* not lint */
32:
33: /*
34: * Disk quota reporting program.
35: */
36: #include <sys/param.h>
37: #include <sys/file.h>
38: #include <sys/stat.h>
39: #include <ufs/quota.h>
40: #include <stdio.h>
41: #include <fstab.h>
42: #include <ctype.h>
43: #include <pwd.h>
44: #include <grp.h>
45: #include <errno.h>
46:
47: struct quotause {
48: struct quotause *next;
49: long flags;
50: struct dqblk dqblk;
51: char fsname[MAXPATHLEN + 1];
52: } *getprivs();
53: #define FOUND 0x01
54:
55: int qflag;
56: int vflag;
57:
58: main(argc, argv)
59: char *argv[];
60: {
61: int ngroups, gidset[NGROUPS];
62: int i, gflag = 0, uflag = 0;
63: char ch;
64: extern char *optarg;
65: extern int optind, errno;
66:
67: if (quotactl("/", 0, 0, (caddr_t)0) < 0 && errno == EOPNOTSUPP) {
68: fprintf(stderr, "There are no quotas on this system\n");
69: exit(0);
70: }
71: while ((ch = getopt(argc, argv, "ugvq")) != EOF) {
72: switch(ch) {
73: case 'g':
74: gflag++;
75: break;
76: case 'u':
77: uflag++;
78: break;
79: case 'v':
80: vflag++;
81: break;
82: case 'q':
83: qflag++;
84: break;
85: default:
86: usage();
87: }
88: }
89: argc -= optind;
90: argv += optind;
91: if (!uflag && !gflag)
92: uflag++;
93: if (argc == 0) {
94: if (uflag)
95: showuid(getuid());
96: if (gflag) {
97: ngroups = getgroups(NGROUPS, gidset);
98: if (ngroups < 0) {
99: perror("quota: getgroups");
100: exit(1);
101: }
102: for (i = 1; i < ngroups; i++)
103: showgid(gidset[i]);
104: }
105: exit(0);
106: }
107: if (uflag && gflag)
108: usage();
109: if (uflag) {
110: for (; argc > 0; argc--, argv++) {
111: if (alldigits(*argv))
112: showuid(atoi(*argv));
113: else
114: showusrname(*argv);
115: }
116: exit(0);
117: }
118: if (gflag) {
119: for (; argc > 0; argc--, argv++) {
120: if (alldigits(*argv))
121: showgid(atoi(*argv));
122: else
123: showgrpname(*argv);
124: }
125: exit(0);
126: }
127: }
128:
129: usage()
130: {
131:
132: fprintf(stderr, "%s\n%s\n%s\n",
133: "Usage: quota [-guqv]",
134: "\tquota [-qv] -u username ...",
135: "\tquota [-qv] -g groupname ...");
136: exit(1);
137: }
138:
139: /*
140: * Print out quotas for a specified user identifier.
141: */
142: showuid(uid)
143: u_long uid;
144: {
145: struct passwd *pwd = getpwuid(uid);
146: u_long myuid;
147: char *name;
148:
149: if (pwd == NULL)
150: name = "(no account)";
151: else
152: name = pwd->pw_name;
153: myuid = getuid();
154: if (uid != myuid && myuid != 0) {
155: printf("quota: %s (uid %d): permission denied\n", name, uid);
156: return;
157: }
158: showquotas(USRQUOTA, uid, name);
159: }
160:
161: /*
162: * Print out quotas for a specifed user name.
163: */
164: showusrname(name)
165: char *name;
166: {
167: struct passwd *pwd = getpwnam(name);
168: u_long myuid;
169:
170: if (pwd == NULL) {
171: fprintf(stderr, "quota: %s: unknown user\n", name);
172: return;
173: }
174: myuid = getuid();
175: if (pwd->pw_uid != myuid && myuid != 0) {
176: fprintf(stderr, "quota: %s (uid %d): permission denied\n",
177: name, pwd->pw_uid);
178: return;
179: }
180: showquotas(USRQUOTA, pwd->pw_uid, name);
181: }
182:
183: /*
184: * Print out quotas for a specified group identifier.
185: */
186: showgid(gid)
187: u_long gid;
188: {
189: struct group *grp = getgrgid(gid);
190: int ngroups, gidset[NGROUPS];
191: register int i;
192: char *name;
193:
194: if (grp == NULL)
195: name = "(no entry)";
196: else
197: name = grp->gr_name;
198: ngroups = getgroups(NGROUPS, gidset);
199: if (ngroups < 0) {
200: perror("quota: getgroups");
201: return;
202: }
203: for (i = 1; i < ngroups; i++)
204: if (gid == gidset[i])
205: break;
206: if (i >= ngroups && getuid() != 0) {
207: fprintf(stderr, "quota: %s (gid %d): permission denied\n",
208: name, gid);
209: return;
210: }
211: showquotas(GRPQUOTA, gid, name);
212: }
213:
214: /*
215: * Print out quotas for a specifed group name.
216: */
217: showgrpname(name)
218: char *name;
219: {
220: struct group *grp = getgrnam(name);
221: int ngroups, gidset[NGROUPS];
222: register int i;
223:
224: if (grp == NULL) {
225: fprintf(stderr, "quota: %s: unknown group\n", name);
226: return;
227: }
228: ngroups = getgroups(NGROUPS, gidset);
229: if (ngroups < 0) {
230: perror("quota: getgroups");
231: return;
232: }
233: for (i = 1; i < ngroups; i++)
234: if (grp->gr_gid == gidset[i])
235: break;
236: if (i >= ngroups && getuid() != 0) {
237: fprintf(stderr, "quota: %s (gid %d): permission denied\n",
238: name, grp->gr_gid);
239: return;
240: }
241: showquotas(GRPQUOTA, grp->gr_gid, name);
242: }
243:
244: showquotas(type, id, name)
245: int type;
246: u_long id;
247: char *name;
248: {
249: register struct quotause *qup;
250: struct quotause *quplist, *getprivs();
251: char *msgi, *msgb, *timeprt();
252: int myuid, fd, lines = 0;
253: static int first;
254: static time_t now;
255:
256: if (now == 0)
257: time(&now);
258: quplist = getprivs(id, type);
259: for (qup = quplist; qup; qup = qup->next) {
260: if (!vflag &&
261: qup->dqblk.dqb_isoftlimit == 0 &&
262: qup->dqblk.dqb_ihardlimit == 0 &&
263: qup->dqblk.dqb_bsoftlimit == 0 &&
264: qup->dqblk.dqb_bhardlimit == 0)
265: continue;
266: msgi = (char *)0;
267: if (qup->dqblk.dqb_ihardlimit &&
268: qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit)
269: msgi = "File limit reached on";
270: else if (qup->dqblk.dqb_isoftlimit &&
271: qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit)
272: if (qup->dqblk.dqb_itime > now)
273: msgi = "In file grace period on";
274: else
275: msgi = "Over file quota on";
276: msgb = (char *)0;
277: if (qup->dqblk.dqb_bhardlimit &&
278: qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit)
279: msgb = "Block limit reached on";
280: else if (qup->dqblk.dqb_bsoftlimit &&
281: qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit)
282: if (qup->dqblk.dqb_btime > now)
283: msgb = "In block grace period on";
284: else
285: msgb = "Over block quota on";
286: if (qflag) {
287: if ((msgi != (char *)0 || msgb != (char *)0) &&
288: lines++ == 0)
289: heading(type, id, name, "");
290: if (msgi != (char *)0)
291: printf("\t%s %s\n", msgi, qup->fsname);
292: if (msgb != (char *)0)
293: printf("\t%s %s\n", msgb, qup->fsname);
294: continue;
295: }
296: if (vflag ||
297: qup->dqblk.dqb_curblocks ||
298: qup->dqblk.dqb_curinodes) {
299: if (lines++ == 0)
300: heading(type, id, name, "");
301: printf("%15s%8d%c%7d%8d%8s"
302: , qup->fsname
303: , dbtob(qup->dqblk.dqb_curblocks) / 1024
304: , (msgb == (char *)0) ? ' ' : '*'
305: , dbtob(qup->dqblk.dqb_bsoftlimit) / 1024
306: , dbtob(qup->dqblk.dqb_bhardlimit) / 1024
307: , (msgb == (char *)0) ? ""
308: : timeprt(qup->dqblk.dqb_btime));
309: printf("%8d%c%7d%8d%8s\n"
310: , qup->dqblk.dqb_curinodes
311: , (msgi == (char *)0) ? ' ' : '*'
312: , qup->dqblk.dqb_isoftlimit
313: , qup->dqblk.dqb_ihardlimit
314: , (msgi == (char *)0) ? ""
315: : timeprt(qup->dqblk.dqb_itime)
316: );
317: continue;
318: }
319: }
320: if (!qflag && lines == 0)
321: heading(type, id, name, "none");
322: }
323:
324: heading(type, id, name, tag)
325: int type;
326: u_long id;
327: char *name, *tag;
328: {
329:
330: printf("Disk quotas for %s %s (%cid %d): %s\n", qfextension[type],
331: name, *qfextension[type], id, tag);
332: if (!qflag && tag[0] == '\0') {
333: printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n"
334: , "Filesystem"
335: , "blocks"
336: , "quota"
337: , "limit"
338: , "grace"
339: , "files"
340: , "quota"
341: , "limit"
342: , "grace"
343: );
344: }
345: }
346:
347: /*
348: * Calculate the grace period and return a printable string for it.
349: */
350: char *
351: timeprt(seconds)
352: time_t seconds;
353: {
354: time_t hours, minutes;
355: static char buf[20];
356: static time_t now;
357:
358: if (now == 0)
359: time(&now);
360: if (now > seconds)
361: return ("none");
362: seconds -= now;
363: minutes = (seconds + 30) / 60;
364: hours = (minutes + 30) / 60;
365: if (hours >= 36) {
366: sprintf(buf, "%ddays", (hours + 12) / 24);
367: return (buf);
368: }
369: if (minutes >= 60) {
370: sprintf(buf, "%2d:%d", minutes / 60, minutes % 60);
371: return (buf);
372: }
373: sprintf(buf, "%2d", minutes);
374: return (buf);
375: }
376:
377: /*
378: * Collect the requested quota information.
379: */
380: struct quotause *
381: getprivs(id, quotatype)
382: register long id;
383: int quotatype;
384: {
385: register struct fstab *fs;
386: register struct quotause *qup, *quptail;
387: struct quotause *quphead;
388: char *qfpathname;
389: int qcmd, fd;
390:
391: setfsent();
392: quphead = (struct quotause *)0;
393: qcmd = QCMD(Q_GETQUOTA, quotatype);
394: while (fs = getfsent()) {
395: if (strcmp(fs->fs_vfstype, "ufs"))
396: continue;
397: if (!hasquota(fs, quotatype, &qfpathname))
398: continue;
399: if ((qup = (struct quotause *)malloc(sizeof *qup)) == NULL) {
400: fprintf(stderr, "quota: out of memory\n");
401: exit(2);
402: }
403: if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) {
404: if ((fd = open(qfpathname, O_RDONLY)) < 0) {
405: perror(qfpathname);
406: free(qup);
407: continue;
408: }
409: lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET);
410: switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) {
411: case 0: /* EOF */
412: /*
413: * Convert implicit 0 quota (EOF)
414: * into an explicit one (zero'ed dqblk)
415: */
416: bzero((caddr_t)&qup->dqblk,
417: sizeof(struct dqblk));
418: break;
419:
420: case sizeof(struct dqblk): /* OK */
421: break;
422:
423: default: /* ERROR */
424: fprintf(stderr, "quota: read error");
425: perror(qfpathname);
426: close(fd);
427: free(qup);
428: continue;
429: }
430: close(fd);
431: }
432: strcpy(qup->fsname, fs->fs_file);
433: if (quphead == NULL)
434: quphead = qup;
435: else
436: quptail->next = qup;
437: quptail = qup;
438: qup->next = 0;
439: }
440: endfsent();
441: return (quphead);
442: }
443:
444: /*
445: * Check to see if a particular quota is to be enabled.
446: */
447: hasquota(fs, type, qfnamep)
448: register struct fstab *fs;
449: int type;
450: char **qfnamep;
451: {
452: register char *opt;
453: char *cp, *index(), *strtok();
454: static char initname, usrname[100], grpname[100];
455: static char buf[BUFSIZ];
456:
457: if (!initname) {
458: sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname);
459: sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname);
460: initname = 1;
461: }
462: strcpy(buf, fs->fs_mntops);
463: for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
464: if (cp = index(opt, '='))
465: *cp++ = '\0';
466: if (type == USRQUOTA && strcmp(opt, usrname) == 0)
467: break;
468: if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
469: break;
470: }
471: if (!opt)
472: return (0);
473: if (cp) {
474: *qfnamep = cp;
475: return (1);
476: }
477: (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
478: *qfnamep = buf;
479: return (1);
480: }
481:
482: alldigits(s)
483: register char *s;
484: {
485: register c;
486:
487: c = *s++;
488: do {
489: if (!isdigit(c))
490: return (0);
491: } while (c = *s++);
492: return (1);
493: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.