121517Smckusick /* 261532Sbostic * Copyright (c) 1980, 1990, 1993 361532Sbostic * The Regents of the University of California. All rights reserved. 434364Sbostic * 541411Smckusick * This code is derived from software contributed to Berkeley by 641411Smckusick * Robert Elz at The University of Melbourne. 741411Smckusick * 842707Sbostic * %sccs.include.redist.c% 921517Smckusick */ 1021517Smckusick 1112703Smckusick #ifndef lint 1261532Sbostic static char copyright[] = 1361532Sbostic "@(#) Copyright (c) 1980, 1990, 1993\n\ 1461532Sbostic The Regents of the University of California. All rights reserved.\n"; 1534364Sbostic #endif /* not lint */ 1612660Smckusick 1721517Smckusick #ifndef lint 18*65941Sbostic static char sccsid[] = "@(#)quotacheck.c 8.3 (Berkeley) 01/29/94"; 1934364Sbostic #endif /* not lint */ 2021517Smckusick 2112660Smckusick /* 2241411Smckusick * Fix up / report on disk quotas & usage 2312660Smckusick */ 2412660Smckusick #include <sys/param.h> 2546783Sbostic #include <sys/stat.h> 2654158Sbostic 2751623Sbostic #include <ufs/ufs/dinode.h> 2851623Sbostic #include <ufs/ufs/quota.h> 2951623Sbostic #include <ufs/ffs/fs.h> 3054158Sbostic 3146783Sbostic #include <fcntl.h> 3212703Smckusick #include <fstab.h> 3312802Smckusick #include <pwd.h> 3441411Smckusick #include <grp.h> 3546783Sbostic #include <errno.h> 3646783Sbostic #include <unistd.h> 3738511Sbostic #include <stdio.h> 3846783Sbostic #include <stdlib.h> 3946783Sbostic #include <string.h> 4012660Smckusick 4145251Smckusick char *qfname = QUOTAFILENAME; 4245251Smckusick char *qfextension[] = INITQFNAMES; 4345251Smckusick char *quotagroup = QUOTAGROUP; 4445251Smckusick 4512660Smckusick union { 4612660Smckusick struct fs sblk; 4712703Smckusick char dummy[MAXBSIZE]; 4812660Smckusick } un; 4912660Smckusick #define sblock un.sblk 5041411Smckusick long dev_bsize = 1; 5141411Smckusick long maxino; 5212703Smckusick 5341443Smckusick struct quotaname { 5441443Smckusick long flags; 5541443Smckusick char grpqfname[MAXPATHLEN + 1]; 5641443Smckusick char usrqfname[MAXPATHLEN + 1]; 5741443Smckusick }; 5841443Smckusick #define HASUSR 1 5941443Smckusick #define HASGRP 2 6041443Smckusick 6112703Smckusick struct fileusage { 6241411Smckusick struct fileusage *fu_next; 6341411Smckusick u_long fu_curinodes; 6441411Smckusick u_long fu_curblocks; 6541411Smckusick u_long fu_id; 6641411Smckusick char fu_name[1]; 6741411Smckusick /* actually bigger */ 6812703Smckusick }; 6941411Smckusick #define FUHASH 1024 /* must be power of two */ 7041411Smckusick struct fileusage *fuhead[MAXQUOTAS][FUHASH]; 7112660Smckusick 7241411Smckusick int aflag; /* all file systems */ 7341411Smckusick int gflag; /* check group quotas */ 7441411Smckusick int uflag; /* check user quotas */ 7541411Smckusick int vflag; /* verbose */ 7641411Smckusick int fi; /* open disk file descriptor */ 7741411Smckusick u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */ 7812703Smckusick 7954158Sbostic struct fileusage * 8054158Sbostic addid __P((u_long, int, char *)); 8154158Sbostic char *blockcheck __P((char *)); 8254158Sbostic void bread __P((daddr_t, char *, long)); 8354158Sbostic int chkquota __P((char *, char *, struct quotaname *)); 8454158Sbostic void err __P((const char *, ...)); 8554158Sbostic void freeinodebuf __P((void)); 8654158Sbostic struct dinode * 8754158Sbostic getnextinode __P((ino_t)); 8854158Sbostic int getquotagid __P((void)); 8954158Sbostic int hasquota __P((struct fstab *, int, char **)); 9054158Sbostic struct fileusage * 9154158Sbostic lookup __P((u_long, int)); 9254158Sbostic void *needchk __P((struct fstab *)); 9354158Sbostic int oneof __P((char *, char*[], int)); 9454158Sbostic void resetinodebuf __P((void)); 9554158Sbostic int update __P((char *, char *, int)); 9654158Sbostic void usage __P((void)); 9754158Sbostic 9854158Sbostic int 9912660Smckusick main(argc, argv) 10012703Smckusick int argc; 10154158Sbostic char *argv[]; 10212660Smckusick { 10312703Smckusick register struct fstab *fs; 10412802Smckusick register struct passwd *pw; 10541411Smckusick register struct group *gr; 10654158Sbostic struct quotaname *auxdata; 107*65941Sbostic int i, argnum, maxrun, errs; 10854158Sbostic long done = 0; 10954158Sbostic char ch, *name; 11012660Smckusick 111*65941Sbostic errs = maxrun = 0; 11241411Smckusick while ((ch = getopt(argc, argv, "aguvl:")) != EOF) { 11341411Smckusick switch(ch) { 11441411Smckusick case 'a': 11541411Smckusick aflag++; 11641411Smckusick break; 11741411Smckusick case 'g': 11841411Smckusick gflag++; 11941411Smckusick break; 12041411Smckusick case 'u': 12141411Smckusick uflag++; 12241411Smckusick break; 12341411Smckusick case 'v': 12441411Smckusick vflag++; 12541411Smckusick break; 12641411Smckusick case 'l': 12741411Smckusick maxrun = atoi(optarg); 12841411Smckusick break; 12941411Smckusick default: 13041411Smckusick usage(); 13141411Smckusick } 13212660Smckusick } 13341411Smckusick argc -= optind; 13441411Smckusick argv += optind; 13541411Smckusick if ((argc == 0 && !aflag) || (argc > 0 && aflag)) 13641411Smckusick usage(); 13741411Smckusick if (!gflag && !uflag) { 13841411Smckusick gflag++; 13941411Smckusick uflag++; 14012703Smckusick } 14141411Smckusick if (gflag) { 14241411Smckusick setgrent(); 14341411Smckusick while ((gr = getgrent()) != 0) 14441411Smckusick (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name); 14541411Smckusick endgrent(); 14624758Sserge } 14741411Smckusick if (uflag) { 14841411Smckusick setpwent(); 14941411Smckusick while ((pw = getpwent()) != 0) 15041411Smckusick (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name); 15141411Smckusick endpwent(); 15212660Smckusick } 15341411Smckusick if (aflag) 15441411Smckusick exit(checkfstab(1, maxrun, needchk, chkquota)); 15554158Sbostic if (setfsent() == 0) 15654158Sbostic err("%s: can't open", FSTAB); 15741411Smckusick while ((fs = getfsent()) != NULL) { 15841411Smckusick if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || 15941411Smckusick (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) && 16041411Smckusick (auxdata = needchk(fs)) && 16141411Smckusick (name = blockcheck(fs->fs_spec))) { 16241411Smckusick done |= 1 << argnum; 16341411Smckusick errs += chkquota(name, fs->fs_file, auxdata); 16424758Sserge } 16512660Smckusick } 16641411Smckusick endfsent(); 16712703Smckusick for (i = 0; i < argc; i++) 16812703Smckusick if ((done & (1 << i)) == 0) 16924782Sserge fprintf(stderr, "%s not found in %s\n", 17024782Sserge argv[i], FSTAB); 17112703Smckusick exit(errs); 17212703Smckusick } 17312660Smckusick 17454158Sbostic void 17541411Smckusick usage() 17624758Sserge { 17754158Sbostic (void)fprintf(stderr, "usage:\t%s\n\t%s\n", 17846783Sbostic "quotacheck -a [-guv]", 17946783Sbostic "quotacheck [-guv] filesys ..."); 18041411Smckusick exit(1); 18141411Smckusick } 18224758Sserge 18354158Sbostic void * 18441411Smckusick needchk(fs) 18541411Smckusick register struct fstab *fs; 18641411Smckusick { 18741443Smckusick register struct quotaname *qnp; 18841443Smckusick char *qfnp; 18924758Sserge 19041443Smckusick if (strcmp(fs->fs_vfstype, "ufs") || 19141443Smckusick strcmp(fs->fs_type, FSTAB_RW)) 19254158Sbostic return (NULL); 19354158Sbostic if ((qnp = malloc(sizeof(*qnp))) == NULL) 19454158Sbostic err("%s", strerror(errno)); 19541443Smckusick qnp->flags = 0; 19641443Smckusick if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) { 19741443Smckusick strcpy(qnp->grpqfname, qfnp); 19841443Smckusick qnp->flags |= HASGRP; 19941443Smckusick } 20041443Smckusick if (uflag && hasquota(fs, USRQUOTA, &qfnp)) { 20141443Smckusick strcpy(qnp->usrqfname, qfnp); 20241443Smckusick qnp->flags |= HASUSR; 20341443Smckusick } 20441443Smckusick if (qnp->flags) 20554158Sbostic return (qnp); 20654158Sbostic free(qnp); 20754158Sbostic return (NULL); 20841411Smckusick } 20924758Sserge 21041411Smckusick /* 21141411Smckusick * Scan the specified filesystem to check quota(s) present on it. 21241411Smckusick */ 21354158Sbostic int 21441443Smckusick chkquota(fsname, mntpt, qnp) 21541411Smckusick char *fsname, *mntpt; 21641443Smckusick register struct quotaname *qnp; 21741411Smckusick { 21841411Smckusick register struct fileusage *fup; 21941411Smckusick register struct dinode *dp; 22041411Smckusick int cg, i, mode, errs = 0; 22141411Smckusick ino_t ino; 22224758Sserge 22354158Sbostic if ((fi = open(fsname, O_RDONLY, 0)) < 0) { 22441411Smckusick perror(fsname); 22541411Smckusick return (1); 22641411Smckusick } 22741411Smckusick if (vflag) { 22854158Sbostic (void)printf("*** Checking "); 22941443Smckusick if (qnp->flags & HASUSR) 23054158Sbostic (void)printf("%s%s", qfextension[USRQUOTA], 23141443Smckusick (qnp->flags & HASGRP) ? " and " : ""); 23241443Smckusick if (qnp->flags & HASGRP) 23354158Sbostic (void)printf("%s", qfextension[GRPQUOTA]); 23454158Sbostic (void)printf(" quotas for %s (%s)\n", fsname, mntpt); 23541411Smckusick } 23641411Smckusick sync(); 23741411Smckusick bread(SBOFF, (char *)&sblock, (long)SBSIZE); 23841411Smckusick dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 23941411Smckusick maxino = sblock.fs_ncg * sblock.fs_ipg; 24041411Smckusick resetinodebuf(); 24141411Smckusick for (ino = 0, cg = 0; cg < sblock.fs_ncg; cg++) { 24241411Smckusick for (i = 0; i < sblock.fs_ipg; i++, ino++) { 24341411Smckusick if (ino < ROOTINO) 24424758Sserge continue; 24541411Smckusick if ((dp = getnextinode(ino)) == NULL) 24624758Sserge continue; 24741411Smckusick if ((mode = dp->di_mode & IFMT) == 0) 24841411Smckusick continue; 24941443Smckusick if (qnp->flags & HASGRP) { 25041411Smckusick fup = addid((u_long)dp->di_gid, GRPQUOTA, 25141411Smckusick (char *)0); 25241411Smckusick fup->fu_curinodes++; 25341411Smckusick if (mode == IFREG || mode == IFDIR || 25441411Smckusick mode == IFLNK) 25541411Smckusick fup->fu_curblocks += dp->di_blocks; 25624758Sserge } 25741443Smckusick if (qnp->flags & HASUSR) { 25841411Smckusick fup = addid((u_long)dp->di_uid, USRQUOTA, 25941411Smckusick (char *)0); 26041411Smckusick fup->fu_curinodes++; 26141411Smckusick if (mode == IFREG || mode == IFDIR || 26241411Smckusick mode == IFLNK) 26341411Smckusick fup->fu_curblocks += dp->di_blocks; 26441411Smckusick } 26524758Sserge } 26641411Smckusick } 26741411Smckusick freeinodebuf(); 26841443Smckusick if (qnp->flags & HASUSR) 26941443Smckusick errs += update(mntpt, qnp->usrqfname, USRQUOTA); 27041443Smckusick if (qnp->flags & HASGRP) 27141443Smckusick errs += update(mntpt, qnp->grpqfname, GRPQUOTA); 27241411Smckusick close(fi); 27324758Sserge return (errs); 27424758Sserge } 27524758Sserge 27641411Smckusick /* 27741411Smckusick * Update a specified quota file. 27841411Smckusick */ 27954158Sbostic int 28041443Smckusick update(fsname, quotafile, type) 28141443Smckusick char *fsname, *quotafile; 28241411Smckusick register int type; 28312703Smckusick { 28412703Smckusick register struct fileusage *fup; 28525377Sserge register FILE *qfi, *qfo; 28641411Smckusick register u_long id, lastid; 28712703Smckusick struct dqblk dqbuf; 28821085Smckusick static int warned = 0; 28941411Smckusick static struct dqblk zerodqbuf; 29041411Smckusick static struct fileusage zerofileusage; 29112660Smckusick 29241411Smckusick if ((qfo = fopen(quotafile, "r+")) == NULL) { 29346783Sbostic if (errno == ENOENT) 29446783Sbostic qfo = fopen(quotafile, "w+"); 29546783Sbostic if (qfo) { 29646783Sbostic (void) fprintf(stderr, 29746783Sbostic "quotacheck: creating quota file %s\n", quotafile); 29846783Sbostic #define MODE (S_IRUSR|S_IWUSR|S_IRGRP) 29946783Sbostic (void) fchown(fileno(qfo), getuid(), getquotagid()); 30046783Sbostic (void) fchmod(fileno(qfo), MODE); 30146783Sbostic } else { 30246783Sbostic (void) fprintf(stderr, 30346783Sbostic "quotacheck: %s: %s\n", quotafile, strerror(errno)); 30441411Smckusick return (1); 30541411Smckusick } 30612660Smckusick } 30741411Smckusick if ((qfi = fopen(quotafile, "r")) == NULL) { 30846783Sbostic (void) fprintf(stderr, 30946783Sbostic "quotacheck: %s: %s\n", quotafile, strerror(errno)); 31046783Sbostic (void) fclose(qfo); 31112703Smckusick return (1); 31212660Smckusick } 31341411Smckusick if (quotactl(fsname, QCMD(Q_SYNC, type), (u_long)0, (caddr_t)0) < 0 && 31441411Smckusick errno == EOPNOTSUPP && !warned && vflag) { 31521085Smckusick warned++; 31654158Sbostic (void)printf("*** Warning: %s\n", 31741411Smckusick "Quotas are not compiled into this kernel"); 31821085Smckusick } 31941411Smckusick for (lastid = highid[type], id = 0; id <= lastid; id++) { 32041411Smckusick if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0) 32112802Smckusick dqbuf = zerodqbuf; 32241411Smckusick if ((fup = lookup(id, type)) == 0) 32324758Sserge fup = &zerofileusage; 32441411Smckusick if (dqbuf.dqb_curinodes == fup->fu_curinodes && 32541411Smckusick dqbuf.dqb_curblocks == fup->fu_curblocks) { 32641411Smckusick fup->fu_curinodes = 0; 32741411Smckusick fup->fu_curblocks = 0; 32825377Sserge fseek(qfo, (long)sizeof(struct dqblk), 1); 32912703Smckusick continue; 33012802Smckusick } 33112703Smckusick if (vflag) { 33241411Smckusick if (aflag) 33341411Smckusick printf("%s: ", fsname); 33441411Smckusick printf("%-8s fixed:", fup->fu_name); 33541411Smckusick if (dqbuf.dqb_curinodes != fup->fu_curinodes) 33654158Sbostic (void)printf("\tinodes %d -> %d", 33741411Smckusick dqbuf.dqb_curinodes, fup->fu_curinodes); 33841411Smckusick if (dqbuf.dqb_curblocks != fup->fu_curblocks) 33954158Sbostic (void)printf("\tblocks %d -> %d", 34041411Smckusick dqbuf.dqb_curblocks, fup->fu_curblocks); 34154158Sbostic (void)printf("\n"); 34212660Smckusick } 34341411Smckusick /* 34441411Smckusick * Reset time limit if have a soft limit and were 34541411Smckusick * previously under it, but are now over it. 34641411Smckusick */ 34741411Smckusick if (dqbuf.dqb_bsoftlimit && 34841411Smckusick dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit && 34941411Smckusick fup->fu_curblocks >= dqbuf.dqb_bsoftlimit) 35041411Smckusick dqbuf.dqb_btime = 0; 35141411Smckusick if (dqbuf.dqb_isoftlimit && 35241411Smckusick dqbuf.dqb_curblocks < dqbuf.dqb_isoftlimit && 35341411Smckusick fup->fu_curblocks >= dqbuf.dqb_isoftlimit) 35441411Smckusick dqbuf.dqb_itime = 0; 35541411Smckusick dqbuf.dqb_curinodes = fup->fu_curinodes; 35641411Smckusick dqbuf.dqb_curblocks = fup->fu_curblocks; 35741411Smckusick fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo); 35841411Smckusick (void) quotactl(fsname, QCMD(Q_SETUSE, type), id, 35941411Smckusick (caddr_t)&dqbuf); 36041411Smckusick fup->fu_curinodes = 0; 36141411Smckusick fup->fu_curblocks = 0; 36212660Smckusick } 36341411Smckusick fclose(qfi); 36425377Sserge fflush(qfo); 36541411Smckusick ftruncate(fileno(qfo), 36641411Smckusick (off_t)((highid[type] + 1) * sizeof(struct dqblk))); 36725377Sserge fclose(qfo); 36812703Smckusick return (0); 36912660Smckusick } 37012660Smckusick 37141411Smckusick /* 37241411Smckusick * Check to see if target appears in list of size cnt. 37341411Smckusick */ 37454158Sbostic int 37541411Smckusick oneof(target, list, cnt) 37641411Smckusick register char *target, *list[]; 37741411Smckusick int cnt; 37812660Smckusick { 37912703Smckusick register int i; 38012660Smckusick 38141411Smckusick for (i = 0; i < cnt; i++) 38241411Smckusick if (strcmp(target, list[i]) == 0) 38341411Smckusick return (i); 38441411Smckusick return (-1); 38512660Smckusick } 38612660Smckusick 38741411Smckusick /* 38841443Smckusick * Determine the group identifier for quota files. 38941443Smckusick */ 39054158Sbostic int 39141443Smckusick getquotagid() 39241443Smckusick { 39341443Smckusick struct group *gr; 39441443Smckusick 39541443Smckusick if (gr = getgrnam(quotagroup)) 39641443Smckusick return (gr->gr_gid); 39741443Smckusick return (-1); 39841443Smckusick } 39941443Smckusick 40041443Smckusick /* 40141411Smckusick * Check to see if a particular quota is to be enabled. 40241411Smckusick */ 40354158Sbostic int 40441443Smckusick hasquota(fs, type, qfnamep) 40541443Smckusick register struct fstab *fs; 40641411Smckusick int type; 40741443Smckusick char **qfnamep; 40812660Smckusick { 40941411Smckusick register char *opt; 41054158Sbostic char *cp; 41141411Smckusick static char initname, usrname[100], grpname[100]; 41241443Smckusick static char buf[BUFSIZ]; 41312660Smckusick 41441411Smckusick if (!initname) { 41554158Sbostic (void)snprintf(usrname, sizeof(usrname), 41654158Sbostic "%s%s", qfextension[USRQUOTA], qfname); 41754158Sbostic (void)snprintf(grpname, sizeof(grpname), 41854158Sbostic "%s%s", qfextension[GRPQUOTA], qfname); 41941411Smckusick initname = 1; 42012660Smckusick } 42141443Smckusick strcpy(buf, fs->fs_mntops); 42241411Smckusick for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 42341443Smckusick if (cp = index(opt, '=')) 42441443Smckusick *cp++ = '\0'; 42541411Smckusick if (type == USRQUOTA && strcmp(opt, usrname) == 0) 42641443Smckusick break; 42741411Smckusick if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 42841443Smckusick break; 42925377Sserge } 43041443Smckusick if (!opt) 43141443Smckusick return (0); 43254158Sbostic if (cp) 43341443Smckusick *qfnamep = cp; 43454158Sbostic else { 43554158Sbostic (void)snprintf(buf, sizeof(buf), 43654158Sbostic "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 43754158Sbostic *qfnamep = buf; 43841443Smckusick } 43941443Smckusick return (1); 44012660Smckusick } 44112660Smckusick 44241411Smckusick /* 44341411Smckusick * Routines to manage the file usage table. 44441411Smckusick * 44541411Smckusick * Lookup an id of a specific type. 44641411Smckusick */ 44712703Smckusick struct fileusage * 44841411Smckusick lookup(id, type) 44941411Smckusick u_long id; 45041411Smckusick int type; 45112660Smckusick { 45212703Smckusick register struct fileusage *fup; 45312660Smckusick 45441411Smckusick for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next) 45541411Smckusick if (fup->fu_id == id) 45612703Smckusick return (fup); 45754158Sbostic return (NULL); 45812660Smckusick } 45912660Smckusick 46041411Smckusick /* 46141411Smckusick * Add a new file usage id if it does not already exist. 46241411Smckusick */ 46312703Smckusick struct fileusage * 46441411Smckusick addid(id, type, name) 46541411Smckusick u_long id; 46641411Smckusick int type; 46741411Smckusick char *name; 46812660Smckusick { 46912703Smckusick struct fileusage *fup, **fhp; 47041411Smckusick int len; 47112660Smckusick 47241411Smckusick if (fup = lookup(id, type)) 47312703Smckusick return (fup); 47441411Smckusick if (name) 47541411Smckusick len = strlen(name); 47641411Smckusick else 47741411Smckusick len = 10; 47854158Sbostic if ((fup = calloc(1, sizeof(*fup) + len)) == NULL) 47954158Sbostic err("%s", strerror(errno)); 48041411Smckusick fhp = &fuhead[type][id & (FUHASH - 1)]; 48112703Smckusick fup->fu_next = *fhp; 48212703Smckusick *fhp = fup; 48341411Smckusick fup->fu_id = id; 48441411Smckusick if (id > highid[type]) 48541411Smckusick highid[type] = id; 48654158Sbostic if (name) 48741411Smckusick bcopy(name, fup->fu_name, len + 1); 48854158Sbostic else 48954158Sbostic (void)sprintf(fup->fu_name, "%u", id); 49012703Smckusick return (fup); 49112660Smckusick } 49212660Smckusick 49341411Smckusick /* 49441411Smckusick * Special purpose version of ginode used to optimize pass 49541411Smckusick * over all the inodes in numerical order. 49641411Smckusick */ 49741411Smckusick ino_t nextino, lastinum; 49841411Smckusick long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 49941411Smckusick struct dinode *inodebuf; 50041411Smckusick #define INOBUFSIZE 56*1024 /* size of buffer to read inodes */ 50141411Smckusick 50241411Smckusick struct dinode * 50341411Smckusick getnextinode(inumber) 50441411Smckusick ino_t inumber; 50512660Smckusick { 50641411Smckusick long size; 50741411Smckusick daddr_t dblk; 50841411Smckusick static struct dinode *dp; 50912660Smckusick 51054158Sbostic if (inumber != nextino++ || inumber > maxino) 51154158Sbostic err("bad inode number %d to nextinode", inumber); 51241411Smckusick if (inumber >= lastinum) { 51341411Smckusick readcnt++; 51464640Sbostic dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum)); 51541411Smckusick if (readcnt % readpercg == 0) { 51641411Smckusick size = partialsize; 51741411Smckusick lastinum += partialcnt; 51841411Smckusick } else { 51941411Smckusick size = inobufsize; 52041411Smckusick lastinum += fullcnt; 52141411Smckusick } 52241411Smckusick bread(dblk, (char *)inodebuf, size); 52341411Smckusick dp = inodebuf; 52441411Smckusick } 52541411Smckusick return (dp++); 52612660Smckusick } 52741411Smckusick 52841411Smckusick /* 52941411Smckusick * Prepare to scan a set of inodes. 53041411Smckusick */ 53154158Sbostic void 53241411Smckusick resetinodebuf() 53341411Smckusick { 53441411Smckusick 53541411Smckusick nextino = 0; 53641411Smckusick lastinum = 0; 53741411Smckusick readcnt = 0; 53841411Smckusick inobufsize = blkroundup(&sblock, INOBUFSIZE); 53941411Smckusick fullcnt = inobufsize / sizeof(struct dinode); 54041411Smckusick readpercg = sblock.fs_ipg / fullcnt; 54141411Smckusick partialcnt = sblock.fs_ipg % fullcnt; 54241411Smckusick partialsize = partialcnt * sizeof(struct dinode); 54341411Smckusick if (partialcnt != 0) { 54441411Smckusick readpercg++; 54541411Smckusick } else { 54641411Smckusick partialcnt = fullcnt; 54741411Smckusick partialsize = inobufsize; 54841411Smckusick } 54941411Smckusick if (inodebuf == NULL && 55054158Sbostic (inodebuf = malloc((u_int)inobufsize)) == NULL) 55154158Sbostic err("%s", strerror(errno)); 55241411Smckusick while (nextino < ROOTINO) 55341411Smckusick getnextinode(nextino); 55441411Smckusick } 55541411Smckusick 55641411Smckusick /* 55741411Smckusick * Free up data structures used to scan inodes. 55841411Smckusick */ 55954158Sbostic void 56041411Smckusick freeinodebuf() 56141411Smckusick { 56241411Smckusick 56341411Smckusick if (inodebuf != NULL) 56454158Sbostic free(inodebuf); 56541411Smckusick inodebuf = NULL; 56641411Smckusick } 56741411Smckusick 56841411Smckusick /* 56941411Smckusick * Read specified disk blocks. 57041411Smckusick */ 57154158Sbostic void 57241411Smckusick bread(bno, buf, cnt) 57341411Smckusick daddr_t bno; 57441411Smckusick char *buf; 57541411Smckusick long cnt; 57641411Smckusick { 57741411Smckusick 57858002Sralph if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0 || 57954158Sbostic read(fi, buf, cnt) != cnt) 58054158Sbostic err("block %ld", bno); 58154158Sbostic } 58241411Smckusick 58354158Sbostic #if __STDC__ 58454158Sbostic #include <stdarg.h> 58554158Sbostic #else 58654158Sbostic #include <varargs.h> 58754158Sbostic #endif 58854158Sbostic 58954158Sbostic void 59054158Sbostic #if __STDC__ 59154158Sbostic err(const char *fmt, ...) 59254158Sbostic #else 59354158Sbostic err(fmt, va_alist) 59454158Sbostic char *fmt; 59554158Sbostic va_dcl 59654158Sbostic #endif 59754158Sbostic { 59854158Sbostic va_list ap; 59954158Sbostic #if __STDC__ 60054158Sbostic va_start(ap, fmt); 60154158Sbostic #else 60254158Sbostic va_start(ap); 60354158Sbostic #endif 60454158Sbostic (void)fprintf(stderr, "quotacheck: "); 60554158Sbostic (void)vfprintf(stderr, fmt, ap); 60654158Sbostic va_end(ap); 60754158Sbostic (void)fprintf(stderr, "\n"); 60854158Sbostic exit(1); 60954158Sbostic /* NOTREACHED */ 61041411Smckusick } 611