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*67700Smckusick static char sccsid[] = "@(#)quotacheck.c 8.4 (Berkeley) 08/17/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> 40*67700Smckusick #include <err.h> 4112660Smckusick 4245251Smckusick char *qfname = QUOTAFILENAME; 4345251Smckusick char *qfextension[] = INITQFNAMES; 4445251Smckusick char *quotagroup = QUOTAGROUP; 4545251Smckusick 4612660Smckusick union { 4712660Smckusick struct fs sblk; 4812703Smckusick char dummy[MAXBSIZE]; 4912660Smckusick } un; 5012660Smckusick #define sblock un.sblk 51*67700Smckusick long dev_bsize; 5241411Smckusick long maxino; 5312703Smckusick 5441443Smckusick struct quotaname { 5541443Smckusick long flags; 5641443Smckusick char grpqfname[MAXPATHLEN + 1]; 5741443Smckusick char usrqfname[MAXPATHLEN + 1]; 5841443Smckusick }; 5941443Smckusick #define HASUSR 1 6041443Smckusick #define HASGRP 2 6141443Smckusick 6212703Smckusick struct fileusage { 6341411Smckusick struct fileusage *fu_next; 6441411Smckusick u_long fu_curinodes; 6541411Smckusick u_long fu_curblocks; 6641411Smckusick u_long fu_id; 6741411Smckusick char fu_name[1]; 6841411Smckusick /* actually bigger */ 6912703Smckusick }; 7041411Smckusick #define FUHASH 1024 /* must be power of two */ 7141411Smckusick struct fileusage *fuhead[MAXQUOTAS][FUHASH]; 7212660Smckusick 7341411Smckusick int aflag; /* all file systems */ 7441411Smckusick int gflag; /* check group quotas */ 7541411Smckusick int uflag; /* check user quotas */ 7641411Smckusick int vflag; /* verbose */ 7741411Smckusick int fi; /* open disk file descriptor */ 7841411Smckusick u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */ 7912703Smckusick 8054158Sbostic struct fileusage * 8154158Sbostic addid __P((u_long, int, char *)); 8254158Sbostic char *blockcheck __P((char *)); 8354158Sbostic void bread __P((daddr_t, char *, long)); 8454158Sbostic int chkquota __P((char *, char *, struct quotaname *)); 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; 10765941Sbostic int i, argnum, maxrun, errs; 10854158Sbostic long done = 0; 10954158Sbostic char ch, *name; 11012660Smckusick 11165941Sbostic 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) 156*67700Smckusick err(1, "%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) 194*67700Smckusick err(1, "%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(); 237*67700Smckusick dev_bsize = 1; 23841411Smckusick bread(SBOFF, (char *)&sblock, (long)SBSIZE); 23941411Smckusick dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 24041411Smckusick maxino = sblock.fs_ncg * sblock.fs_ipg; 24141411Smckusick resetinodebuf(); 24241411Smckusick for (ino = 0, cg = 0; cg < sblock.fs_ncg; cg++) { 24341411Smckusick for (i = 0; i < sblock.fs_ipg; i++, ino++) { 24441411Smckusick if (ino < ROOTINO) 24524758Sserge continue; 24641411Smckusick if ((dp = getnextinode(ino)) == NULL) 24724758Sserge continue; 24841411Smckusick if ((mode = dp->di_mode & IFMT) == 0) 24941411Smckusick continue; 25041443Smckusick if (qnp->flags & HASGRP) { 25141411Smckusick fup = addid((u_long)dp->di_gid, GRPQUOTA, 25241411Smckusick (char *)0); 25341411Smckusick fup->fu_curinodes++; 25441411Smckusick if (mode == IFREG || mode == IFDIR || 25541411Smckusick mode == IFLNK) 25641411Smckusick fup->fu_curblocks += dp->di_blocks; 25724758Sserge } 25841443Smckusick if (qnp->flags & HASUSR) { 25941411Smckusick fup = addid((u_long)dp->di_uid, USRQUOTA, 26041411Smckusick (char *)0); 26141411Smckusick fup->fu_curinodes++; 26241411Smckusick if (mode == IFREG || mode == IFDIR || 26341411Smckusick mode == IFLNK) 26441411Smckusick fup->fu_curblocks += dp->di_blocks; 26541411Smckusick } 26624758Sserge } 26741411Smckusick } 26841411Smckusick freeinodebuf(); 26941443Smckusick if (qnp->flags & HASUSR) 27041443Smckusick errs += update(mntpt, qnp->usrqfname, USRQUOTA); 27141443Smckusick if (qnp->flags & HASGRP) 27241443Smckusick errs += update(mntpt, qnp->grpqfname, GRPQUOTA); 27341411Smckusick close(fi); 27424758Sserge return (errs); 27524758Sserge } 27624758Sserge 27741411Smckusick /* 27841411Smckusick * Update a specified quota file. 27941411Smckusick */ 28054158Sbostic int 28141443Smckusick update(fsname, quotafile, type) 28241443Smckusick char *fsname, *quotafile; 28341411Smckusick register int type; 28412703Smckusick { 28512703Smckusick register struct fileusage *fup; 28625377Sserge register FILE *qfi, *qfo; 28741411Smckusick register u_long id, lastid; 28812703Smckusick struct dqblk dqbuf; 28921085Smckusick static int warned = 0; 29041411Smckusick static struct dqblk zerodqbuf; 29141411Smckusick static struct fileusage zerofileusage; 29212660Smckusick 29341411Smckusick if ((qfo = fopen(quotafile, "r+")) == NULL) { 29446783Sbostic if (errno == ENOENT) 29546783Sbostic qfo = fopen(quotafile, "w+"); 29646783Sbostic if (qfo) { 29746783Sbostic (void) fprintf(stderr, 29846783Sbostic "quotacheck: creating quota file %s\n", quotafile); 29946783Sbostic #define MODE (S_IRUSR|S_IWUSR|S_IRGRP) 30046783Sbostic (void) fchown(fileno(qfo), getuid(), getquotagid()); 30146783Sbostic (void) fchmod(fileno(qfo), MODE); 30246783Sbostic } else { 30346783Sbostic (void) fprintf(stderr, 30446783Sbostic "quotacheck: %s: %s\n", quotafile, strerror(errno)); 30541411Smckusick return (1); 30641411Smckusick } 30712660Smckusick } 30841411Smckusick if ((qfi = fopen(quotafile, "r")) == NULL) { 30946783Sbostic (void) fprintf(stderr, 31046783Sbostic "quotacheck: %s: %s\n", quotafile, strerror(errno)); 31146783Sbostic (void) fclose(qfo); 31212703Smckusick return (1); 31312660Smckusick } 31441411Smckusick if (quotactl(fsname, QCMD(Q_SYNC, type), (u_long)0, (caddr_t)0) < 0 && 31541411Smckusick errno == EOPNOTSUPP && !warned && vflag) { 31621085Smckusick warned++; 31754158Sbostic (void)printf("*** Warning: %s\n", 31841411Smckusick "Quotas are not compiled into this kernel"); 31921085Smckusick } 32041411Smckusick for (lastid = highid[type], id = 0; id <= lastid; id++) { 32141411Smckusick if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0) 32212802Smckusick dqbuf = zerodqbuf; 32341411Smckusick if ((fup = lookup(id, type)) == 0) 32424758Sserge fup = &zerofileusage; 32541411Smckusick if (dqbuf.dqb_curinodes == fup->fu_curinodes && 32641411Smckusick dqbuf.dqb_curblocks == fup->fu_curblocks) { 32741411Smckusick fup->fu_curinodes = 0; 32841411Smckusick fup->fu_curblocks = 0; 32925377Sserge fseek(qfo, (long)sizeof(struct dqblk), 1); 33012703Smckusick continue; 33112802Smckusick } 33212703Smckusick if (vflag) { 33341411Smckusick if (aflag) 33441411Smckusick printf("%s: ", fsname); 33541411Smckusick printf("%-8s fixed:", fup->fu_name); 33641411Smckusick if (dqbuf.dqb_curinodes != fup->fu_curinodes) 33754158Sbostic (void)printf("\tinodes %d -> %d", 33841411Smckusick dqbuf.dqb_curinodes, fup->fu_curinodes); 33941411Smckusick if (dqbuf.dqb_curblocks != fup->fu_curblocks) 34054158Sbostic (void)printf("\tblocks %d -> %d", 34141411Smckusick dqbuf.dqb_curblocks, fup->fu_curblocks); 34254158Sbostic (void)printf("\n"); 34312660Smckusick } 34441411Smckusick /* 34541411Smckusick * Reset time limit if have a soft limit and were 34641411Smckusick * previously under it, but are now over it. 34741411Smckusick */ 34841411Smckusick if (dqbuf.dqb_bsoftlimit && 34941411Smckusick dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit && 35041411Smckusick fup->fu_curblocks >= dqbuf.dqb_bsoftlimit) 35141411Smckusick dqbuf.dqb_btime = 0; 35241411Smckusick if (dqbuf.dqb_isoftlimit && 35341411Smckusick dqbuf.dqb_curblocks < dqbuf.dqb_isoftlimit && 35441411Smckusick fup->fu_curblocks >= dqbuf.dqb_isoftlimit) 35541411Smckusick dqbuf.dqb_itime = 0; 35641411Smckusick dqbuf.dqb_curinodes = fup->fu_curinodes; 35741411Smckusick dqbuf.dqb_curblocks = fup->fu_curblocks; 35841411Smckusick fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo); 35941411Smckusick (void) quotactl(fsname, QCMD(Q_SETUSE, type), id, 36041411Smckusick (caddr_t)&dqbuf); 36141411Smckusick fup->fu_curinodes = 0; 36241411Smckusick fup->fu_curblocks = 0; 36312660Smckusick } 36441411Smckusick fclose(qfi); 36525377Sserge fflush(qfo); 36641411Smckusick ftruncate(fileno(qfo), 36741411Smckusick (off_t)((highid[type] + 1) * sizeof(struct dqblk))); 36825377Sserge fclose(qfo); 36912703Smckusick return (0); 37012660Smckusick } 37112660Smckusick 37241411Smckusick /* 37341411Smckusick * Check to see if target appears in list of size cnt. 37441411Smckusick */ 37554158Sbostic int 37641411Smckusick oneof(target, list, cnt) 37741411Smckusick register char *target, *list[]; 37841411Smckusick int cnt; 37912660Smckusick { 38012703Smckusick register int i; 38112660Smckusick 38241411Smckusick for (i = 0; i < cnt; i++) 38341411Smckusick if (strcmp(target, list[i]) == 0) 38441411Smckusick return (i); 38541411Smckusick return (-1); 38612660Smckusick } 38712660Smckusick 38841411Smckusick /* 38941443Smckusick * Determine the group identifier for quota files. 39041443Smckusick */ 39154158Sbostic int 39241443Smckusick getquotagid() 39341443Smckusick { 39441443Smckusick struct group *gr; 39541443Smckusick 39641443Smckusick if (gr = getgrnam(quotagroup)) 39741443Smckusick return (gr->gr_gid); 39841443Smckusick return (-1); 39941443Smckusick } 40041443Smckusick 40141443Smckusick /* 40241411Smckusick * Check to see if a particular quota is to be enabled. 40341411Smckusick */ 40454158Sbostic int 40541443Smckusick hasquota(fs, type, qfnamep) 40641443Smckusick register struct fstab *fs; 40741411Smckusick int type; 40841443Smckusick char **qfnamep; 40912660Smckusick { 41041411Smckusick register char *opt; 41154158Sbostic char *cp; 41241411Smckusick static char initname, usrname[100], grpname[100]; 41341443Smckusick static char buf[BUFSIZ]; 41412660Smckusick 41541411Smckusick if (!initname) { 41654158Sbostic (void)snprintf(usrname, sizeof(usrname), 41754158Sbostic "%s%s", qfextension[USRQUOTA], qfname); 41854158Sbostic (void)snprintf(grpname, sizeof(grpname), 41954158Sbostic "%s%s", qfextension[GRPQUOTA], qfname); 42041411Smckusick initname = 1; 42112660Smckusick } 42241443Smckusick strcpy(buf, fs->fs_mntops); 42341411Smckusick for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 42441443Smckusick if (cp = index(opt, '=')) 42541443Smckusick *cp++ = '\0'; 42641411Smckusick if (type == USRQUOTA && strcmp(opt, usrname) == 0) 42741443Smckusick break; 42841411Smckusick if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 42941443Smckusick break; 43025377Sserge } 43141443Smckusick if (!opt) 43241443Smckusick return (0); 43354158Sbostic if (cp) 43441443Smckusick *qfnamep = cp; 43554158Sbostic else { 43654158Sbostic (void)snprintf(buf, sizeof(buf), 43754158Sbostic "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 43854158Sbostic *qfnamep = buf; 43941443Smckusick } 44041443Smckusick return (1); 44112660Smckusick } 44212660Smckusick 44341411Smckusick /* 44441411Smckusick * Routines to manage the file usage table. 44541411Smckusick * 44641411Smckusick * Lookup an id of a specific type. 44741411Smckusick */ 44812703Smckusick struct fileusage * 44941411Smckusick lookup(id, type) 45041411Smckusick u_long id; 45141411Smckusick int type; 45212660Smckusick { 45312703Smckusick register struct fileusage *fup; 45412660Smckusick 45541411Smckusick for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next) 45641411Smckusick if (fup->fu_id == id) 45712703Smckusick return (fup); 45854158Sbostic return (NULL); 45912660Smckusick } 46012660Smckusick 46141411Smckusick /* 46241411Smckusick * Add a new file usage id if it does not already exist. 46341411Smckusick */ 46412703Smckusick struct fileusage * 46541411Smckusick addid(id, type, name) 46641411Smckusick u_long id; 46741411Smckusick int type; 46841411Smckusick char *name; 46912660Smckusick { 47012703Smckusick struct fileusage *fup, **fhp; 47141411Smckusick int len; 47212660Smckusick 47341411Smckusick if (fup = lookup(id, type)) 47412703Smckusick return (fup); 47541411Smckusick if (name) 47641411Smckusick len = strlen(name); 47741411Smckusick else 47841411Smckusick len = 10; 47954158Sbostic if ((fup = calloc(1, sizeof(*fup) + len)) == NULL) 480*67700Smckusick err(1, "%s", strerror(errno)); 48141411Smckusick fhp = &fuhead[type][id & (FUHASH - 1)]; 48212703Smckusick fup->fu_next = *fhp; 48312703Smckusick *fhp = fup; 48441411Smckusick fup->fu_id = id; 48541411Smckusick if (id > highid[type]) 48641411Smckusick highid[type] = id; 48754158Sbostic if (name) 48841411Smckusick bcopy(name, fup->fu_name, len + 1); 48954158Sbostic else 49054158Sbostic (void)sprintf(fup->fu_name, "%u", id); 49112703Smckusick return (fup); 49212660Smckusick } 49312660Smckusick 49441411Smckusick /* 49541411Smckusick * Special purpose version of ginode used to optimize pass 49641411Smckusick * over all the inodes in numerical order. 49741411Smckusick */ 49841411Smckusick ino_t nextino, lastinum; 49941411Smckusick long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 50041411Smckusick struct dinode *inodebuf; 50141411Smckusick #define INOBUFSIZE 56*1024 /* size of buffer to read inodes */ 50241411Smckusick 50341411Smckusick struct dinode * 50441411Smckusick getnextinode(inumber) 50541411Smckusick ino_t inumber; 50612660Smckusick { 50741411Smckusick long size; 50841411Smckusick daddr_t dblk; 50941411Smckusick static struct dinode *dp; 51012660Smckusick 51154158Sbostic if (inumber != nextino++ || inumber > maxino) 512*67700Smckusick err(1, "bad inode number %d to nextinode", inumber); 51341411Smckusick if (inumber >= lastinum) { 51441411Smckusick readcnt++; 51564640Sbostic dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum)); 51641411Smckusick if (readcnt % readpercg == 0) { 51741411Smckusick size = partialsize; 51841411Smckusick lastinum += partialcnt; 51941411Smckusick } else { 52041411Smckusick size = inobufsize; 52141411Smckusick lastinum += fullcnt; 52241411Smckusick } 52341411Smckusick bread(dblk, (char *)inodebuf, size); 52441411Smckusick dp = inodebuf; 52541411Smckusick } 52641411Smckusick return (dp++); 52712660Smckusick } 52841411Smckusick 52941411Smckusick /* 53041411Smckusick * Prepare to scan a set of inodes. 53141411Smckusick */ 53254158Sbostic void 53341411Smckusick resetinodebuf() 53441411Smckusick { 53541411Smckusick 53641411Smckusick nextino = 0; 53741411Smckusick lastinum = 0; 53841411Smckusick readcnt = 0; 53941411Smckusick inobufsize = blkroundup(&sblock, INOBUFSIZE); 54041411Smckusick fullcnt = inobufsize / sizeof(struct dinode); 54141411Smckusick readpercg = sblock.fs_ipg / fullcnt; 54241411Smckusick partialcnt = sblock.fs_ipg % fullcnt; 54341411Smckusick partialsize = partialcnt * sizeof(struct dinode); 54441411Smckusick if (partialcnt != 0) { 54541411Smckusick readpercg++; 54641411Smckusick } else { 54741411Smckusick partialcnt = fullcnt; 54841411Smckusick partialsize = inobufsize; 54941411Smckusick } 55041411Smckusick if (inodebuf == NULL && 55154158Sbostic (inodebuf = malloc((u_int)inobufsize)) == NULL) 552*67700Smckusick err(1, "%s", strerror(errno)); 55341411Smckusick while (nextino < ROOTINO) 55441411Smckusick getnextinode(nextino); 55541411Smckusick } 55641411Smckusick 55741411Smckusick /* 55841411Smckusick * Free up data structures used to scan inodes. 55941411Smckusick */ 56054158Sbostic void 56141411Smckusick freeinodebuf() 56241411Smckusick { 56341411Smckusick 56441411Smckusick if (inodebuf != NULL) 56554158Sbostic free(inodebuf); 56641411Smckusick inodebuf = NULL; 56741411Smckusick } 56841411Smckusick 56941411Smckusick /* 57041411Smckusick * Read specified disk blocks. 57141411Smckusick */ 57254158Sbostic void 57341411Smckusick bread(bno, buf, cnt) 57441411Smckusick daddr_t bno; 57541411Smckusick char *buf; 57641411Smckusick long cnt; 57741411Smckusick { 57841411Smckusick 57958002Sralph if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0 || 58054158Sbostic read(fi, buf, cnt) != cnt) 581*67700Smckusick err(1, "block %ld", bno); 58254158Sbostic } 583