Annotation of coherent/d/bin/quot.c, revision 1.1.1.1

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 = &centries[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 = &centries[((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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.