1: /* 2: * Copyright (c) 1980, 1990, 1993 3: * The Regents of the University of California. 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, with or without 9: * modification, are permitted provided that the following conditions 10: * are met: 11: * 1. Redistributions of source code must retain the above copyright 12: * notice, this list of conditions and the following disclaimer. 13: * 2. Redistributions in binary form must reproduce the above copyright 14: * notice, this list of conditions and the following disclaimer in the 15: * documentation and/or other materials provided with the distribution. 16: * 3. All advertising materials mentioning features or use of this software 17: * must display the following acknowledgement: 18: * This product includes software developed by the University of 19: * California, Berkeley and its contributors. 20: * 4. Neither the name of the University nor the names of its contributors 21: * may be used to endorse or promote products derived from this software 22: * without specific prior written permission. 23: * 24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34: * SUCH DAMAGE. 35: */ 36: 37: #if !defined(lint) && defined(DOSCCS) 38: static char copyright[] = 39: "@(#) Copyright (c) 1980, 1990, 1993\n\ 40: The Regents of the University of California. All rights reserved.\n"; 41: 42: static char sccsid[] = "@(#)repquota.c 8.1 (Berkeley) 6/6/93"; 43: #endif /* not lint */ 44: 45: /* 46: * Quota report 47: */ 48: #include <sys/param.h> 49: #include <sys/stat.h> 50: #include <sys/quota.h> 51: #include <fstab.h> 52: #include <pwd.h> 53: #include <stdio.h> 54: #include <errno.h> 55: #include <string.h> 56: 57: char *qfname = QUOTAFILENAME; 58: 59: struct fileusage { 60: struct fileusage *fu_next; 61: struct dqblk fu_dqblk; 62: u_int fu_id; 63: char fu_name[1]; 64: /* actually bigger */ 65: }; 66: #define FUHASH 256 /* must be power of two */ 67: struct fileusage *fuhead[FUHASH]; 68: struct fileusage *lookup(); 69: struct fileusage *addid(); 70: u_int highid; /* highest addid()'ed identifier per type */ 71: 72: int vflag; /* verbose */ 73: int aflag; /* all file systems */ 74: 75: main(argc, argv) 76: int argc; 77: char **argv; 78: { 79: register struct fstab *fs; 80: register struct passwd *pw; 81: int errs = 0; 82: int i, argnum; 83: long done = 0; 84: extern char *optarg; 85: extern int optind; 86: char ch, *qfnp; 87: 88: while ((ch = getopt(argc, argv, "aguv")) != EOF) { 89: switch(ch) { 90: case 'a': 91: aflag++; 92: break; 93: case 'v': 94: vflag++; 95: break; 96: default: 97: usage(); 98: } 99: } 100: argc -= optind; 101: argv += optind; 102: if (argc == 0 && !aflag) 103: usage(); 104: 105: setpwent(); 106: while ((pw = getpwent()) != 0) 107: (void) addid(pw->pw_uid, pw->pw_name); 108: endpwent(); 109: 110: setfsent(); 111: while ((fs = getfsent()) != NULL) { 112: if (strcmp(fs->fs_vfstype, "ufs")) 113: continue; 114: if (aflag) { 115: if (hasquota(fs, &qfnp)) 116: errs += repquota(fs, qfnp); 117: continue; 118: } 119: if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || 120: (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) { 121: done |= 1 << argnum; 122: if (hasquota(fs, &qfnp)) 123: errs += repquota(fs, qfnp); 124: } 125: } 126: endfsent(); 127: for (i = 0; i < argc; i++) 128: if ((done & (1 << i)) == 0) 129: fprintf(stderr, "%s not found in fstab\n", argv[i]); 130: exit(errs); 131: } 132: 133: usage() 134: { 135: fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 136: "repquota [-v] [-g] [-u] -a", 137: "repquota [-v] [-g] [-u] filesys ..."); 138: exit(1); 139: } 140: 141: repquota(fs, qfpathname) 142: register struct fstab *fs; 143: char *qfpathname; 144: { 145: register struct fileusage *fup; 146: FILE *qf; 147: u_int id; 148: struct dqblk dqbuf; 149: struct stat statb; 150: static struct dqblk zerodqblk; 151: static int warned = 0; 152: static int multiple = 0; 153: extern int errno; 154: 155: if ((qf = fopen(qfpathname, "r")) == NULL) { 156: perror(qfpathname); 157: return (1); 158: } 159: if (fstat(fileno(qf), &statb) < 0) { 160: perror(qfpathname); 161: fclose(qf); 162: return(1); 163: } 164: if (quota(Q_SYNC, 0, statb.st_dev, 0) < 0 && 165: errno == EOPNOTSUPP && !warned && vflag) { 166: warned++; 167: fprintf(stdout, 168: "*** Warning: Quotas are not compiled into this kernel\n"); 169: } 170: if (multiple++) 171: printf("\n"); 172: if (vflag) 173: fprintf(stdout, "*** Report for quotas on %s (%s)\n", 174: fs->fs_file, fs->fs_spec); 175: for (id = 0; ; id++) { 176: fread(&dqbuf, sizeof(struct dqblk), 1, qf); 177: if (feof(qf)) 178: break; 179: if (dqbuf.dqb_curinodes == 0 && dqbuf.dqb_curblocks == 0) 180: continue; 181: if ((fup = lookup(id)) == 0) 182: fup = addid(id, (char *)0); 183: fup->fu_dqblk = dqbuf; 184: } 185: fclose(qf); 186: printf(" Block limits File limits\n"); 187: printf("User used soft hard warn used soft hard warn\n"); 188: for (id = 0; id <= highid; id++) { 189: fup = lookup(id); 190: if (fup == 0) 191: continue; 192: if (fup->fu_dqblk.dqb_curinodes == 0 && 193: fup->fu_dqblk.dqb_curblocks == 0) 194: continue; 195: printf("%-10s", fup->fu_name); 196: printf("%c%c%8ld%8ld%8ld%5u", 197: fup->fu_dqblk.dqb_bsoftlimit && 198: fup->fu_dqblk.dqb_curblocks >= 199: fup->fu_dqblk.dqb_bsoftlimit ? '+' : '-', 200: fup->fu_dqblk.dqb_isoftlimit && 201: fup->fu_dqblk.dqb_curinodes >= 202: fup->fu_dqblk.dqb_isoftlimit ? '+' : '-', 203: fup->fu_dqblk.dqb_curblocks / 1024, 204: fup->fu_dqblk.dqb_bsoftlimit / 1024, 205: fup->fu_dqblk.dqb_bhardlimit / 1024, 206: fup->fu_dqblk.dqb_bwarn); 207: 208: printf(" %6u%6u%6u%6u\n", 209: fup->fu_dqblk.dqb_curinodes, 210: fup->fu_dqblk.dqb_isoftlimit, 211: fup->fu_dqblk.dqb_ihardlimit, 212: fup->fu_dqblk.dqb_iwarn); 213: fup->fu_dqblk = zerodqblk; 214: } 215: return (0); 216: } 217: 218: /* 219: * Check to see if target appears in list of size cnt. 220: */ 221: oneof(target, list, cnt) 222: register char *target, *list[]; 223: int cnt; 224: { 225: register int i; 226: 227: for (i = 0; i < cnt; i++) 228: if (strcmp(target, list[i]) == 0) 229: return (i); 230: return (-1); 231: } 232: 233: /* 234: * Check to see if a particular quota is to be enabled. 235: */ 236: hasquota(fs, qfnamep) 237: register struct fstab *fs; 238: char **qfnamep; 239: { 240: register char *opt; 241: char *cp; 242: static char initname, usrname[100]; 243: static char buf[BUFSIZ]; 244: 245: if (!initname) { 246: strcpy(usrname, qfname); 247: initname = 1; 248: } 249: strcpy(buf, fs->fs_mntops); 250: for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 251: if (cp = index(opt, '=')) 252: *cp++ = '\0'; 253: if (strcmp(opt, usrname) == 0) 254: break; 255: if (strcmp(opt, FSTAB_RQ) == 0) /* XXX compatibility */ 256: break; 257: } 258: if (!opt) 259: return (0); 260: if (cp) { 261: *qfnamep = cp; 262: return (1); 263: } 264: (void) sprintf(buf, "%s/%s", fs->fs_file, qfname); 265: *qfnamep = buf; 266: return (1); 267: } 268: 269: /* 270: * Routines to manage the file usage table. 271: * 272: * Lookup an id. 273: */ 274: struct fileusage * 275: lookup(id) 276: u_int id; 277: { 278: register struct fileusage *fup; 279: 280: for (fup = fuhead[id & (FUHASH-1)]; fup != 0; fup = fup->fu_next) 281: if (fup->fu_id == id) 282: return (fup); 283: return ((struct fileusage *)0); 284: } 285: 286: /* 287: * Add a new file usage id if it does not already exist. 288: */ 289: struct fileusage * 290: addid(id, name) 291: u_short id; 292: char *name; 293: { 294: struct fileusage *fup, **fhp; 295: int len; 296: extern char *calloc(); 297: 298: if (fup = lookup(id)) 299: return (fup); 300: if (name) 301: len = strlen(name); 302: else 303: len = 10; 304: if ((fup = (struct fileusage *)calloc(1, sizeof(*fup) + len)) == NULL) { 305: fprintf(stderr, "out of memory for fileusage structures\n"); 306: exit(1); 307: } 308: fhp = &fuhead[id & (FUHASH - 1)]; 309: fup->fu_next = *fhp; 310: *fhp = fup; 311: fup->fu_id = id; 312: if (id > highid) 313: highid = id; 314: if (name) { 315: bcopy(name, fup->fu_name, len + 1); 316: } else { 317: sprintf(fup->fu_name, "%u", id); 318: } 319: return (fup); 320: }