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*69000Sbostic static char sccsid[] = "@(#)quotacheck.c 8.6 (Berkeley) 04/28/95";
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>
2667976Smckusick #include <sys/queue.h>
2754158Sbostic
2851623Sbostic #include <ufs/ufs/dinode.h>
2951623Sbostic #include <ufs/ufs/quota.h>
3051623Sbostic #include <ufs/ffs/fs.h>
3154158Sbostic
3246783Sbostic #include <fcntl.h>
3312703Smckusick #include <fstab.h>
3412802Smckusick #include <pwd.h>
3541411Smckusick #include <grp.h>
3646783Sbostic #include <errno.h>
3746783Sbostic #include <unistd.h>
3838511Sbostic #include <stdio.h>
3946783Sbostic #include <stdlib.h>
4046783Sbostic #include <string.h>
4167700Smckusick #include <err.h>
4212660Smckusick
4345251Smckusick char *qfname = QUOTAFILENAME;
4445251Smckusick char *qfextension[] = INITQFNAMES;
4545251Smckusick char *quotagroup = QUOTAGROUP;
4645251Smckusick
4712660Smckusick union {
4812660Smckusick struct fs sblk;
4912703Smckusick char dummy[MAXBSIZE];
5012660Smckusick } un;
5112660Smckusick #define sblock un.sblk
5267700Smckusick long dev_bsize;
5341411Smckusick long maxino;
5412703Smckusick
5541443Smckusick struct quotaname {
5641443Smckusick long flags;
5741443Smckusick char grpqfname[MAXPATHLEN + 1];
5841443Smckusick char usrqfname[MAXPATHLEN + 1];
5941443Smckusick };
6041443Smckusick #define HASUSR 1
6141443Smckusick #define HASGRP 2
6241443Smckusick
6312703Smckusick struct fileusage {
6441411Smckusick struct fileusage *fu_next;
6541411Smckusick u_long fu_curinodes;
6641411Smckusick u_long fu_curblocks;
6741411Smckusick u_long fu_id;
6841411Smckusick char fu_name[1];
6941411Smckusick /* actually bigger */
7012703Smckusick };
7141411Smckusick #define FUHASH 1024 /* must be power of two */
7241411Smckusick struct fileusage *fuhead[MAXQUOTAS][FUHASH];
7312660Smckusick
7441411Smckusick int aflag; /* all file systems */
7541411Smckusick int gflag; /* check group quotas */
7641411Smckusick int uflag; /* check user quotas */
7741411Smckusick int vflag; /* verbose */
7841411Smckusick int fi; /* open disk file descriptor */
7941411Smckusick u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */
8012703Smckusick
8154158Sbostic struct fileusage *
8254158Sbostic addid __P((u_long, int, char *));
8354158Sbostic char *blockcheck __P((char *));
8454158Sbostic void bread __P((daddr_t, char *, long));
8554158Sbostic int chkquota __P((char *, char *, struct quotaname *));
8654158Sbostic void freeinodebuf __P((void));
8754158Sbostic struct dinode *
8854158Sbostic getnextinode __P((ino_t));
8954158Sbostic int getquotagid __P((void));
9054158Sbostic int hasquota __P((struct fstab *, int, char **));
9154158Sbostic struct fileusage *
9254158Sbostic lookup __P((u_long, int));
9354158Sbostic void *needchk __P((struct fstab *));
9454158Sbostic int oneof __P((char *, char*[], int));
9554158Sbostic void resetinodebuf __P((void));
9654158Sbostic int update __P((char *, char *, int));
9754158Sbostic void usage __P((void));
9854158Sbostic
9954158Sbostic int
main(argc,argv)10012660Smckusick main(argc, argv)
10112703Smckusick int argc;
10254158Sbostic char *argv[];
10312660Smckusick {
10412703Smckusick register struct fstab *fs;
10512802Smckusick register struct passwd *pw;
10641411Smckusick register struct group *gr;
10754158Sbostic struct quotaname *auxdata;
10865941Sbostic int i, argnum, maxrun, errs;
10954158Sbostic long done = 0;
11054158Sbostic char ch, *name;
11112660Smckusick
11265941Sbostic errs = maxrun = 0;
11341411Smckusick while ((ch = getopt(argc, argv, "aguvl:")) != EOF) {
11441411Smckusick switch(ch) {
11541411Smckusick case 'a':
11641411Smckusick aflag++;
11741411Smckusick break;
11841411Smckusick case 'g':
11941411Smckusick gflag++;
12041411Smckusick break;
12141411Smckusick case 'u':
12241411Smckusick uflag++;
12341411Smckusick break;
12441411Smckusick case 'v':
12541411Smckusick vflag++;
12641411Smckusick break;
12741411Smckusick case 'l':
12841411Smckusick maxrun = atoi(optarg);
12941411Smckusick break;
13041411Smckusick default:
13141411Smckusick usage();
13241411Smckusick }
13312660Smckusick }
13441411Smckusick argc -= optind;
13541411Smckusick argv += optind;
13641411Smckusick if ((argc == 0 && !aflag) || (argc > 0 && aflag))
13741411Smckusick usage();
13841411Smckusick if (!gflag && !uflag) {
13941411Smckusick gflag++;
14041411Smckusick uflag++;
14112703Smckusick }
14241411Smckusick if (gflag) {
14341411Smckusick setgrent();
14441411Smckusick while ((gr = getgrent()) != 0)
14541411Smckusick (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name);
14641411Smckusick endgrent();
14724758Sserge }
14841411Smckusick if (uflag) {
14941411Smckusick setpwent();
15041411Smckusick while ((pw = getpwent()) != 0)
15141411Smckusick (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name);
15241411Smckusick endpwent();
15312660Smckusick }
15441411Smckusick if (aflag)
15541411Smckusick exit(checkfstab(1, maxrun, needchk, chkquota));
15654158Sbostic if (setfsent() == 0)
15767700Smckusick err(1, "%s: can't open", FSTAB);
15841411Smckusick while ((fs = getfsent()) != NULL) {
15941411Smckusick if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
16041411Smckusick (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) &&
16141411Smckusick (auxdata = needchk(fs)) &&
16241411Smckusick (name = blockcheck(fs->fs_spec))) {
16341411Smckusick done |= 1 << argnum;
16441411Smckusick errs += chkquota(name, fs->fs_file, auxdata);
16524758Sserge }
16612660Smckusick }
16741411Smckusick endfsent();
16812703Smckusick for (i = 0; i < argc; i++)
16912703Smckusick if ((done & (1 << i)) == 0)
17024782Sserge fprintf(stderr, "%s not found in %s\n",
17124782Sserge argv[i], FSTAB);
17212703Smckusick exit(errs);
17312703Smckusick }
17412660Smckusick
17554158Sbostic void
usage()17641411Smckusick usage()
17724758Sserge {
17854158Sbostic (void)fprintf(stderr, "usage:\t%s\n\t%s\n",
17946783Sbostic "quotacheck -a [-guv]",
18046783Sbostic "quotacheck [-guv] filesys ...");
18141411Smckusick exit(1);
18241411Smckusick }
18324758Sserge
18454158Sbostic void *
needchk(fs)18541411Smckusick needchk(fs)
18641411Smckusick register struct fstab *fs;
18741411Smckusick {
18841443Smckusick register struct quotaname *qnp;
18941443Smckusick char *qfnp;
19024758Sserge
19141443Smckusick if (strcmp(fs->fs_vfstype, "ufs") ||
19241443Smckusick strcmp(fs->fs_type, FSTAB_RW))
19354158Sbostic return (NULL);
19454158Sbostic if ((qnp = malloc(sizeof(*qnp))) == NULL)
19567700Smckusick err(1, "%s", strerror(errno));
19641443Smckusick qnp->flags = 0;
19741443Smckusick if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) {
19841443Smckusick strcpy(qnp->grpqfname, qfnp);
19941443Smckusick qnp->flags |= HASGRP;
20041443Smckusick }
20141443Smckusick if (uflag && hasquota(fs, USRQUOTA, &qfnp)) {
20241443Smckusick strcpy(qnp->usrqfname, qfnp);
20341443Smckusick qnp->flags |= HASUSR;
20441443Smckusick }
20541443Smckusick if (qnp->flags)
20654158Sbostic return (qnp);
20754158Sbostic free(qnp);
20854158Sbostic return (NULL);
20941411Smckusick }
21024758Sserge
21141411Smckusick /*
21241411Smckusick * Scan the specified filesystem to check quota(s) present on it.
21341411Smckusick */
21454158Sbostic int
chkquota(fsname,mntpt,qnp)21541443Smckusick chkquota(fsname, mntpt, qnp)
21641411Smckusick char *fsname, *mntpt;
21741443Smckusick register struct quotaname *qnp;
21841411Smckusick {
21941411Smckusick register struct fileusage *fup;
22041411Smckusick register struct dinode *dp;
22141411Smckusick int cg, i, mode, errs = 0;
22241411Smckusick ino_t ino;
22324758Sserge
22454158Sbostic if ((fi = open(fsname, O_RDONLY, 0)) < 0) {
22541411Smckusick perror(fsname);
22641411Smckusick return (1);
22741411Smckusick }
22841411Smckusick if (vflag) {
22954158Sbostic (void)printf("*** Checking ");
23041443Smckusick if (qnp->flags & HASUSR)
23154158Sbostic (void)printf("%s%s", qfextension[USRQUOTA],
23241443Smckusick (qnp->flags & HASGRP) ? " and " : "");
23341443Smckusick if (qnp->flags & HASGRP)
23454158Sbostic (void)printf("%s", qfextension[GRPQUOTA]);
23554158Sbostic (void)printf(" quotas for %s (%s)\n", fsname, mntpt);
23641411Smckusick }
23741411Smckusick sync();
23867700Smckusick dev_bsize = 1;
23941411Smckusick bread(SBOFF, (char *)&sblock, (long)SBSIZE);
24041411Smckusick dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
24141411Smckusick maxino = sblock.fs_ncg * sblock.fs_ipg;
24241411Smckusick resetinodebuf();
24341411Smckusick for (ino = 0, cg = 0; cg < sblock.fs_ncg; cg++) {
24441411Smckusick for (i = 0; i < sblock.fs_ipg; i++, ino++) {
24541411Smckusick if (ino < ROOTINO)
24624758Sserge continue;
24741411Smckusick if ((dp = getnextinode(ino)) == NULL)
24824758Sserge continue;
24941411Smckusick if ((mode = dp->di_mode & IFMT) == 0)
25041411Smckusick continue;
25141443Smckusick if (qnp->flags & HASGRP) {
25241411Smckusick fup = addid((u_long)dp->di_gid, GRPQUOTA,
25341411Smckusick (char *)0);
25441411Smckusick fup->fu_curinodes++;
25541411Smckusick if (mode == IFREG || mode == IFDIR ||
25641411Smckusick mode == IFLNK)
25741411Smckusick fup->fu_curblocks += dp->di_blocks;
25824758Sserge }
25941443Smckusick if (qnp->flags & HASUSR) {
26041411Smckusick fup = addid((u_long)dp->di_uid, USRQUOTA,
26141411Smckusick (char *)0);
26241411Smckusick fup->fu_curinodes++;
26341411Smckusick if (mode == IFREG || mode == IFDIR ||
26441411Smckusick mode == IFLNK)
26541411Smckusick fup->fu_curblocks += dp->di_blocks;
26641411Smckusick }
26724758Sserge }
26841411Smckusick }
26941411Smckusick freeinodebuf();
27041443Smckusick if (qnp->flags & HASUSR)
27141443Smckusick errs += update(mntpt, qnp->usrqfname, USRQUOTA);
27241443Smckusick if (qnp->flags & HASGRP)
27341443Smckusick errs += update(mntpt, qnp->grpqfname, GRPQUOTA);
27441411Smckusick close(fi);
27524758Sserge return (errs);
27624758Sserge }
27724758Sserge
27841411Smckusick /*
27941411Smckusick * Update a specified quota file.
28041411Smckusick */
28154158Sbostic int
update(fsname,quotafile,type)28241443Smckusick update(fsname, quotafile, type)
28341443Smckusick char *fsname, *quotafile;
28441411Smckusick register int type;
28512703Smckusick {
28612703Smckusick register struct fileusage *fup;
28725377Sserge register FILE *qfi, *qfo;
28841411Smckusick register u_long id, lastid;
28912703Smckusick struct dqblk dqbuf;
29021085Smckusick static int warned = 0;
29141411Smckusick static struct dqblk zerodqbuf;
29241411Smckusick static struct fileusage zerofileusage;
29312660Smckusick
29441411Smckusick if ((qfo = fopen(quotafile, "r+")) == NULL) {
29546783Sbostic if (errno == ENOENT)
29646783Sbostic qfo = fopen(quotafile, "w+");
29746783Sbostic if (qfo) {
29846783Sbostic (void) fprintf(stderr,
29946783Sbostic "quotacheck: creating quota file %s\n", quotafile);
30046783Sbostic #define MODE (S_IRUSR|S_IWUSR|S_IRGRP)
30146783Sbostic (void) fchown(fileno(qfo), getuid(), getquotagid());
30246783Sbostic (void) fchmod(fileno(qfo), MODE);
30346783Sbostic } else {
30446783Sbostic (void) fprintf(stderr,
30546783Sbostic "quotacheck: %s: %s\n", quotafile, strerror(errno));
30641411Smckusick return (1);
30741411Smckusick }
30812660Smckusick }
30941411Smckusick if ((qfi = fopen(quotafile, "r")) == NULL) {
31046783Sbostic (void) fprintf(stderr,
31146783Sbostic "quotacheck: %s: %s\n", quotafile, strerror(errno));
31246783Sbostic (void) fclose(qfo);
31312703Smckusick return (1);
31412660Smckusick }
31541411Smckusick if (quotactl(fsname, QCMD(Q_SYNC, type), (u_long)0, (caddr_t)0) < 0 &&
31641411Smckusick errno == EOPNOTSUPP && !warned && vflag) {
31721085Smckusick warned++;
31854158Sbostic (void)printf("*** Warning: %s\n",
31941411Smckusick "Quotas are not compiled into this kernel");
32021085Smckusick }
32141411Smckusick for (lastid = highid[type], id = 0; id <= lastid; id++) {
32241411Smckusick if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0)
32312802Smckusick dqbuf = zerodqbuf;
32441411Smckusick if ((fup = lookup(id, type)) == 0)
32524758Sserge fup = &zerofileusage;
32641411Smckusick if (dqbuf.dqb_curinodes == fup->fu_curinodes &&
32741411Smckusick dqbuf.dqb_curblocks == fup->fu_curblocks) {
32841411Smckusick fup->fu_curinodes = 0;
32941411Smckusick fup->fu_curblocks = 0;
33025377Sserge fseek(qfo, (long)sizeof(struct dqblk), 1);
33112703Smckusick continue;
33212802Smckusick }
33312703Smckusick if (vflag) {
33441411Smckusick if (aflag)
33541411Smckusick printf("%s: ", fsname);
33641411Smckusick printf("%-8s fixed:", fup->fu_name);
33741411Smckusick if (dqbuf.dqb_curinodes != fup->fu_curinodes)
33854158Sbostic (void)printf("\tinodes %d -> %d",
33941411Smckusick dqbuf.dqb_curinodes, fup->fu_curinodes);
34041411Smckusick if (dqbuf.dqb_curblocks != fup->fu_curblocks)
34154158Sbostic (void)printf("\tblocks %d -> %d",
34241411Smckusick dqbuf.dqb_curblocks, fup->fu_curblocks);
34354158Sbostic (void)printf("\n");
34412660Smckusick }
34541411Smckusick /*
34641411Smckusick * Reset time limit if have a soft limit and were
34741411Smckusick * previously under it, but are now over it.
34841411Smckusick */
34941411Smckusick if (dqbuf.dqb_bsoftlimit &&
35041411Smckusick dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit &&
35141411Smckusick fup->fu_curblocks >= dqbuf.dqb_bsoftlimit)
35241411Smckusick dqbuf.dqb_btime = 0;
35341411Smckusick if (dqbuf.dqb_isoftlimit &&
35441411Smckusick dqbuf.dqb_curblocks < dqbuf.dqb_isoftlimit &&
35541411Smckusick fup->fu_curblocks >= dqbuf.dqb_isoftlimit)
35641411Smckusick dqbuf.dqb_itime = 0;
35741411Smckusick dqbuf.dqb_curinodes = fup->fu_curinodes;
35841411Smckusick dqbuf.dqb_curblocks = fup->fu_curblocks;
35941411Smckusick fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo);
36041411Smckusick (void) quotactl(fsname, QCMD(Q_SETUSE, type), id,
36141411Smckusick (caddr_t)&dqbuf);
36241411Smckusick fup->fu_curinodes = 0;
36341411Smckusick fup->fu_curblocks = 0;
36412660Smckusick }
36541411Smckusick fclose(qfi);
36625377Sserge fflush(qfo);
36741411Smckusick ftruncate(fileno(qfo),
36841411Smckusick (off_t)((highid[type] + 1) * sizeof(struct dqblk)));
36925377Sserge fclose(qfo);
37012703Smckusick return (0);
37112660Smckusick }
37212660Smckusick
37341411Smckusick /*
37441411Smckusick * Check to see if target appears in list of size cnt.
37541411Smckusick */
37654158Sbostic int
oneof(target,list,cnt)37741411Smckusick oneof(target, list, cnt)
37841411Smckusick register char *target, *list[];
37941411Smckusick int cnt;
38012660Smckusick {
38112703Smckusick register int i;
38212660Smckusick
38341411Smckusick for (i = 0; i < cnt; i++)
38441411Smckusick if (strcmp(target, list[i]) == 0)
38541411Smckusick return (i);
38641411Smckusick return (-1);
38712660Smckusick }
38812660Smckusick
38941411Smckusick /*
39041443Smckusick * Determine the group identifier for quota files.
39141443Smckusick */
39254158Sbostic int
getquotagid()39341443Smckusick getquotagid()
39441443Smckusick {
39541443Smckusick struct group *gr;
39641443Smckusick
39741443Smckusick if (gr = getgrnam(quotagroup))
39841443Smckusick return (gr->gr_gid);
39941443Smckusick return (-1);
40041443Smckusick }
40141443Smckusick
40241443Smckusick /*
40341411Smckusick * Check to see if a particular quota is to be enabled.
40441411Smckusick */
40554158Sbostic int
hasquota(fs,type,qfnamep)40641443Smckusick hasquota(fs, type, qfnamep)
40741443Smckusick register struct fstab *fs;
40841411Smckusick int type;
40941443Smckusick char **qfnamep;
41012660Smckusick {
41141411Smckusick register char *opt;
41254158Sbostic char *cp;
41341411Smckusick static char initname, usrname[100], grpname[100];
41441443Smckusick static char buf[BUFSIZ];
41512660Smckusick
41641411Smckusick if (!initname) {
41754158Sbostic (void)snprintf(usrname, sizeof(usrname),
41854158Sbostic "%s%s", qfextension[USRQUOTA], qfname);
41954158Sbostic (void)snprintf(grpname, sizeof(grpname),
42054158Sbostic "%s%s", qfextension[GRPQUOTA], qfname);
42141411Smckusick initname = 1;
42212660Smckusick }
42341443Smckusick strcpy(buf, fs->fs_mntops);
42441411Smckusick for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
425*69000Sbostic if (cp = strchr(opt, '='))
42641443Smckusick *cp++ = '\0';
42741411Smckusick if (type == USRQUOTA && strcmp(opt, usrname) == 0)
42841443Smckusick break;
42941411Smckusick if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
43041443Smckusick break;
43125377Sserge }
43241443Smckusick if (!opt)
43341443Smckusick return (0);
43454158Sbostic if (cp)
43541443Smckusick *qfnamep = cp;
43654158Sbostic else {
43754158Sbostic (void)snprintf(buf, sizeof(buf),
43854158Sbostic "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
43954158Sbostic *qfnamep = buf;
44041443Smckusick }
44141443Smckusick return (1);
44212660Smckusick }
44312660Smckusick
44441411Smckusick /*
44541411Smckusick * Routines to manage the file usage table.
44641411Smckusick *
44741411Smckusick * Lookup an id of a specific type.
44841411Smckusick */
44912703Smckusick struct fileusage *
lookup(id,type)45041411Smckusick lookup(id, type)
45141411Smckusick u_long id;
45241411Smckusick int type;
45312660Smckusick {
45412703Smckusick register struct fileusage *fup;
45512660Smckusick
45641411Smckusick for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next)
45741411Smckusick if (fup->fu_id == id)
45812703Smckusick return (fup);
45954158Sbostic return (NULL);
46012660Smckusick }
46112660Smckusick
46241411Smckusick /*
46341411Smckusick * Add a new file usage id if it does not already exist.
46441411Smckusick */
46512703Smckusick struct fileusage *
addid(id,type,name)46641411Smckusick addid(id, type, name)
46741411Smckusick u_long id;
46841411Smckusick int type;
46941411Smckusick char *name;
47012660Smckusick {
47112703Smckusick struct fileusage *fup, **fhp;
47241411Smckusick int len;
47312660Smckusick
47441411Smckusick if (fup = lookup(id, type))
47512703Smckusick return (fup);
47641411Smckusick if (name)
47741411Smckusick len = strlen(name);
47841411Smckusick else
47941411Smckusick len = 10;
48054158Sbostic if ((fup = calloc(1, sizeof(*fup) + len)) == NULL)
48167700Smckusick err(1, "%s", strerror(errno));
48241411Smckusick fhp = &fuhead[type][id & (FUHASH - 1)];
48312703Smckusick fup->fu_next = *fhp;
48412703Smckusick *fhp = fup;
48541411Smckusick fup->fu_id = id;
48641411Smckusick if (id > highid[type])
48741411Smckusick highid[type] = id;
48854158Sbostic if (name)
489*69000Sbostic memmove(fup->fu_name, name, len + 1);
49054158Sbostic else
49154158Sbostic (void)sprintf(fup->fu_name, "%u", id);
49212703Smckusick return (fup);
49312660Smckusick }
49412660Smckusick
49541411Smckusick /*
49641411Smckusick * Special purpose version of ginode used to optimize pass
49741411Smckusick * over all the inodes in numerical order.
49841411Smckusick */
49941411Smckusick ino_t nextino, lastinum;
50041411Smckusick long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
50141411Smckusick struct dinode *inodebuf;
50241411Smckusick #define INOBUFSIZE 56*1024 /* size of buffer to read inodes */
50341411Smckusick
50441411Smckusick struct dinode *
getnextinode(inumber)50541411Smckusick getnextinode(inumber)
50641411Smckusick ino_t inumber;
50712660Smckusick {
50841411Smckusick long size;
50941411Smckusick daddr_t dblk;
51041411Smckusick static struct dinode *dp;
51112660Smckusick
51254158Sbostic if (inumber != nextino++ || inumber > maxino)
51367700Smckusick err(1, "bad inode number %d to nextinode", inumber);
51441411Smckusick if (inumber >= lastinum) {
51541411Smckusick readcnt++;
51664640Sbostic dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
51741411Smckusick if (readcnt % readpercg == 0) {
51841411Smckusick size = partialsize;
51941411Smckusick lastinum += partialcnt;
52041411Smckusick } else {
52141411Smckusick size = inobufsize;
52241411Smckusick lastinum += fullcnt;
52341411Smckusick }
52441411Smckusick bread(dblk, (char *)inodebuf, size);
52541411Smckusick dp = inodebuf;
52641411Smckusick }
52741411Smckusick return (dp++);
52812660Smckusick }
52941411Smckusick
53041411Smckusick /*
53141411Smckusick * Prepare to scan a set of inodes.
53241411Smckusick */
53354158Sbostic void
resetinodebuf()53441411Smckusick resetinodebuf()
53541411Smckusick {
53641411Smckusick
53741411Smckusick nextino = 0;
53841411Smckusick lastinum = 0;
53941411Smckusick readcnt = 0;
54041411Smckusick inobufsize = blkroundup(&sblock, INOBUFSIZE);
54141411Smckusick fullcnt = inobufsize / sizeof(struct dinode);
54241411Smckusick readpercg = sblock.fs_ipg / fullcnt;
54341411Smckusick partialcnt = sblock.fs_ipg % fullcnt;
54441411Smckusick partialsize = partialcnt * sizeof(struct dinode);
54541411Smckusick if (partialcnt != 0) {
54641411Smckusick readpercg++;
54741411Smckusick } else {
54841411Smckusick partialcnt = fullcnt;
54941411Smckusick partialsize = inobufsize;
55041411Smckusick }
55141411Smckusick if (inodebuf == NULL &&
55254158Sbostic (inodebuf = malloc((u_int)inobufsize)) == NULL)
55367700Smckusick err(1, "%s", strerror(errno));
55441411Smckusick while (nextino < ROOTINO)
55541411Smckusick getnextinode(nextino);
55641411Smckusick }
55741411Smckusick
55841411Smckusick /*
55941411Smckusick * Free up data structures used to scan inodes.
56041411Smckusick */
56154158Sbostic void
freeinodebuf()56241411Smckusick freeinodebuf()
56341411Smckusick {
56441411Smckusick
56541411Smckusick if (inodebuf != NULL)
56654158Sbostic free(inodebuf);
56741411Smckusick inodebuf = NULL;
56841411Smckusick }
56941411Smckusick
57041411Smckusick /*
57141411Smckusick * Read specified disk blocks.
57241411Smckusick */
57354158Sbostic void
bread(bno,buf,cnt)57441411Smckusick bread(bno, buf, cnt)
57541411Smckusick daddr_t bno;
57641411Smckusick char *buf;
57741411Smckusick long cnt;
57841411Smckusick {
57941411Smckusick
58058002Sralph if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0 ||
58154158Sbostic read(fi, buf, cnt) != cnt)
58267700Smckusick err(1, "block %ld", bno);
58354158Sbostic }
584