xref: /freebsd/usr.sbin/quot/quot.c (revision c433b438)
116c2ba93SPeter Wemm /*
216c2ba93SPeter Wemm  * Copyright (C) 1991, 1994 Wolfgang Solfrank.
316c2ba93SPeter Wemm  * Copyright (C) 1991, 1994 TooLs GmbH.
416c2ba93SPeter Wemm  * All rights reserved.
516c2ba93SPeter Wemm  *
616c2ba93SPeter Wemm  * Redistribution and use in source and binary forms, with or without
716c2ba93SPeter Wemm  * modification, are permitted provided that the following conditions
816c2ba93SPeter Wemm  * are met:
916c2ba93SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
1016c2ba93SPeter Wemm  *    notice, this list of conditions and the following disclaimer.
1116c2ba93SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
1216c2ba93SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
1316c2ba93SPeter Wemm  *    documentation and/or other materials provided with the distribution.
1416c2ba93SPeter Wemm  * 3. All advertising materials mentioning features or use of this software
1516c2ba93SPeter Wemm  *    must display the following acknowledgement:
1616c2ba93SPeter Wemm  *	This product includes software developed by TooLs GmbH.
1716c2ba93SPeter Wemm  * 4. The name of TooLs GmbH may not be used to endorse or promote products
1816c2ba93SPeter Wemm  *    derived from this software without specific prior written permission.
1916c2ba93SPeter Wemm  *
2016c2ba93SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
2116c2ba93SPeter Wemm  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2216c2ba93SPeter Wemm  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2316c2ba93SPeter Wemm  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2416c2ba93SPeter Wemm  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2516c2ba93SPeter Wemm  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2616c2ba93SPeter Wemm  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2716c2ba93SPeter Wemm  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2816c2ba93SPeter Wemm  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2916c2ba93SPeter Wemm  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3016c2ba93SPeter Wemm  */
3116c2ba93SPeter Wemm 
32b728350eSDavid E. O'Brien #include <sys/cdefs.h>
33b728350eSDavid E. O'Brien __FBSDID("$FreeBSD$");
3416c2ba93SPeter Wemm 
3516c2ba93SPeter Wemm #include <sys/param.h>
369f60cc9eSDag-Erling Smørgrav #include <sys/stdint.h>
3716c2ba93SPeter Wemm #include <sys/mount.h>
38386f1d1bSPoul-Henning Kamp #include <sys/disklabel.h>
3916c2ba93SPeter Wemm #include <sys/time.h>
401c85e6a3SKirk McKusick #include <ufs/ufs/dinode.h>
4116c2ba93SPeter Wemm #include <ufs/ffs/fs.h>
4216c2ba93SPeter Wemm 
436980f0ebSPhilippe Charnier #include <err.h>
446980f0ebSPhilippe Charnier #include <fcntl.h>
4581f1ec27SPaul Saab #include <fstab.h>
466980f0ebSPhilippe Charnier #include <errno.h>
471a37aa56SDavid E. O'Brien #include <paths.h>
486980f0ebSPhilippe Charnier #include <pwd.h>
4916c2ba93SPeter Wemm #include <stdio.h>
5016c2ba93SPeter Wemm #include <stdlib.h>
5116c2ba93SPeter Wemm #include <string.h>
526980f0ebSPhilippe Charnier #include <unistd.h>
5316c2ba93SPeter Wemm 
5416c2ba93SPeter Wemm /* some flags of what to do: */
5516c2ba93SPeter Wemm static char estimate;
5616c2ba93SPeter Wemm static char count;
5716c2ba93SPeter Wemm static char unused;
5857cdc152SMike Heffner static void (*func)(int, struct fs *, char *);
5916c2ba93SPeter Wemm static long blocksize;
6016c2ba93SPeter Wemm static char *header;
61bc6ba9aeSMike Barcroft static int headerlen;
6216c2ba93SPeter Wemm 
631c85e6a3SKirk McKusick static union dinode *get_inode(int, struct fs *, ino_t);
641c85e6a3SKirk McKusick static int	virtualblocks(struct fs *, union dinode *);
651c85e6a3SKirk McKusick static int	isfree(struct fs *, union dinode *);
6657cdc152SMike Heffner static void	inituser(void);
6757cdc152SMike Heffner static void	usrrehash(void);
6857cdc152SMike Heffner static struct user *user(uid_t);
6957cdc152SMike Heffner static int	cmpusers(const void *, const void *);
7057cdc152SMike Heffner static void	uses(uid_t, daddr_t, time_t);
7157cdc152SMike Heffner static void	initfsizes(void);
7257cdc152SMike Heffner static void	dofsizes(int, struct fs *, char *);
7357cdc152SMike Heffner static void	douser(int, struct fs *, char *);
7457cdc152SMike Heffner static void	donames(int, struct fs *, char *);
7557cdc152SMike Heffner static void	usage(void);
7657cdc152SMike Heffner static void	quot(char *, char *);
7757cdc152SMike Heffner 
7816c2ba93SPeter Wemm /*
7916c2ba93SPeter Wemm  * Original BSD quot doesn't round to number of frags/blocks,
8016c2ba93SPeter Wemm  * doesn't account for indirection blocks and gets it totally
8116c2ba93SPeter Wemm  * wrong if the	size is a multiple of the blocksize.
8216c2ba93SPeter Wemm  * The new code always counts the number of 512 byte blocks
8316c2ba93SPeter Wemm  * instead of the number of kilobytes and converts them	to
8416c2ba93SPeter Wemm  * kByte when done (on request).
859983067eSMatthew Dillon  *
869983067eSMatthew Dillon  * Due to the size of modern disks, we must cast intermediate
879983067eSMatthew Dillon  * values to 64 bits to prevent potential overflows.
8816c2ba93SPeter Wemm  */
8916c2ba93SPeter Wemm #ifdef	COMPAT
9016c2ba93SPeter Wemm #define	SIZE(n)	(n)
9116c2ba93SPeter Wemm #else
929983067eSMatthew Dillon #define	SIZE(n) ((int)(((quad_t)(n) * 512 + blocksize - 1)/blocksize))
9316c2ba93SPeter Wemm #endif
9416c2ba93SPeter Wemm 
9516c2ba93SPeter Wemm #define	INOCNT(fs)	((fs)->fs_ipg)
961c85e6a3SKirk McKusick #define	INOSZ(fs) \
971c85e6a3SKirk McKusick 	(((fs)->fs_magic == FS_UFS1_MAGIC ? sizeof(struct ufs1_dinode) : \
981c85e6a3SKirk McKusick 	sizeof(struct ufs2_dinode)) * INOCNT(fs))
9916c2ba93SPeter Wemm 
1001c85e6a3SKirk McKusick union dinode {
1011c85e6a3SKirk McKusick 	struct ufs1_dinode dp1;
1021c85e6a3SKirk McKusick 	struct ufs2_dinode dp2;
1031c85e6a3SKirk McKusick };
1041c85e6a3SKirk McKusick #define	DIP(fs, dp, field) \
1051c85e6a3SKirk McKusick 	(((fs)->fs_magic == FS_UFS1_MAGIC) ? \
1061c85e6a3SKirk McKusick 	(dp)->dp1.field : (dp)->dp2.field)
1071c85e6a3SKirk McKusick 
1081c85e6a3SKirk McKusick static union dinode *
1096980f0ebSPhilippe Charnier get_inode(fd,super,ino)
11057cdc152SMike Heffner 	int fd;
11116c2ba93SPeter Wemm 	struct fs *super;
11216c2ba93SPeter Wemm 	ino_t ino;
11316c2ba93SPeter Wemm {
1141c85e6a3SKirk McKusick 	static caddr_t ipbuf;
115bee3d34fSDavid Malone 	static struct cg *cgp;
11616c2ba93SPeter Wemm 	static ino_t last;
117bee3d34fSDavid Malone 	static int cg;
118bee3d34fSDavid Malone 	struct ufs2_dinode *di2;
11916c2ba93SPeter Wemm 
12016c2ba93SPeter Wemm 	if (fd < 0) {		/* flush cache */
1211c85e6a3SKirk McKusick 		if (ipbuf) {
1221c85e6a3SKirk McKusick 			free(ipbuf);
1231c85e6a3SKirk McKusick 			ipbuf = 0;
124c433b438SMaxim Konovalov 			if (super != NULL && super->fs_magic == FS_UFS2_MAGIC) {
125bee3d34fSDavid Malone 				free(cgp);
126bee3d34fSDavid Malone 				cgp = 0;
127bee3d34fSDavid Malone 			}
12816c2ba93SPeter Wemm 		}
12916c2ba93SPeter Wemm 		return 0;
13016c2ba93SPeter Wemm 	}
13116c2ba93SPeter Wemm 
1321c85e6a3SKirk McKusick 	if (!ipbuf || ino < last || ino >= last + INOCNT(super)) {
133bee3d34fSDavid Malone 		if (super->fs_magic == FS_UFS2_MAGIC &&
134bee3d34fSDavid Malone 		    (!cgp || cg != ino_to_cg(super, ino))) {
135bee3d34fSDavid Malone 			cg = ino_to_cg(super, ino);
136bee3d34fSDavid Malone 			if (!cgp && !(cgp = malloc(super->fs_cgsize)))
137bee3d34fSDavid Malone 				errx(1, "allocate cg");
138bee3d34fSDavid Malone 			if (lseek(fd, (off_t)cgtod(super, cg) << super->fs_fshift, 0) < 0)
139bee3d34fSDavid Malone 				err(1, "lseek cg");
140bee3d34fSDavid Malone 			if (read(fd, cgp, super->fs_cgsize) != super->fs_cgsize)
141bee3d34fSDavid Malone 				err(1, "read cg");
142bee3d34fSDavid Malone 			if (!cg_chkmagic(cgp))
143bee3d34fSDavid Malone 				errx(1, "cg has bad magic");
144bee3d34fSDavid Malone 		}
1451c85e6a3SKirk McKusick 		if (!ipbuf
1461c85e6a3SKirk McKusick 		    && !(ipbuf = malloc(INOSZ(super))))
1476980f0ebSPhilippe Charnier 			errx(1, "allocate inodes");
14816c2ba93SPeter Wemm 		last = (ino / INOCNT(super)) * INOCNT(super);
149c9d12677SJordan K. Hubbard 		if (lseek(fd, (off_t)ino_to_fsba(super, last) << super->fs_fshift, 0) < (off_t)0
1501c85e6a3SKirk McKusick 		    || read(fd, ipbuf, INOSZ(super)) != (ssize_t)INOSZ(super))
1516980f0ebSPhilippe Charnier 			err(1, "read inodes");
15216c2ba93SPeter Wemm 	}
15316c2ba93SPeter Wemm 
1541c85e6a3SKirk McKusick 	if (super->fs_magic == FS_UFS1_MAGIC)
1551c85e6a3SKirk McKusick 		return ((union dinode *)
1561c85e6a3SKirk McKusick 		    &((struct ufs1_dinode *)ipbuf)[ino % INOCNT(super)]);
157bee3d34fSDavid Malone 	di2 = &((struct ufs2_dinode *)ipbuf)[ino % INOCNT(super)];
158bee3d34fSDavid Malone 	/* If the inode is unused, it might be unallocated too, so zero it. */
159bee3d34fSDavid Malone 	if (isclr(cg_inosused(cgp), ino % super->fs_ipg))
160bee3d34fSDavid Malone 		bzero(di2, sizeof (*di2));
161bee3d34fSDavid Malone 	return ((union dinode *)di2);
16216c2ba93SPeter Wemm }
16316c2ba93SPeter Wemm 
16416c2ba93SPeter Wemm #ifdef	COMPAT
1651c85e6a3SKirk McKusick #define	actualblocks(fs, dp)	(DIP(fs, dp, di_blocks) / 2)
16616c2ba93SPeter Wemm #else
1671c85e6a3SKirk McKusick #define	actualblocks(fs, dp)	DIP(fs, dp, di_blocks)
16816c2ba93SPeter Wemm #endif
16916c2ba93SPeter Wemm 
1701c85e6a3SKirk McKusick static int virtualblocks(super, dp)
17116c2ba93SPeter Wemm 	struct fs *super;
1721c85e6a3SKirk McKusick 	union dinode *dp;
17316c2ba93SPeter Wemm {
17416c2ba93SPeter Wemm 	register off_t nblk, sz;
17516c2ba93SPeter Wemm 
1761c85e6a3SKirk McKusick 	sz = DIP(super, dp, di_size);
17716c2ba93SPeter Wemm #ifdef	COMPAT
17816c2ba93SPeter Wemm 	if (lblkno(super,sz) >= NDADDR) {
17916c2ba93SPeter Wemm 		nblk = blkroundup(super,sz);
18016c2ba93SPeter Wemm 		if (sz == nblk)
18116c2ba93SPeter Wemm 			nblk += super->fs_bsize;
18216c2ba93SPeter Wemm 	}
18316c2ba93SPeter Wemm 
18416c2ba93SPeter Wemm 	return sz / 1024;
18516c2ba93SPeter Wemm 
18616c2ba93SPeter Wemm #else	/* COMPAT */
18716c2ba93SPeter Wemm 
18816c2ba93SPeter Wemm 	if (lblkno(super,sz) >= NDADDR) {
18916c2ba93SPeter Wemm 		nblk = blkroundup(super,sz);
19016c2ba93SPeter Wemm 		sz = lblkno(super,nblk);
19116c2ba93SPeter Wemm 		sz = (sz - NDADDR + NINDIR(super) - 1) / NINDIR(super);
19216c2ba93SPeter Wemm 		while (sz > 0) {
19316c2ba93SPeter Wemm 			nblk += sz * super->fs_bsize;
19416c2ba93SPeter Wemm 			/* sz - 1 rounded up */
19516c2ba93SPeter Wemm 			sz = (sz - 1 + NINDIR(super) - 1) / NINDIR(super);
19616c2ba93SPeter Wemm 		}
19716c2ba93SPeter Wemm 	} else
19816c2ba93SPeter Wemm 		nblk = fragroundup(super,sz);
19916c2ba93SPeter Wemm 
20016c2ba93SPeter Wemm 	return nblk / 512;
20116c2ba93SPeter Wemm #endif	/* COMPAT */
20216c2ba93SPeter Wemm }
20316c2ba93SPeter Wemm 
2046980f0ebSPhilippe Charnier static int
2051c85e6a3SKirk McKusick isfree(super, dp)
2061c85e6a3SKirk McKusick 	struct fs *super;
2071c85e6a3SKirk McKusick 	union dinode *dp;
20816c2ba93SPeter Wemm {
20916c2ba93SPeter Wemm #ifdef	COMPAT
2101c85e6a3SKirk McKusick 	return (DIP(super, dp, di_mode) & IFMT) == 0;
21116c2ba93SPeter Wemm #else	/* COMPAT */
21216c2ba93SPeter Wemm 
2131c85e6a3SKirk McKusick 	switch (DIP(super, dp, di_mode) & IFMT) {
21416c2ba93SPeter Wemm 	case IFIFO:
21516c2ba93SPeter Wemm 	case IFLNK:		/* should check FASTSYMLINK? */
21616c2ba93SPeter Wemm 	case IFDIR:
21716c2ba93SPeter Wemm 	case IFREG:
21816c2ba93SPeter Wemm 		return 0;
219bee3d34fSDavid Malone 	case IFCHR:
220bee3d34fSDavid Malone 	case IFBLK:
221bee3d34fSDavid Malone 	case IFSOCK:
222bee3d34fSDavid Malone 	case IFWHT:
223bee3d34fSDavid Malone 	case 0:
22416c2ba93SPeter Wemm 		return 1;
225bee3d34fSDavid Malone 	default:
226bee3d34fSDavid Malone 		errx(1, "unknown IFMT 0%o", DIP(super, dp, di_mode) & IFMT);
22716c2ba93SPeter Wemm 	}
22816c2ba93SPeter Wemm #endif
22916c2ba93SPeter Wemm }
23016c2ba93SPeter Wemm 
23116c2ba93SPeter Wemm static struct user {
23216c2ba93SPeter Wemm 	uid_t uid;
23316c2ba93SPeter Wemm 	char *name;
23416c2ba93SPeter Wemm 	daddr_t space;
23516c2ba93SPeter Wemm 	long count;
23616c2ba93SPeter Wemm 	daddr_t spc30;
23716c2ba93SPeter Wemm 	daddr_t spc60;
23816c2ba93SPeter Wemm 	daddr_t spc90;
23916c2ba93SPeter Wemm } *users;
24016c2ba93SPeter Wemm static int nusers;
24116c2ba93SPeter Wemm 
2426980f0ebSPhilippe Charnier static void
2436980f0ebSPhilippe Charnier inituser()
24416c2ba93SPeter Wemm {
24557cdc152SMike Heffner 	register int i;
24616c2ba93SPeter Wemm 	register struct user *usr;
24716c2ba93SPeter Wemm 
24816c2ba93SPeter Wemm 	if (!nusers) {
24916c2ba93SPeter Wemm 		nusers = 8;
25016c2ba93SPeter Wemm 		if (!(users =
2516980f0ebSPhilippe Charnier 		    (struct user *)calloc(nusers,sizeof(struct user))))
2526980f0ebSPhilippe Charnier 			errx(1, "allocate users");
25316c2ba93SPeter Wemm 	} else {
25416c2ba93SPeter Wemm 		for (usr = users, i = nusers; --i >= 0; usr++) {
25516c2ba93SPeter Wemm 			usr->space = usr->spc30 = usr->spc60 = usr->spc90 = 0;
25616c2ba93SPeter Wemm 			usr->count = 0;
25716c2ba93SPeter Wemm 		}
25816c2ba93SPeter Wemm 	}
25916c2ba93SPeter Wemm }
26016c2ba93SPeter Wemm 
2616980f0ebSPhilippe Charnier static void
2626980f0ebSPhilippe Charnier usrrehash()
26316c2ba93SPeter Wemm {
26457cdc152SMike Heffner 	register int i;
26516c2ba93SPeter Wemm 	register struct user *usr, *usrn;
26616c2ba93SPeter Wemm 	struct user *svusr;
26716c2ba93SPeter Wemm 
26816c2ba93SPeter Wemm 	svusr = users;
26916c2ba93SPeter Wemm 	nusers <<= 1;
2706980f0ebSPhilippe Charnier 	if (!(users = (struct user *)calloc(nusers,sizeof(struct user))))
2716980f0ebSPhilippe Charnier 		errx(1, "allocate users");
27216c2ba93SPeter Wemm 	for (usr = svusr, i = nusers >> 1; --i >= 0; usr++) {
27316c2ba93SPeter Wemm 		for (usrn = users + (usr->uid&(nusers - 1)); usrn->name;
27416c2ba93SPeter Wemm 		    usrn--) {
27516c2ba93SPeter Wemm 			if (usrn <= users)
27616c2ba93SPeter Wemm 				usrn = users + nusers;
27716c2ba93SPeter Wemm 		}
27816c2ba93SPeter Wemm 		*usrn = *usr;
27916c2ba93SPeter Wemm 	}
28016c2ba93SPeter Wemm }
28116c2ba93SPeter Wemm 
2826980f0ebSPhilippe Charnier static struct user *
2836980f0ebSPhilippe Charnier user(uid)
28416c2ba93SPeter Wemm 	uid_t uid;
28516c2ba93SPeter Wemm {
28616c2ba93SPeter Wemm 	register struct user *usr;
28757cdc152SMike Heffner 	register int i;
28816c2ba93SPeter Wemm 	struct passwd *pwd;
28916c2ba93SPeter Wemm 
29016c2ba93SPeter Wemm 	while (1) {
29116c2ba93SPeter Wemm 		for (usr = users + (uid&(nusers - 1)), i = nusers; --i >= 0;
29216c2ba93SPeter Wemm 		    usr--) {
29316c2ba93SPeter Wemm 			if (!usr->name) {
29416c2ba93SPeter Wemm 				usr->uid = uid;
29516c2ba93SPeter Wemm 
29616c2ba93SPeter Wemm 				if (!(pwd = getpwuid(uid))) {
2976980f0ebSPhilippe Charnier 					if ((usr->name = (char *)malloc(7)))
29816c2ba93SPeter Wemm 						sprintf(usr->name,"#%d",uid);
29916c2ba93SPeter Wemm 				} else {
3006980f0ebSPhilippe Charnier 					if ((usr->name = (char *)
3016980f0ebSPhilippe Charnier 					    malloc(strlen(pwd->pw_name) + 1)))
30216c2ba93SPeter Wemm 						strcpy(usr->name,pwd->pw_name);
30316c2ba93SPeter Wemm 				}
3046980f0ebSPhilippe Charnier 				if (!usr->name)
3056980f0ebSPhilippe Charnier 					errx(1, "allocate users");
30616c2ba93SPeter Wemm 
30716c2ba93SPeter Wemm 				return usr;
30816c2ba93SPeter Wemm 
30916c2ba93SPeter Wemm 			} else if (usr->uid == uid)
31016c2ba93SPeter Wemm 				return usr;
31116c2ba93SPeter Wemm 
31216c2ba93SPeter Wemm 			if (usr <= users)
31316c2ba93SPeter Wemm 				usr = users + nusers;
31416c2ba93SPeter Wemm 		}
31516c2ba93SPeter Wemm 		usrrehash();
31616c2ba93SPeter Wemm 	}
31716c2ba93SPeter Wemm }
31816c2ba93SPeter Wemm 
3196980f0ebSPhilippe Charnier static int
32057cdc152SMike Heffner cmpusers(v1,v2)
32157cdc152SMike Heffner 	const void *v1, *v2;
32216c2ba93SPeter Wemm {
32357cdc152SMike Heffner 	const struct user *u1, *u2;
32457cdc152SMike Heffner 	u1 = (const struct user *)v1;
32557cdc152SMike Heffner 	u2 = (const struct user *)v2;
32657cdc152SMike Heffner 
32716c2ba93SPeter Wemm 	return u2->space - u1->space;
32816c2ba93SPeter Wemm }
32916c2ba93SPeter Wemm 
33016c2ba93SPeter Wemm #define	sortusers(users)	(qsort((users),nusers,sizeof(struct user), \
33116c2ba93SPeter Wemm 				    cmpusers))
33216c2ba93SPeter Wemm 
3336980f0ebSPhilippe Charnier static void
3346980f0ebSPhilippe Charnier uses(uid,blks,act)
33516c2ba93SPeter Wemm 	uid_t uid;
33616c2ba93SPeter Wemm 	daddr_t blks;
33716c2ba93SPeter Wemm 	time_t act;
33816c2ba93SPeter Wemm {
33916c2ba93SPeter Wemm 	static time_t today;
34016c2ba93SPeter Wemm 	register struct user *usr;
34116c2ba93SPeter Wemm 
34216c2ba93SPeter Wemm 	if (!today)
34316c2ba93SPeter Wemm 		time(&today);
34416c2ba93SPeter Wemm 
34516c2ba93SPeter Wemm 	usr = user(uid);
34616c2ba93SPeter Wemm 	usr->count++;
34716c2ba93SPeter Wemm 	usr->space += blks;
34816c2ba93SPeter Wemm 
34916c2ba93SPeter Wemm 	if (today - act > 90L * 24L * 60L * 60L)
35016c2ba93SPeter Wemm 		usr->spc90 += blks;
35116c2ba93SPeter Wemm 	if (today - act > 60L * 24L * 60L * 60L)
35216c2ba93SPeter Wemm 		usr->spc60 += blks;
35316c2ba93SPeter Wemm 	if (today - act > 30L * 24L * 60L * 60L)
35416c2ba93SPeter Wemm 		usr->spc30 += blks;
35516c2ba93SPeter Wemm }
35616c2ba93SPeter Wemm 
35716c2ba93SPeter Wemm #ifdef	COMPAT
35816c2ba93SPeter Wemm #define	FSZCNT	500
35916c2ba93SPeter Wemm #else
36016c2ba93SPeter Wemm #define	FSZCNT	512
36116c2ba93SPeter Wemm #endif
36216c2ba93SPeter Wemm struct fsizes {
36316c2ba93SPeter Wemm 	struct fsizes *fsz_next;
36416c2ba93SPeter Wemm 	daddr_t fsz_first, fsz_last;
36516c2ba93SPeter Wemm 	ino_t fsz_count[FSZCNT];
36616c2ba93SPeter Wemm 	daddr_t fsz_sz[FSZCNT];
36716c2ba93SPeter Wemm } *fsizes;
36816c2ba93SPeter Wemm 
3696980f0ebSPhilippe Charnier static void
3706980f0ebSPhilippe Charnier initfsizes()
37116c2ba93SPeter Wemm {
37216c2ba93SPeter Wemm 	register struct fsizes *fp;
37357cdc152SMike Heffner 	register int i;
37416c2ba93SPeter Wemm 
37516c2ba93SPeter Wemm 	for (fp = fsizes; fp; fp = fp->fsz_next) {
37616c2ba93SPeter Wemm 		for (i = FSZCNT; --i >= 0;) {
37716c2ba93SPeter Wemm 			fp->fsz_count[i] = 0;
37816c2ba93SPeter Wemm 			fp->fsz_sz[i] = 0;
37916c2ba93SPeter Wemm 		}
38016c2ba93SPeter Wemm 	}
38116c2ba93SPeter Wemm }
38216c2ba93SPeter Wemm 
3836980f0ebSPhilippe Charnier static void
3846980f0ebSPhilippe Charnier dofsizes(fd, super, name)
38557cdc152SMike Heffner 	int fd;
38616c2ba93SPeter Wemm 	struct fs *super;
38716c2ba93SPeter Wemm 	char *name;
38816c2ba93SPeter Wemm {
38916c2ba93SPeter Wemm 	ino_t inode, maxino;
3901c85e6a3SKirk McKusick 	union dinode *dp;
39116c2ba93SPeter Wemm 	daddr_t sz, ksz;
39216c2ba93SPeter Wemm 	struct fsizes *fp, **fsp;
39357cdc152SMike Heffner 	register int i;
39416c2ba93SPeter Wemm 
39516c2ba93SPeter Wemm 	maxino = super->fs_ncg * super->fs_ipg - 1;
39616c2ba93SPeter Wemm #ifdef	COMPAT
3976980f0ebSPhilippe Charnier 	if (!(fsizes = (struct fsizes *)malloc(sizeof(struct fsizes))))
398652b7200SPhilippe Charnier 		errx(1, "allocate fsize structure");
39916c2ba93SPeter Wemm #endif	/* COMPAT */
40016c2ba93SPeter Wemm 	for (inode = 0; inode < maxino; inode++) {
40116c2ba93SPeter Wemm 		errno = 0;
4021c85e6a3SKirk McKusick 		if ((dp = get_inode(fd,super,inode))
40316c2ba93SPeter Wemm #ifdef	COMPAT
4041c85e6a3SKirk McKusick 		    && ((DIP(super, dp, di_mode) & IFMT) == IFREG
4051c85e6a3SKirk McKusick 			|| (DIP(super, dp, di_mode) & IFMT) == IFDIR)
40616c2ba93SPeter Wemm #else	/* COMPAT */
4071c85e6a3SKirk McKusick 		    && !isfree(super, dp)
40816c2ba93SPeter Wemm #endif	/* COMPAT */
40916c2ba93SPeter Wemm 		    ) {
4101c85e6a3SKirk McKusick 			sz = estimate ? virtualblocks(super, dp) :
4111c85e6a3SKirk McKusick 			    actualblocks(super, dp);
41216c2ba93SPeter Wemm #ifdef	COMPAT
41316c2ba93SPeter Wemm 			if (sz >= FSZCNT) {
41416c2ba93SPeter Wemm 				fsizes->fsz_count[FSZCNT-1]++;
41516c2ba93SPeter Wemm 				fsizes->fsz_sz[FSZCNT-1] += sz;
41616c2ba93SPeter Wemm 			} else {
41716c2ba93SPeter Wemm 				fsizes->fsz_count[sz]++;
41816c2ba93SPeter Wemm 				fsizes->fsz_sz[sz] += sz;
41916c2ba93SPeter Wemm 			}
42016c2ba93SPeter Wemm #else	/* COMPAT */
42116c2ba93SPeter Wemm 			ksz = SIZE(sz);
4226980f0ebSPhilippe Charnier 			for (fsp = &fsizes; (fp = *fsp); fsp = &fp->fsz_next) {
42316c2ba93SPeter Wemm 				if (ksz < fp->fsz_last)
42416c2ba93SPeter Wemm 					break;
42516c2ba93SPeter Wemm 			}
42616c2ba93SPeter Wemm 			if (!fp || ksz < fp->fsz_first) {
42716c2ba93SPeter Wemm 				if (!(fp = (struct fsizes *)
4286980f0ebSPhilippe Charnier 				    malloc(sizeof(struct fsizes))))
429652b7200SPhilippe Charnier 					errx(1, "allocate fsize structure");
43016c2ba93SPeter Wemm 				fp->fsz_next = *fsp;
43116c2ba93SPeter Wemm 				*fsp = fp;
43216c2ba93SPeter Wemm 				fp->fsz_first = (ksz / FSZCNT) * FSZCNT;
43316c2ba93SPeter Wemm 				fp->fsz_last = fp->fsz_first + FSZCNT;
43416c2ba93SPeter Wemm 				for (i = FSZCNT; --i >= 0;) {
43516c2ba93SPeter Wemm 					fp->fsz_count[i] = 0;
43616c2ba93SPeter Wemm 					fp->fsz_sz[i] = 0;
43716c2ba93SPeter Wemm 				}
43816c2ba93SPeter Wemm 			}
43916c2ba93SPeter Wemm 			fp->fsz_count[ksz % FSZCNT]++;
44016c2ba93SPeter Wemm 			fp->fsz_sz[ksz % FSZCNT] += sz;
44116c2ba93SPeter Wemm #endif	/* COMPAT */
44216c2ba93SPeter Wemm 		} else if (errno) {
4436980f0ebSPhilippe Charnier 			err(1, "%s", name);
44416c2ba93SPeter Wemm 		}
44516c2ba93SPeter Wemm 	}
44616c2ba93SPeter Wemm 	sz = 0;
44716c2ba93SPeter Wemm 	for (fp = fsizes; fp; fp = fp->fsz_next) {
44816c2ba93SPeter Wemm 		for (i = 0; i < FSZCNT; i++) {
44916c2ba93SPeter Wemm 			if (fp->fsz_count[i])
4509f60cc9eSDag-Erling Smørgrav 				printf("%jd\t%jd\t%d\n",
4519f60cc9eSDag-Erling Smørgrav 				    (intmax_t)(fp->fsz_first + i),
4529f60cc9eSDag-Erling Smørgrav 				    (intmax_t)fp->fsz_count[i],
45316c2ba93SPeter Wemm 				    SIZE(sz += fp->fsz_sz[i]));
45416c2ba93SPeter Wemm 		}
45516c2ba93SPeter Wemm 	}
45616c2ba93SPeter Wemm }
45716c2ba93SPeter Wemm 
4586980f0ebSPhilippe Charnier static void
4596980f0ebSPhilippe Charnier douser(fd, super, name)
46057cdc152SMike Heffner 	int fd;
46116c2ba93SPeter Wemm 	struct fs *super;
46216c2ba93SPeter Wemm 	char *name;
46316c2ba93SPeter Wemm {
46416c2ba93SPeter Wemm 	ino_t inode, maxino;
46516c2ba93SPeter Wemm 	struct user *usr, *usrs;
4661c85e6a3SKirk McKusick 	union dinode *dp;
46757cdc152SMike Heffner 	register int n;
46816c2ba93SPeter Wemm 
46916c2ba93SPeter Wemm 	maxino = super->fs_ncg * super->fs_ipg - 1;
47016c2ba93SPeter Wemm 	for (inode = 0; inode < maxino; inode++) {
47116c2ba93SPeter Wemm 		errno = 0;
4721c85e6a3SKirk McKusick 		if ((dp = get_inode(fd,super,inode))
4731c85e6a3SKirk McKusick 		    && !isfree(super, dp))
4741c85e6a3SKirk McKusick 			uses(DIP(super, dp, di_uid),
4751c85e6a3SKirk McKusick 			    estimate ? virtualblocks(super, dp) :
4761c85e6a3SKirk McKusick 				actualblocks(super, dp),
4771c85e6a3SKirk McKusick 			    DIP(super, dp, di_atime));
47816c2ba93SPeter Wemm 		else if (errno) {
4796980f0ebSPhilippe Charnier 			err(1, "%s", name);
48016c2ba93SPeter Wemm 		}
48116c2ba93SPeter Wemm 	}
4826980f0ebSPhilippe Charnier 	if (!(usrs = (struct user *)malloc(nusers * sizeof(struct user))))
4836980f0ebSPhilippe Charnier 		errx(1, "allocate users");
48416c2ba93SPeter Wemm 	bcopy(users,usrs,nusers * sizeof(struct user));
48516c2ba93SPeter Wemm 	sortusers(usrs);
48616c2ba93SPeter Wemm 	for (usr = usrs, n = nusers; --n >= 0 && usr->count; usr++) {
48716c2ba93SPeter Wemm 		printf("%5d",SIZE(usr->space));
48816c2ba93SPeter Wemm 		if (count)
48957cdc152SMike Heffner 			printf("\t%5ld",usr->count);
49016c2ba93SPeter Wemm 		printf("\t%-8s",usr->name);
49116c2ba93SPeter Wemm 		if (unused)
49216c2ba93SPeter Wemm 			printf("\t%5d\t%5d\t%5d",
49316c2ba93SPeter Wemm 			       SIZE(usr->spc30),
49416c2ba93SPeter Wemm 			       SIZE(usr->spc60),
49516c2ba93SPeter Wemm 			       SIZE(usr->spc90));
49616c2ba93SPeter Wemm 		printf("\n");
49716c2ba93SPeter Wemm 	}
49816c2ba93SPeter Wemm 	free(usrs);
49916c2ba93SPeter Wemm }
50016c2ba93SPeter Wemm 
5016980f0ebSPhilippe Charnier static void
5026980f0ebSPhilippe Charnier donames(fd, super, name)
50357cdc152SMike Heffner 	int fd;
50416c2ba93SPeter Wemm 	struct fs *super;
50516c2ba93SPeter Wemm 	char *name;
50616c2ba93SPeter Wemm {
50716c2ba93SPeter Wemm 	int c;
50818b51f79SStefan Farfeleder 	ino_t inode;
50916c2ba93SPeter Wemm 	ino_t maxino;
5101c85e6a3SKirk McKusick 	union dinode *dp;
51116c2ba93SPeter Wemm 
51216c2ba93SPeter Wemm 	maxino = super->fs_ncg * super->fs_ipg - 1;
51316c2ba93SPeter Wemm 	/* first skip the name of the filesystem */
51416c2ba93SPeter Wemm 	while ((c = getchar()) != EOF && (c < '0' || c > '9'))
51516c2ba93SPeter Wemm 		while ((c = getchar()) != EOF && c != '\n');
51616c2ba93SPeter Wemm 	ungetc(c,stdin);
51757cdc152SMike Heffner 	while (scanf("%u",&inode) == 1) {
51857cdc152SMike Heffner 		if (inode > maxino) {
5196980f0ebSPhilippe Charnier 			warnx("illegal inode %d",inode);
52016c2ba93SPeter Wemm 			return;
52116c2ba93SPeter Wemm 		}
52216c2ba93SPeter Wemm 		errno = 0;
5231c85e6a3SKirk McKusick 		if ((dp = get_inode(fd,super,inode))
5241c85e6a3SKirk McKusick 		    && !isfree(super, dp)) {
5251c85e6a3SKirk McKusick 			printf("%s\t",user(DIP(super, dp, di_uid))->name);
52616c2ba93SPeter Wemm 			/* now skip whitespace */
52716c2ba93SPeter Wemm 			while ((c = getchar()) == ' ' || c == '\t');
52816c2ba93SPeter Wemm 			/* and print out the remainder of the input line */
52916c2ba93SPeter Wemm 			while (c != EOF && c != '\n') {
53016c2ba93SPeter Wemm 				putchar(c);
53116c2ba93SPeter Wemm 				c = getchar();
53216c2ba93SPeter Wemm 			}
53316c2ba93SPeter Wemm 			putchar('\n');
53416c2ba93SPeter Wemm 		} else {
53516c2ba93SPeter Wemm 			if (errno) {
5366980f0ebSPhilippe Charnier 				err(1, "%s", name);
53716c2ba93SPeter Wemm 			}
53816c2ba93SPeter Wemm 			/* skip this line */
53916c2ba93SPeter Wemm 			while ((c = getchar()) != EOF && c != '\n');
54016c2ba93SPeter Wemm 		}
54116c2ba93SPeter Wemm 		if (c == EOF)
54216c2ba93SPeter Wemm 			break;
54316c2ba93SPeter Wemm 	}
54416c2ba93SPeter Wemm }
54516c2ba93SPeter Wemm 
5466980f0ebSPhilippe Charnier static void
5476980f0ebSPhilippe Charnier usage()
54816c2ba93SPeter Wemm {
54916c2ba93SPeter Wemm #ifdef	COMPAT
5506980f0ebSPhilippe Charnier 	fprintf(stderr,"usage: quot [-nfcvha] [filesystem ...]\n");
55116c2ba93SPeter Wemm #else	/* COMPAT */
5526980f0ebSPhilippe Charnier 	fprintf(stderr,"usage: quot [-acfhknv] [filesystem ...]\n");
55316c2ba93SPeter Wemm #endif	/* COMPAT */
55416c2ba93SPeter Wemm 	exit(1);
55516c2ba93SPeter Wemm }
55616c2ba93SPeter Wemm 
5571c85e6a3SKirk McKusick /*
5581c85e6a3SKirk McKusick  * Possible superblock locations ordered from most to least likely.
5591c85e6a3SKirk McKusick  */
5601c85e6a3SKirk McKusick static int sblock_try[] = SBLOCKSEARCH;
5611c85e6a3SKirk McKusick static char superblock[SBLOCKSIZE];
56216c2ba93SPeter Wemm 
5636980f0ebSPhilippe Charnier void
56416c2ba93SPeter Wemm quot(name,mp)
56516c2ba93SPeter Wemm 	char *name, *mp;
56616c2ba93SPeter Wemm {
5671c85e6a3SKirk McKusick 	int i, fd;
5681c85e6a3SKirk McKusick 	struct fs *fs;
56916c2ba93SPeter Wemm 
57057cdc152SMike Heffner 	get_inode(-1, NULL, 0);		/* flush cache */
57116c2ba93SPeter Wemm 	inituser();
57216c2ba93SPeter Wemm 	initfsizes();
5731c85e6a3SKirk McKusick 	if ((fd = open(name,0)) < 0) {
5746980f0ebSPhilippe Charnier 		warn("%s", name);
57516c2ba93SPeter Wemm 		close(fd);
57616c2ba93SPeter Wemm 		return;
57716c2ba93SPeter Wemm 	}
5781c85e6a3SKirk McKusick 	for (i = 0; sblock_try[i] != -1; i++) {
5791c85e6a3SKirk McKusick 		if (lseek(fd, sblock_try[i], 0) != sblock_try[i]) {
5801c85e6a3SKirk McKusick 			close(fd);
5811c85e6a3SKirk McKusick 			return;
5821c85e6a3SKirk McKusick 		}
5831c85e6a3SKirk McKusick 		if (read(fd, superblock, SBLOCKSIZE) != SBLOCKSIZE) {
5841c85e6a3SKirk McKusick 			close(fd);
5851c85e6a3SKirk McKusick 			return;
5861c85e6a3SKirk McKusick 		}
5871c85e6a3SKirk McKusick 		fs = (struct fs *)superblock;
5881c85e6a3SKirk McKusick 		if ((fs->fs_magic == FS_UFS1_MAGIC ||
5891c85e6a3SKirk McKusick 		     (fs->fs_magic == FS_UFS2_MAGIC &&
5906c45bec6STim J. Robbins 		      fs->fs_sblockloc == sblock_try[i])) &&
5911c85e6a3SKirk McKusick 		    fs->fs_bsize <= MAXBSIZE &&
5921c85e6a3SKirk McKusick 		    fs->fs_bsize >= sizeof(struct fs))
5931c85e6a3SKirk McKusick 			break;
5941c85e6a3SKirk McKusick 	}
5951c85e6a3SKirk McKusick 	if (sblock_try[i] == -1) {
5966980f0ebSPhilippe Charnier 		warnx("%s: not a BSD filesystem",name);
59716c2ba93SPeter Wemm 		close(fd);
59816c2ba93SPeter Wemm 		return;
59916c2ba93SPeter Wemm 	}
60016c2ba93SPeter Wemm 	printf("%s:",name);
60116c2ba93SPeter Wemm 	if (mp)
60216c2ba93SPeter Wemm 		printf(" (%s)",mp);
60316c2ba93SPeter Wemm 	putchar('\n');
6041c85e6a3SKirk McKusick 	(*func)(fd, fs, name);
60516c2ba93SPeter Wemm 	close(fd);
60616c2ba93SPeter Wemm }
60716c2ba93SPeter Wemm 
6086980f0ebSPhilippe Charnier int
6096980f0ebSPhilippe Charnier main(argc,argv)
61057cdc152SMike Heffner 	int argc;
61116c2ba93SPeter Wemm 	char **argv;
61216c2ba93SPeter Wemm {
61316c2ba93SPeter Wemm 	char all = 0;
61416c2ba93SPeter Wemm 	struct statfs *mp;
61581f1ec27SPaul Saab 	struct fstab *fs;
61616c2ba93SPeter Wemm 	char dev[MNAMELEN + 1];
61716c2ba93SPeter Wemm 	char *nm;
61816c2ba93SPeter Wemm 	int cnt;
61916c2ba93SPeter Wemm 
62016c2ba93SPeter Wemm 	func = douser;
62116c2ba93SPeter Wemm #ifndef	COMPAT
62216c2ba93SPeter Wemm 	header = getbsize(&headerlen,&blocksize);
62316c2ba93SPeter Wemm #endif
62416c2ba93SPeter Wemm 	while (--argc > 0 && **++argv == '-') {
62516c2ba93SPeter Wemm 		while (*++*argv) {
62616c2ba93SPeter Wemm 			switch (**argv) {
62716c2ba93SPeter Wemm 			case 'n':
62816c2ba93SPeter Wemm 				func = donames;
62916c2ba93SPeter Wemm 				break;
63016c2ba93SPeter Wemm 			case 'c':
63116c2ba93SPeter Wemm 				func = dofsizes;
63216c2ba93SPeter Wemm 				break;
63316c2ba93SPeter Wemm 			case 'a':
63416c2ba93SPeter Wemm 				all = 1;
63516c2ba93SPeter Wemm 				break;
63616c2ba93SPeter Wemm 			case 'f':
63716c2ba93SPeter Wemm 				count = 1;
63816c2ba93SPeter Wemm 				break;
63916c2ba93SPeter Wemm 			case 'h':
64016c2ba93SPeter Wemm 				estimate = 1;
64116c2ba93SPeter Wemm 				break;
64216c2ba93SPeter Wemm #ifndef	COMPAT
64316c2ba93SPeter Wemm 			case 'k':
64416c2ba93SPeter Wemm 				blocksize = 1024;
64516c2ba93SPeter Wemm 				break;
64616c2ba93SPeter Wemm #endif	/* COMPAT */
64716c2ba93SPeter Wemm 			case 'v':
64816c2ba93SPeter Wemm 				unused = 1;
64916c2ba93SPeter Wemm 				break;
65016c2ba93SPeter Wemm 			default:
65116c2ba93SPeter Wemm 				usage();
65216c2ba93SPeter Wemm 			}
65316c2ba93SPeter Wemm 		}
65416c2ba93SPeter Wemm 	}
65516c2ba93SPeter Wemm 	if (all) {
65616c2ba93SPeter Wemm 		cnt = getmntinfo(&mp,MNT_NOWAIT);
65716c2ba93SPeter Wemm 		for (; --cnt >= 0; mp++) {
658b49d184bSBruce Evans 			if (!strncmp(mp->f_fstypename, "ufs", MFSNAMELEN)) {
6596980f0ebSPhilippe Charnier 				if ((nm = strrchr(mp->f_mntfromname,'/'))) {
6601a37aa56SDavid E. O'Brien 					sprintf(dev,"%s%s",_PATH_DEV,nm + 1);
66116c2ba93SPeter Wemm 					nm = dev;
66216c2ba93SPeter Wemm 				} else
66316c2ba93SPeter Wemm 					nm = mp->f_mntfromname;
66416c2ba93SPeter Wemm 				quot(nm,mp->f_mntonname);
66516c2ba93SPeter Wemm 			}
66616c2ba93SPeter Wemm 		}
66716c2ba93SPeter Wemm 	}
66881f1ec27SPaul Saab 	while (--argc >= 0) {
66981f1ec27SPaul Saab 		if ((fs = getfsfile(*argv)) != NULL)
67081f1ec27SPaul Saab 			quot(fs->fs_spec, 0);
67181f1ec27SPaul Saab 		else
67281f1ec27SPaul Saab 			quot(*argv,0);
67381f1ec27SPaul Saab 		argv++;
67481f1ec27SPaul Saab 	}
67516c2ba93SPeter Wemm 	return 0;
67616c2ba93SPeter Wemm }
677