121517Smckusick /* 2*41411Smckusick * Copyright (c) 1980, 1990 Regents of the University of California. 334364Sbostic * All rights reserved. 434364Sbostic * 5*41411Smckusick * This code is derived from software contributed to Berkeley by 6*41411Smckusick * Robert Elz at The University of Melbourne. 7*41411Smckusick * 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[] = 23*41411Smckusick "@(#) 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*41411Smckusick static char sccsid[] = "@(#)quotacheck.c 5.12 (Berkeley) 05/04/90"; 2934364Sbostic #endif /* not lint */ 3021517Smckusick 3112660Smckusick /* 32*41411Smckusick * Fix up / report on disk quotas & usage 3312660Smckusick */ 3412660Smckusick #include <sys/param.h> 35*41411Smckusick #include <ufs/dinode.h> 3638511Sbostic #include <ufs/fs.h> 3738511Sbostic #include <ufs/quota.h> 3812703Smckusick #include <fstab.h> 3912802Smckusick #include <pwd.h> 40*41411Smckusick #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 49*41411Smckusick long dev_bsize = 1; 50*41411Smckusick long maxino; 5112703Smckusick 5212703Smckusick struct fileusage { 53*41411Smckusick struct fileusage *fu_next; 54*41411Smckusick u_long fu_curinodes; 55*41411Smckusick u_long fu_curblocks; 56*41411Smckusick u_long fu_id; 57*41411Smckusick char fu_name[1]; 58*41411Smckusick /* actually bigger */ 5912703Smckusick }; 60*41411Smckusick #define FUHASH 1024 /* must be power of two */ 61*41411Smckusick struct fileusage *fuhead[MAXQUOTAS][FUHASH]; 6212703Smckusick struct fileusage *lookup(); 63*41411Smckusick struct fileusage *addid(); 64*41411Smckusick struct dinode *getnextinode(); 6512660Smckusick 66*41411Smckusick #define HASUSR 1 67*41411Smckusick #define HASGRP 2 6812660Smckusick 69*41411Smckusick int aflag; /* all file systems */ 70*41411Smckusick int gflag; /* check group quotas */ 71*41411Smckusick int uflag; /* check user quotas */ 72*41411Smckusick int vflag; /* verbose */ 73*41411Smckusick int fi; /* open disk file descriptor */ 74*41411Smckusick u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */ 7512703Smckusick 7612660Smckusick main(argc, argv) 7712703Smckusick int argc; 7812660Smckusick char **argv; 7912660Smckusick { 8012703Smckusick register struct fstab *fs; 8112802Smckusick register struct passwd *pw; 82*41411Smckusick register struct group *gr; 83*41411Smckusick int i, argnum, maxrun, errs = 0; 84*41411Smckusick long auxdata, done = 0; 85*41411Smckusick char ch, *name, *blockcheck(); 86*41411Smckusick int needchk(), chkquota(); 87*41411Smckusick extern char *optarg; 88*41411Smckusick extern int optind; 8912660Smckusick 90*41411Smckusick while ((ch = getopt(argc, argv, "aguvl:")) != EOF) { 91*41411Smckusick switch(ch) { 92*41411Smckusick case 'a': 93*41411Smckusick aflag++; 94*41411Smckusick break; 95*41411Smckusick case 'g': 96*41411Smckusick gflag++; 97*41411Smckusick break; 98*41411Smckusick case 'u': 99*41411Smckusick uflag++; 100*41411Smckusick break; 101*41411Smckusick case 'v': 102*41411Smckusick vflag++; 103*41411Smckusick break; 104*41411Smckusick case 'l': 105*41411Smckusick maxrun = atoi(optarg); 106*41411Smckusick break; 107*41411Smckusick default: 108*41411Smckusick usage(); 109*41411Smckusick } 11012660Smckusick } 111*41411Smckusick argc -= optind; 112*41411Smckusick argv += optind; 113*41411Smckusick if ((argc == 0 && !aflag) || (argc > 0 && aflag)) 114*41411Smckusick usage(); 115*41411Smckusick if (!gflag && !uflag) { 116*41411Smckusick gflag++; 117*41411Smckusick uflag++; 11812703Smckusick } 119*41411Smckusick if (gflag) { 120*41411Smckusick setgrent(); 121*41411Smckusick while ((gr = getgrent()) != 0) 122*41411Smckusick (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name); 123*41411Smckusick endgrent(); 12424758Sserge } 125*41411Smckusick if (uflag) { 126*41411Smckusick setpwent(); 127*41411Smckusick while ((pw = getpwent()) != 0) 128*41411Smckusick (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name); 129*41411Smckusick endpwent(); 13012660Smckusick } 131*41411Smckusick if (aflag) 132*41411Smckusick exit(checkfstab(1, maxrun, needchk, chkquota)); 133*41411Smckusick if (setfsent() == 0) { 134*41411Smckusick fprintf(stderr, "Can't open "); 135*41411Smckusick perror(FSTAB); 136*41411Smckusick exit(8); 13712802Smckusick } 138*41411Smckusick while ((fs = getfsent()) != NULL) { 139*41411Smckusick if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || 140*41411Smckusick (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) && 141*41411Smckusick (auxdata = needchk(fs)) && 142*41411Smckusick (name = blockcheck(fs->fs_spec))) { 143*41411Smckusick done |= 1 << argnum; 144*41411Smckusick errs += chkquota(name, fs->fs_file, auxdata); 14524758Sserge } 14612660Smckusick } 147*41411Smckusick endfsent(); 14812703Smckusick for (i = 0; i < argc; i++) 14912703Smckusick if ((done & (1 << i)) == 0) 15024782Sserge fprintf(stderr, "%s not found in %s\n", 15124782Sserge argv[i], FSTAB); 15212703Smckusick exit(errs); 15312703Smckusick } 15412660Smckusick 155*41411Smckusick usage() 15624758Sserge { 15724758Sserge 158*41411Smckusick fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 159*41411Smckusick "quotacheck [-g] [-u] [-v] -a", 160*41411Smckusick "quotacheck [-g] [-u] [-v] filesys ..."); 161*41411Smckusick exit(1); 162*41411Smckusick } 16324758Sserge 164*41411Smckusick needchk(fs) 165*41411Smckusick register struct fstab *fs; 166*41411Smckusick { 167*41411Smckusick int auxdata = 0; 16824758Sserge 169*41411Smckusick if (gflag && hasquota(fs->fs_mntops, GRPQUOTA)) 170*41411Smckusick auxdata |= HASGRP; 171*41411Smckusick if (uflag && hasquota(fs->fs_mntops, USRQUOTA)) 172*41411Smckusick auxdata |= HASUSR; 173*41411Smckusick return (auxdata); 174*41411Smckusick } 17524758Sserge 176*41411Smckusick /* 177*41411Smckusick * Scan the specified filesystem to check quota(s) present on it. 178*41411Smckusick */ 179*41411Smckusick chkquota(fsname, mntpt, auxdata) 180*41411Smckusick char *fsname, *mntpt; 181*41411Smckusick long auxdata; 182*41411Smckusick { 183*41411Smckusick register struct fileusage *fup; 184*41411Smckusick register struct dinode *dp; 185*41411Smckusick int cg, i, mode, errs = 0; 186*41411Smckusick ino_t ino; 18724758Sserge 188*41411Smckusick if ((fi = open(fsname, 0)) < 0) { 189*41411Smckusick perror(fsname); 190*41411Smckusick return (1); 191*41411Smckusick } 192*41411Smckusick if (vflag) { 193*41411Smckusick fprintf(stdout, "*** Checking "); 194*41411Smckusick if (auxdata & HASUSR) 195*41411Smckusick fprintf(stdout, "%s%s", qfextension[USRQUOTA], 196*41411Smckusick (auxdata & HASGRP) ? " and " : ""); 197*41411Smckusick if (auxdata & HASGRP) 198*41411Smckusick fprintf(stdout, "%s", qfextension[GRPQUOTA]); 199*41411Smckusick fprintf(stdout, " quotas for %s (%s)\n", fsname, mntpt); 200*41411Smckusick } 201*41411Smckusick sync(); 202*41411Smckusick bread(SBOFF, (char *)&sblock, (long)SBSIZE); 203*41411Smckusick dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 204*41411Smckusick maxino = sblock.fs_ncg * sblock.fs_ipg; 205*41411Smckusick resetinodebuf(); 206*41411Smckusick for (ino = 0, cg = 0; cg < sblock.fs_ncg; cg++) { 207*41411Smckusick for (i = 0; i < sblock.fs_ipg; i++, ino++) { 208*41411Smckusick if (ino < ROOTINO) 20924758Sserge continue; 210*41411Smckusick if ((dp = getnextinode(ino)) == NULL) 21124758Sserge continue; 212*41411Smckusick if ((mode = dp->di_mode & IFMT) == 0) 213*41411Smckusick continue; 214*41411Smckusick if (auxdata & HASGRP) { 215*41411Smckusick fup = addid((u_long)dp->di_gid, GRPQUOTA, 216*41411Smckusick (char *)0); 217*41411Smckusick fup->fu_curinodes++; 218*41411Smckusick if (mode == IFREG || mode == IFDIR || 219*41411Smckusick mode == IFLNK) 220*41411Smckusick fup->fu_curblocks += dp->di_blocks; 22124758Sserge } 222*41411Smckusick if (auxdata & HASUSR) { 223*41411Smckusick fup = addid((u_long)dp->di_uid, USRQUOTA, 224*41411Smckusick (char *)0); 225*41411Smckusick fup->fu_curinodes++; 226*41411Smckusick if (mode == IFREG || mode == IFDIR || 227*41411Smckusick mode == IFLNK) 228*41411Smckusick fup->fu_curblocks += dp->di_blocks; 229*41411Smckusick } 23024758Sserge } 231*41411Smckusick } 232*41411Smckusick freeinodebuf(); 233*41411Smckusick if (auxdata & HASUSR) 234*41411Smckusick errs += update(mntpt, USRQUOTA); 235*41411Smckusick if (auxdata & HASGRP) 236*41411Smckusick errs += update(mntpt, GRPQUOTA); 237*41411Smckusick close(fi); 23824758Sserge return (errs); 23924758Sserge } 24024758Sserge 241*41411Smckusick /* 242*41411Smckusick * Update a specified quota file. 243*41411Smckusick */ 244*41411Smckusick update(fsname, type) 245*41411Smckusick char *fsname; 246*41411Smckusick register int type; 24712703Smckusick { 24812703Smckusick register struct fileusage *fup; 24925377Sserge register FILE *qfi, *qfo; 250*41411Smckusick register u_long id, lastid; 25112703Smckusick struct dqblk dqbuf; 252*41411Smckusick char quotafile[MAXPATHLEN + 1]; 253*41411Smckusick extern int errno; 25421085Smckusick static int warned = 0; 255*41411Smckusick static struct dqblk zerodqbuf; 256*41411Smckusick static struct fileusage zerofileusage; 25712660Smckusick 258*41411Smckusick (void) sprintf(quotafile, "%s/%s.%s", fsname, qfname, 259*41411Smckusick qfextension[type]); 260*41411Smckusick if ((qfo = fopen(quotafile, "r+")) == NULL) { 261*41411Smckusick if (errno != ENOENT) { 262*41411Smckusick perror(quotafile); 263*41411Smckusick return (1); 264*41411Smckusick } 265*41411Smckusick if ((qfo = fopen(quotafile, "w+")) == NULL) { 266*41411Smckusick perror(quotafile); 267*41411Smckusick return (1); 268*41411Smckusick } 26912660Smckusick } 270*41411Smckusick if ((qfi = fopen(quotafile, "r")) == NULL) { 271*41411Smckusick perror(quotafile); 272*41411Smckusick fclose(qfo); 27312703Smckusick return (1); 27412660Smckusick } 275*41411Smckusick if (quotactl(fsname, QCMD(Q_SYNC, type), (u_long)0, (caddr_t)0) < 0 && 276*41411Smckusick errno == EOPNOTSUPP && !warned && vflag) { 27721085Smckusick warned++; 278*41411Smckusick fprintf(stdout, "*** Warning: %s\n", 279*41411Smckusick "Quotas are not compiled into this kernel"); 28021085Smckusick } 281*41411Smckusick for (lastid = highid[type], id = 0; id <= lastid; id++) { 282*41411Smckusick if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0) 28312802Smckusick dqbuf = zerodqbuf; 284*41411Smckusick if ((fup = lookup(id, type)) == 0) 28524758Sserge fup = &zerofileusage; 286*41411Smckusick if (dqbuf.dqb_curinodes == fup->fu_curinodes && 287*41411Smckusick dqbuf.dqb_curblocks == fup->fu_curblocks) { 288*41411Smckusick fup->fu_curinodes = 0; 289*41411Smckusick fup->fu_curblocks = 0; 29025377Sserge fseek(qfo, (long)sizeof(struct dqblk), 1); 29112703Smckusick continue; 29212802Smckusick } 29312703Smckusick if (vflag) { 294*41411Smckusick if (aflag) 295*41411Smckusick printf("%s: ", fsname); 296*41411Smckusick printf("%-8s fixed:", fup->fu_name); 297*41411Smckusick if (dqbuf.dqb_curinodes != fup->fu_curinodes) 29825377Sserge fprintf(stdout, "\tinodes %d -> %d", 299*41411Smckusick dqbuf.dqb_curinodes, fup->fu_curinodes); 300*41411Smckusick if (dqbuf.dqb_curblocks != fup->fu_curblocks) 30125377Sserge fprintf(stdout, "\tblocks %d -> %d", 302*41411Smckusick dqbuf.dqb_curblocks, fup->fu_curblocks); 30324758Sserge fprintf(stdout, "\n"); 30412660Smckusick } 305*41411Smckusick /* 306*41411Smckusick * Reset time limit if have a soft limit and were 307*41411Smckusick * previously under it, but are now over it. 308*41411Smckusick */ 309*41411Smckusick if (dqbuf.dqb_bsoftlimit && 310*41411Smckusick dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit && 311*41411Smckusick fup->fu_curblocks >= dqbuf.dqb_bsoftlimit) 312*41411Smckusick dqbuf.dqb_btime = 0; 313*41411Smckusick if (dqbuf.dqb_isoftlimit && 314*41411Smckusick dqbuf.dqb_curblocks < dqbuf.dqb_isoftlimit && 315*41411Smckusick fup->fu_curblocks >= dqbuf.dqb_isoftlimit) 316*41411Smckusick dqbuf.dqb_itime = 0; 317*41411Smckusick dqbuf.dqb_curinodes = fup->fu_curinodes; 318*41411Smckusick dqbuf.dqb_curblocks = fup->fu_curblocks; 319*41411Smckusick fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo); 320*41411Smckusick (void) quotactl(fsname, QCMD(Q_SETUSE, type), id, 321*41411Smckusick (caddr_t)&dqbuf); 322*41411Smckusick fup->fu_curinodes = 0; 323*41411Smckusick fup->fu_curblocks = 0; 32412660Smckusick } 325*41411Smckusick fclose(qfi); 32625377Sserge fflush(qfo); 327*41411Smckusick ftruncate(fileno(qfo), 328*41411Smckusick (off_t)((highid[type] + 1) * sizeof(struct dqblk))); 32925377Sserge fclose(qfo); 33012703Smckusick return (0); 33112660Smckusick } 33212660Smckusick 333*41411Smckusick /* 334*41411Smckusick * Check to see if target appears in list of size cnt. 335*41411Smckusick */ 336*41411Smckusick oneof(target, list, cnt) 337*41411Smckusick register char *target, *list[]; 338*41411Smckusick int cnt; 33912660Smckusick { 34012703Smckusick register int i; 34112660Smckusick 342*41411Smckusick for (i = 0; i < cnt; i++) 343*41411Smckusick if (strcmp(target, list[i]) == 0) 344*41411Smckusick return (i); 345*41411Smckusick return (-1); 34612660Smckusick } 34712660Smckusick 348*41411Smckusick /* 349*41411Smckusick * Check to see if a particular quota is to be enabled. 350*41411Smckusick */ 351*41411Smckusick hasquota(options, type) 352*41411Smckusick char *options; 353*41411Smckusick int type; 35412660Smckusick { 355*41411Smckusick register char *opt; 356*41411Smckusick char buf[BUFSIZ]; 357*41411Smckusick char *strtok(); 358*41411Smckusick static char initname, usrname[100], grpname[100]; 35912660Smckusick 360*41411Smckusick if (!initname) { 361*41411Smckusick sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); 362*41411Smckusick sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); 363*41411Smckusick initname = 1; 36412660Smckusick } 365*41411Smckusick strcpy(buf, options); 366*41411Smckusick for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 367*41411Smckusick if (type == USRQUOTA && strcmp(opt, usrname) == 0) 368*41411Smckusick return(1); 369*41411Smckusick if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 370*41411Smckusick return(1); 37125377Sserge } 372*41411Smckusick return (0); 37312660Smckusick } 37412660Smckusick 375*41411Smckusick /* 376*41411Smckusick * Routines to manage the file usage table. 377*41411Smckusick * 378*41411Smckusick * Lookup an id of a specific type. 379*41411Smckusick */ 38012703Smckusick struct fileusage * 381*41411Smckusick lookup(id, type) 382*41411Smckusick u_long id; 383*41411Smckusick int type; 38412660Smckusick { 38512703Smckusick register struct fileusage *fup; 38612660Smckusick 387*41411Smckusick for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next) 388*41411Smckusick if (fup->fu_id == id) 38912703Smckusick return (fup); 39012703Smckusick return ((struct fileusage *)0); 39112660Smckusick } 39212660Smckusick 393*41411Smckusick /* 394*41411Smckusick * Add a new file usage id if it does not already exist. 395*41411Smckusick */ 39612703Smckusick struct fileusage * 397*41411Smckusick addid(id, type, name) 398*41411Smckusick u_long id; 399*41411Smckusick int type; 400*41411Smckusick char *name; 40112660Smckusick { 40212703Smckusick struct fileusage *fup, **fhp; 403*41411Smckusick int len; 40424661Sserge extern char *calloc(); 40512660Smckusick 406*41411Smckusick if (fup = lookup(id, type)) 40712703Smckusick return (fup); 408*41411Smckusick if (name) 409*41411Smckusick len = strlen(name); 410*41411Smckusick else 411*41411Smckusick len = 10; 412*41411Smckusick if ((fup = (struct fileusage *)calloc(1, sizeof(*fup) + len)) == NULL) { 41312703Smckusick fprintf(stderr, "out of memory for fileusage structures\n"); 41412703Smckusick exit(1); 41512703Smckusick } 416*41411Smckusick fhp = &fuhead[type][id & (FUHASH - 1)]; 41712703Smckusick fup->fu_next = *fhp; 41812703Smckusick *fhp = fup; 419*41411Smckusick fup->fu_id = id; 420*41411Smckusick if (id > highid[type]) 421*41411Smckusick highid[type] = id; 422*41411Smckusick if (name) { 423*41411Smckusick bcopy(name, fup->fu_name, len + 1); 424*41411Smckusick } else { 425*41411Smckusick sprintf(fup->fu_name, "%u", id); 426*41411Smckusick } 42712703Smckusick return (fup); 42812660Smckusick } 42912660Smckusick 430*41411Smckusick /* 431*41411Smckusick * Special purpose version of ginode used to optimize pass 432*41411Smckusick * over all the inodes in numerical order. 433*41411Smckusick */ 434*41411Smckusick ino_t nextino, lastinum; 435*41411Smckusick long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 436*41411Smckusick struct dinode *inodebuf; 437*41411Smckusick #define INOBUFSIZE 56*1024 /* size of buffer to read inodes */ 438*41411Smckusick 439*41411Smckusick struct dinode * 440*41411Smckusick getnextinode(inumber) 441*41411Smckusick ino_t inumber; 44212660Smckusick { 443*41411Smckusick long size; 444*41411Smckusick daddr_t dblk; 445*41411Smckusick static struct dinode *dp; 44612660Smckusick 447*41411Smckusick if (inumber != nextino++ || inumber > maxino) { 448*41411Smckusick fprintf(stderr, "bad inode number %d to nextinode\n", inumber); 449*41411Smckusick exit(1); 45012703Smckusick } 451*41411Smckusick if (inumber >= lastinum) { 452*41411Smckusick readcnt++; 453*41411Smckusick dblk = fsbtodb(&sblock, itod(&sblock, lastinum)); 454*41411Smckusick if (readcnt % readpercg == 0) { 455*41411Smckusick size = partialsize; 456*41411Smckusick lastinum += partialcnt; 457*41411Smckusick } else { 458*41411Smckusick size = inobufsize; 459*41411Smckusick lastinum += fullcnt; 460*41411Smckusick } 461*41411Smckusick bread(dblk, (char *)inodebuf, size); 462*41411Smckusick dp = inodebuf; 463*41411Smckusick } 464*41411Smckusick return (dp++); 46512660Smckusick } 466*41411Smckusick 467*41411Smckusick /* 468*41411Smckusick * Prepare to scan a set of inodes. 469*41411Smckusick */ 470*41411Smckusick resetinodebuf() 471*41411Smckusick { 472*41411Smckusick 473*41411Smckusick nextino = 0; 474*41411Smckusick lastinum = 0; 475*41411Smckusick readcnt = 0; 476*41411Smckusick inobufsize = blkroundup(&sblock, INOBUFSIZE); 477*41411Smckusick fullcnt = inobufsize / sizeof(struct dinode); 478*41411Smckusick readpercg = sblock.fs_ipg / fullcnt; 479*41411Smckusick partialcnt = sblock.fs_ipg % fullcnt; 480*41411Smckusick partialsize = partialcnt * sizeof(struct dinode); 481*41411Smckusick if (partialcnt != 0) { 482*41411Smckusick readpercg++; 483*41411Smckusick } else { 484*41411Smckusick partialcnt = fullcnt; 485*41411Smckusick partialsize = inobufsize; 486*41411Smckusick } 487*41411Smckusick if (inodebuf == NULL && 488*41411Smckusick (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) { 489*41411Smckusick fprintf(stderr, "Cannot allocate space for inode buffer\n"); 490*41411Smckusick exit(1); 491*41411Smckusick } 492*41411Smckusick while (nextino < ROOTINO) 493*41411Smckusick getnextinode(nextino); 494*41411Smckusick } 495*41411Smckusick 496*41411Smckusick /* 497*41411Smckusick * Free up data structures used to scan inodes. 498*41411Smckusick */ 499*41411Smckusick freeinodebuf() 500*41411Smckusick { 501*41411Smckusick 502*41411Smckusick if (inodebuf != NULL) 503*41411Smckusick free((char *)inodebuf); 504*41411Smckusick inodebuf = NULL; 505*41411Smckusick } 506*41411Smckusick 507*41411Smckusick /* 508*41411Smckusick * Read specified disk blocks. 509*41411Smckusick */ 510*41411Smckusick bread(bno, buf, cnt) 511*41411Smckusick daddr_t bno; 512*41411Smckusick char *buf; 513*41411Smckusick long cnt; 514*41411Smckusick { 515*41411Smckusick 516*41411Smckusick if (lseek(fi, bno * dev_bsize, 0) < 0) { 517*41411Smckusick perror("lseek"); 518*41411Smckusick exit(1); 519*41411Smckusick } 520*41411Smckusick 521*41411Smckusick if (read(fi, buf, cnt) != cnt) { 522*41411Smckusick perror("read"); 523*41411Smckusick exit(1); 524*41411Smckusick } 525*41411Smckusick } 526