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 * 8*42707Sbostic * %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*42707Sbostic static char sccsid[] = "@(#)quotacheck.c 5.14 (Berkeley) 06/01/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 3412660Smckusick union { 3512660Smckusick struct fs sblk; 3612703Smckusick char dummy[MAXBSIZE]; 3712660Smckusick } un; 3812660Smckusick #define sblock un.sblk 3941411Smckusick long dev_bsize = 1; 4041411Smckusick long maxino; 4112703Smckusick 4241443Smckusick struct quotaname { 4341443Smckusick long flags; 4441443Smckusick char grpqfname[MAXPATHLEN + 1]; 4541443Smckusick char usrqfname[MAXPATHLEN + 1]; 4641443Smckusick }; 4741443Smckusick #define HASUSR 1 4841443Smckusick #define HASGRP 2 4941443Smckusick 5012703Smckusick struct fileusage { 5141411Smckusick struct fileusage *fu_next; 5241411Smckusick u_long fu_curinodes; 5341411Smckusick u_long fu_curblocks; 5441411Smckusick u_long fu_id; 5541411Smckusick char fu_name[1]; 5641411Smckusick /* actually bigger */ 5712703Smckusick }; 5841411Smckusick #define FUHASH 1024 /* must be power of two */ 5941411Smckusick struct fileusage *fuhead[MAXQUOTAS][FUHASH]; 6012703Smckusick struct fileusage *lookup(); 6141411Smckusick struct fileusage *addid(); 6241411Smckusick struct dinode *getnextinode(); 6312660Smckusick 6441411Smckusick int aflag; /* all file systems */ 6541411Smckusick int gflag; /* check group quotas */ 6641411Smckusick int uflag; /* check user quotas */ 6741411Smckusick int vflag; /* verbose */ 6841411Smckusick int fi; /* open disk file descriptor */ 6941411Smckusick u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */ 7012703Smckusick 7112660Smckusick main(argc, argv) 7212703Smckusick int argc; 7312660Smckusick char **argv; 7412660Smckusick { 7512703Smckusick register struct fstab *fs; 7612802Smckusick register struct passwd *pw; 7741411Smckusick register struct group *gr; 7841411Smckusick int i, argnum, maxrun, errs = 0; 7941411Smckusick long auxdata, done = 0; 8041411Smckusick char ch, *name, *blockcheck(); 8141411Smckusick int needchk(), chkquota(); 8241411Smckusick extern char *optarg; 8341411Smckusick extern int optind; 8412660Smckusick 8541411Smckusick while ((ch = getopt(argc, argv, "aguvl:")) != EOF) { 8641411Smckusick switch(ch) { 8741411Smckusick case 'a': 8841411Smckusick aflag++; 8941411Smckusick break; 9041411Smckusick case 'g': 9141411Smckusick gflag++; 9241411Smckusick break; 9341411Smckusick case 'u': 9441411Smckusick uflag++; 9541411Smckusick break; 9641411Smckusick case 'v': 9741411Smckusick vflag++; 9841411Smckusick break; 9941411Smckusick case 'l': 10041411Smckusick maxrun = atoi(optarg); 10141411Smckusick break; 10241411Smckusick default: 10341411Smckusick usage(); 10441411Smckusick } 10512660Smckusick } 10641411Smckusick argc -= optind; 10741411Smckusick argv += optind; 10841411Smckusick if ((argc == 0 && !aflag) || (argc > 0 && aflag)) 10941411Smckusick usage(); 11041411Smckusick if (!gflag && !uflag) { 11141411Smckusick gflag++; 11241411Smckusick uflag++; 11312703Smckusick } 11441411Smckusick if (gflag) { 11541411Smckusick setgrent(); 11641411Smckusick while ((gr = getgrent()) != 0) 11741411Smckusick (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name); 11841411Smckusick endgrent(); 11924758Sserge } 12041411Smckusick if (uflag) { 12141411Smckusick setpwent(); 12241411Smckusick while ((pw = getpwent()) != 0) 12341411Smckusick (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name); 12441411Smckusick endpwent(); 12512660Smckusick } 12641411Smckusick if (aflag) 12741411Smckusick exit(checkfstab(1, maxrun, needchk, chkquota)); 12841411Smckusick if (setfsent() == 0) { 12941411Smckusick fprintf(stderr, "Can't open "); 13041411Smckusick perror(FSTAB); 13141411Smckusick exit(8); 13212802Smckusick } 13341411Smckusick while ((fs = getfsent()) != NULL) { 13441411Smckusick if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || 13541411Smckusick (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) && 13641411Smckusick (auxdata = needchk(fs)) && 13741411Smckusick (name = blockcheck(fs->fs_spec))) { 13841411Smckusick done |= 1 << argnum; 13941411Smckusick errs += chkquota(name, fs->fs_file, auxdata); 14024758Sserge } 14112660Smckusick } 14241411Smckusick endfsent(); 14312703Smckusick for (i = 0; i < argc; i++) 14412703Smckusick if ((done & (1 << i)) == 0) 14524782Sserge fprintf(stderr, "%s not found in %s\n", 14624782Sserge argv[i], FSTAB); 14712703Smckusick exit(errs); 14812703Smckusick } 14912660Smckusick 15041411Smckusick usage() 15124758Sserge { 15224758Sserge 15341411Smckusick fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 15441411Smckusick "quotacheck [-g] [-u] [-v] -a", 15541411Smckusick "quotacheck [-g] [-u] [-v] filesys ..."); 15641411Smckusick exit(1); 15741411Smckusick } 15824758Sserge 15941411Smckusick needchk(fs) 16041411Smckusick register struct fstab *fs; 16141411Smckusick { 16241443Smckusick register struct quotaname *qnp; 16341443Smckusick char *qfnp; 16424758Sserge 16541443Smckusick if (strcmp(fs->fs_vfstype, "ufs") || 16641443Smckusick strcmp(fs->fs_type, FSTAB_RW)) 16741443Smckusick return (0); 16841443Smckusick if ((qnp = (struct quotaname *)malloc(sizeof *qnp)) == 0) { 16941443Smckusick fprintf(stderr, "out of memory for quota structures\n"); 17041443Smckusick exit(1); 17141443Smckusick } 17241443Smckusick qnp->flags = 0; 17341443Smckusick if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) { 17441443Smckusick strcpy(qnp->grpqfname, qfnp); 17541443Smckusick qnp->flags |= HASGRP; 17641443Smckusick } 17741443Smckusick if (uflag && hasquota(fs, USRQUOTA, &qfnp)) { 17841443Smckusick strcpy(qnp->usrqfname, qfnp); 17941443Smckusick qnp->flags |= HASUSR; 18041443Smckusick } 18141443Smckusick if (qnp->flags) 18241443Smckusick return ((int)qnp); 18341443Smckusick free((char *)qnp); 18441443Smckusick return (0); 18541411Smckusick } 18624758Sserge 18741411Smckusick /* 18841411Smckusick * Scan the specified filesystem to check quota(s) present on it. 18941411Smckusick */ 19041443Smckusick chkquota(fsname, mntpt, qnp) 19141411Smckusick char *fsname, *mntpt; 19241443Smckusick register struct quotaname *qnp; 19341411Smckusick { 19441411Smckusick register struct fileusage *fup; 19541411Smckusick register struct dinode *dp; 19641411Smckusick int cg, i, mode, errs = 0; 19741411Smckusick ino_t ino; 19824758Sserge 19941411Smckusick if ((fi = open(fsname, 0)) < 0) { 20041411Smckusick perror(fsname); 20141411Smckusick return (1); 20241411Smckusick } 20341411Smckusick if (vflag) { 20441411Smckusick fprintf(stdout, "*** Checking "); 20541443Smckusick if (qnp->flags & HASUSR) 20641411Smckusick fprintf(stdout, "%s%s", qfextension[USRQUOTA], 20741443Smckusick (qnp->flags & HASGRP) ? " and " : ""); 20841443Smckusick if (qnp->flags & HASGRP) 20941411Smckusick fprintf(stdout, "%s", qfextension[GRPQUOTA]); 21041411Smckusick fprintf(stdout, " quotas for %s (%s)\n", fsname, mntpt); 21141411Smckusick } 21241411Smckusick sync(); 21341411Smckusick bread(SBOFF, (char *)&sblock, (long)SBSIZE); 21441411Smckusick dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 21541411Smckusick maxino = sblock.fs_ncg * sblock.fs_ipg; 21641411Smckusick resetinodebuf(); 21741411Smckusick for (ino = 0, cg = 0; cg < sblock.fs_ncg; cg++) { 21841411Smckusick for (i = 0; i < sblock.fs_ipg; i++, ino++) { 21941411Smckusick if (ino < ROOTINO) 22024758Sserge continue; 22141411Smckusick if ((dp = getnextinode(ino)) == NULL) 22224758Sserge continue; 22341411Smckusick if ((mode = dp->di_mode & IFMT) == 0) 22441411Smckusick continue; 22541443Smckusick if (qnp->flags & HASGRP) { 22641411Smckusick fup = addid((u_long)dp->di_gid, GRPQUOTA, 22741411Smckusick (char *)0); 22841411Smckusick fup->fu_curinodes++; 22941411Smckusick if (mode == IFREG || mode == IFDIR || 23041411Smckusick mode == IFLNK) 23141411Smckusick fup->fu_curblocks += dp->di_blocks; 23224758Sserge } 23341443Smckusick if (qnp->flags & HASUSR) { 23441411Smckusick fup = addid((u_long)dp->di_uid, USRQUOTA, 23541411Smckusick (char *)0); 23641411Smckusick fup->fu_curinodes++; 23741411Smckusick if (mode == IFREG || mode == IFDIR || 23841411Smckusick mode == IFLNK) 23941411Smckusick fup->fu_curblocks += dp->di_blocks; 24041411Smckusick } 24124758Sserge } 24241411Smckusick } 24341411Smckusick freeinodebuf(); 24441443Smckusick if (qnp->flags & HASUSR) 24541443Smckusick errs += update(mntpt, qnp->usrqfname, USRQUOTA); 24641443Smckusick if (qnp->flags & HASGRP) 24741443Smckusick errs += update(mntpt, qnp->grpqfname, GRPQUOTA); 24841411Smckusick close(fi); 24924758Sserge return (errs); 25024758Sserge } 25124758Sserge 25241411Smckusick /* 25341411Smckusick * Update a specified quota file. 25441411Smckusick */ 25541443Smckusick update(fsname, quotafile, type) 25641443Smckusick char *fsname, *quotafile; 25741411Smckusick register int type; 25812703Smckusick { 25912703Smckusick register struct fileusage *fup; 26025377Sserge register FILE *qfi, *qfo; 26141411Smckusick register u_long id, lastid; 26212703Smckusick struct dqblk dqbuf; 26341411Smckusick extern int errno; 26421085Smckusick static int warned = 0; 26541411Smckusick static struct dqblk zerodqbuf; 26641411Smckusick static struct fileusage zerofileusage; 26712660Smckusick 26841411Smckusick if ((qfo = fopen(quotafile, "r+")) == NULL) { 26941411Smckusick if (errno != ENOENT) { 27041411Smckusick perror(quotafile); 27141411Smckusick return (1); 27241411Smckusick } 27341411Smckusick if ((qfo = fopen(quotafile, "w+")) == NULL) { 27441411Smckusick perror(quotafile); 27541411Smckusick return (1); 27641411Smckusick } 27741443Smckusick fprintf(stderr, "Creating quota file %s\n", quotafile); 27841443Smckusick (void) fchown(fileno(qfo), getuid(), getquotagid()); 27941443Smckusick (void) fchmod(fileno(qfo), 0640); 28012660Smckusick } 28141411Smckusick if ((qfi = fopen(quotafile, "r")) == NULL) { 28241411Smckusick perror(quotafile); 28341411Smckusick fclose(qfo); 28412703Smckusick return (1); 28512660Smckusick } 28641411Smckusick if (quotactl(fsname, QCMD(Q_SYNC, type), (u_long)0, (caddr_t)0) < 0 && 28741411Smckusick errno == EOPNOTSUPP && !warned && vflag) { 28821085Smckusick warned++; 28941411Smckusick fprintf(stdout, "*** Warning: %s\n", 29041411Smckusick "Quotas are not compiled into this kernel"); 29121085Smckusick } 29241411Smckusick for (lastid = highid[type], id = 0; id <= lastid; id++) { 29341411Smckusick if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0) 29412802Smckusick dqbuf = zerodqbuf; 29541411Smckusick if ((fup = lookup(id, type)) == 0) 29624758Sserge fup = &zerofileusage; 29741411Smckusick if (dqbuf.dqb_curinodes == fup->fu_curinodes && 29841411Smckusick dqbuf.dqb_curblocks == fup->fu_curblocks) { 29941411Smckusick fup->fu_curinodes = 0; 30041411Smckusick fup->fu_curblocks = 0; 30125377Sserge fseek(qfo, (long)sizeof(struct dqblk), 1); 30212703Smckusick continue; 30312802Smckusick } 30412703Smckusick if (vflag) { 30541411Smckusick if (aflag) 30641411Smckusick printf("%s: ", fsname); 30741411Smckusick printf("%-8s fixed:", fup->fu_name); 30841411Smckusick if (dqbuf.dqb_curinodes != fup->fu_curinodes) 30925377Sserge fprintf(stdout, "\tinodes %d -> %d", 31041411Smckusick dqbuf.dqb_curinodes, fup->fu_curinodes); 31141411Smckusick if (dqbuf.dqb_curblocks != fup->fu_curblocks) 31225377Sserge fprintf(stdout, "\tblocks %d -> %d", 31341411Smckusick dqbuf.dqb_curblocks, fup->fu_curblocks); 31424758Sserge fprintf(stdout, "\n"); 31512660Smckusick } 31641411Smckusick /* 31741411Smckusick * Reset time limit if have a soft limit and were 31841411Smckusick * previously under it, but are now over it. 31941411Smckusick */ 32041411Smckusick if (dqbuf.dqb_bsoftlimit && 32141411Smckusick dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit && 32241411Smckusick fup->fu_curblocks >= dqbuf.dqb_bsoftlimit) 32341411Smckusick dqbuf.dqb_btime = 0; 32441411Smckusick if (dqbuf.dqb_isoftlimit && 32541411Smckusick dqbuf.dqb_curblocks < dqbuf.dqb_isoftlimit && 32641411Smckusick fup->fu_curblocks >= dqbuf.dqb_isoftlimit) 32741411Smckusick dqbuf.dqb_itime = 0; 32841411Smckusick dqbuf.dqb_curinodes = fup->fu_curinodes; 32941411Smckusick dqbuf.dqb_curblocks = fup->fu_curblocks; 33041411Smckusick fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo); 33141411Smckusick (void) quotactl(fsname, QCMD(Q_SETUSE, type), id, 33241411Smckusick (caddr_t)&dqbuf); 33341411Smckusick fup->fu_curinodes = 0; 33441411Smckusick fup->fu_curblocks = 0; 33512660Smckusick } 33641411Smckusick fclose(qfi); 33725377Sserge fflush(qfo); 33841411Smckusick ftruncate(fileno(qfo), 33941411Smckusick (off_t)((highid[type] + 1) * sizeof(struct dqblk))); 34025377Sserge fclose(qfo); 34112703Smckusick return (0); 34212660Smckusick } 34312660Smckusick 34441411Smckusick /* 34541411Smckusick * Check to see if target appears in list of size cnt. 34641411Smckusick */ 34741411Smckusick oneof(target, list, cnt) 34841411Smckusick register char *target, *list[]; 34941411Smckusick int cnt; 35012660Smckusick { 35112703Smckusick register int i; 35212660Smckusick 35341411Smckusick for (i = 0; i < cnt; i++) 35441411Smckusick if (strcmp(target, list[i]) == 0) 35541411Smckusick return (i); 35641411Smckusick return (-1); 35712660Smckusick } 35812660Smckusick 35941411Smckusick /* 36041443Smckusick * Determine the group identifier for quota files. 36141443Smckusick */ 36241443Smckusick getquotagid() 36341443Smckusick { 36441443Smckusick struct group *gr; 36541443Smckusick 36641443Smckusick if (gr = getgrnam(quotagroup)) 36741443Smckusick return (gr->gr_gid); 36841443Smckusick return (-1); 36941443Smckusick } 37041443Smckusick 37141443Smckusick /* 37241411Smckusick * Check to see if a particular quota is to be enabled. 37341411Smckusick */ 37441443Smckusick hasquota(fs, type, qfnamep) 37541443Smckusick register struct fstab *fs; 37641411Smckusick int type; 37741443Smckusick char **qfnamep; 37812660Smckusick { 37941411Smckusick register char *opt; 38041443Smckusick char *cp, *index(), *strtok(); 38141411Smckusick static char initname, usrname[100], grpname[100]; 38241443Smckusick static char buf[BUFSIZ]; 38312660Smckusick 38441411Smckusick if (!initname) { 38541411Smckusick sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); 38641411Smckusick sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); 38741411Smckusick initname = 1; 38812660Smckusick } 38941443Smckusick strcpy(buf, fs->fs_mntops); 39041411Smckusick for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 39141443Smckusick if (cp = index(opt, '=')) 39241443Smckusick *cp++ = '\0'; 39341411Smckusick if (type == USRQUOTA && strcmp(opt, usrname) == 0) 39441443Smckusick break; 39541411Smckusick if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 39641443Smckusick break; 39725377Sserge } 39841443Smckusick if (!opt) 39941443Smckusick return (0); 40041443Smckusick if (cp) { 40141443Smckusick *qfnamep = cp; 40241443Smckusick return (1); 40341443Smckusick } 40441443Smckusick (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 40541443Smckusick *qfnamep = buf; 40641443Smckusick return (1); 40712660Smckusick } 40812660Smckusick 40941411Smckusick /* 41041411Smckusick * Routines to manage the file usage table. 41141411Smckusick * 41241411Smckusick * Lookup an id of a specific type. 41341411Smckusick */ 41412703Smckusick struct fileusage * 41541411Smckusick lookup(id, type) 41641411Smckusick u_long id; 41741411Smckusick int type; 41812660Smckusick { 41912703Smckusick register struct fileusage *fup; 42012660Smckusick 42141411Smckusick for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next) 42241411Smckusick if (fup->fu_id == id) 42312703Smckusick return (fup); 42412703Smckusick return ((struct fileusage *)0); 42512660Smckusick } 42612660Smckusick 42741411Smckusick /* 42841411Smckusick * Add a new file usage id if it does not already exist. 42941411Smckusick */ 43012703Smckusick struct fileusage * 43141411Smckusick addid(id, type, name) 43241411Smckusick u_long id; 43341411Smckusick int type; 43441411Smckusick char *name; 43512660Smckusick { 43612703Smckusick struct fileusage *fup, **fhp; 43741411Smckusick int len; 43824661Sserge extern char *calloc(); 43912660Smckusick 44041411Smckusick if (fup = lookup(id, type)) 44112703Smckusick return (fup); 44241411Smckusick if (name) 44341411Smckusick len = strlen(name); 44441411Smckusick else 44541411Smckusick len = 10; 44641411Smckusick if ((fup = (struct fileusage *)calloc(1, sizeof(*fup) + len)) == NULL) { 44712703Smckusick fprintf(stderr, "out of memory for fileusage structures\n"); 44812703Smckusick exit(1); 44912703Smckusick } 45041411Smckusick fhp = &fuhead[type][id & (FUHASH - 1)]; 45112703Smckusick fup->fu_next = *fhp; 45212703Smckusick *fhp = fup; 45341411Smckusick fup->fu_id = id; 45441411Smckusick if (id > highid[type]) 45541411Smckusick highid[type] = id; 45641411Smckusick if (name) { 45741411Smckusick bcopy(name, fup->fu_name, len + 1); 45841411Smckusick } else { 45941411Smckusick sprintf(fup->fu_name, "%u", id); 46041411Smckusick } 46112703Smckusick return (fup); 46212660Smckusick } 46312660Smckusick 46441411Smckusick /* 46541411Smckusick * Special purpose version of ginode used to optimize pass 46641411Smckusick * over all the inodes in numerical order. 46741411Smckusick */ 46841411Smckusick ino_t nextino, lastinum; 46941411Smckusick long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 47041411Smckusick struct dinode *inodebuf; 47141411Smckusick #define INOBUFSIZE 56*1024 /* size of buffer to read inodes */ 47241411Smckusick 47341411Smckusick struct dinode * 47441411Smckusick getnextinode(inumber) 47541411Smckusick ino_t inumber; 47612660Smckusick { 47741411Smckusick long size; 47841411Smckusick daddr_t dblk; 47941411Smckusick static struct dinode *dp; 48012660Smckusick 48141411Smckusick if (inumber != nextino++ || inumber > maxino) { 48241411Smckusick fprintf(stderr, "bad inode number %d to nextinode\n", inumber); 48341411Smckusick exit(1); 48412703Smckusick } 48541411Smckusick if (inumber >= lastinum) { 48641411Smckusick readcnt++; 48741411Smckusick dblk = fsbtodb(&sblock, itod(&sblock, lastinum)); 48841411Smckusick if (readcnt % readpercg == 0) { 48941411Smckusick size = partialsize; 49041411Smckusick lastinum += partialcnt; 49141411Smckusick } else { 49241411Smckusick size = inobufsize; 49341411Smckusick lastinum += fullcnt; 49441411Smckusick } 49541411Smckusick bread(dblk, (char *)inodebuf, size); 49641411Smckusick dp = inodebuf; 49741411Smckusick } 49841411Smckusick return (dp++); 49912660Smckusick } 50041411Smckusick 50141411Smckusick /* 50241411Smckusick * Prepare to scan a set of inodes. 50341411Smckusick */ 50441411Smckusick resetinodebuf() 50541411Smckusick { 50641411Smckusick 50741411Smckusick nextino = 0; 50841411Smckusick lastinum = 0; 50941411Smckusick readcnt = 0; 51041411Smckusick inobufsize = blkroundup(&sblock, INOBUFSIZE); 51141411Smckusick fullcnt = inobufsize / sizeof(struct dinode); 51241411Smckusick readpercg = sblock.fs_ipg / fullcnt; 51341411Smckusick partialcnt = sblock.fs_ipg % fullcnt; 51441411Smckusick partialsize = partialcnt * sizeof(struct dinode); 51541411Smckusick if (partialcnt != 0) { 51641411Smckusick readpercg++; 51741411Smckusick } else { 51841411Smckusick partialcnt = fullcnt; 51941411Smckusick partialsize = inobufsize; 52041411Smckusick } 52141411Smckusick if (inodebuf == NULL && 52241411Smckusick (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) { 52341411Smckusick fprintf(stderr, "Cannot allocate space for inode buffer\n"); 52441411Smckusick exit(1); 52541411Smckusick } 52641411Smckusick while (nextino < ROOTINO) 52741411Smckusick getnextinode(nextino); 52841411Smckusick } 52941411Smckusick 53041411Smckusick /* 53141411Smckusick * Free up data structures used to scan inodes. 53241411Smckusick */ 53341411Smckusick freeinodebuf() 53441411Smckusick { 53541411Smckusick 53641411Smckusick if (inodebuf != NULL) 53741411Smckusick free((char *)inodebuf); 53841411Smckusick inodebuf = NULL; 53941411Smckusick } 54041411Smckusick 54141411Smckusick /* 54241411Smckusick * Read specified disk blocks. 54341411Smckusick */ 54441411Smckusick bread(bno, buf, cnt) 54541411Smckusick daddr_t bno; 54641411Smckusick char *buf; 54741411Smckusick long cnt; 54841411Smckusick { 54941411Smckusick 55041411Smckusick if (lseek(fi, bno * dev_bsize, 0) < 0) { 55141411Smckusick perror("lseek"); 55241411Smckusick exit(1); 55341411Smckusick } 55441411Smckusick 55541411Smckusick if (read(fi, buf, cnt) != cnt) { 55641411Smckusick perror("read"); 55741411Smckusick exit(1); 55841411Smckusick } 55941411Smckusick } 560