1*12703Smckusick #ifndef lint
2*12703Smckusick static char sccsid[] = "@(#)quotacheck.c	4.2 (Berkeley, Melbourne) 05/24/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 <pwd.h>
1212660Smckusick #include <sys/param.h>
1312660Smckusick #include <sys/inode.h>
1412660Smckusick #include <sys/fs.h>
1512660Smckusick #define	QUOTA
1612660Smckusick #include <sys/quota.h>
1712660Smckusick #include <sys/stat.h>
18*12703Smckusick #include <fstab.h>
1912660Smckusick 
2012660Smckusick union {
2112660Smckusick 	struct	fs	sblk;
22*12703Smckusick 	char	dummy[MAXBSIZE];
2312660Smckusick } un;
2412660Smckusick #define	sblock	un.sblk
25*12703Smckusick 
26*12703Smckusick #define	ITABSZ	256
2712660Smckusick struct	dinode	itab[ITABSZ];
2812660Smckusick struct	dinode	*dp;
2912660Smckusick long	blocks;
3012660Smckusick dev_t	dev;
3112660Smckusick 
32*12703Smckusick struct fileusage {
33*12703Smckusick 	struct dqusage fu_usage;
34*12703Smckusick 	u_short	fu_uid;
35*12703Smckusick 	struct fileusage *fu_next;
36*12703Smckusick };
37*12703Smckusick #define FUHASH 997
38*12703Smckusick struct fileusage *fuhead[FUHASH];
39*12703Smckusick struct fileusage *lookup();
40*12703Smckusick struct fileusage *adduid();
41*12703Smckusick int highuid;
4212660Smckusick 
43*12703Smckusick int fi;
44*12703Smckusick ino_t ino;
45*12703Smckusick long done;
4612660Smckusick struct	passwd	*getpwent();
4712660Smckusick struct	dinode	*ginode();
48*12703Smckusick char *malloc(), *makerawname();
4912660Smckusick 
50*12703Smckusick int	vflag;		/* verbose */
51*12703Smckusick int	aflag;		/* all file systems */
52*12703Smckusick 
53*12703Smckusick char *qfname = "quotas";
54*12703Smckusick char quotafile[MAXPATHLEN + 1];
55*12703Smckusick 
5612660Smckusick main(argc, argv)
57*12703Smckusick 	int argc;
5812660Smckusick 	char **argv;
5912660Smckusick {
60*12703Smckusick 	register struct fstab *fs;
61*12703Smckusick 	int i, errs = 0;
6212660Smckusick 
63*12703Smckusick again:
64*12703Smckusick 	argc--, argv++;
65*12703Smckusick 	if (argc > 0 && strcmp(*argv, "-v") == 0) {
66*12703Smckusick 		vflag++;
67*12703Smckusick 		goto again;
6812660Smckusick 	}
69*12703Smckusick 	if (argc > 0 && strcmp(*argv, "-a") == 0) {
70*12703Smckusick 		aflag++;
71*12703Smckusick 		goto again;
72*12703Smckusick 	}
73*12703Smckusick 	if (argc <= 0 && !aflag) {
74*12703Smckusick 		fprintf(stderr, "Usage:\n\t%s\n\t%s\n",
75*12703Smckusick 			"quotacheck [-v] -a",
76*12703Smckusick 			"quotacheck [-v] filesys ...");
7712660Smckusick 		exit(1);
7812660Smckusick 	}
79*12703Smckusick 	setfsent();
80*12703Smckusick 	while ((fs = getfsent()) != NULL) {
81*12703Smckusick 		if (aflag &&
82*12703Smckusick 		    (fs->fs_type == 0 || strcmp(fs->fs_type, "rq") != 0))
83*12703Smckusick 			continue;
84*12703Smckusick 		if (!aflag &&
85*12703Smckusick 		    !(oneof(fs->fs_file, argv, argc) ||
86*12703Smckusick 		      oneof(fs->fs_spec, argv, argc)))
87*12703Smckusick 			continue;
88*12703Smckusick 		(void) sprintf(quotafile, "%s/%s", fs->fs_file, qfname);
89*12703Smckusick 		errs += chkquota(fs->fs_spec, quotafile);
9012660Smckusick 	}
91*12703Smckusick 	endfsent();
92*12703Smckusick 	for (i = 0; i < argc; i++)
93*12703Smckusick 		if ((done & (1 << i)) == 0)
94*12703Smckusick 			fprintf(stderr, "%s not found in /etc/fstab\n",
95*12703Smckusick 				argv[i]);
96*12703Smckusick 	exit(errs);
97*12703Smckusick }
9812660Smckusick 
99*12703Smckusick chkquota(fsdev, qffile)
100*12703Smckusick 	char *fsdev;
101*12703Smckusick 	char *qffile;
102*12703Smckusick {
103*12703Smckusick 	register struct fileusage *fup;
104*12703Smckusick 	dev_t quotadev;
105*12703Smckusick 	FILE *qf;
106*12703Smckusick 	u_short uid;
107*12703Smckusick 	int cg, i;
108*12703Smckusick 	char *rawdisk;
109*12703Smckusick 	struct stat statb;
110*12703Smckusick 	struct dqblk dqbuf;
11112660Smckusick 
112*12703Smckusick 	rawdisk = makerawname(fsdev);
113*12703Smckusick 	if (vflag)
114*12703Smckusick 		fprintf(stdout, "*** Check quotas for %s\n", rawdisk);
115*12703Smckusick 	fi = open(rawdisk, 0);
116*12703Smckusick 	if (fi < 0) {
117*12703Smckusick 		perror(rawdisk);
118*12703Smckusick 		return (1);
11912660Smckusick 	}
120*12703Smckusick 	qf = fopen(qffile, "r+");
121*12703Smckusick 	if (qf == NULL) {
122*12703Smckusick 		perror(qffile);
123*12703Smckusick 		return (1);
12412660Smckusick 	}
125*12703Smckusick 	if (fstat(fileno(qf), &statb) < 0) {
126*12703Smckusick 		perror(qffile);
127*12703Smckusick 		return (1);
128*12703Smckusick 	}
129*12703Smckusick 	quotadev = statb.st_dev;
130*12703Smckusick 	if (stat(fsdev, &statb) < 0) {
131*12703Smckusick 		perror(fsdev);
132*12703Smckusick 		return (1);
133*12703Smckusick 	}
134*12703Smckusick 	if (quotadev != statb.st_rdev) {
135*12703Smckusick 		fprintf(stderr, "%s dev (0x%x) mismatch %s dev (0x%x)\n",
136*12703Smckusick 			qffile, quotadev, fsdev, statb.st_rdev);
137*12703Smckusick 		return (1);
138*12703Smckusick 	}
139*12703Smckusick 	quota(Q_SYNC, 0, quotadev, 0);
14012660Smckusick 	sync();
14112660Smckusick 	bread(SBLOCK, (char *)&sblock, SBSIZE);
14212660Smckusick 	ino = 0;
14312660Smckusick 	for (cg = 0; cg < sblock.fs_ncg; cg++) {
14412660Smckusick 		dp = NULL;
14512660Smckusick 		for (i = 0; i < sblock.fs_ipg; i++)
14612660Smckusick 			acct(ginode());
14712660Smckusick 	}
148*12703Smckusick 	for (uid = 0; uid <= highuid; uid++) {
149*12703Smckusick 		fup = lookup(uid);
150*12703Smckusick 		if (fup == 0)
151*12703Smckusick 			continue;
152*12703Smckusick 		fseek(qf, uid * sizeof(struct dqblk), 0);
153*12703Smckusick 		i = fread(&dqbuf, sizeof(struct dqblk), 1, qf);
154*12703Smckusick 		if (i == 0)
155*12703Smckusick 			bzero(&dqbuf, sizeof(struct dqblk));
156*12703Smckusick 		if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes &&
157*12703Smckusick 		    dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks)
158*12703Smckusick 			continue;
159*12703Smckusick 		if (vflag) {
160*12703Smckusick 			fprintf(stdout, "uid %d fixed:", uid);
161*12703Smckusick 			fprintf(stdout, " inodes (old %d, new %d)",
162*12703Smckusick 			    dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes);
163*12703Smckusick 			fprintf(stdout, " blocks (old %d, new %d)\n",
164*12703Smckusick 			    dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks);
16512660Smckusick 		}
166*12703Smckusick 		dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes;
167*12703Smckusick 		dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks;
168*12703Smckusick 		fseek(qf, uid * sizeof(struct dqblk), 0);
169*12703Smckusick 		fwrite(&dqbuf, sizeof(struct dqblk), 1, qf);
170*12703Smckusick 		quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage);
17112660Smckusick 	}
172*12703Smckusick 	return (0);
17312660Smckusick }
17412660Smckusick 
17512660Smckusick acct(ip)
17612660Smckusick 	register struct dinode *ip;
17712660Smckusick {
17812660Smckusick 	register n;
179*12703Smckusick 	register struct fileusage *fup;
18012660Smckusick 
18112660Smckusick 	if (ip == NULL)
18212660Smckusick 		return;
18312660Smckusick 	if (ip->di_mode == 0)
18412660Smckusick 		return;
185*12703Smckusick 	fup = lookup(ip->di_uid);
186*12703Smckusick 	if (fup == 0)
187*12703Smckusick 		fup = adduid(ip->di_uid);
188*12703Smckusick 	fup->fu_usage.du_curinodes++;
18912660Smckusick 	if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK)
19012660Smckusick 		return;
191*12703Smckusick 	fup->fu_usage.du_curblocks += ip->di_blocks;
19212660Smckusick }
19312660Smckusick 
194*12703Smckusick oneof(target, list, n)
195*12703Smckusick 	char *target, *list[];
196*12703Smckusick 	register int n;
19712660Smckusick {
198*12703Smckusick 	register int i;
19912660Smckusick 
200*12703Smckusick 	for (i = 0; i < n; i++)
201*12703Smckusick 		if (strcmp(target, list[i]) == 0) {
202*12703Smckusick 			done |= 1 << i;
203*12703Smckusick 			return (1);
204*12703Smckusick 		}
205*12703Smckusick 	return (0);
20612660Smckusick }
20712660Smckusick 
20812660Smckusick struct dinode *
20912660Smckusick ginode()
21012660Smckusick {
21112660Smckusick 	register unsigned long iblk;
21212660Smckusick 
21312660Smckusick 	if (dp == NULL || ++dp >= &itab[ITABSZ]) {
21412660Smckusick 		iblk = itod(&sblock, ino);
21512660Smckusick 		bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab);
21612660Smckusick 		dp = &itab[ino % INOPB(&sblock)];
21712660Smckusick 	}
21812660Smckusick 	if (ino++ < ROOTINO)
21912660Smckusick 		return(NULL);
22012660Smckusick 	return(dp);
22112660Smckusick }
22212660Smckusick 
22312660Smckusick bread(bno, buf, cnt)
22412660Smckusick 	long unsigned bno;
22512660Smckusick 	char *buf;
22612660Smckusick {
22712660Smckusick 
228*12703Smckusick 	lseek(fi, (long)dbtob(bno), 0);
22912660Smckusick 	if (read(fi, buf, cnt) != cnt) {
23012660Smckusick 		printf("read error %u\n", bno);
23112660Smckusick 		exit(1);
23212660Smckusick 	}
23312660Smckusick }
23412660Smckusick 
235*12703Smckusick struct fileusage *
236*12703Smckusick lookup(uid)
237*12703Smckusick 	u_short uid;
23812660Smckusick {
239*12703Smckusick 	register struct fileusage *fup;
24012660Smckusick 
241*12703Smckusick 	for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next)
242*12703Smckusick 		if (fup->fu_uid == uid)
243*12703Smckusick 			return (fup);
244*12703Smckusick 	return ((struct fileusage *)0);
24512660Smckusick }
24612660Smckusick 
247*12703Smckusick struct fileusage *
248*12703Smckusick adduid(uid)
249*12703Smckusick 	u_short uid;
25012660Smckusick {
251*12703Smckusick 	struct fileusage *fup, **fhp;
25212660Smckusick 
253*12703Smckusick 	fup = lookup(uid);
254*12703Smckusick 	if (fup != 0)
255*12703Smckusick 		return (fup);
256*12703Smckusick 	fup = (struct fileusage *)calloc(1, sizeof(struct fileusage));
257*12703Smckusick 	if (fup == 0) {
258*12703Smckusick 		fprintf(stderr, "out of memory for fileusage structures\n");
259*12703Smckusick 		exit(1);
260*12703Smckusick 	}
261*12703Smckusick 	fhp = &fuhead[uid % FUHASH];
262*12703Smckusick 	fup->fu_next = *fhp;
263*12703Smckusick 	*fhp = fup;
264*12703Smckusick 	fup->fu_uid = uid;
265*12703Smckusick 	if (uid > highuid)
266*12703Smckusick 		highuid = uid;
267*12703Smckusick 	return (fup);
26812660Smckusick }
26912660Smckusick 
27012660Smckusick char *
271*12703Smckusick makerawname(name)
272*12703Smckusick 	char *name;
27312660Smckusick {
274*12703Smckusick 	register char *cp;
275*12703Smckusick 	char tmp, ch, *rindex();
276*12703Smckusick 	static char rawname[MAXPATHLEN];
27712660Smckusick 
278*12703Smckusick 	strcpy(rawname, name);
279*12703Smckusick 	cp = rindex(rawname, '/') + 1;
280*12703Smckusick 	if (cp == (char *)1 || *cp == 'r')
281*12703Smckusick 		return (name);
282*12703Smckusick 	for (ch = 'r'; *cp != '\0'; ) {
283*12703Smckusick 		tmp = *cp;
284*12703Smckusick 		*cp++ = ch;
285*12703Smckusick 		ch = tmp;
286*12703Smckusick 	}
287*12703Smckusick 	*cp++ = ch;
288*12703Smckusick 	*cp = '\0';
289*12703Smckusick 	return (rawname);
29012660Smckusick }
291