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: #if defined(DOSCCS) && !defined(lint) 8: char copyright[] = 9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10: All rights reserved.\n"; 11: 12: static char sccsid[] = "@(#)quota.c 5.4.3 (2.11BSD GTE) 1996/2/7"; 13: #endif 14: 15: /* 16: * Disk quota reporting program. 17: */ 18: #include <stdio.h> 19: #include <fstab.h> 20: #include <ctype.h> 21: #include <pwd.h> 22: #include <errno.h> 23: #include <string.h> 24: 25: #include <sys/param.h> 26: #include <sys/quota.h> 27: #include <sys/file.h> 28: #include <sys/stat.h> 29: 30: int qflag; 31: int vflag; 32: int done; 33: int morethanone; 34: char *qfname = "quotas"; 35: 36: main(argc, argv) 37: char *argv[]; 38: { 39: register char *cp; 40: extern int errno; 41: 42: if (quota(Q_SYNC, 0, 0, (caddr_t)0) < 0 && errno == EINVAL) { 43: fprintf(stderr, "There are no quotas on this system\n"); 44: exit(0); 45: } 46: argc--,argv++; 47: while (argc > 0) { 48: if (argv[0][0] == '-') 49: for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { 50: 51: case 'v': 52: vflag++; 53: break; 54: 55: case 'q': 56: qflag++; 57: break; 58: 59: default: 60: fprintf(stderr, "quota: %c: unknown option\n", 61: *cp); 62: exit(1); 63: } 64: else 65: break; 66: argc--, argv++; 67: } 68: morethanone = argc > 1; 69: if (argc == 0) { 70: showuid(getuid()); 71: exit(0); 72: } 73: for (; argc > 0; argc--, argv++) { 74: if (alldigits(*argv)) 75: showuid(atoi(*argv)); 76: else 77: showname(*argv); 78: } 79: } 80: 81: showuid(uid) 82: int uid; 83: { 84: struct passwd *pwd = getpwuid(uid); 85: 86: if (pwd == NULL) 87: showquotas(uid, "(no account)"); 88: else 89: showquotas(uid, pwd->pw_name); 90: } 91: 92: showname(name) 93: char *name; 94: { 95: struct passwd *pwd = getpwnam(name); 96: 97: if (pwd == NULL) { 98: fprintf(stderr, "quota: %s: unknown user\n", name); 99: return; 100: } 101: showquotas(pwd->pw_uid, name); 102: } 103: 104: showquotas(uid, name) 105: int uid; 106: char *name; 107: { 108: register struct fstab *fs; 109: register char *msgi, *msgb; 110: register enab = 1; 111: dev_t fsdev; 112: struct stat statb; 113: char *qfpathname; 114: struct dqblk dqblk; 115: int myuid, fd; 116: char iwarn[8], dwarn[8]; 117: 118: myuid = getuid(); 119: if (uid != myuid && myuid != 0) { 120: printf("quota: %s (uid %d): permission denied\n", name, uid); 121: return; 122: } 123: done = 0; 124: (void) setfsent(); 125: while (fs = getfsent()) { 126: if (strcmp(fs->fs_vfstype, "ufs")) 127: continue; 128: if (!hasquota(fs, &qfpathname)) 129: continue; 130: if (stat(fs->fs_spec, &statb) < 0) 131: continue; 132: msgi = msgb = (char *) 0; 133: /* 134: * This check for the quota file being in the filesystem to which the quotas 135: * belong is silly but the kernel enforces it. When the kernel is fixed the 136: * check can be removed. 137: */ 138: fsdev = statb.st_rdev; 139: if (stat(qfpathname, &statb) < 0 || statb.st_dev != fsdev) 140: continue; 141: if (quota(Q_GETDLIM, uid, fsdev, (caddr_t)&dqblk)) { 142: fd = open(qfpathname, O_RDONLY); 143: if (fd < 0) 144: continue; 145: (void) lseek(fd, (off_t)(uid * sizeof (dqblk)), L_SET); 146: switch (read(fd, (char *)&dqblk, sizeof dqblk)) { 147: case 0: /* EOF */ 148: /* 149: * Convert implicit 0 quota (EOF) 150: * into an explicit one (zero'ed dqblk). 151: */ 152: bzero((caddr_t)&dqblk, sizeof dqblk); 153: break; 154: 155: case sizeof dqblk: /* OK */ 156: #ifdef pdp11 157: dqblk.dqb_curblocks= btodb(dqblk.dqb_curblocks); 158: dqblk.dqb_bsoftlimit = btodb(dqblk.dqb_bsoftlimit); 159: dqblk.dqb_bhardlimit = btodb(dqblk.dqb_bhardlimit); 160: #endif 161: break; 162: 163: default: /* ERROR */ 164: fprintf(stderr, "quota: read error in "); 165: perror(qfpathname); 166: (void) close(fd); 167: continue; 168: } 169: (void) close(fd); 170: if (!vflag && dqblk.dqb_isoftlimit == 0 && 171: dqblk.dqb_bsoftlimit == 0) 172: continue; 173: enab = 0; 174: } 175: if (dqblk.dqb_ihardlimit && 176: dqblk.dqb_curinodes >= dqblk.dqb_ihardlimit) 177: msgi = "File count limit reached on %s"; 178: else if (enab && dqblk.dqb_iwarn == 0) 179: msgi = "Out of inode warnings on %s"; 180: else if (dqblk.dqb_isoftlimit && 181: dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit) 182: msgi = "Too many files on %s"; 183: if (dqblk.dqb_bhardlimit && 184: dqblk.dqb_curblocks >= dqblk.dqb_bhardlimit) 185: msgb = "Block limit reached on %s"; 186: else if (enab && dqblk.dqb_bwarn == 0) 187: msgb = "Out of block warnings on %s"; 188: else if (dqblk.dqb_bsoftlimit && 189: dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit) 190: msgb = "Over disc quota on %s"; 191: if (dqblk.dqb_iwarn < MAX_IQ_WARN) 192: (void) sprintf(iwarn, "%d", dqblk.dqb_iwarn); 193: else 194: iwarn[0] = '\0'; 195: if (dqblk.dqb_bwarn < MAX_DQ_WARN) 196: (void) sprintf(dwarn, "%d", dqblk.dqb_bwarn); 197: else 198: dwarn[0] = '\0'; 199: if (qflag) { 200: if (msgi != (char *)0 || msgb != (char *)0) 201: heading(uid, name); 202: if (msgi != (char *)0) 203: xprintf(msgi, fs->fs_file); 204: if (msgb != (char *)0) 205: xprintf(msgb, fs->fs_file); 206: continue; 207: } 208: if (vflag || dqblk.dqb_curblocks || dqblk.dqb_curinodes) { 209: heading(uid, name); 210: #ifdef pdp11 211: printf("%10s%8ld%c%7ld%8ld%8s%8d%c%7u%8u%8s\n" 212: , fs->fs_file 213: , dqblk.dqb_curblocks 214: , (msgb == (char *)0) ? ' ' : '*' 215: , dqblk.dqb_bsoftlimit 216: , dqblk.dqb_bhardlimit 217: #else 218: printf("%10s%8d%c%7d%8d%8s%8d%c%7d%8d%8s\n" 219: , fs->fs_file 220: , dbtob(dqblk.dqb_curblocks) / 1024 221: , (msgb == (char *)0) ? ' ' : '*' 222: , dbtob(dqblk.dqb_bsoftlimit) / 1024 223: , dbtob(dqblk.dqb_bhardlimit) / 1024 224: #endif 225: , dwarn 226: , dqblk.dqb_curinodes 227: , (msgi == (char *)0) ? ' ' : '*' 228: , dqblk.dqb_isoftlimit 229: , dqblk.dqb_ihardlimit 230: , iwarn 231: ); 232: } 233: } 234: (void) endfsent(); 235: if (!done && !qflag) { 236: if (morethanone) 237: (void) putchar('\n'); 238: xprintf("Disc quotas for %s (uid %d):", name, uid); 239: xprintf("none."); 240: } 241: xprintf((char *)0); 242: } 243: 244: heading(uid, name) 245: int uid; 246: char *name; 247: { 248: 249: if (done++) 250: return; 251: xprintf((char *)0); 252: if (qflag) { 253: if (!morethanone) 254: return; 255: xprintf("User %s (uid %d):", name, uid); 256: xprintf((char *)0); 257: return; 258: } 259: (void) putchar('\n'); 260: xprintf("Disc quotas for %s (uid %d):", name, uid); 261: xprintf((char *)0); 262: printf("%10s%8s %7s%8s%8s%8s %7s%8s%8s\n" 263: , "Filsys" 264: , "current" 265: , "quota" 266: , "limit" 267: , "#warns" 268: , "files" 269: , "quota" 270: , "limit" 271: , "#warns" 272: ); 273: } 274: 275: /*VARARGS1*/ 276: xprintf(fmt, arg1, arg2, arg3, arg4, arg5, arg6) 277: char *fmt; 278: { 279: char buf[100]; 280: static int column; 281: 282: if (fmt == 0 && column || column >= 40) { 283: (void) putchar('\n'); 284: column = 0; 285: } 286: if (fmt == 0) 287: return; 288: (void) sprintf(buf, fmt, arg1, arg2, arg3, arg4, arg5, arg6); 289: if (column != 0 && strlen(buf) < 39) 290: while (column++ < 40) 291: (void) putchar(' '); 292: else if (column) { 293: (void) putchar('\n'); 294: column = 0; 295: } 296: printf("%s", buf); 297: column += strlen(buf); 298: } 299: 300: /* 301: * Check to see if a particular quota is to be enabled. 302: */ 303: hasquota(fs, qfnamep) 304: register struct fstab *fs; 305: char **qfnamep; 306: { 307: register char *opt; 308: char *cp; 309: static char initname, usrname[100]; 310: static char buf[BUFSIZ]; 311: 312: if (!initname) { 313: strcpy(usrname, qfname); 314: initname = 1; 315: } 316: strcpy(buf, fs->fs_mntops); 317: for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 318: if (cp = index(opt, '=')) 319: *cp++ = '\0'; 320: if (strcmp(opt, usrname) == 0) 321: break; 322: if (strcmp(opt, FSTAB_RQ) == 0) /* XXX compatibility */ 323: break; 324: } 325: if (!opt) 326: return (0); 327: if (cp) { 328: *qfnamep = cp; 329: return (1); 330: } 331: (void) sprintf(buf, "%s/%s", fs->fs_file, qfname); 332: *qfnamep = buf; 333: return (1); 334: } 335: 336: alldigits(s) 337: register char *s; 338: { 339: register c; 340: 341: c = *s++; 342: do { 343: if (!isdigit(c)) 344: return (0); 345: } while (c = *s++); 346: return (1); 347: }