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