|
|
1.1 ! root 1: /* ! 2: * Produce various information about ! 3: * filesystem space usage and owners. ! 4: * The options of this command seem a ! 5: * little too disjoint in their functionality. ! 6: */ ! 7: ! 8: #include <stdio.h> ! 9: #include <sys/ino.h> ! 10: #include <sys/filsys.h> ! 11: #include <canon.h> ! 12: #include <pwd.h> ! 13: #include <ctype.h> ! 14: ! 15: #define NHASH 64 /* Hash names table (power of 2) */ ! 16: #define NIREAD (20*BUFSIZ) /* Inode bytes per read */ ! 17: #define NCUM 2047 /* Number of different size entries */ ! 18: #define BADSIZE (-1) /* not valid - for hash synonym checking */ ! 19: #define BADUID (-1) /* not valid - for hash synonyms */ ! 20: ! 21: /* ! 22: * Hash table of names ! 23: */ ! 24: typedef struct NAME { ! 25: struct NAME *n_next; ! 26: unsigned short n_uid; ! 27: char n_name[]; ! 28: } NAME; ! 29: ! 30: /* ! 31: * Entry of hash table of ! 32: * -f and ordinary options. ! 33: */ ! 34: typedef struct FENTRY { ! 35: unsigned short f_uid; ! 36: long f_nfiles; ! 37: long f_nblocks; ! 38: } FENTRY; ! 39: ! 40: /* ! 41: * Entry of hash table for ! 42: * -c (cumulative sizes) ! 43: */ ! 44: typedef struct CENTRY { ! 45: unsigned long c_nblocks; /* Size of file in blocks */ ! 46: long c_nfiles; /* #files of that size */ ! 47: } CENTRY; ! 48: ! 49: NAME *names[NHASH]; ! 50: FENTRY *fentries; /* File count and size entries */ ! 51: FENTRY *efp; /* Pointer to end of `fentries' */ ! 52: CENTRY *centries; /* Cumulative size entries */ ! 53: CENTRY *ecp; /* Pointer to end of `centries' */ ! 54: CENTRY *lastcep; /* Last for sorting */ ! 55: char ibuf[NIREAD]; /* I-node read buffer */ ! 56: char incopt[] = "incompatible options given"; ! 57: ! 58: int cflag; /* cumulative sizes list */ ! 59: int fflag; /* #files as well as space */ ! 60: int nflag; /* List of files and owners (via ncheck) */ ! 61: int tflag; /* Print a total */ ! 62: int nuids; /* Number of uids found in /etc/passwd */ ! 63: ino_t readino; /* Last i-number read from input (`-n') */ ! 64: char *readfile; /* Last filename read as above */ ! 65: char *line; /* Line that is read in */ ! 66: ! 67: char *username(); ! 68: char *alloc(); ! 69: FENTRY *getfentry(); ! 70: CENTRY *getcentry(); ! 71: int fcomp(); ! 72: int ccomp(); ! 73: ! 74: main(argc, argv) ! 75: int argc; ! 76: register char *argv[]; ! 77: { ! 78: register char *ap; ! 79: register int es = 0; ! 80: register int mflag; ! 81: register int fd; ! 82: ! 83: while (argc>1 && *argv[1]=='-') { ! 84: for (ap = &argv[1][1]; *ap!='\0'; ap++) ! 85: switch (*ap) { ! 86: case 'n': ! 87: nflag++; ! 88: if (cflag || fflag) ! 89: cerr(incopt); ! 90: break; ! 91: ! 92: case 'c': ! 93: cflag++; ! 94: if (nflag || fflag) ! 95: cerr(incopt); ! 96: break; ! 97: ! 98: case 'f': ! 99: fflag++; ! 100: if (nflag || cflag) ! 101: cerr(incopt); ! 102: break; ! 103: ! 104: case 't': ! 105: tflag++; ! 106: if (nflag) ! 107: cerr(incopt); ! 108: break; ! 109: ! 110: default: ! 111: usage(); ! 112: } ! 113: argv++; ! 114: argc--; ! 115: } ! 116: argv++; ! 117: if (argc < 2) ! 118: usage(); ! 119: mflag = 0; ! 120: if (argv[0]!=NULL && argv[1]!=NULL) ! 121: mflag++; ! 122: for ( ; *argv!=NULL; argv++) { ! 123: if ((fd = open(*argv, 0)) < 0) { ! 124: cwarn("cannot open `%s'", *argv); ! 125: continue; ! 126: } ! 127: if (mflag) ! 128: fprintf(stderr, "%s:\n", *argv); ! 129: quotinit(); ! 130: es |= quot(fd, *argv); ! 131: quotterm(); ! 132: close(fd); ! 133: } ! 134: exit(es); ! 135: } ! 136: ! 137: /* ! 138: * Initialise things for `quot' for ! 139: * each filesystem pass. ! 140: */ ! 141: quotinit() ! 142: { ! 143: if (!cflag && nuids==0) { ! 144: readnames(); ! 145: nuids *= 2; ! 146: } ! 147: if (!nflag && !cflag) { ! 148: register FENTRY *fep; ! 149: ! 150: fentries = (FENTRY *)alloc(nuids*sizeof (FENTRY)); ! 151: efp = &fentries[nuids]; ! 152: for (fep = fentries; fep < efp; fep++) ! 153: fep->f_uid = BADUID; ! 154: } else if (cflag) { ! 155: register CENTRY *cep; ! 156: ! 157: centries = (CENTRY *)alloc(NCUM*sizeof(CENTRY)); ! 158: lastcep = centries; ! 159: ecp = ¢ries[NCUM]; ! 160: for (cep = centries; cep < ecp; cep++) ! 161: cep->c_nblocks = BADSIZE; ! 162: } else { ! 163: line = alloc(1000); ! 164: readino = 0; ! 165: } ! 166: } ! 167: ! 168: /* ! 169: * Routine run between filesystems ! 170: * to clean up allocated storage. ! 171: * Also may print out tables. ! 172: */ ! 173: quotterm() ! 174: { ! 175: if (fentries != NULL) { ! 176: register FENTRY *fep; ! 177: long totblocks = 0; ! 178: long totfiles = 0; ! 179: ! 180: qsort((char *)fentries, nuids, sizeof(FENTRY), fcomp); ! 181: for (fep=fentries; fep < efp; fep++) { ! 182: if (fep->f_uid == BADUID) ! 183: break; ! 184: if (tflag) { ! 185: totblocks += fep->f_nblocks; ! 186: totfiles += fep->f_nfiles; ! 187: } ! 188: if (fflag) ! 189: printf("%8ld ", fep->f_nfiles); ! 190: printf("%8ld %s\n", fep->f_nblocks, ! 191: username(fep->f_uid)); ! 192: } ! 193: if (tflag) { ! 194: if (fflag) ! 195: printf("%8ld ", totfiles); ! 196: printf("%8ld Total\n", totblocks); ! 197: } ! 198: free((char *)fentries); ! 199: fentries = NULL; ! 200: } else if (centries != NULL) { ! 201: register CENTRY *cep; ! 202: long cumblocks = 0; ! 203: ! 204: qsort((char *)centries, lastcep-centries, sizeof(CENTRY), ccomp); ! 205: for (cep = centries; cep < lastcep; cep++) { ! 206: if (cep->c_nblocks == BADSIZE) ! 207: break; ! 208: cumblocks += cep->c_nblocks*cep->c_nfiles; ! 209: printf("%8ld %8ld %10ld\n", cep->c_nblocks, ! 210: cep->c_nfiles, cumblocks); ! 211: } ! 212: free((char *)centries); ! 213: centries = NULL; ! 214: } ! 215: } ! 216: ! 217: /* ! 218: * Called for each filesystem that is read. ! 219: */ ! 220: quot(fsfd, fs) ! 221: int fsfd; ! 222: char *fs; ! 223: { ! 224: register ino_t maxino; ! 225: register ino_t inum; ! 226: ! 227: { ! 228: register struct filsys *sbp; ! 229: ! 230: lseek(fsfd, (fsize_t)(SUPERI*BSIZE), 0); ! 231: if (read(fsfd, ibuf, BSIZE) != BSIZE) ! 232: cerr("%s: bad filesystem format", fs); ! 233: sbp = ibuf; ! 234: canshort(sbp->s_isize); ! 235: candaddr(sbp->s_fsize); ! 236: if (sbp->s_isize > sbp->s_fsize) { ! 237: cwarn("%s: ridiculous fsize/isize", fs); ! 238: return (1); ! 239: } ! 240: maxino = (sbp->s_isize-INODEI) * INOPB; ! 241: } ! 242: lseek(fsfd, (fsize_t)(INODEI*BSIZE), 0); ! 243: inum = 0; ! 244: for (;;) { ! 245: register struct dinode *ip; ! 246: ! 247: if (read(fsfd, ibuf, sizeof ibuf) <= 0) { ! 248: cwarn("%s: i-node read error", fs); ! 249: return (1); ! 250: } ! 251: for (ip=ibuf; ip < &ibuf[NIREAD]; ip++) { ! 252: if (inum++ >= maxino) ! 253: break; ! 254: canshort(ip->di_uid); ! 255: canshort(ip->di_mode); ! 256: cansize(ip->di_size); ! 257: if (ilook(ip, inum)) ! 258: return (0); ! 259: } ! 260: if (inum > maxino) ! 261: break; ! 262: } ! 263: return (0); ! 264: } ! 265: ! 266: /* ! 267: * Routine that looks at every I-node ! 268: * that we find. ! 269: * Return 1 for premature end. ! 270: */ ! 271: ilook(ip, ino) ! 272: register struct dinode *ip; ! 273: register ino_t ino; ! 274: { ! 275: ! 276: if (ip->di_mode == 0) ! 277: return (0); ! 278: if (nflag) { ! 279: register char *lp; ! 280: ! 281: while (ino > readino) { ! 282: if (gets(line) == NULL) ! 283: return (1); ! 284: for (lp=line; *lp==' ' || *lp=='\t'; lp++) ! 285: ; ! 286: if (!isdigit(*lp)) ! 287: continue; ! 288: readino = atoi(lp); ! 289: while (isdigit(*lp)) ! 290: lp++; ! 291: while (*lp==' ' || *lp=='\t') ! 292: lp++; ! 293: readfile = lp; ! 294: } ! 295: if (readino == ino) ! 296: printf("%-16s %s\n", username(ip->di_uid), readfile); ! 297: } else if (cflag) { ! 298: register CENTRY *cep; ! 299: long size; ! 300: ! 301: size = (ip->di_size+BSIZE-1)/BSIZE; ! 302: cep = getcentry(size); ! 303: cep->c_nfiles++; ! 304: } else { ! 305: register FENTRY *fep; ! 306: ! 307: fep = getfentry(ip->di_uid); ! 308: fep->f_nfiles++; ! 309: switch (ip->di_mode & IFMT) { ! 310: case IFREG: ! 311: case IFDIR: ! 312: fep->f_nblocks += (ip->di_size+BSIZE-1)/BSIZE; ! 313: break; ! 314: } ! 315: } ! 316: return (0); ! 317: } ! 318: ! 319: /* ! 320: * Using hashing from a large pool, ! 321: * return a pointer to where the FENTRY ! 322: * for that uid was put or created. ! 323: * The table has to be contiguous for sorting. ! 324: */ ! 325: FENTRY * ! 326: getfentry(uid) ! 327: register short unsigned uid; ! 328: { ! 329: register FENTRY *fep; ! 330: ! 331: fep = &fentries[(uid<<1)%nuids]; ! 332: for (;;) { ! 333: if (fep >= efp) ! 334: fep = fentries; ! 335: if (fep->f_uid == uid) ! 336: return (fep); ! 337: if (fep->f_uid == BADUID) { ! 338: fep->f_uid = uid; ! 339: return (fep); ! 340: } ! 341: fep++; ! 342: } ! 343: } ! 344: ! 345: /* ! 346: * Return a CENTRY for a particular file size. ! 347: * This is hashed much like the FENTRY code ! 348: * above. ! 349: */ ! 350: CENTRY * ! 351: getcentry(nb) ! 352: long nb; ! 353: { ! 354: register CENTRY *cep; ! 355: ! 356: cep = ¢ries[((unsigned)nb<<1)%NCUM]; ! 357: for (;;) { ! 358: if (cep >= ecp) ! 359: cep = centries; ! 360: if (cep->c_nblocks == nb) ! 361: return (cep); ! 362: if (cep->c_nblocks == BADSIZE) { ! 363: cep->c_nblocks = nb; ! 364: if (cep > lastcep) ! 365: lastcep = cep+1; ! 366: return (cep); ! 367: } ! 368: cep++; ! 369: } ! 370: } ! 371: ! 372: /* ! 373: * Read all of the names from `/etc/passwd' ! 374: * and build up a hash table. ! 375: * Duplicates are discarded. ! 376: */ ! 377: readnames() ! 378: { ! 379: register NAME *np; ! 380: register unsigned short hash; ! 381: register struct passwd *pwp; ! 382: ! 383: while ((pwp = getpwent()) != NULL) { ! 384: hash = pwp->pw_uid%NHASH; ! 385: for (np = names[hash]; np != NULL; np = np->n_next) ! 386: if (np->n_uid == pwp->pw_uid) ! 387: break; ! 388: if (np == NULL) { ! 389: nuids++; ! 390: np = (NAME*)alloc(sizeof(NAME)+strlen(pwp->pw_name)+1); ! 391: strcpy(np->n_name, pwp->pw_name); ! 392: np->n_uid = pwp->pw_uid; ! 393: np->n_next = names[hash]; ! 394: names[hash] = np; ! 395: } ! 396: } ! 397: endpwent(); ! 398: } ! 399: ! 400: /* ! 401: * Return user name for a particular number. ! 402: * Names that are not located are given the string ! 403: * representation of the number. ! 404: */ ! 405: char * ! 406: username(uid) ! 407: unsigned short uid; ! 408: { ! 409: register NAME *np; ! 410: static char buf[12]; ! 411: ! 412: for (np = names[uid%NHASH]; np != NULL; np = np->n_next) ! 413: if (np->n_uid == uid) ! 414: return (np->n_name); ! 415: return (sprintf(buf, "%u", uid)); ! 416: } ! 417: ! 418: /* ! 419: * Comparison routine for no options ! 420: * and `-f'. Sort by # blocks, then ! 421: * # files. ! 422: */ ! 423: fcomp(fep1, fep2) ! 424: register FENTRY *fep1, *fep2; ! 425: { ! 426: if (fep1->f_nblocks < fep2->f_nblocks) ! 427: return (1); ! 428: if (fep1->f_nblocks > fep2->f_nblocks) ! 429: return (-1); ! 430: if (fep1->f_nfiles < fep2->f_nfiles) ! 431: return (1); ! 432: if (fep1->f_nfiles > fep2->f_nfiles) ! 433: return (-1); ! 434: return (0); ! 435: } ! 436: ! 437: /* ! 438: * Sort comparison routine for the ! 439: * `-c' (cumulative size table) ! 440: * option. ! 441: */ ! 442: ccomp(cep1, cep2) ! 443: register CENTRY *cep1, *cep2; ! 444: { ! 445: if (cep1->c_nblocks < cep2->c_nblocks) ! 446: return (-1); ! 447: if (cep1->c_nblocks > cep2->c_nblocks) ! 448: return (1); ! 449: return (0); ! 450: } ! 451: ! 452: /* ! 453: * Call allocator and check for errors. ! 454: */ ! 455: char * ! 456: alloc(nb) ! 457: register unsigned nb; ! 458: { ! 459: register char *ap; ! 460: ! 461: if ((ap = calloc(nb, 1)) == NULL) ! 462: cerr("out of memory"); ! 463: return (ap); ! 464: } ! 465: ! 466: /* ! 467: * Errors and usage message. ! 468: */ ! 469: /* VARARGS */ ! 470: cerr(x) ! 471: { ! 472: fprintf(stderr, "quot: %r\n", &x); ! 473: exit(1); ! 474: } ! 475: ! 476: cwarn(x) ! 477: { ! 478: fprintf(stderr, "quot: %r\n", &x); ! 479: exit(1); ! 480: } ! 481: ! 482: usage() ! 483: { ! 484: fprintf(stderr, "Usage: quot [-n] [-c] [-ft] filesystem [ ... ]\n"); ! 485: exit(1); ! 486: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.