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*67976Smckusick static char sccsid[] = "@(#)quotacheck.c 8.5 (Berkeley) 11/22/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> 26*67976Smckusick #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 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 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 * 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 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 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 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 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 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, ",")) { 42541443Smckusick if (cp = index(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 * 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 * 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) 48941411Smckusick bcopy(name, fup->fu_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 * 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 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 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 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