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 * 834364Sbostic * Redistribution and use in source and binary forms are permitted 934778Sbostic * provided that the above copyright notice and this paragraph are 1034778Sbostic * duplicated in all such forms and that any documentation, 1134778Sbostic * advertising materials, and other materials related to such 1234778Sbostic * distribution and use acknowledge that the software was developed 1334778Sbostic * by the University of California, Berkeley. The name of the 1434778Sbostic * University may not be used to endorse or promote products derived 1534778Sbostic * from this software without specific prior written permission. 1634778Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1734778Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1834778Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1921517Smckusick */ 2021517Smckusick 2112703Smckusick #ifndef lint 2221517Smckusick char copyright[] = 2341411Smckusick "@(#) Copyright (c) 1980, 1990 Regents of the University of California.\n\ 2421517Smckusick All rights reserved.\n"; 2534364Sbostic #endif /* not lint */ 2612660Smckusick 2721517Smckusick #ifndef lint 28*41443Smckusick static char sccsid[] = "@(#)quotacheck.c 5.13 (Berkeley) 05/06/90"; 2934364Sbostic #endif /* not lint */ 3021517Smckusick 3112660Smckusick /* 3241411Smckusick * Fix up / report on disk quotas & usage 3312660Smckusick */ 3412660Smckusick #include <sys/param.h> 3541411Smckusick #include <ufs/dinode.h> 3638511Sbostic #include <ufs/fs.h> 3738511Sbostic #include <ufs/quota.h> 3812703Smckusick #include <fstab.h> 3912802Smckusick #include <pwd.h> 4041411Smckusick #include <grp.h> 4138511Sbostic #include <stdio.h> 4238511Sbostic #include <errno.h> 4312660Smckusick 4412660Smckusick union { 4512660Smckusick struct fs sblk; 4612703Smckusick char dummy[MAXBSIZE]; 4712660Smckusick } un; 4812660Smckusick #define sblock un.sblk 4941411Smckusick long dev_bsize = 1; 5041411Smckusick long maxino; 5112703Smckusick 52*41443Smckusick struct quotaname { 53*41443Smckusick long flags; 54*41443Smckusick char grpqfname[MAXPATHLEN + 1]; 55*41443Smckusick char usrqfname[MAXPATHLEN + 1]; 56*41443Smckusick }; 57*41443Smckusick #define HASUSR 1 58*41443Smckusick #define HASGRP 2 59*41443Smckusick 6012703Smckusick struct fileusage { 6141411Smckusick struct fileusage *fu_next; 6241411Smckusick u_long fu_curinodes; 6341411Smckusick u_long fu_curblocks; 6441411Smckusick u_long fu_id; 6541411Smckusick char fu_name[1]; 6641411Smckusick /* actually bigger */ 6712703Smckusick }; 6841411Smckusick #define FUHASH 1024 /* must be power of two */ 6941411Smckusick struct fileusage *fuhead[MAXQUOTAS][FUHASH]; 7012703Smckusick struct fileusage *lookup(); 7141411Smckusick struct fileusage *addid(); 7241411Smckusick struct dinode *getnextinode(); 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 8112660Smckusick main(argc, argv) 8212703Smckusick int argc; 8312660Smckusick char **argv; 8412660Smckusick { 8512703Smckusick register struct fstab *fs; 8612802Smckusick register struct passwd *pw; 8741411Smckusick register struct group *gr; 8841411Smckusick int i, argnum, maxrun, errs = 0; 8941411Smckusick long auxdata, done = 0; 9041411Smckusick char ch, *name, *blockcheck(); 9141411Smckusick int needchk(), chkquota(); 9241411Smckusick extern char *optarg; 9341411Smckusick extern int optind; 9412660Smckusick 9541411Smckusick while ((ch = getopt(argc, argv, "aguvl:")) != EOF) { 9641411Smckusick switch(ch) { 9741411Smckusick case 'a': 9841411Smckusick aflag++; 9941411Smckusick break; 10041411Smckusick case 'g': 10141411Smckusick gflag++; 10241411Smckusick break; 10341411Smckusick case 'u': 10441411Smckusick uflag++; 10541411Smckusick break; 10641411Smckusick case 'v': 10741411Smckusick vflag++; 10841411Smckusick break; 10941411Smckusick case 'l': 11041411Smckusick maxrun = atoi(optarg); 11141411Smckusick break; 11241411Smckusick default: 11341411Smckusick usage(); 11441411Smckusick } 11512660Smckusick } 11641411Smckusick argc -= optind; 11741411Smckusick argv += optind; 11841411Smckusick if ((argc == 0 && !aflag) || (argc > 0 && aflag)) 11941411Smckusick usage(); 12041411Smckusick if (!gflag && !uflag) { 12141411Smckusick gflag++; 12241411Smckusick uflag++; 12312703Smckusick } 12441411Smckusick if (gflag) { 12541411Smckusick setgrent(); 12641411Smckusick while ((gr = getgrent()) != 0) 12741411Smckusick (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name); 12841411Smckusick endgrent(); 12924758Sserge } 13041411Smckusick if (uflag) { 13141411Smckusick setpwent(); 13241411Smckusick while ((pw = getpwent()) != 0) 13341411Smckusick (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name); 13441411Smckusick endpwent(); 13512660Smckusick } 13641411Smckusick if (aflag) 13741411Smckusick exit(checkfstab(1, maxrun, needchk, chkquota)); 13841411Smckusick if (setfsent() == 0) { 13941411Smckusick fprintf(stderr, "Can't open "); 14041411Smckusick perror(FSTAB); 14141411Smckusick exit(8); 14212802Smckusick } 14341411Smckusick while ((fs = getfsent()) != NULL) { 14441411Smckusick if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || 14541411Smckusick (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) && 14641411Smckusick (auxdata = needchk(fs)) && 14741411Smckusick (name = blockcheck(fs->fs_spec))) { 14841411Smckusick done |= 1 << argnum; 14941411Smckusick errs += chkquota(name, fs->fs_file, auxdata); 15024758Sserge } 15112660Smckusick } 15241411Smckusick endfsent(); 15312703Smckusick for (i = 0; i < argc; i++) 15412703Smckusick if ((done & (1 << i)) == 0) 15524782Sserge fprintf(stderr, "%s not found in %s\n", 15624782Sserge argv[i], FSTAB); 15712703Smckusick exit(errs); 15812703Smckusick } 15912660Smckusick 16041411Smckusick usage() 16124758Sserge { 16224758Sserge 16341411Smckusick fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 16441411Smckusick "quotacheck [-g] [-u] [-v] -a", 16541411Smckusick "quotacheck [-g] [-u] [-v] filesys ..."); 16641411Smckusick exit(1); 16741411Smckusick } 16824758Sserge 16941411Smckusick needchk(fs) 17041411Smckusick register struct fstab *fs; 17141411Smckusick { 172*41443Smckusick register struct quotaname *qnp; 173*41443Smckusick char *qfnp; 17424758Sserge 175*41443Smckusick if (strcmp(fs->fs_vfstype, "ufs") || 176*41443Smckusick strcmp(fs->fs_type, FSTAB_RW)) 177*41443Smckusick return (0); 178*41443Smckusick if ((qnp = (struct quotaname *)malloc(sizeof *qnp)) == 0) { 179*41443Smckusick fprintf(stderr, "out of memory for quota structures\n"); 180*41443Smckusick exit(1); 181*41443Smckusick } 182*41443Smckusick qnp->flags = 0; 183*41443Smckusick if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) { 184*41443Smckusick strcpy(qnp->grpqfname, qfnp); 185*41443Smckusick qnp->flags |= HASGRP; 186*41443Smckusick } 187*41443Smckusick if (uflag && hasquota(fs, USRQUOTA, &qfnp)) { 188*41443Smckusick strcpy(qnp->usrqfname, qfnp); 189*41443Smckusick qnp->flags |= HASUSR; 190*41443Smckusick } 191*41443Smckusick if (qnp->flags) 192*41443Smckusick return ((int)qnp); 193*41443Smckusick free((char *)qnp); 194*41443Smckusick return (0); 19541411Smckusick } 19624758Sserge 19741411Smckusick /* 19841411Smckusick * Scan the specified filesystem to check quota(s) present on it. 19941411Smckusick */ 200*41443Smckusick chkquota(fsname, mntpt, qnp) 20141411Smckusick char *fsname, *mntpt; 202*41443Smckusick register struct quotaname *qnp; 20341411Smckusick { 20441411Smckusick register struct fileusage *fup; 20541411Smckusick register struct dinode *dp; 20641411Smckusick int cg, i, mode, errs = 0; 20741411Smckusick ino_t ino; 20824758Sserge 20941411Smckusick if ((fi = open(fsname, 0)) < 0) { 21041411Smckusick perror(fsname); 21141411Smckusick return (1); 21241411Smckusick } 21341411Smckusick if (vflag) { 21441411Smckusick fprintf(stdout, "*** Checking "); 215*41443Smckusick if (qnp->flags & HASUSR) 21641411Smckusick fprintf(stdout, "%s%s", qfextension[USRQUOTA], 217*41443Smckusick (qnp->flags & HASGRP) ? " and " : ""); 218*41443Smckusick if (qnp->flags & HASGRP) 21941411Smckusick fprintf(stdout, "%s", qfextension[GRPQUOTA]); 22041411Smckusick fprintf(stdout, " quotas for %s (%s)\n", fsname, mntpt); 22141411Smckusick } 22241411Smckusick sync(); 22341411Smckusick bread(SBOFF, (char *)&sblock, (long)SBSIZE); 22441411Smckusick dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 22541411Smckusick maxino = sblock.fs_ncg * sblock.fs_ipg; 22641411Smckusick resetinodebuf(); 22741411Smckusick for (ino = 0, cg = 0; cg < sblock.fs_ncg; cg++) { 22841411Smckusick for (i = 0; i < sblock.fs_ipg; i++, ino++) { 22941411Smckusick if (ino < ROOTINO) 23024758Sserge continue; 23141411Smckusick if ((dp = getnextinode(ino)) == NULL) 23224758Sserge continue; 23341411Smckusick if ((mode = dp->di_mode & IFMT) == 0) 23441411Smckusick continue; 235*41443Smckusick if (qnp->flags & HASGRP) { 23641411Smckusick fup = addid((u_long)dp->di_gid, GRPQUOTA, 23741411Smckusick (char *)0); 23841411Smckusick fup->fu_curinodes++; 23941411Smckusick if (mode == IFREG || mode == IFDIR || 24041411Smckusick mode == IFLNK) 24141411Smckusick fup->fu_curblocks += dp->di_blocks; 24224758Sserge } 243*41443Smckusick if (qnp->flags & HASUSR) { 24441411Smckusick fup = addid((u_long)dp->di_uid, USRQUOTA, 24541411Smckusick (char *)0); 24641411Smckusick fup->fu_curinodes++; 24741411Smckusick if (mode == IFREG || mode == IFDIR || 24841411Smckusick mode == IFLNK) 24941411Smckusick fup->fu_curblocks += dp->di_blocks; 25041411Smckusick } 25124758Sserge } 25241411Smckusick } 25341411Smckusick freeinodebuf(); 254*41443Smckusick if (qnp->flags & HASUSR) 255*41443Smckusick errs += update(mntpt, qnp->usrqfname, USRQUOTA); 256*41443Smckusick if (qnp->flags & HASGRP) 257*41443Smckusick errs += update(mntpt, qnp->grpqfname, GRPQUOTA); 25841411Smckusick close(fi); 25924758Sserge return (errs); 26024758Sserge } 26124758Sserge 26241411Smckusick /* 26341411Smckusick * Update a specified quota file. 26441411Smckusick */ 265*41443Smckusick update(fsname, quotafile, type) 266*41443Smckusick char *fsname, *quotafile; 26741411Smckusick register int type; 26812703Smckusick { 26912703Smckusick register struct fileusage *fup; 27025377Sserge register FILE *qfi, *qfo; 27141411Smckusick register u_long id, lastid; 27212703Smckusick struct dqblk dqbuf; 27341411Smckusick extern int errno; 27421085Smckusick static int warned = 0; 27541411Smckusick static struct dqblk zerodqbuf; 27641411Smckusick static struct fileusage zerofileusage; 27712660Smckusick 27841411Smckusick if ((qfo = fopen(quotafile, "r+")) == NULL) { 27941411Smckusick if (errno != ENOENT) { 28041411Smckusick perror(quotafile); 28141411Smckusick return (1); 28241411Smckusick } 28341411Smckusick if ((qfo = fopen(quotafile, "w+")) == NULL) { 28441411Smckusick perror(quotafile); 28541411Smckusick return (1); 28641411Smckusick } 287*41443Smckusick fprintf(stderr, "Creating quota file %s\n", quotafile); 288*41443Smckusick (void) fchown(fileno(qfo), getuid(), getquotagid()); 289*41443Smckusick (void) fchmod(fileno(qfo), 0640); 29012660Smckusick } 29141411Smckusick if ((qfi = fopen(quotafile, "r")) == NULL) { 29241411Smckusick perror(quotafile); 29341411Smckusick fclose(qfo); 29412703Smckusick return (1); 29512660Smckusick } 29641411Smckusick if (quotactl(fsname, QCMD(Q_SYNC, type), (u_long)0, (caddr_t)0) < 0 && 29741411Smckusick errno == EOPNOTSUPP && !warned && vflag) { 29821085Smckusick warned++; 29941411Smckusick fprintf(stdout, "*** Warning: %s\n", 30041411Smckusick "Quotas are not compiled into this kernel"); 30121085Smckusick } 30241411Smckusick for (lastid = highid[type], id = 0; id <= lastid; id++) { 30341411Smckusick if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0) 30412802Smckusick dqbuf = zerodqbuf; 30541411Smckusick if ((fup = lookup(id, type)) == 0) 30624758Sserge fup = &zerofileusage; 30741411Smckusick if (dqbuf.dqb_curinodes == fup->fu_curinodes && 30841411Smckusick dqbuf.dqb_curblocks == fup->fu_curblocks) { 30941411Smckusick fup->fu_curinodes = 0; 31041411Smckusick fup->fu_curblocks = 0; 31125377Sserge fseek(qfo, (long)sizeof(struct dqblk), 1); 31212703Smckusick continue; 31312802Smckusick } 31412703Smckusick if (vflag) { 31541411Smckusick if (aflag) 31641411Smckusick printf("%s: ", fsname); 31741411Smckusick printf("%-8s fixed:", fup->fu_name); 31841411Smckusick if (dqbuf.dqb_curinodes != fup->fu_curinodes) 31925377Sserge fprintf(stdout, "\tinodes %d -> %d", 32041411Smckusick dqbuf.dqb_curinodes, fup->fu_curinodes); 32141411Smckusick if (dqbuf.dqb_curblocks != fup->fu_curblocks) 32225377Sserge fprintf(stdout, "\tblocks %d -> %d", 32341411Smckusick dqbuf.dqb_curblocks, fup->fu_curblocks); 32424758Sserge fprintf(stdout, "\n"); 32512660Smckusick } 32641411Smckusick /* 32741411Smckusick * Reset time limit if have a soft limit and were 32841411Smckusick * previously under it, but are now over it. 32941411Smckusick */ 33041411Smckusick if (dqbuf.dqb_bsoftlimit && 33141411Smckusick dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit && 33241411Smckusick fup->fu_curblocks >= dqbuf.dqb_bsoftlimit) 33341411Smckusick dqbuf.dqb_btime = 0; 33441411Smckusick if (dqbuf.dqb_isoftlimit && 33541411Smckusick dqbuf.dqb_curblocks < dqbuf.dqb_isoftlimit && 33641411Smckusick fup->fu_curblocks >= dqbuf.dqb_isoftlimit) 33741411Smckusick dqbuf.dqb_itime = 0; 33841411Smckusick dqbuf.dqb_curinodes = fup->fu_curinodes; 33941411Smckusick dqbuf.dqb_curblocks = fup->fu_curblocks; 34041411Smckusick fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo); 34141411Smckusick (void) quotactl(fsname, QCMD(Q_SETUSE, type), id, 34241411Smckusick (caddr_t)&dqbuf); 34341411Smckusick fup->fu_curinodes = 0; 34441411Smckusick fup->fu_curblocks = 0; 34512660Smckusick } 34641411Smckusick fclose(qfi); 34725377Sserge fflush(qfo); 34841411Smckusick ftruncate(fileno(qfo), 34941411Smckusick (off_t)((highid[type] + 1) * sizeof(struct dqblk))); 35025377Sserge fclose(qfo); 35112703Smckusick return (0); 35212660Smckusick } 35312660Smckusick 35441411Smckusick /* 35541411Smckusick * Check to see if target appears in list of size cnt. 35641411Smckusick */ 35741411Smckusick oneof(target, list, cnt) 35841411Smckusick register char *target, *list[]; 35941411Smckusick int cnt; 36012660Smckusick { 36112703Smckusick register int i; 36212660Smckusick 36341411Smckusick for (i = 0; i < cnt; i++) 36441411Smckusick if (strcmp(target, list[i]) == 0) 36541411Smckusick return (i); 36641411Smckusick return (-1); 36712660Smckusick } 36812660Smckusick 36941411Smckusick /* 370*41443Smckusick * Determine the group identifier for quota files. 371*41443Smckusick */ 372*41443Smckusick getquotagid() 373*41443Smckusick { 374*41443Smckusick struct group *gr; 375*41443Smckusick 376*41443Smckusick if (gr = getgrnam(quotagroup)) 377*41443Smckusick return (gr->gr_gid); 378*41443Smckusick return (-1); 379*41443Smckusick } 380*41443Smckusick 381*41443Smckusick /* 38241411Smckusick * Check to see if a particular quota is to be enabled. 38341411Smckusick */ 384*41443Smckusick hasquota(fs, type, qfnamep) 385*41443Smckusick register struct fstab *fs; 38641411Smckusick int type; 387*41443Smckusick char **qfnamep; 38812660Smckusick { 38941411Smckusick register char *opt; 390*41443Smckusick char *cp, *index(), *strtok(); 39141411Smckusick static char initname, usrname[100], grpname[100]; 392*41443Smckusick static char buf[BUFSIZ]; 39312660Smckusick 39441411Smckusick if (!initname) { 39541411Smckusick sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); 39641411Smckusick sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); 39741411Smckusick initname = 1; 39812660Smckusick } 399*41443Smckusick strcpy(buf, fs->fs_mntops); 40041411Smckusick for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 401*41443Smckusick if (cp = index(opt, '=')) 402*41443Smckusick *cp++ = '\0'; 40341411Smckusick if (type == USRQUOTA && strcmp(opt, usrname) == 0) 404*41443Smckusick break; 40541411Smckusick if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 406*41443Smckusick break; 40725377Sserge } 408*41443Smckusick if (!opt) 409*41443Smckusick return (0); 410*41443Smckusick if (cp) { 411*41443Smckusick *qfnamep = cp; 412*41443Smckusick return (1); 413*41443Smckusick } 414*41443Smckusick (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 415*41443Smckusick *qfnamep = buf; 416*41443Smckusick return (1); 41712660Smckusick } 41812660Smckusick 41941411Smckusick /* 42041411Smckusick * Routines to manage the file usage table. 42141411Smckusick * 42241411Smckusick * Lookup an id of a specific type. 42341411Smckusick */ 42412703Smckusick struct fileusage * 42541411Smckusick lookup(id, type) 42641411Smckusick u_long id; 42741411Smckusick int type; 42812660Smckusick { 42912703Smckusick register struct fileusage *fup; 43012660Smckusick 43141411Smckusick for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next) 43241411Smckusick if (fup->fu_id == id) 43312703Smckusick return (fup); 43412703Smckusick return ((struct fileusage *)0); 43512660Smckusick } 43612660Smckusick 43741411Smckusick /* 43841411Smckusick * Add a new file usage id if it does not already exist. 43941411Smckusick */ 44012703Smckusick struct fileusage * 44141411Smckusick addid(id, type, name) 44241411Smckusick u_long id; 44341411Smckusick int type; 44441411Smckusick char *name; 44512660Smckusick { 44612703Smckusick struct fileusage *fup, **fhp; 44741411Smckusick int len; 44824661Sserge extern char *calloc(); 44912660Smckusick 45041411Smckusick if (fup = lookup(id, type)) 45112703Smckusick return (fup); 45241411Smckusick if (name) 45341411Smckusick len = strlen(name); 45441411Smckusick else 45541411Smckusick len = 10; 45641411Smckusick if ((fup = (struct fileusage *)calloc(1, sizeof(*fup) + len)) == NULL) { 45712703Smckusick fprintf(stderr, "out of memory for fileusage structures\n"); 45812703Smckusick exit(1); 45912703Smckusick } 46041411Smckusick fhp = &fuhead[type][id & (FUHASH - 1)]; 46112703Smckusick fup->fu_next = *fhp; 46212703Smckusick *fhp = fup; 46341411Smckusick fup->fu_id = id; 46441411Smckusick if (id > highid[type]) 46541411Smckusick highid[type] = id; 46641411Smckusick if (name) { 46741411Smckusick bcopy(name, fup->fu_name, len + 1); 46841411Smckusick } else { 46941411Smckusick sprintf(fup->fu_name, "%u", id); 47041411Smckusick } 47112703Smckusick return (fup); 47212660Smckusick } 47312660Smckusick 47441411Smckusick /* 47541411Smckusick * Special purpose version of ginode used to optimize pass 47641411Smckusick * over all the inodes in numerical order. 47741411Smckusick */ 47841411Smckusick ino_t nextino, lastinum; 47941411Smckusick long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 48041411Smckusick struct dinode *inodebuf; 48141411Smckusick #define INOBUFSIZE 56*1024 /* size of buffer to read inodes */ 48241411Smckusick 48341411Smckusick struct dinode * 48441411Smckusick getnextinode(inumber) 48541411Smckusick ino_t inumber; 48612660Smckusick { 48741411Smckusick long size; 48841411Smckusick daddr_t dblk; 48941411Smckusick static struct dinode *dp; 49012660Smckusick 49141411Smckusick if (inumber != nextino++ || inumber > maxino) { 49241411Smckusick fprintf(stderr, "bad inode number %d to nextinode\n", inumber); 49341411Smckusick exit(1); 49412703Smckusick } 49541411Smckusick if (inumber >= lastinum) { 49641411Smckusick readcnt++; 49741411Smckusick dblk = fsbtodb(&sblock, itod(&sblock, lastinum)); 49841411Smckusick if (readcnt % readpercg == 0) { 49941411Smckusick size = partialsize; 50041411Smckusick lastinum += partialcnt; 50141411Smckusick } else { 50241411Smckusick size = inobufsize; 50341411Smckusick lastinum += fullcnt; 50441411Smckusick } 50541411Smckusick bread(dblk, (char *)inodebuf, size); 50641411Smckusick dp = inodebuf; 50741411Smckusick } 50841411Smckusick return (dp++); 50912660Smckusick } 51041411Smckusick 51141411Smckusick /* 51241411Smckusick * Prepare to scan a set of inodes. 51341411Smckusick */ 51441411Smckusick resetinodebuf() 51541411Smckusick { 51641411Smckusick 51741411Smckusick nextino = 0; 51841411Smckusick lastinum = 0; 51941411Smckusick readcnt = 0; 52041411Smckusick inobufsize = blkroundup(&sblock, INOBUFSIZE); 52141411Smckusick fullcnt = inobufsize / sizeof(struct dinode); 52241411Smckusick readpercg = sblock.fs_ipg / fullcnt; 52341411Smckusick partialcnt = sblock.fs_ipg % fullcnt; 52441411Smckusick partialsize = partialcnt * sizeof(struct dinode); 52541411Smckusick if (partialcnt != 0) { 52641411Smckusick readpercg++; 52741411Smckusick } else { 52841411Smckusick partialcnt = fullcnt; 52941411Smckusick partialsize = inobufsize; 53041411Smckusick } 53141411Smckusick if (inodebuf == NULL && 53241411Smckusick (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) { 53341411Smckusick fprintf(stderr, "Cannot allocate space for inode buffer\n"); 53441411Smckusick exit(1); 53541411Smckusick } 53641411Smckusick while (nextino < ROOTINO) 53741411Smckusick getnextinode(nextino); 53841411Smckusick } 53941411Smckusick 54041411Smckusick /* 54141411Smckusick * Free up data structures used to scan inodes. 54241411Smckusick */ 54341411Smckusick freeinodebuf() 54441411Smckusick { 54541411Smckusick 54641411Smckusick if (inodebuf != NULL) 54741411Smckusick free((char *)inodebuf); 54841411Smckusick inodebuf = NULL; 54941411Smckusick } 55041411Smckusick 55141411Smckusick /* 55241411Smckusick * Read specified disk blocks. 55341411Smckusick */ 55441411Smckusick bread(bno, buf, cnt) 55541411Smckusick daddr_t bno; 55641411Smckusick char *buf; 55741411Smckusick long cnt; 55841411Smckusick { 55941411Smckusick 56041411Smckusick if (lseek(fi, bno * dev_bsize, 0) < 0) { 56141411Smckusick perror("lseek"); 56241411Smckusick exit(1); 56341411Smckusick } 56441411Smckusick 56541411Smckusick if (read(fi, buf, cnt) != cnt) { 56641411Smckusick perror("read"); 56741411Smckusick exit(1); 56841411Smckusick } 56941411Smckusick } 570