112703Smckusick #ifndef lint
2*12802Smckusick static char sccsid[] = "@(#)quotacheck.c	4.3 (Berkeley, Melbourne) 05/27/83";
312660Smckusick #endif
412660Smckusick 
512660Smckusick /*
612660Smckusick  * Fix up / report on disc quotas & usage
712660Smckusick  */
812660Smckusick #include <stdio.h>
912660Smckusick #include <ctype.h>
1012660Smckusick #include <signal.h>
1112660Smckusick #include <sys/param.h>
1212660Smckusick #include <sys/inode.h>
1312660Smckusick #include <sys/fs.h>
1412660Smckusick #include <sys/quota.h>
1512660Smckusick #include <sys/stat.h>
1612703Smckusick #include <fstab.h>
17*12802Smckusick #include <pwd.h>
1812660Smckusick 
1912660Smckusick union {
2012660Smckusick 	struct	fs	sblk;
2112703Smckusick 	char	dummy[MAXBSIZE];
2212660Smckusick } un;
2312660Smckusick #define	sblock	un.sblk
2412703Smckusick 
2512703Smckusick #define	ITABSZ	256
2612660Smckusick struct	dinode	itab[ITABSZ];
2712660Smckusick struct	dinode	*dp;
2812660Smckusick long	blocks;
2912660Smckusick dev_t	dev;
3012660Smckusick 
31*12802Smckusick #define LOGINNAMESIZE 8
3212703Smckusick struct fileusage {
33*12802Smckusick 	struct fileusage *fu_next;
3412703Smckusick 	struct dqusage fu_usage;
3512703Smckusick 	u_short	fu_uid;
36*12802Smckusick 	char fu_name[LOGINNAMESIZE + 1];
3712703Smckusick };
3812703Smckusick #define FUHASH 997
3912703Smckusick struct fileusage *fuhead[FUHASH];
4012703Smckusick struct fileusage *lookup();
4112703Smckusick struct fileusage *adduid();
4212703Smckusick int highuid;
4312660Smckusick 
4412703Smckusick int fi;
4512703Smckusick ino_t ino;
4612703Smckusick long done;
4712660Smckusick struct	passwd	*getpwent();
4812660Smckusick struct	dinode	*ginode();
4912703Smckusick char *malloc(), *makerawname();
5012660Smckusick 
5112703Smckusick int	vflag;		/* verbose */
5212703Smckusick int	aflag;		/* all file systems */
5312703Smckusick 
5412703Smckusick char *qfname = "quotas";
5512703Smckusick char quotafile[MAXPATHLEN + 1];
56*12802Smckusick struct dqblk zerodqbuf;
5712703Smckusick 
5812660Smckusick main(argc, argv)
5912703Smckusick 	int argc;
6012660Smckusick 	char **argv;
6112660Smckusick {
6212703Smckusick 	register struct fstab *fs;
63*12802Smckusick 	register struct fileusage *fup;
64*12802Smckusick 	register struct passwd *pw;
6512703Smckusick 	int i, errs = 0;
6612660Smckusick 
6712703Smckusick again:
6812703Smckusick 	argc--, argv++;
6912703Smckusick 	if (argc > 0 && strcmp(*argv, "-v") == 0) {
7012703Smckusick 		vflag++;
7112703Smckusick 		goto again;
7212660Smckusick 	}
7312703Smckusick 	if (argc > 0 && strcmp(*argv, "-a") == 0) {
7412703Smckusick 		aflag++;
7512703Smckusick 		goto again;
7612703Smckusick 	}
7712703Smckusick 	if (argc <= 0 && !aflag) {
7812703Smckusick 		fprintf(stderr, "Usage:\n\t%s\n\t%s\n",
7912703Smckusick 			"quotacheck [-v] -a",
8012703Smckusick 			"quotacheck [-v] filesys ...");
8112660Smckusick 		exit(1);
8212660Smckusick 	}
83*12802Smckusick 	if (vflag) {
84*12802Smckusick 		setpwent();
85*12802Smckusick 		while ((pw = getpwent()) != 0) {
86*12802Smckusick 			fup = lookup(pw->pw_uid);
87*12802Smckusick 			if (fup == 0)
88*12802Smckusick 				fup = adduid(pw->pw_uid);
89*12802Smckusick 			strncpy(fup->fu_name, pw->pw_name,
90*12802Smckusick 				sizeof(fup->fu_name));
91*12802Smckusick 		}
92*12802Smckusick 		endpwent();
93*12802Smckusick 	}
9412703Smckusick 	setfsent();
9512703Smckusick 	while ((fs = getfsent()) != NULL) {
9612703Smckusick 		if (aflag &&
9712703Smckusick 		    (fs->fs_type == 0 || strcmp(fs->fs_type, "rq") != 0))
9812703Smckusick 			continue;
9912703Smckusick 		if (!aflag &&
10012703Smckusick 		    !(oneof(fs->fs_file, argv, argc) ||
10112703Smckusick 		      oneof(fs->fs_spec, argv, argc)))
10212703Smckusick 			continue;
10312703Smckusick 		(void) sprintf(quotafile, "%s/%s", fs->fs_file, qfname);
10412703Smckusick 		errs += chkquota(fs->fs_spec, quotafile);
10512660Smckusick 	}
10612703Smckusick 	endfsent();
10712703Smckusick 	for (i = 0; i < argc; i++)
10812703Smckusick 		if ((done & (1 << i)) == 0)
10912703Smckusick 			fprintf(stderr, "%s not found in /etc/fstab\n",
11012703Smckusick 				argv[i]);
11112703Smckusick 	exit(errs);
11212703Smckusick }
11312660Smckusick 
11412703Smckusick chkquota(fsdev, qffile)
11512703Smckusick 	char *fsdev;
11612703Smckusick 	char *qffile;
11712703Smckusick {
11812703Smckusick 	register struct fileusage *fup;
11912703Smckusick 	dev_t quotadev;
12012703Smckusick 	FILE *qf;
12112703Smckusick 	u_short uid;
12212703Smckusick 	int cg, i;
12312703Smckusick 	char *rawdisk;
12412703Smckusick 	struct stat statb;
12512703Smckusick 	struct dqblk dqbuf;
12612660Smckusick 
12712703Smckusick 	rawdisk = makerawname(fsdev);
12812703Smckusick 	if (vflag)
12912703Smckusick 		fprintf(stdout, "*** Check quotas for %s\n", rawdisk);
13012703Smckusick 	fi = open(rawdisk, 0);
13112703Smckusick 	if (fi < 0) {
13212703Smckusick 		perror(rawdisk);
13312703Smckusick 		return (1);
13412660Smckusick 	}
13512703Smckusick 	qf = fopen(qffile, "r+");
13612703Smckusick 	if (qf == NULL) {
13712703Smckusick 		perror(qffile);
13812703Smckusick 		return (1);
13912660Smckusick 	}
14012703Smckusick 	if (fstat(fileno(qf), &statb) < 0) {
14112703Smckusick 		perror(qffile);
14212703Smckusick 		return (1);
14312703Smckusick 	}
14412703Smckusick 	quotadev = statb.st_dev;
14512703Smckusick 	if (stat(fsdev, &statb) < 0) {
14612703Smckusick 		perror(fsdev);
14712703Smckusick 		return (1);
14812703Smckusick 	}
14912703Smckusick 	if (quotadev != statb.st_rdev) {
15012703Smckusick 		fprintf(stderr, "%s dev (0x%x) mismatch %s dev (0x%x)\n",
15112703Smckusick 			qffile, quotadev, fsdev, statb.st_rdev);
15212703Smckusick 		return (1);
15312703Smckusick 	}
15412703Smckusick 	quota(Q_SYNC, 0, quotadev, 0);
15512660Smckusick 	sync();
15612660Smckusick 	bread(SBLOCK, (char *)&sblock, SBSIZE);
15712660Smckusick 	ino = 0;
15812660Smckusick 	for (cg = 0; cg < sblock.fs_ncg; cg++) {
15912660Smckusick 		dp = NULL;
16012660Smckusick 		for (i = 0; i < sblock.fs_ipg; i++)
16112660Smckusick 			acct(ginode());
16212660Smckusick 	}
16312703Smckusick 	for (uid = 0; uid <= highuid; uid++) {
16412703Smckusick 		fup = lookup(uid);
16512703Smckusick 		if (fup == 0)
16612703Smckusick 			continue;
16712703Smckusick 		fseek(qf, uid * sizeof(struct dqblk), 0);
16812703Smckusick 		i = fread(&dqbuf, sizeof(struct dqblk), 1, qf);
16912703Smckusick 		if (i == 0)
170*12802Smckusick 			dqbuf = zerodqbuf;
17112703Smckusick 		if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes &&
172*12802Smckusick 		    dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) {
173*12802Smckusick 			fup->fu_usage.du_curinodes = 0;
174*12802Smckusick 			fup->fu_usage.du_curblocks = 0;
17512703Smckusick 			continue;
176*12802Smckusick 		}
17712703Smckusick 		if (vflag) {
178*12802Smckusick 			if (fup->fu_name[0] != '\0')
179*12802Smckusick 				printf("%-10s fixed:", fup->fu_name);
180*12802Smckusick 			else
181*12802Smckusick 				printf("#%-9d fixed:", uid);
18212703Smckusick 			fprintf(stdout, " inodes (old %d, new %d)",
18312703Smckusick 			    dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes);
18412703Smckusick 			fprintf(stdout, " blocks (old %d, new %d)\n",
18512703Smckusick 			    dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks);
18612660Smckusick 		}
18712703Smckusick 		dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes;
18812703Smckusick 		dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks;
189*12802Smckusick 		fup->fu_usage.du_curinodes = 0;
190*12802Smckusick 		fup->fu_usage.du_curblocks = 0;
19112703Smckusick 		fseek(qf, uid * sizeof(struct dqblk), 0);
19212703Smckusick 		fwrite(&dqbuf, sizeof(struct dqblk), 1, qf);
19312703Smckusick 		quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage);
19412660Smckusick 	}
19512703Smckusick 	return (0);
19612660Smckusick }
19712660Smckusick 
19812660Smckusick acct(ip)
19912660Smckusick 	register struct dinode *ip;
20012660Smckusick {
20112660Smckusick 	register n;
20212703Smckusick 	register struct fileusage *fup;
20312660Smckusick 
20412660Smckusick 	if (ip == NULL)
20512660Smckusick 		return;
20612660Smckusick 	if (ip->di_mode == 0)
20712660Smckusick 		return;
20812703Smckusick 	fup = lookup(ip->di_uid);
20912703Smckusick 	if (fup == 0)
21012703Smckusick 		fup = adduid(ip->di_uid);
21112703Smckusick 	fup->fu_usage.du_curinodes++;
21212660Smckusick 	if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK)
21312660Smckusick 		return;
21412703Smckusick 	fup->fu_usage.du_curblocks += ip->di_blocks;
21512660Smckusick }
21612660Smckusick 
21712703Smckusick oneof(target, list, n)
21812703Smckusick 	char *target, *list[];
21912703Smckusick 	register int n;
22012660Smckusick {
22112703Smckusick 	register int i;
22212660Smckusick 
22312703Smckusick 	for (i = 0; i < n; i++)
22412703Smckusick 		if (strcmp(target, list[i]) == 0) {
22512703Smckusick 			done |= 1 << i;
22612703Smckusick 			return (1);
22712703Smckusick 		}
22812703Smckusick 	return (0);
22912660Smckusick }
23012660Smckusick 
23112660Smckusick struct dinode *
23212660Smckusick ginode()
23312660Smckusick {
23412660Smckusick 	register unsigned long iblk;
23512660Smckusick 
23612660Smckusick 	if (dp == NULL || ++dp >= &itab[ITABSZ]) {
23712660Smckusick 		iblk = itod(&sblock, ino);
23812660Smckusick 		bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab);
23912660Smckusick 		dp = &itab[ino % INOPB(&sblock)];
24012660Smckusick 	}
24112660Smckusick 	if (ino++ < ROOTINO)
24212660Smckusick 		return(NULL);
24312660Smckusick 	return(dp);
24412660Smckusick }
24512660Smckusick 
24612660Smckusick bread(bno, buf, cnt)
24712660Smckusick 	long unsigned bno;
24812660Smckusick 	char *buf;
24912660Smckusick {
25012660Smckusick 
25112703Smckusick 	lseek(fi, (long)dbtob(bno), 0);
25212660Smckusick 	if (read(fi, buf, cnt) != cnt) {
25312660Smckusick 		printf("read error %u\n", bno);
25412660Smckusick 		exit(1);
25512660Smckusick 	}
25612660Smckusick }
25712660Smckusick 
25812703Smckusick struct fileusage *
25912703Smckusick lookup(uid)
26012703Smckusick 	u_short uid;
26112660Smckusick {
26212703Smckusick 	register struct fileusage *fup;
26312660Smckusick 
26412703Smckusick 	for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next)
26512703Smckusick 		if (fup->fu_uid == uid)
26612703Smckusick 			return (fup);
26712703Smckusick 	return ((struct fileusage *)0);
26812660Smckusick }
26912660Smckusick 
27012703Smckusick struct fileusage *
27112703Smckusick adduid(uid)
27212703Smckusick 	u_short uid;
27312660Smckusick {
27412703Smckusick 	struct fileusage *fup, **fhp;
27512660Smckusick 
27612703Smckusick 	fup = lookup(uid);
27712703Smckusick 	if (fup != 0)
27812703Smckusick 		return (fup);
27912703Smckusick 	fup = (struct fileusage *)calloc(1, sizeof(struct fileusage));
28012703Smckusick 	if (fup == 0) {
28112703Smckusick 		fprintf(stderr, "out of memory for fileusage structures\n");
28212703Smckusick 		exit(1);
28312703Smckusick 	}
28412703Smckusick 	fhp = &fuhead[uid % FUHASH];
28512703Smckusick 	fup->fu_next = *fhp;
28612703Smckusick 	*fhp = fup;
28712703Smckusick 	fup->fu_uid = uid;
28812703Smckusick 	if (uid > highuid)
28912703Smckusick 		highuid = uid;
29012703Smckusick 	return (fup);
29112660Smckusick }
29212660Smckusick 
29312660Smckusick char *
29412703Smckusick makerawname(name)
29512703Smckusick 	char *name;
29612660Smckusick {
29712703Smckusick 	register char *cp;
29812703Smckusick 	char tmp, ch, *rindex();
29912703Smckusick 	static char rawname[MAXPATHLEN];
30012660Smckusick 
30112703Smckusick 	strcpy(rawname, name);
30212703Smckusick 	cp = rindex(rawname, '/') + 1;
30312703Smckusick 	if (cp == (char *)1 || *cp == 'r')
30412703Smckusick 		return (name);
30512703Smckusick 	for (ch = 'r'; *cp != '\0'; ) {
30612703Smckusick 		tmp = *cp;
30712703Smckusick 		*cp++ = ch;
30812703Smckusick 		ch = tmp;
30912703Smckusick 	}
31012703Smckusick 	*cp++ = ch;
31112703Smckusick 	*cp = '\0';
31212703Smckusick 	return (rawname);
31312660Smckusick }
314