Annotation of 43BSDReno/sbin/quotacheck/quotacheck.c, revision 1.1.1.1

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
                      9:  * provided that: (1) source distributions retain this entire copyright
                     10:  * notice and comment, and (2) distributions including binaries display
                     11:  * the following acknowledgement:  ``This product includes software
                     12:  * developed by the University of California, Berkeley and its contributors''
                     13:  * in the documentation or other materials provided with the distribution
                     14:  * and in all advertising materials mentioning features or use of this
                     15:  * software. Neither the name of the University nor the names of its
                     16:  * contributors may be used to endorse or promote products derived
                     17:  * from this software without specific prior written permission.
                     18:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
                     19:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
                     20:  * WARRANTIES OF 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[] = "@(#)quotacheck.c       5.14 (Berkeley) 6/1/90";
                     31: #endif /* not lint */
                     32: 
                     33: /*
                     34:  * Fix up / report on disk quotas & usage
                     35:  */
                     36: #include <sys/param.h>
                     37: #include <ufs/dinode.h>
                     38: #include <ufs/fs.h>
                     39: #include <ufs/quota.h>
                     40: #include <fstab.h>
                     41: #include <pwd.h>
                     42: #include <grp.h>
                     43: #include <stdio.h>
                     44: #include <errno.h>
                     45: 
                     46: union {
                     47:        struct  fs      sblk;
                     48:        char    dummy[MAXBSIZE];
                     49: } un;
                     50: #define        sblock  un.sblk
                     51: long dev_bsize = 1;
                     52: long maxino;
                     53: 
                     54: struct quotaname {
                     55:        long    flags;
                     56:        char    grpqfname[MAXPATHLEN + 1];
                     57:        char    usrqfname[MAXPATHLEN + 1];
                     58: };
                     59: #define        HASUSR  1
                     60: #define        HASGRP  2
                     61: 
                     62: struct fileusage {
                     63:        struct  fileusage *fu_next;
                     64:        u_long  fu_curinodes;
                     65:        u_long  fu_curblocks;
                     66:        u_long  fu_id;
                     67:        char    fu_name[1];
                     68:        /* actually bigger */
                     69: };
                     70: #define FUHASH 1024    /* must be power of two */
                     71: struct fileusage *fuhead[MAXQUOTAS][FUHASH];
                     72: struct fileusage *lookup();
                     73: struct fileusage *addid();
                     74: struct dinode *getnextinode();
                     75: 
                     76: int    aflag;                  /* all file systems */
                     77: int    gflag;                  /* check group quotas */
                     78: int    uflag;                  /* check user quotas */
                     79: int    vflag;                  /* verbose */
                     80: int    fi;                     /* open disk file descriptor */
                     81: u_long highid[MAXQUOTAS];      /* highest addid()'ed identifier per type */
                     82: 
                     83: main(argc, argv)
                     84:        int argc;
                     85:        char **argv;
                     86: {
                     87:        register struct fstab *fs;
                     88:        register struct passwd *pw;
                     89:        register struct group *gr;
                     90:        int i, argnum, maxrun, errs = 0;
                     91:        long auxdata, done = 0;
                     92:        char ch, *name, *blockcheck();
                     93:        int needchk(), chkquota();
                     94:        extern char *optarg;
                     95:        extern int optind;
                     96: 
                     97:        while ((ch = getopt(argc, argv, "aguvl:")) != EOF) {
                     98:                switch(ch) {
                     99:                case 'a':
                    100:                        aflag++;
                    101:                        break;
                    102:                case 'g':
                    103:                        gflag++;
                    104:                        break;
                    105:                case 'u':
                    106:                        uflag++;
                    107:                        break;
                    108:                case 'v':
                    109:                        vflag++;
                    110:                        break;
                    111:                case 'l':
                    112:                        maxrun = atoi(optarg);
                    113:                        break;
                    114:                default:
                    115:                        usage();
                    116:                }
                    117:        }
                    118:        argc -= optind;
                    119:        argv += optind;
                    120:        if ((argc == 0 && !aflag) || (argc > 0 && aflag))
                    121:                usage();
                    122:        if (!gflag && !uflag) {
                    123:                gflag++;
                    124:                uflag++;
                    125:        }
                    126:        if (gflag) {
                    127:                setgrent();
                    128:                while ((gr = getgrent()) != 0)
                    129:                        (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name);
                    130:                endgrent();
                    131:        }
                    132:        if (uflag) {
                    133:                setpwent();
                    134:                while ((pw = getpwent()) != 0)
                    135:                        (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name);
                    136:                endpwent();
                    137:        }
                    138:        if (aflag)
                    139:                exit(checkfstab(1, maxrun, needchk, chkquota));
                    140:        if (setfsent() == 0) {
                    141:                fprintf(stderr, "Can't open ");
                    142:                perror(FSTAB);
                    143:                exit(8);
                    144:        }
                    145:        while ((fs = getfsent()) != NULL) {
                    146:                if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
                    147:                    (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) &&
                    148:                    (auxdata = needchk(fs)) &&
                    149:                    (name = blockcheck(fs->fs_spec))) {
                    150:                        done |= 1 << argnum;
                    151:                        errs += chkquota(name, fs->fs_file, auxdata);
                    152:                }
                    153:        }
                    154:        endfsent();
                    155:        for (i = 0; i < argc; i++)
                    156:                if ((done & (1 << i)) == 0)
                    157:                        fprintf(stderr, "%s not found in %s\n",
                    158:                                argv[i], FSTAB);
                    159:        exit(errs);
                    160: }
                    161: 
                    162: usage()
                    163: {
                    164: 
                    165:        fprintf(stderr, "Usage:\n\t%s\n\t%s\n",
                    166:                "quotacheck [-g] [-u] [-v] -a",
                    167:                "quotacheck [-g] [-u] [-v] filesys ...");
                    168:        exit(1);
                    169: }
                    170: 
                    171: needchk(fs)
                    172:        register struct fstab *fs;
                    173: {
                    174:        register struct quotaname *qnp;
                    175:        char *qfnp;
                    176: 
                    177:        if (strcmp(fs->fs_vfstype, "ufs") ||
                    178:            strcmp(fs->fs_type, FSTAB_RW))
                    179:                return (0);
                    180:        if ((qnp = (struct quotaname *)malloc(sizeof *qnp)) == 0) {
                    181:                fprintf(stderr, "out of memory for quota structures\n");
                    182:                exit(1);
                    183:        }
                    184:        qnp->flags = 0;
                    185:        if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) {
                    186:                strcpy(qnp->grpqfname, qfnp);
                    187:                qnp->flags |= HASGRP;
                    188:        }
                    189:        if (uflag && hasquota(fs, USRQUOTA, &qfnp)) {
                    190:                strcpy(qnp->usrqfname, qfnp);
                    191:                qnp->flags |= HASUSR;
                    192:        }
                    193:        if (qnp->flags)
                    194:                return ((int)qnp);
                    195:        free((char *)qnp);
                    196:        return (0);
                    197: }
                    198: 
                    199: /*
                    200:  * Scan the specified filesystem to check quota(s) present on it.
                    201:  */
                    202: chkquota(fsname, mntpt, qnp)
                    203:        char *fsname, *mntpt;
                    204:        register struct quotaname *qnp;
                    205: {
                    206:        register struct fileusage *fup;
                    207:        register struct dinode *dp;
                    208:        int cg, i, mode, errs = 0;
                    209:        ino_t ino;
                    210: 
                    211:        if ((fi = open(fsname, 0)) < 0) {
                    212:                perror(fsname);
                    213:                return (1);
                    214:        }
                    215:        if (vflag) {
                    216:                fprintf(stdout, "*** Checking ");
                    217:                if (qnp->flags & HASUSR)
                    218:                        fprintf(stdout, "%s%s", qfextension[USRQUOTA],
                    219:                            (qnp->flags & HASGRP) ? " and " : "");
                    220:                if (qnp->flags & HASGRP)
                    221:                        fprintf(stdout, "%s", qfextension[GRPQUOTA]);
                    222:                fprintf(stdout, " quotas for %s (%s)\n", fsname, mntpt);
                    223:        }
                    224:        sync();
                    225:        bread(SBOFF, (char *)&sblock, (long)SBSIZE);
                    226:        dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
                    227:        maxino = sblock.fs_ncg * sblock.fs_ipg;
                    228:        resetinodebuf();
                    229:        for (ino = 0, cg = 0; cg < sblock.fs_ncg; cg++) {
                    230:                for (i = 0; i < sblock.fs_ipg; i++, ino++) {
                    231:                        if (ino < ROOTINO)
                    232:                                continue;
                    233:                        if ((dp = getnextinode(ino)) == NULL)
                    234:                                continue;
                    235:                        if ((mode = dp->di_mode & IFMT) == 0)
                    236:                                continue;
                    237:                        if (qnp->flags & HASGRP) {
                    238:                                fup = addid((u_long)dp->di_gid, GRPQUOTA,
                    239:                                    (char *)0);
                    240:                                fup->fu_curinodes++;
                    241:                                if (mode == IFREG || mode == IFDIR ||
                    242:                                    mode == IFLNK)
                    243:                                        fup->fu_curblocks += dp->di_blocks;
                    244:                        }
                    245:                        if (qnp->flags & HASUSR) {
                    246:                                fup = addid((u_long)dp->di_uid, USRQUOTA,
                    247:                                    (char *)0);
                    248:                                fup->fu_curinodes++;
                    249:                                if (mode == IFREG || mode == IFDIR ||
                    250:                                    mode == IFLNK)
                    251:                                        fup->fu_curblocks += dp->di_blocks;
                    252:                        }
                    253:                }
                    254:        }
                    255:        freeinodebuf();
                    256:        if (qnp->flags & HASUSR)
                    257:                errs += update(mntpt, qnp->usrqfname, USRQUOTA);
                    258:        if (qnp->flags & HASGRP)
                    259:                errs += update(mntpt, qnp->grpqfname, GRPQUOTA);
                    260:        close(fi);
                    261:        return (errs);
                    262: }
                    263: 
                    264: /*
                    265:  * Update a specified quota file.
                    266:  */
                    267: update(fsname, quotafile, type)
                    268:        char *fsname, *quotafile;
                    269:        register int type;
                    270: {
                    271:        register struct fileusage *fup;
                    272:        register FILE *qfi, *qfo;
                    273:        register u_long id, lastid;
                    274:        struct dqblk dqbuf;
                    275:        extern int errno;
                    276:        static int warned = 0;
                    277:        static struct dqblk zerodqbuf;
                    278:        static struct fileusage zerofileusage;
                    279: 
                    280:        if ((qfo = fopen(quotafile, "r+")) == NULL) {
                    281:                if (errno != ENOENT) {
                    282:                        perror(quotafile);
                    283:                        return (1);
                    284:                }
                    285:                if ((qfo = fopen(quotafile, "w+")) == NULL) {
                    286:                        perror(quotafile);
                    287:                        return (1);
                    288:                }
                    289:                fprintf(stderr, "Creating quota file %s\n", quotafile);
                    290:                (void) fchown(fileno(qfo), getuid(), getquotagid());
                    291:                (void) fchmod(fileno(qfo), 0640);
                    292:        }
                    293:        if ((qfi = fopen(quotafile, "r")) == NULL) {
                    294:                perror(quotafile);
                    295:                fclose(qfo);
                    296:                return (1);
                    297:        }
                    298:        if (quotactl(fsname, QCMD(Q_SYNC, type), (u_long)0, (caddr_t)0) < 0 &&
                    299:            errno == EOPNOTSUPP && !warned && vflag) {
                    300:                warned++;
                    301:                fprintf(stdout, "*** Warning: %s\n",
                    302:                    "Quotas are not compiled into this kernel");
                    303:        }
                    304:        for (lastid = highid[type], id = 0; id <= lastid; id++) {
                    305:                if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0)
                    306:                        dqbuf = zerodqbuf;
                    307:                if ((fup = lookup(id, type)) == 0)
                    308:                        fup = &zerofileusage;
                    309:                if (dqbuf.dqb_curinodes == fup->fu_curinodes &&
                    310:                    dqbuf.dqb_curblocks == fup->fu_curblocks) {
                    311:                        fup->fu_curinodes = 0;
                    312:                        fup->fu_curblocks = 0;
                    313:                        fseek(qfo, (long)sizeof(struct dqblk), 1);
                    314:                        continue;
                    315:                }
                    316:                if (vflag) {
                    317:                        if (aflag)
                    318:                                printf("%s: ", fsname);
                    319:                        printf("%-8s fixed:", fup->fu_name);
                    320:                        if (dqbuf.dqb_curinodes != fup->fu_curinodes)
                    321:                                fprintf(stdout, "\tinodes %d -> %d",
                    322:                                        dqbuf.dqb_curinodes, fup->fu_curinodes);
                    323:                        if (dqbuf.dqb_curblocks != fup->fu_curblocks)
                    324:                                fprintf(stdout, "\tblocks %d -> %d",
                    325:                                        dqbuf.dqb_curblocks, fup->fu_curblocks);
                    326:                        fprintf(stdout, "\n");
                    327:                }
                    328:                /*
                    329:                 * Reset time limit if have a soft limit and were
                    330:                 * previously under it, but are now over it.
                    331:                 */
                    332:                if (dqbuf.dqb_bsoftlimit &&
                    333:                    dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit &&
                    334:                    fup->fu_curblocks >= dqbuf.dqb_bsoftlimit)
                    335:                        dqbuf.dqb_btime = 0;
                    336:                if (dqbuf.dqb_isoftlimit &&
                    337:                    dqbuf.dqb_curblocks < dqbuf.dqb_isoftlimit &&
                    338:                    fup->fu_curblocks >= dqbuf.dqb_isoftlimit)
                    339:                        dqbuf.dqb_itime = 0;
                    340:                dqbuf.dqb_curinodes = fup->fu_curinodes;
                    341:                dqbuf.dqb_curblocks = fup->fu_curblocks;
                    342:                fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo);
                    343:                (void) quotactl(fsname, QCMD(Q_SETUSE, type), id,
                    344:                    (caddr_t)&dqbuf);
                    345:                fup->fu_curinodes = 0;
                    346:                fup->fu_curblocks = 0;
                    347:        }
                    348:        fclose(qfi);
                    349:        fflush(qfo);
                    350:        ftruncate(fileno(qfo),
                    351:            (off_t)((highid[type] + 1) * sizeof(struct dqblk)));
                    352:        fclose(qfo);
                    353:        return (0);
                    354: }
                    355: 
                    356: /*
                    357:  * Check to see if target appears in list of size cnt.
                    358:  */
                    359: oneof(target, list, cnt)
                    360:        register char *target, *list[];
                    361:        int cnt;
                    362: {
                    363:        register int i;
                    364: 
                    365:        for (i = 0; i < cnt; i++)
                    366:                if (strcmp(target, list[i]) == 0)
                    367:                        return (i);
                    368:        return (-1);
                    369: }
                    370: 
                    371: /*
                    372:  * Determine the group identifier for quota files.
                    373:  */
                    374: getquotagid()
                    375: {
                    376:        struct group *gr;
                    377: 
                    378:        if (gr = getgrnam(quotagroup))
                    379:                return (gr->gr_gid);
                    380:        return (-1);
                    381: }
                    382: 
                    383: /*
                    384:  * Check to see if a particular quota is to be enabled.
                    385:  */
                    386: hasquota(fs, type, qfnamep)
                    387:        register struct fstab *fs;
                    388:        int type;
                    389:        char **qfnamep;
                    390: {
                    391:        register char *opt;
                    392:        char *cp, *index(), *strtok();
                    393:        static char initname, usrname[100], grpname[100];
                    394:        static char buf[BUFSIZ];
                    395: 
                    396:        if (!initname) {
                    397:                sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname);
                    398:                sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname);
                    399:                initname = 1;
                    400:        }
                    401:        strcpy(buf, fs->fs_mntops);
                    402:        for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
                    403:                if (cp = index(opt, '='))
                    404:                        *cp++ = '\0';
                    405:                if (type == USRQUOTA && strcmp(opt, usrname) == 0)
                    406:                        break;
                    407:                if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
                    408:                        break;
                    409:        }
                    410:        if (!opt)
                    411:                return (0);
                    412:        if (cp) {
                    413:                *qfnamep = cp;
                    414:                return (1);
                    415:        }
                    416:        (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
                    417:        *qfnamep = buf;
                    418:        return (1);
                    419: }
                    420: 
                    421: /*
                    422:  * Routines to manage the file usage table.
                    423:  *
                    424:  * Lookup an id of a specific type.
                    425:  */
                    426: struct fileusage *
                    427: lookup(id, type)
                    428:        u_long id;
                    429:        int type;
                    430: {
                    431:        register struct fileusage *fup;
                    432: 
                    433:        for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next)
                    434:                if (fup->fu_id == id)
                    435:                        return (fup);
                    436:        return ((struct fileusage *)0);
                    437: }
                    438: 
                    439: /*
                    440:  * Add a new file usage id if it does not already exist.
                    441:  */
                    442: struct fileusage *
                    443: addid(id, type, name)
                    444:        u_long id;
                    445:        int type;
                    446:        char *name;
                    447: {
                    448:        struct fileusage *fup, **fhp;
                    449:        int len;
                    450:        extern char *calloc();
                    451: 
                    452:        if (fup = lookup(id, type))
                    453:                return (fup);
                    454:        if (name)
                    455:                len = strlen(name);
                    456:        else
                    457:                len = 10;
                    458:        if ((fup = (struct fileusage *)calloc(1, sizeof(*fup) + len)) == NULL) {
                    459:                fprintf(stderr, "out of memory for fileusage structures\n");
                    460:                exit(1);
                    461:        }
                    462:        fhp = &fuhead[type][id & (FUHASH - 1)];
                    463:        fup->fu_next = *fhp;
                    464:        *fhp = fup;
                    465:        fup->fu_id = id;
                    466:        if (id > highid[type])
                    467:                highid[type] = id;
                    468:        if (name) {
                    469:                bcopy(name, fup->fu_name, len + 1);
                    470:        } else {
                    471:                sprintf(fup->fu_name, "%u", id);
                    472:        }
                    473:        return (fup);
                    474: }
                    475: 
                    476: /*
                    477:  * Special purpose version of ginode used to optimize pass
                    478:  * over all the inodes in numerical order.
                    479:  */
                    480: ino_t nextino, lastinum;
                    481: long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
                    482: struct dinode *inodebuf;
                    483: #define        INOBUFSIZE      56*1024 /* size of buffer to read inodes */
                    484: 
                    485: struct dinode *
                    486: getnextinode(inumber)
                    487:        ino_t inumber;
                    488: {
                    489:        long size;
                    490:        daddr_t dblk;
                    491:        static struct dinode *dp;
                    492: 
                    493:        if (inumber != nextino++ || inumber > maxino) {
                    494:                fprintf(stderr, "bad inode number %d to nextinode\n", inumber);
                    495:                exit(1);
                    496:        }
                    497:        if (inumber >= lastinum) {
                    498:                readcnt++;
                    499:                dblk = fsbtodb(&sblock, itod(&sblock, lastinum));
                    500:                if (readcnt % readpercg == 0) {
                    501:                        size = partialsize;
                    502:                        lastinum += partialcnt;
                    503:                } else {
                    504:                        size = inobufsize;
                    505:                        lastinum += fullcnt;
                    506:                }
                    507:                bread(dblk, (char *)inodebuf, size);
                    508:                dp = inodebuf;
                    509:        }
                    510:        return (dp++);
                    511: }
                    512: 
                    513: /*
                    514:  * Prepare to scan a set of inodes.
                    515:  */
                    516: resetinodebuf()
                    517: {
                    518: 
                    519:        nextino = 0;
                    520:        lastinum = 0;
                    521:        readcnt = 0;
                    522:        inobufsize = blkroundup(&sblock, INOBUFSIZE);
                    523:        fullcnt = inobufsize / sizeof(struct dinode);
                    524:        readpercg = sblock.fs_ipg / fullcnt;
                    525:        partialcnt = sblock.fs_ipg % fullcnt;
                    526:        partialsize = partialcnt * sizeof(struct dinode);
                    527:        if (partialcnt != 0) {
                    528:                readpercg++;
                    529:        } else {
                    530:                partialcnt = fullcnt;
                    531:                partialsize = inobufsize;
                    532:        }
                    533:        if (inodebuf == NULL &&
                    534:           (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) {
                    535:                fprintf(stderr, "Cannot allocate space for inode buffer\n");
                    536:                exit(1);
                    537:        }
                    538:        while (nextino < ROOTINO)
                    539:                getnextinode(nextino);
                    540: }
                    541: 
                    542: /*
                    543:  * Free up data structures used to scan inodes.
                    544:  */
                    545: freeinodebuf()
                    546: {
                    547: 
                    548:        if (inodebuf != NULL)
                    549:                free((char *)inodebuf);
                    550:        inodebuf = NULL;
                    551: }
                    552: 
                    553: /*
                    554:  * Read specified disk blocks.
                    555:  */
                    556: bread(bno, buf, cnt)
                    557:        daddr_t bno;
                    558:        char *buf;
                    559:        long cnt;
                    560: {
                    561: 
                    562:        if (lseek(fi, bno * dev_bsize, 0) < 0) {
                    563:                perror("lseek");
                    564:                exit(1);
                    565:        }
                    566: 
                    567:        if (read(fi, buf, cnt) != cnt) {
                    568:                perror("read");
                    569:                exit(1);
                    570:        }
                    571: }

unix.superglobalmegacorp.com

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