121517Smckusick /* 241411Smckusick * Copyright (c) 1980, 1990 Regents of the University of California. 334364Sbostic * 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 1221517Smckusick char copyright[] = 1341411Smckusick "@(#) Copyright (c) 1980, 1990 Regents of the University of California.\n\ 1421517Smckusick All rights reserved.\n"; 1534364Sbostic #endif /* not lint */ 1612660Smckusick 1721517Smckusick #ifndef lint 18*45251Smckusick static char sccsid[] = "@(#)quotacheck.c 5.15 (Berkeley) 09/27/90"; 1934364Sbostic #endif /* not lint */ 2021517Smckusick 2112660Smckusick /* 2241411Smckusick * Fix up / report on disk quotas & usage 2312660Smckusick */ 2412660Smckusick #include <sys/param.h> 2541411Smckusick #include <ufs/dinode.h> 2638511Sbostic #include <ufs/fs.h> 2738511Sbostic #include <ufs/quota.h> 2812703Smckusick #include <fstab.h> 2912802Smckusick #include <pwd.h> 3041411Smckusick #include <grp.h> 3138511Sbostic #include <stdio.h> 3238511Sbostic #include <errno.h> 3312660Smckusick 34*45251Smckusick char *qfname = QUOTAFILENAME; 35*45251Smckusick char *qfextension[] = INITQFNAMES; 36*45251Smckusick char *quotagroup = QUOTAGROUP; 37*45251Smckusick 3812660Smckusick union { 3912660Smckusick struct fs sblk; 4012703Smckusick char dummy[MAXBSIZE]; 4112660Smckusick } un; 4212660Smckusick #define sblock un.sblk 4341411Smckusick long dev_bsize = 1; 4441411Smckusick long maxino; 4512703Smckusick 4641443Smckusick struct quotaname { 4741443Smckusick long flags; 4841443Smckusick char grpqfname[MAXPATHLEN + 1]; 4941443Smckusick char usrqfname[MAXPATHLEN + 1]; 5041443Smckusick }; 5141443Smckusick #define HASUSR 1 5241443Smckusick #define HASGRP 2 5341443Smckusick 5412703Smckusick struct fileusage { 5541411Smckusick struct fileusage *fu_next; 5641411Smckusick u_long fu_curinodes; 5741411Smckusick u_long fu_curblocks; 5841411Smckusick u_long fu_id; 5941411Smckusick char fu_name[1]; 6041411Smckusick /* actually bigger */ 6112703Smckusick }; 6241411Smckusick #define FUHASH 1024 /* must be power of two */ 6341411Smckusick struct fileusage *fuhead[MAXQUOTAS][FUHASH]; 6412703Smckusick struct fileusage *lookup(); 6541411Smckusick struct fileusage *addid(); 6641411Smckusick struct dinode *getnextinode(); 6712660Smckusick 6841411Smckusick int aflag; /* all file systems */ 6941411Smckusick int gflag; /* check group quotas */ 7041411Smckusick int uflag; /* check user quotas */ 7141411Smckusick int vflag; /* verbose */ 7241411Smckusick int fi; /* open disk file descriptor */ 7341411Smckusick u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */ 7412703Smckusick 7512660Smckusick main(argc, argv) 7612703Smckusick int argc; 7712660Smckusick char **argv; 7812660Smckusick { 7912703Smckusick register struct fstab *fs; 8012802Smckusick register struct passwd *pw; 8141411Smckusick register struct group *gr; 8241411Smckusick int i, argnum, maxrun, errs = 0; 8341411Smckusick long auxdata, done = 0; 8441411Smckusick char ch, *name, *blockcheck(); 8541411Smckusick int needchk(), chkquota(); 8641411Smckusick extern char *optarg; 8741411Smckusick extern int optind; 8812660Smckusick 8941411Smckusick while ((ch = getopt(argc, argv, "aguvl:")) != EOF) { 9041411Smckusick switch(ch) { 9141411Smckusick case 'a': 9241411Smckusick aflag++; 9341411Smckusick break; 9441411Smckusick case 'g': 9541411Smckusick gflag++; 9641411Smckusick break; 9741411Smckusick case 'u': 9841411Smckusick uflag++; 9941411Smckusick break; 10041411Smckusick case 'v': 10141411Smckusick vflag++; 10241411Smckusick break; 10341411Smckusick case 'l': 10441411Smckusick maxrun = atoi(optarg); 10541411Smckusick break; 10641411Smckusick default: 10741411Smckusick usage(); 10841411Smckusick } 10912660Smckusick } 11041411Smckusick argc -= optind; 11141411Smckusick argv += optind; 11241411Smckusick if ((argc == 0 && !aflag) || (argc > 0 && aflag)) 11341411Smckusick usage(); 11441411Smckusick if (!gflag && !uflag) { 11541411Smckusick gflag++; 11641411Smckusick uflag++; 11712703Smckusick } 11841411Smckusick if (gflag) { 11941411Smckusick setgrent(); 12041411Smckusick while ((gr = getgrent()) != 0) 12141411Smckusick (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name); 12241411Smckusick endgrent(); 12324758Sserge } 12441411Smckusick if (uflag) { 12541411Smckusick setpwent(); 12641411Smckusick while ((pw = getpwent()) != 0) 12741411Smckusick (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name); 12841411Smckusick endpwent(); 12912660Smckusick } 13041411Smckusick if (aflag) 13141411Smckusick exit(checkfstab(1, maxrun, needchk, chkquota)); 13241411Smckusick if (setfsent() == 0) { 13341411Smckusick fprintf(stderr, "Can't open "); 13441411Smckusick perror(FSTAB); 13541411Smckusick exit(8); 13612802Smckusick } 13741411Smckusick while ((fs = getfsent()) != NULL) { 13841411Smckusick if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || 13941411Smckusick (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) && 14041411Smckusick (auxdata = needchk(fs)) && 14141411Smckusick (name = blockcheck(fs->fs_spec))) { 14241411Smckusick done |= 1 << argnum; 14341411Smckusick errs += chkquota(name, fs->fs_file, auxdata); 14424758Sserge } 14512660Smckusick } 14641411Smckusick endfsent(); 14712703Smckusick for (i = 0; i < argc; i++) 14812703Smckusick if ((done & (1 << i)) == 0) 14924782Sserge fprintf(stderr, "%s not found in %s\n", 15024782Sserge argv[i], FSTAB); 15112703Smckusick exit(errs); 15212703Smckusick } 15312660Smckusick 15441411Smckusick usage() 15524758Sserge { 15624758Sserge 15741411Smckusick fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 15841411Smckusick "quotacheck [-g] [-u] [-v] -a", 15941411Smckusick "quotacheck [-g] [-u] [-v] filesys ..."); 16041411Smckusick exit(1); 16141411Smckusick } 16224758Sserge 16341411Smckusick needchk(fs) 16441411Smckusick register struct fstab *fs; 16541411Smckusick { 16641443Smckusick register struct quotaname *qnp; 16741443Smckusick char *qfnp; 16824758Sserge 16941443Smckusick if (strcmp(fs->fs_vfstype, "ufs") || 17041443Smckusick strcmp(fs->fs_type, FSTAB_RW)) 17141443Smckusick return (0); 17241443Smckusick if ((qnp = (struct quotaname *)malloc(sizeof *qnp)) == 0) { 17341443Smckusick fprintf(stderr, "out of memory for quota structures\n"); 17441443Smckusick exit(1); 17541443Smckusick } 17641443Smckusick qnp->flags = 0; 17741443Smckusick if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) { 17841443Smckusick strcpy(qnp->grpqfname, qfnp); 17941443Smckusick qnp->flags |= HASGRP; 18041443Smckusick } 18141443Smckusick if (uflag && hasquota(fs, USRQUOTA, &qfnp)) { 18241443Smckusick strcpy(qnp->usrqfname, qfnp); 18341443Smckusick qnp->flags |= HASUSR; 18441443Smckusick } 18541443Smckusick if (qnp->flags) 18641443Smckusick return ((int)qnp); 18741443Smckusick free((char *)qnp); 18841443Smckusick return (0); 18941411Smckusick } 19024758Sserge 19141411Smckusick /* 19241411Smckusick * Scan the specified filesystem to check quota(s) present on it. 19341411Smckusick */ 19441443Smckusick chkquota(fsname, mntpt, qnp) 19541411Smckusick char *fsname, *mntpt; 19641443Smckusick register struct quotaname *qnp; 19741411Smckusick { 19841411Smckusick register struct fileusage *fup; 19941411Smckusick register struct dinode *dp; 20041411Smckusick int cg, i, mode, errs = 0; 20141411Smckusick ino_t ino; 20224758Sserge 20341411Smckusick if ((fi = open(fsname, 0)) < 0) { 20441411Smckusick perror(fsname); 20541411Smckusick return (1); 20641411Smckusick } 20741411Smckusick if (vflag) { 20841411Smckusick fprintf(stdout, "*** Checking "); 20941443Smckusick if (qnp->flags & HASUSR) 21041411Smckusick fprintf(stdout, "%s%s", qfextension[USRQUOTA], 21141443Smckusick (qnp->flags & HASGRP) ? " and " : ""); 21241443Smckusick if (qnp->flags & HASGRP) 21341411Smckusick fprintf(stdout, "%s", qfextension[GRPQUOTA]); 21441411Smckusick fprintf(stdout, " quotas for %s (%s)\n", fsname, mntpt); 21541411Smckusick } 21641411Smckusick sync(); 21741411Smckusick bread(SBOFF, (char *)&sblock, (long)SBSIZE); 21841411Smckusick dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 21941411Smckusick maxino = sblock.fs_ncg * sblock.fs_ipg; 22041411Smckusick resetinodebuf(); 22141411Smckusick for (ino = 0, cg = 0; cg < sblock.fs_ncg; cg++) { 22241411Smckusick for (i = 0; i < sblock.fs_ipg; i++, ino++) { 22341411Smckusick if (ino < ROOTINO) 22424758Sserge continue; 22541411Smckusick if ((dp = getnextinode(ino)) == NULL) 22624758Sserge continue; 22741411Smckusick if ((mode = dp->di_mode & IFMT) == 0) 22841411Smckusick continue; 22941443Smckusick if (qnp->flags & HASGRP) { 23041411Smckusick fup = addid((u_long)dp->di_gid, GRPQUOTA, 23141411Smckusick (char *)0); 23241411Smckusick fup->fu_curinodes++; 23341411Smckusick if (mode == IFREG || mode == IFDIR || 23441411Smckusick mode == IFLNK) 23541411Smckusick fup->fu_curblocks += dp->di_blocks; 23624758Sserge } 23741443Smckusick if (qnp->flags & HASUSR) { 23841411Smckusick fup = addid((u_long)dp->di_uid, USRQUOTA, 23941411Smckusick (char *)0); 24041411Smckusick fup->fu_curinodes++; 24141411Smckusick if (mode == IFREG || mode == IFDIR || 24241411Smckusick mode == IFLNK) 24341411Smckusick fup->fu_curblocks += dp->di_blocks; 24441411Smckusick } 24524758Sserge } 24641411Smckusick } 24741411Smckusick freeinodebuf(); 24841443Smckusick if (qnp->flags & HASUSR) 24941443Smckusick errs += update(mntpt, qnp->usrqfname, USRQUOTA); 25041443Smckusick if (qnp->flags & HASGRP) 25141443Smckusick errs += update(mntpt, qnp->grpqfname, GRPQUOTA); 25241411Smckusick close(fi); 25324758Sserge return (errs); 25424758Sserge } 25524758Sserge 25641411Smckusick /* 25741411Smckusick * Update a specified quota file. 25841411Smckusick */ 25941443Smckusick update(fsname, quotafile, type) 26041443Smckusick char *fsname, *quotafile; 26141411Smckusick register int type; 26212703Smckusick { 26312703Smckusick register struct fileusage *fup; 26425377Sserge register FILE *qfi, *qfo; 26541411Smckusick register u_long id, lastid; 26612703Smckusick struct dqblk dqbuf; 26741411Smckusick extern int errno; 26821085Smckusick static int warned = 0; 26941411Smckusick static struct dqblk zerodqbuf; 27041411Smckusick static struct fileusage zerofileusage; 27112660Smckusick 27241411Smckusick if ((qfo = fopen(quotafile, "r+")) == NULL) { 27341411Smckusick if (errno != ENOENT) { 27441411Smckusick perror(quotafile); 27541411Smckusick return (1); 27641411Smckusick } 27741411Smckusick if ((qfo = fopen(quotafile, "w+")) == NULL) { 27841411Smckusick perror(quotafile); 27941411Smckusick return (1); 28041411Smckusick } 28141443Smckusick fprintf(stderr, "Creating quota file %s\n", quotafile); 28241443Smckusick (void) fchown(fileno(qfo), getuid(), getquotagid()); 28341443Smckusick (void) fchmod(fileno(qfo), 0640); 28412660Smckusick } 28541411Smckusick if ((qfi = fopen(quotafile, "r")) == NULL) { 28641411Smckusick perror(quotafile); 28741411Smckusick fclose(qfo); 28812703Smckusick return (1); 28912660Smckusick } 29041411Smckusick if (quotactl(fsname, QCMD(Q_SYNC, type), (u_long)0, (caddr_t)0) < 0 && 29141411Smckusick errno == EOPNOTSUPP && !warned && vflag) { 29221085Smckusick warned++; 29341411Smckusick fprintf(stdout, "*** Warning: %s\n", 29441411Smckusick "Quotas are not compiled into this kernel"); 29521085Smckusick } 29641411Smckusick for (lastid = highid[type], id = 0; id <= lastid; id++) { 29741411Smckusick if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0) 29812802Smckusick dqbuf = zerodqbuf; 29941411Smckusick if ((fup = lookup(id, type)) == 0) 30024758Sserge fup = &zerofileusage; 30141411Smckusick if (dqbuf.dqb_curinodes == fup->fu_curinodes && 30241411Smckusick dqbuf.dqb_curblocks == fup->fu_curblocks) { 30341411Smckusick fup->fu_curinodes = 0; 30441411Smckusick fup->fu_curblocks = 0; 30525377Sserge fseek(qfo, (long)sizeof(struct dqblk), 1); 30612703Smckusick continue; 30712802Smckusick } 30812703Smckusick if (vflag) { 30941411Smckusick if (aflag) 31041411Smckusick printf("%s: ", fsname); 31141411Smckusick printf("%-8s fixed:", fup->fu_name); 31241411Smckusick if (dqbuf.dqb_curinodes != fup->fu_curinodes) 31325377Sserge fprintf(stdout, "\tinodes %d -> %d", 31441411Smckusick dqbuf.dqb_curinodes, fup->fu_curinodes); 31541411Smckusick if (dqbuf.dqb_curblocks != fup->fu_curblocks) 31625377Sserge fprintf(stdout, "\tblocks %d -> %d", 31741411Smckusick dqbuf.dqb_curblocks, fup->fu_curblocks); 31824758Sserge fprintf(stdout, "\n"); 31912660Smckusick } 32041411Smckusick /* 32141411Smckusick * Reset time limit if have a soft limit and were 32241411Smckusick * previously under it, but are now over it. 32341411Smckusick */ 32441411Smckusick if (dqbuf.dqb_bsoftlimit && 32541411Smckusick dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit && 32641411Smckusick fup->fu_curblocks >= dqbuf.dqb_bsoftlimit) 32741411Smckusick dqbuf.dqb_btime = 0; 32841411Smckusick if (dqbuf.dqb_isoftlimit && 32941411Smckusick dqbuf.dqb_curblocks < dqbuf.dqb_isoftlimit && 33041411Smckusick fup->fu_curblocks >= dqbuf.dqb_isoftlimit) 33141411Smckusick dqbuf.dqb_itime = 0; 33241411Smckusick dqbuf.dqb_curinodes = fup->fu_curinodes; 33341411Smckusick dqbuf.dqb_curblocks = fup->fu_curblocks; 33441411Smckusick fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo); 33541411Smckusick (void) quotactl(fsname, QCMD(Q_SETUSE, type), id, 33641411Smckusick (caddr_t)&dqbuf); 33741411Smckusick fup->fu_curinodes = 0; 33841411Smckusick fup->fu_curblocks = 0; 33912660Smckusick } 34041411Smckusick fclose(qfi); 34125377Sserge fflush(qfo); 34241411Smckusick ftruncate(fileno(qfo), 34341411Smckusick (off_t)((highid[type] + 1) * sizeof(struct dqblk))); 34425377Sserge fclose(qfo); 34512703Smckusick return (0); 34612660Smckusick } 34712660Smckusick 34841411Smckusick /* 34941411Smckusick * Check to see if target appears in list of size cnt. 35041411Smckusick */ 35141411Smckusick oneof(target, list, cnt) 35241411Smckusick register char *target, *list[]; 35341411Smckusick int cnt; 35412660Smckusick { 35512703Smckusick register int i; 35612660Smckusick 35741411Smckusick for (i = 0; i < cnt; i++) 35841411Smckusick if (strcmp(target, list[i]) == 0) 35941411Smckusick return (i); 36041411Smckusick return (-1); 36112660Smckusick } 36212660Smckusick 36341411Smckusick /* 36441443Smckusick * Determine the group identifier for quota files. 36541443Smckusick */ 36641443Smckusick getquotagid() 36741443Smckusick { 36841443Smckusick struct group *gr; 36941443Smckusick 37041443Smckusick if (gr = getgrnam(quotagroup)) 37141443Smckusick return (gr->gr_gid); 37241443Smckusick return (-1); 37341443Smckusick } 37441443Smckusick 37541443Smckusick /* 37641411Smckusick * Check to see if a particular quota is to be enabled. 37741411Smckusick */ 37841443Smckusick hasquota(fs, type, qfnamep) 37941443Smckusick register struct fstab *fs; 38041411Smckusick int type; 38141443Smckusick char **qfnamep; 38212660Smckusick { 38341411Smckusick register char *opt; 38441443Smckusick char *cp, *index(), *strtok(); 38541411Smckusick static char initname, usrname[100], grpname[100]; 38641443Smckusick static char buf[BUFSIZ]; 38712660Smckusick 38841411Smckusick if (!initname) { 38941411Smckusick sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); 39041411Smckusick sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); 39141411Smckusick initname = 1; 39212660Smckusick } 39341443Smckusick strcpy(buf, fs->fs_mntops); 39441411Smckusick for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 39541443Smckusick if (cp = index(opt, '=')) 39641443Smckusick *cp++ = '\0'; 39741411Smckusick if (type == USRQUOTA && strcmp(opt, usrname) == 0) 39841443Smckusick break; 39941411Smckusick if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 40041443Smckusick break; 40125377Sserge } 40241443Smckusick if (!opt) 40341443Smckusick return (0); 40441443Smckusick if (cp) { 40541443Smckusick *qfnamep = cp; 40641443Smckusick return (1); 40741443Smckusick } 40841443Smckusick (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 40941443Smckusick *qfnamep = buf; 41041443Smckusick return (1); 41112660Smckusick } 41212660Smckusick 41341411Smckusick /* 41441411Smckusick * Routines to manage the file usage table. 41541411Smckusick * 41641411Smckusick * Lookup an id of a specific type. 41741411Smckusick */ 41812703Smckusick struct fileusage * 41941411Smckusick lookup(id, type) 42041411Smckusick u_long id; 42141411Smckusick int type; 42212660Smckusick { 42312703Smckusick register struct fileusage *fup; 42412660Smckusick 42541411Smckusick for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next) 42641411Smckusick if (fup->fu_id == id) 42712703Smckusick return (fup); 42812703Smckusick return ((struct fileusage *)0); 42912660Smckusick } 43012660Smckusick 43141411Smckusick /* 43241411Smckusick * Add a new file usage id if it does not already exist. 43341411Smckusick */ 43412703Smckusick struct fileusage * 43541411Smckusick addid(id, type, name) 43641411Smckusick u_long id; 43741411Smckusick int type; 43841411Smckusick char *name; 43912660Smckusick { 44012703Smckusick struct fileusage *fup, **fhp; 44141411Smckusick int len; 44224661Sserge extern char *calloc(); 44312660Smckusick 44441411Smckusick if (fup = lookup(id, type)) 44512703Smckusick return (fup); 44641411Smckusick if (name) 44741411Smckusick len = strlen(name); 44841411Smckusick else 44941411Smckusick len = 10; 45041411Smckusick if ((fup = (struct fileusage *)calloc(1, sizeof(*fup) + len)) == NULL) { 45112703Smckusick fprintf(stderr, "out of memory for fileusage structures\n"); 45212703Smckusick exit(1); 45312703Smckusick } 45441411Smckusick fhp = &fuhead[type][id & (FUHASH - 1)]; 45512703Smckusick fup->fu_next = *fhp; 45612703Smckusick *fhp = fup; 45741411Smckusick fup->fu_id = id; 45841411Smckusick if (id > highid[type]) 45941411Smckusick highid[type] = id; 46041411Smckusick if (name) { 46141411Smckusick bcopy(name, fup->fu_name, len + 1); 46241411Smckusick } else { 46341411Smckusick sprintf(fup->fu_name, "%u", id); 46441411Smckusick } 46512703Smckusick return (fup); 46612660Smckusick } 46712660Smckusick 46841411Smckusick /* 46941411Smckusick * Special purpose version of ginode used to optimize pass 47041411Smckusick * over all the inodes in numerical order. 47141411Smckusick */ 47241411Smckusick ino_t nextino, lastinum; 47341411Smckusick long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 47441411Smckusick struct dinode *inodebuf; 47541411Smckusick #define INOBUFSIZE 56*1024 /* size of buffer to read inodes */ 47641411Smckusick 47741411Smckusick struct dinode * 47841411Smckusick getnextinode(inumber) 47941411Smckusick ino_t inumber; 48012660Smckusick { 48141411Smckusick long size; 48241411Smckusick daddr_t dblk; 48341411Smckusick static struct dinode *dp; 48412660Smckusick 48541411Smckusick if (inumber != nextino++ || inumber > maxino) { 48641411Smckusick fprintf(stderr, "bad inode number %d to nextinode\n", inumber); 48741411Smckusick exit(1); 48812703Smckusick } 48941411Smckusick if (inumber >= lastinum) { 49041411Smckusick readcnt++; 49141411Smckusick dblk = fsbtodb(&sblock, itod(&sblock, lastinum)); 49241411Smckusick if (readcnt % readpercg == 0) { 49341411Smckusick size = partialsize; 49441411Smckusick lastinum += partialcnt; 49541411Smckusick } else { 49641411Smckusick size = inobufsize; 49741411Smckusick lastinum += fullcnt; 49841411Smckusick } 49941411Smckusick bread(dblk, (char *)inodebuf, size); 50041411Smckusick dp = inodebuf; 50141411Smckusick } 50241411Smckusick return (dp++); 50312660Smckusick } 50441411Smckusick 50541411Smckusick /* 50641411Smckusick * Prepare to scan a set of inodes. 50741411Smckusick */ 50841411Smckusick resetinodebuf() 50941411Smckusick { 51041411Smckusick 51141411Smckusick nextino = 0; 51241411Smckusick lastinum = 0; 51341411Smckusick readcnt = 0; 51441411Smckusick inobufsize = blkroundup(&sblock, INOBUFSIZE); 51541411Smckusick fullcnt = inobufsize / sizeof(struct dinode); 51641411Smckusick readpercg = sblock.fs_ipg / fullcnt; 51741411Smckusick partialcnt = sblock.fs_ipg % fullcnt; 51841411Smckusick partialsize = partialcnt * sizeof(struct dinode); 51941411Smckusick if (partialcnt != 0) { 52041411Smckusick readpercg++; 52141411Smckusick } else { 52241411Smckusick partialcnt = fullcnt; 52341411Smckusick partialsize = inobufsize; 52441411Smckusick } 52541411Smckusick if (inodebuf == NULL && 52641411Smckusick (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) { 52741411Smckusick fprintf(stderr, "Cannot allocate space for inode buffer\n"); 52841411Smckusick exit(1); 52941411Smckusick } 53041411Smckusick while (nextino < ROOTINO) 53141411Smckusick getnextinode(nextino); 53241411Smckusick } 53341411Smckusick 53441411Smckusick /* 53541411Smckusick * Free up data structures used to scan inodes. 53641411Smckusick */ 53741411Smckusick freeinodebuf() 53841411Smckusick { 53941411Smckusick 54041411Smckusick if (inodebuf != NULL) 54141411Smckusick free((char *)inodebuf); 54241411Smckusick inodebuf = NULL; 54341411Smckusick } 54441411Smckusick 54541411Smckusick /* 54641411Smckusick * Read specified disk blocks. 54741411Smckusick */ 54841411Smckusick bread(bno, buf, cnt) 54941411Smckusick daddr_t bno; 55041411Smckusick char *buf; 55141411Smckusick long cnt; 55241411Smckusick { 55341411Smckusick 55441411Smckusick if (lseek(fi, bno * dev_bsize, 0) < 0) { 55541411Smckusick perror("lseek"); 55641411Smckusick exit(1); 55741411Smckusick } 55841411Smckusick 55941411Smckusick if (read(fi, buf, cnt) != cnt) { 56041411Smckusick perror("read"); 56141411Smckusick exit(1); 56241411Smckusick } 56341411Smckusick } 564