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