# 2.11BSD#431 - /usr/src/sbin/quotacheck/quotacheck.c

##### Functions

    addid             X
    bread             X
    chkquota          X
    freeinodebuf      X
    getnextinode      X
    getquotagid       X
    hasquota          X
    lookup            X
    main              X
    needchk           X
    oneof             X
    resetinodebuf     X
    update            X
    usage             X

##### Variables

    aflag             X
    fi                X
    fuhead            X
    highid            X
    inobufsize        X
    inodebuf          X
    lastinum          X
    maxino            X
    nextino           X
    qfname            X
    quotagroup        X
    vflag             X

##### Macros

    FUHASH            X
    HASUSR            X
    INOBUFSIZE        X
    sblock            X

##### struct's

    fileusage         X
    quotaname         X

       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[] = "@(#)quotacheck.c	8.3.1 (2.11BSD) 1996/1/23";
      43: #endif /* not lint */
      44:
      45: /*
      46:  * Fix up / report on disk quotas & usage
      47:  */
      48: #include <sys/param.h>
      49: #include <sys/stat.h>
      50:
      51: #include <sys/inode.h>
      52: #include <sys/quota.h>
      53: #include <sys/fs.h>
      54:
      55: #include <fcntl.h>
      56: #include <fstab.h>
      57: #include <pwd.h>
      58: #include <grp.h>
      59: #include <errno.h>
      60: #include <unistd.h>
      61: #include <stdio.h>
      62: #include <stdlib.h>
      63: #include <string.h>
      64:
      65: char *qfname = QUOTAFILENAME;
      66: char *quotagroup = QUOTAGROUP;
      67:
      68: union {
      69:     struct  fs  sblk;
      70:     char    dummy[MAXBSIZE];
      71: } un;
      72: #define sblock  un.sblk
      73: ino_t maxino;
      74:
      75: struct quotaname {
      76:     char    flags;
      77:     char    usrqfname[MAXPATHLEN + 1];
      78: };
      79: #define HASUSR  1
      80:
      81: struct fileusage {
      82:     struct  fileusage *fu_next;
      83:     ino_t   fu_curinodes;
      84:     u_long  fu_curblocks;
      85:     uid_t   fu_id;
      86:     char    fu_name[1];
      87:     /* actually bigger */
      88: };
      89: #define FUHASH 256  /* must be power of two */
      90: struct fileusage *fuhead[FUHASH];
      91:
      92: int aflag;          /* all file systems */
      93: int vflag;          /* verbose */
      94: int fi;         /* open disk file descriptor */
      95: uid_t   highid;         /* highest addid()'ed identifier */
      96:
      97: struct fileusage *addid();
      98: char    *blockcheck();
      99: void    bread();
     100: int chkquota();
     101: void    freeinodebuf();
     102: struct  dinode *getnextinode();
     103: gid_t    getquotagid();
     104: int  hasquota();
     105: struct fileusage *lookup();
     106: void    *needchk();
     107: int  oneof();
     108: void     resetinodebuf();
     109: int  update();
     110: void     usage();
     111:
     112: int
     113: main(argc, argv)
     114:     int argc;
     115:     char *argv[];
     116: {
     117:     register struct fstab *fs;
     118:     register struct passwd *pw;
     119:     struct quotaname *auxdata;
     120:     int i, argnum, maxrun, errs, ch;
     121:     long done = 0;
     122:     char *name;
     123:
     124:     errs = maxrun = 0;
     125:     while ((ch = getopt(argc, argv, "avl:")) != EOF) {
     126:         switch(ch) {
     127:         case 'a':
     128:             aflag++;
     129:             break;
     130:         case 'v':
     131:             vflag++;
     132:             break;
     133:         case 'l':
     134:             maxrun = atoi(optarg);
     135:             break;
     136:         default:
     137:             usage();
     138:         }
     139:     }
     140:     argc -= optind;
     141:     argv += optind;
     142:     if ((argc == 0 && !aflag) || (argc > 0 && aflag))
     143:         usage();
     144:
     145:     setpwent();
     146:     while ((pw = getpwent()) != 0)
     147:         (void) addid(pw->pw_uid, pw->pw_name);
     148:     endpwent();
     149:
     150:     if (aflag)
     151:         exit(checkfstab(1, maxrun, needchk, chkquota));
     152:     if (setfsent() == 0)
     153:         err(1, "can't open %s", FSTAB);
     154:     while ((fs = getfsent()) != NULL) {
     155:         if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
     156:             (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) &&
     157:             (auxdata = (struct quotaname *)needchk(fs)) &&
     158:             (name = blockcheck(fs->fs_spec))) {
     159:             done |= 1 << argnum;
     160:             errs += chkquota(name, fs->fs_file, auxdata);
     161:         }
     162:     }
     163:     endfsent();
     164:     for (i = 0; i < argc; i++)
     165:         if ((done & (1 << i)) == 0)
     166:             warn("%s not found in %s", argv[i], FSTAB);
     167:     exit(errs);
     168: }
     169:
     170: void
     171: usage()
     172: {
     173:     (void)err(1, "usage:\t%s\n\t%s\n",
     174:         "quotacheck -a [-v] [-l num]",
     175:         "quotacheck [-v] filesys ...");
     176: /* NOTREACHED */
     177: }
     178:
     179: void *
     180: needchk(fs)
     181:     register struct fstab *fs;
     182: {
     183:     register struct quotaname *qnp;
     184:     char *qfnp;
     185:
     186:     if (strcmp(fs->fs_vfstype, "ufs") ||
     187:         (strcmp(fs->fs_type, FSTAB_RW) && strcmp(fs->fs_type, FSTAB_RQ)))
     188:         return ((void *)NULL);
     189:     if ((qnp = (struct quotaname *)malloc(sizeof(*qnp))) == NULL)
     190:         nomem();
     191:     qnp->flags = 0;
     192:     if (hasquota(fs, &qfnp)) {
     193:         strcpy(qnp->usrqfname, qfnp);
     194:         qnp->flags |= HASUSR;
     195:     }
     196:     if (qnp->flags)
     197:         return ((void *)qnp);
     198:     free(qnp);
     199:     return ((void *)NULL);
     200: }
     201:
     202: /*
     203:  * Scan the specified filesystem to check quota(s) present on it.
     204:  */
     205: int
     206: chkquota(fsname, mntpt, qnp)
     207:     char *fsname, *mntpt;
     208:     register struct quotaname *qnp;
     209: {
     210:     register struct fileusage *fup;
     211:     register struct dinode *dp;
     212:     int mode, errs = 0;
     213:     ino_t ino;
     214:
     215:     if ((fi = open(fsname, O_RDONLY, 0)) < 0) {
     216:         perror(fsname);
     217:         return (1);
     218:     }
     219:     if (vflag)
     220:         (void)printf("*** Checking quotas for %s (%s)\n",
     221:             fsname, mntpt);
     222:     sync();
     223:     bread(SBLOCK, (char *)&sblock, SBSIZE);
     224:     maxino = (sblock.fs_isize - 2) * INOPB;
     225:     resetinodebuf();
     226:     for (ino = ROOTINO; ino < maxino; ino++) {
     227:         if ((dp = getnextinode(ino)) == NULL)
     228:             continue;
     229:         if ((mode = dp->di_mode & IFMT) == 0)
     230:             continue;
     231:         if (qnp->flags & HASUSR) {
     232:             fup = addid(dp->di_uid, (char *)0);
     233:             fup->fu_curinodes++;
     234:             if (mode == IFREG || mode == IFDIR || mode == IFLNK)
     235:                 fup->fu_curblocks += dp->di_size;
     236:         }
     237:     }
     238:     freeinodebuf();
     239:     if (qnp->flags & HASUSR)
     240:         errs += update(fsname, mntpt, qnp->usrqfname);
     241:     close(fi);
     242:     return (errs);
     243: }
     244:
     245: /*
     246:  * Update a specified quota file.
     247:  */
     248: int
     249: update(fsdev, fsname, quotafile)
     250:     char *fsdev, *fsname, *quotafile;
     251: {
     252:     register struct fileusage *fup;
     253:     register FILE *qfi, *qfo;
     254:     uid_t id, lastid;
     255:     struct dqblk dqbuf;
     256:     struct stat  statb;
     257:     struct dqusage dqu;
     258:     dev_t  quotadev;
     259:     static int warned = 0;
     260:     static struct dqblk zerodqbuf;
     261:     static struct fileusage zerofileusage;
     262:
     263:     if ((qfo = fopen(quotafile, "r+")) == NULL) {
     264:         if (errno == ENOENT)
     265:             qfo = fopen(quotafile, "w+");
     266:         if (qfo) {
     267:             (void) warn("creating quota file %s", quotafile);
     268:             (void) fchown(fileno(qfo), getuid(), getquotagid());
     269:             (void) fchmod(fileno(qfo), 0640);
     270:         } else {
     271:             (void) warn("%s: %s", quotafile, strerror(errno));
     272:             return (1);
     273:         }
     274:     }
     275:     if ((qfi = fopen(quotafile, "r")) == NULL) {
     276:         (void) warn("%s: %s", quotafile, strerror(errno));
     277:         (void) fclose(qfo);
     278:         return (1);
     279:     }
     280: /*
     281:  * We check that the quota file resides in the filesystem being checked.  This
     282:  * restriction is imposed by the kernel for now.
     283: */
     284:     fstat(fileno(qfi), &statb);
     285:     quotadev = statb.st_dev;
     286:     if (stat(unrawname(fsdev), &statb) < 0) {
     287:         warn("Can't stat %s", fsname);
     288:         fclose(qfi);
     289:         fclose(qfo);
     290:         return(1);
     291:     }
     292:     if (quotadev != statb.st_rdev)  {
     293:         warn("%s dev (0x%x) mismatch %s dev (0x%x)", quotafile,
     294:             quotadev, fsname, statb.st_rdev);
     295:         fclose(qfi);
     296:         fclose(qfo);
     297:         return(1);
     298:     }
     299:     if (quota(Q_SYNC, 0, quotadev, 0) < 0 &&
     300:         errno == EOPNOTSUPP && !warned && vflag) {
     301:         warned++;
     302:         (void)printf("*** Warning: %s\n",
     303:             "Quotas are not compiled into this kernel");
     304:     }
     305:     for (lastid = highid, id = 0; id <= lastid; id++) {
     306:         if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0)
     307:             dqbuf = zerodqbuf;
     308:         if ((fup = lookup(id)) == 0)
     309:             fup = &zerofileusage;
     310:         if (dqbuf.dqb_curinodes == fup->fu_curinodes &&
     311:             dqbuf.dqb_curblocks == fup->fu_curblocks) {
     312:             fup->fu_curinodes = 0;
     313:             fup->fu_curblocks = 0;
     314:             fseek(qfo, (long)sizeof(struct dqblk), 1);
     315:             continue;
     316:         }
     317:         if (vflag) {
     318:             if (aflag)
     319:                 printf("%s: ", fsname);
     320:             printf("%-8s fixed:", fup->fu_name);
     321:             if (dqbuf.dqb_curinodes != fup->fu_curinodes)
     322:                 (void)printf("\tinodes %u -> %u",
     323:                     dqbuf.dqb_curinodes, fup->fu_curinodes);
     324:             if (dqbuf.dqb_curblocks != fup->fu_curblocks)
     325:                 (void)printf("\tbytes %ld -> %ld",
     326:                     dqbuf.dqb_curblocks, fup->fu_curblocks);
     327:             (void)printf("\n");
     328:         }
     329:         dqbuf.dqb_curinodes = fup->fu_curinodes;
     330:         dqbuf.dqb_curblocks = fup->fu_curblocks;
     331:         fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo);
     332: /*
     333:  * Need to convert from bytes to blocks for system call interface.
     334:  */
     335:         dqu.du_curblocks = btodb(fup->fu_curblocks);
     336:         dqu.du_curinodes = fup->fu_curinodes;
     337:         (void) quota(Q_SETDUSE, id, quotadev, &dqu);
     338:         fup->fu_curinodes = 0;
     339:         fup->fu_curblocks = 0;
     340:     }
     341:     fclose(qfi);
     342:     fflush(qfo);
     343:     ftruncate(fileno(qfo), (off_t)(highid + 1) * sizeof(struct dqblk));
     344:     fclose(qfo);
     345:     return (0);
     346: }
     347:
     348: /*
     349:  * Check to see if target appears in list of size cnt.
     350:  */
     351: int
     352: oneof(target, list, cnt)
     353:     register char *target, *list[];
     354:     int cnt;
     355: {
     356:     register int i;
     357:
     358:     for (i = 0; i < cnt; i++)
     359:         if (strcmp(target, list[i]) == 0)
     360:             return (i);
     361:     return (-1);
     362: }
     363:
     364: /*
     365:  * Determine the group identifier for quota files.
     366:  */
     367: gid_t
     368: getquotagid()
     369: {
     370:     struct group *gr;
     371:
     372:     if (gr = getgrnam(quotagroup))
     373:         return (gr->gr_gid);
     374:     return (-1);
     375: }
     376:
     377: /*
     378:  * Check to see if a particular quota is to be enabled.
     379:  */
     380: hasquota(fs, qfnamep)
     381:     register struct fstab *fs;
     382:     char **qfnamep;
     383: {
     384:     register char *opt;
     385:     char *cp;
     386:     static char initname, usrname[100];
     387:     static char buf[BUFSIZ];
     388:
     389:     if (!initname) {
     390:         strcpy(usrname, qfname);
     391:         initname = 1;
     392:     }
     393:     strcpy(buf, fs->fs_mntops);
     394:     for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
     395:         if (cp = index(opt, '='))
     396:             *cp++ = '\0';
     397:         if (strcmp(opt, usrname) == 0)
     398:             break;
     399:         if (strcmp(opt, FSTAB_RQ) == 0) /* XXX compatibility */
     400:             break;
     401:     }
     402:     if (!opt)
     403:         return (0);
     404:     if (cp) {
     405:         *qfnamep = cp;
     406:         return (1);
     407:     }
     408:     (void) sprintf(buf, "%s/%s", fs->fs_file, qfname);
     409:     *qfnamep = buf;
     410:     return (1);
     411: }
     412:
     413: /*
     414:  * Routines to manage the file usage table.
     415:  *
     416:  * Lookup an id.
     417:  */
     418: struct fileusage *
     419: lookup(id)
     420:     uid_t id;
     421: {
     422:     register struct fileusage *fup;
     423:
     424:     for (fup = fuhead[id & (FUHASH-1)]; fup != 0; fup = fup->fu_next)
     425:         if (fup->fu_id == id)
     426:             return (fup);
     427:     return (NULL);
     428: }
     429:
     430: /*
     431:  * Add a new file usage id if it does not already exist.
     432:  */
     433: struct fileusage *
     434: addid(id, name)
     435:     uid_t id;
     436:     char *name;
     437: {
     438:     register struct fileusage *fup, **fhp;
     439:     int len;
     440:
     441:     if (fup = lookup(id))
     442:         return (fup);
     443:     if (name)
     444:         len = strlen(name);
     445:     else
     446:         len = 10;
     447:     if ((fup = (struct fileusage *)calloc(1, sizeof(*fup) + len)) == NULL)
     448:         err("%s", strerror(errno));
     449:     fhp = &fuhead[id & (FUHASH - 1)];
     450:     fup->fu_next = *fhp;
     451:     *fhp = fup;
     452:     fup->fu_id = id;
     453:     if (id > highid)
     454:         highid = id;
     455:     if (name)
     456:         bcopy(name, fup->fu_name, len + 1);
     457:     else
     458:         (void)sprintf(fup->fu_name, "%u", id);
     459:     return (fup);
     460: }
     461:
     462: /*
     463:  * Special purpose version of ginode used to optimize pass
     464:  * over all the inodes in numerical order.
     465:  */
     466: ino_t nextino;
     467: long lastinum;
     468: int inobufsize;
     469: struct dinode *inodebuf;
     470: #define INOBUFSIZE  128 /* number of inodes to read at a time */
     471:
     472: struct dinode *
     473: getnextinode(inumber)
     474:     ino_t inumber;
     475: {
     476:     daddr_t dblk;
     477:     static struct dinode *dp;
     478:
     479:     if (inumber != nextino++ || inumber >= maxino)
     480:         err(1, "bad inode number %d to nextinode", inumber);
     481:     if (inumber > lastinum) {
     482:         dblk = itod(inumber);
     483:         lastinum += INOBUFSIZE;
     484:         bread(dblk, (char *)inodebuf, inobufsize);
     485:         dp = inodebuf;
     486:     }
     487:     return (dp++);
     488: }
     489:
     490: /*
     491:  * Prepare to scan a set of inodes.
     492:  */
     493: void
     494: resetinodebuf()
     495: {
     496:
     497:     nextino = 1;
     498:     lastinum = 0;
     499:     inobufsize = INOBUFSIZE * sizeof (struct dinode);
     500:     if (inodebuf == NULL &&
     501:         (inodebuf = (struct dinode *)malloc(inobufsize)) == NULL)
     502:         nomem();
     503:     while (nextino < ROOTINO)
     504:         getnextinode(nextino);
     505: }
     506:
     507: /*
     508:  * Free up data structures used to scan inodes.
     509:  */
     510: void
     511: freeinodebuf()
     512: {
     513:
     514:     if (inodebuf != NULL)
     515:         free(inodebuf);
     516:     inodebuf = NULL;
     517: }
     518:
     519: /*
     520:  * Read specified disk blocks.
     521:  */
     522: void
     523: bread(bno, buf, cnt)
     524:     daddr_t bno;
     525:     char *buf;
     526:     int cnt;
     527: {
     528:
     529:     if (lseek(fi, (off_t)bno * DEV_BSIZE, 0) == -1 ||
     530:         read(fi, buf, cnt) != cnt)
     531:         err(1, "block %ld", bno);
     532: }

#### Defined functions

addid defined in line 433; used 3 times

- in line 97, 147, 232

bread defined in line 522; used 3 times

- in line 99, 223, 484

chkquota defined in line 205; used 3 times

- in line 100, 151, 160

freeinodebuf defined in line 510; used 2 times

- in line 101, 238

getnextinode defined in line 472; used 3 times

- in line 102, 227, 504

getquotagid defined in line 367; used 2 times

- in line 103, 268

hasquota defined in line 380; used 2 times

- in line 104, 192

lookup defined in line 418; used 3 times

- in line 105, 308, 441

main defined in line 112; never used
needchk defined in line 179; used 3 times

- in line 106, 151, 157

oneof defined in line 351; used 3 times

- in line 107, 155-156(2)

resetinodebuf defined in line 493; used 2 times

- in line 108, 225

update defined in line 248; used 2 times

- in line 109, 240

usage defined in line 170; used 3 times

- in line 110, 137, 143

#### Defined variables

aflag defined in line 92; used 5 times

- in line 128, 142(2), 150, 318

copyright defined in line 38; never used
fi defined in line 94; used 4 times

- in line 215, 241, 529-530(2)

fuhead defined in line 90; used 2 times

- in line 424, 449

highid defined in line 95; used 4 times

- in line 305, 343, 453-454(2)

inobufsize defined in line 468; used 3 times

- in line 484, 499-501(2)

inodebuf defined in line 469; used 7 times

- in line 484-485(2), 500-501(2), 514-516(3)

lastinum defined in line 467; used 3 times

- in line 481-483(2), 498

maxino defined in line 73; used 3 times

- in line 224-226(2), 479

nextino defined in line 466; used 4 times

- in line 479, 497, 503-504(2)

qfname defined in line 65; used 2 times

- in line 390, 408

quotagroup defined in line 66; used 1 times

- in line 372

sccsid defined in line 42; never used
vflag defined in line 93; used 4 times

- in line 131, 219, 300, 317

#### Defined struct's

fileusage defined in line 81; used 24 times

- in line 82(2), 90(2), 97(2), 105(2), 210(2), 252(2), 261(2), 418-422(4), 433-438(4), 447(2)

quotaname defined in line 75; used 10 times

- in line 119(2), 157(2), 183(2), 189(2), 208(2)

#### Defined macros

FUHASH defined in line 89; used 3 times

- in line 90, 424, 449

HASUSR defined in line 79; used 3 times

- in line 194, 231, 239

INOBUFSIZE defined in line 470; used 2 times

- in line 483, 499

sblock defined in line 72; used 2 times

- in line 223-224(2)

Last modified: 1996-01-25 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2759 |