112032Speter/*
212032Speter * Copyright (C) 1991, 1994 Wolfgang Solfrank.
312032Speter * Copyright (C) 1991, 1994 TooLs GmbH.
412032Speter * All rights reserved.
512032Speter *
612032Speter * Redistribution and use in source and binary forms, with or without
712032Speter * modification, are permitted provided that the following conditions
812032Speter * are met:
912032Speter * 1. Redistributions of source code must retain the above copyright
1012032Speter *    notice, this list of conditions and the following disclaimer.
1112032Speter * 2. Redistributions in binary form must reproduce the above copyright
1212032Speter *    notice, this list of conditions and the following disclaimer in the
1312032Speter *    documentation and/or other materials provided with the distribution.
1412032Speter * 3. All advertising materials mentioning features or use of this software
1512032Speter *    must display the following acknowledgement:
1612032Speter *	This product includes software developed by TooLs GmbH.
1712032Speter * 4. The name of TooLs GmbH may not be used to endorse or promote products
1812032Speter *    derived from this software without specific prior written permission.
1912032Speter *
2012032Speter * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
2112032Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2212032Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2312032Speter * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2412032Speter * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2512032Speter * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2612032Speter * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2712032Speter * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2812032Speter * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2912032Speter * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3012032Speter */
3112032Speter
32114601Sobrien#include <sys/cdefs.h>
33114601Sobrien__FBSDID("$FreeBSD$");
3412032Speter
3512032Speter#include <sys/param.h>
3696638Sdes#include <sys/stdint.h>
3712032Speter#include <sys/mount.h>
3896479Sphk#include <sys/disklabel.h>
3998542Smckusick#include <ufs/ufs/dinode.h>
4012032Speter#include <ufs/ffs/fs.h>
4112032Speter
4230262Scharnier#include <err.h>
4330262Scharnier#include <fcntl.h>
4474071Sps#include <fstab.h>
4530262Scharnier#include <errno.h>
4669793Sobrien#include <paths.h>
4730262Scharnier#include <pwd.h>
4812032Speter#include <stdio.h>
4912032Speter#include <stdlib.h>
5012032Speter#include <string.h>
51217769Smckusick#include <time.h>
5230262Scharnier#include <unistd.h>
5312032Speter
5412032Speter/* some flags of what to do: */
5512032Speterstatic char estimate;
5612032Speterstatic char count;
5712032Speterstatic char unused;
5887554Smikehstatic void (*func)(int, struct fs *, char *);
5912032Speterstatic long blocksize;
6012032Speterstatic char *header;
61108458Smikestatic int headerlen;
6212032Speter
6398542Smckusickstatic union dinode *get_inode(int, struct fs *, ino_t);
6498542Smckusickstatic int	virtualblocks(struct fs *, union dinode *);
6598542Smckusickstatic int	isfree(struct fs *, union dinode *);
6687554Smikehstatic void	inituser(void);
6787554Smikehstatic void	usrrehash(void);
6887554Smikehstatic struct user *user(uid_t);
6987554Smikehstatic int	cmpusers(const void *, const void *);
7087554Smikehstatic void	uses(uid_t, daddr_t, time_t);
7187554Smikehstatic void	initfsizes(void);
7287554Smikehstatic void	dofsizes(int, struct fs *, char *);
7387554Smikehstatic void	douser(int, struct fs *, char *);
7487554Smikehstatic void	donames(int, struct fs *, char *);
7587554Smikehstatic void	usage(void);
7687554Smikehstatic void	quot(char *, char *);
7787554Smikeh
7812032Speter/*
7912032Speter * Original BSD quot doesn't round to number of frags/blocks,
8012032Speter * doesn't account for indirection blocks and gets it totally
8112032Speter * wrong if the	size is a multiple of the blocksize.
8212032Speter * The new code always counts the number of 512 byte blocks
8312032Speter * instead of the number of kilobytes and converts them	to
8412032Speter * kByte when done (on request).
8541727Sdillon *
8641727Sdillon * Due to the size of modern disks, we must cast intermediate
8741727Sdillon * values to 64 bits to prevent potential overflows.
8812032Speter */
8912032Speter#ifdef	COMPAT
9012032Speter#define	SIZE(n)	(n)
9112032Speter#else
9241727Sdillon#define	SIZE(n) ((int)(((quad_t)(n) * 512 + blocksize - 1)/blocksize))
9312032Speter#endif
9412032Speter
9512032Speter#define	INOCNT(fs)	((fs)->fs_ipg)
9698542Smckusick#define	INOSZ(fs) \
9798542Smckusick	(((fs)->fs_magic == FS_UFS1_MAGIC ? sizeof(struct ufs1_dinode) : \
9898542Smckusick	sizeof(struct ufs2_dinode)) * INOCNT(fs))
9912032Speter
10098542Smckusickunion dinode {
10198542Smckusick	struct ufs1_dinode dp1;
10298542Smckusick	struct ufs2_dinode dp2;
10398542Smckusick};
10498542Smckusick#define	DIP(fs, dp, field) \
10598542Smckusick	(((fs)->fs_magic == FS_UFS1_MAGIC) ? \
10698542Smckusick	(dp)->dp1.field : (dp)->dp2.field)
10798542Smckusick
10898542Smckusickstatic union dinode *
109180187Sdesget_inode(int fd, struct fs *super, ino_t ino)
11012032Speter{
11198542Smckusick	static caddr_t ipbuf;
112156015Sdwmalone	static struct cg *cgp;
11312032Speter	static ino_t last;
114156015Sdwmalone	static int cg;
115156015Sdwmalone	struct ufs2_dinode *di2;
116180187Sdes
11712032Speter	if (fd < 0) {		/* flush cache */
11898542Smckusick		if (ipbuf) {
11998542Smckusick			free(ipbuf);
12098542Smckusick			ipbuf = 0;
121162831Smaxim			if (super != NULL && super->fs_magic == FS_UFS2_MAGIC) {
122156015Sdwmalone				free(cgp);
123156015Sdwmalone				cgp = 0;
124156015Sdwmalone			}
12512032Speter		}
12612032Speter		return 0;
12712032Speter	}
128180187Sdes
12998542Smckusick	if (!ipbuf || ino < last || ino >= last + INOCNT(super)) {
130156015Sdwmalone		if (super->fs_magic == FS_UFS2_MAGIC &&
131156015Sdwmalone		    (!cgp || cg != ino_to_cg(super, ino))) {
132156015Sdwmalone			cg = ino_to_cg(super, ino);
133156015Sdwmalone			if (!cgp && !(cgp = malloc(super->fs_cgsize)))
134156015Sdwmalone				errx(1, "allocate cg");
135156015Sdwmalone			if (lseek(fd, (off_t)cgtod(super, cg) << super->fs_fshift, 0) < 0)
136156015Sdwmalone				err(1, "lseek cg");
137156015Sdwmalone			if (read(fd, cgp, super->fs_cgsize) != super->fs_cgsize)
138156015Sdwmalone				err(1, "read cg");
139156015Sdwmalone			if (!cg_chkmagic(cgp))
140156015Sdwmalone				errx(1, "cg has bad magic");
141156015Sdwmalone		}
14298542Smckusick		if (!ipbuf
14398542Smckusick		    && !(ipbuf = malloc(INOSZ(super))))
14430262Scharnier			errx(1, "allocate inodes");
14512032Speter		last = (ino / INOCNT(super)) * INOCNT(super);
14628160Sjkh		if (lseek(fd, (off_t)ino_to_fsba(super, last) << super->fs_fshift, 0) < (off_t)0
14798542Smckusick		    || read(fd, ipbuf, INOSZ(super)) != (ssize_t)INOSZ(super))
14830262Scharnier			err(1, "read inodes");
14912032Speter	}
150180187Sdes
15198542Smckusick	if (super->fs_magic == FS_UFS1_MAGIC)
15298542Smckusick		return ((union dinode *)
15398542Smckusick		    &((struct ufs1_dinode *)ipbuf)[ino % INOCNT(super)]);
154156015Sdwmalone	di2 = &((struct ufs2_dinode *)ipbuf)[ino % INOCNT(super)];
155156015Sdwmalone	/* If the inode is unused, it might be unallocated too, so zero it. */
156156015Sdwmalone	if (isclr(cg_inosused(cgp), ino % super->fs_ipg))
157156015Sdwmalone		bzero(di2, sizeof (*di2));
158156015Sdwmalone	return ((union dinode *)di2);
15912032Speter}
16012032Speter
16112032Speter#ifdef	COMPAT
16298542Smckusick#define	actualblocks(fs, dp)	(DIP(fs, dp, di_blocks) / 2)
16312032Speter#else
16498542Smckusick#define	actualblocks(fs, dp)	DIP(fs, dp, di_blocks)
16512032Speter#endif
16612032Speter
167180187Sdesstatic int virtualblocks(struct fs *super, union dinode *dp)
16812032Speter{
169180187Sdes	off_t nblk, sz;
170180187Sdes
17198542Smckusick	sz = DIP(super, dp, di_size);
17212032Speter#ifdef	COMPAT
17312032Speter	if (lblkno(super,sz) >= NDADDR) {
17412032Speter		nblk = blkroundup(super,sz);
17512032Speter		if (sz == nblk)
17612032Speter			nblk += super->fs_bsize;
17712032Speter	}
178180187Sdes
17912032Speter	return sz / 1024;
180180187Sdes
18112032Speter#else	/* COMPAT */
182180187Sdes
18312032Speter	if (lblkno(super,sz) >= NDADDR) {
18412032Speter		nblk = blkroundup(super,sz);
18512032Speter		sz = lblkno(super,nblk);
18612032Speter		sz = (sz - NDADDR + NINDIR(super) - 1) / NINDIR(super);
18712032Speter		while (sz > 0) {
18812032Speter			nblk += sz * super->fs_bsize;
18912032Speter			/* sz - 1 rounded up */
19012032Speter			sz = (sz - 1 + NINDIR(super) - 1) / NINDIR(super);
19112032Speter		}
19212032Speter	} else
19312032Speter		nblk = fragroundup(super,sz);
194180187Sdes
19512032Speter	return nblk / 512;
19612032Speter#endif	/* COMPAT */
19712032Speter}
19812032Speter
19930262Scharnierstatic int
200180187Sdesisfree(struct fs *super, union dinode *dp)
20112032Speter{
20212032Speter#ifdef	COMPAT
20398542Smckusick	return (DIP(super, dp, di_mode) & IFMT) == 0;
20412032Speter#else	/* COMPAT */
205180187Sdes
20698542Smckusick	switch (DIP(super, dp, di_mode) & IFMT) {
20712032Speter	case IFIFO:
20812032Speter	case IFLNK:		/* should check FASTSYMLINK? */
20912032Speter	case IFDIR:
21012032Speter	case IFREG:
21112032Speter		return 0;
212156015Sdwmalone	case IFCHR:
213156015Sdwmalone	case IFBLK:
214156015Sdwmalone	case IFSOCK:
215156015Sdwmalone	case IFWHT:
216156015Sdwmalone	case 0:
217156015Sdwmalone		return 1;
21812032Speter	default:
219156015Sdwmalone		errx(1, "unknown IFMT 0%o", DIP(super, dp, di_mode) & IFMT);
22012032Speter	}
22112032Speter#endif
22212032Speter}
22312032Speter
22412032Speterstatic struct user {
22512032Speter	uid_t uid;
22612032Speter	char *name;
22712032Speter	daddr_t space;
22812032Speter	long count;
22912032Speter	daddr_t spc30;
23012032Speter	daddr_t spc60;
23112032Speter	daddr_t spc90;
23212032Speter} *users;
23312032Speterstatic int nusers;
23412032Speter
23530262Scharnierstatic void
236180187Sdesinituser(void)
23712032Speter{
238180187Sdes	int i;
239180187Sdes	struct user *usr;
240180187Sdes
24112032Speter	if (!nusers) {
24212032Speter		nusers = 8;
24312032Speter		if (!(users =
24430262Scharnier		    (struct user *)calloc(nusers,sizeof(struct user))))
24530262Scharnier			errx(1, "allocate users");
24612032Speter	} else {
24712032Speter		for (usr = users, i = nusers; --i >= 0; usr++) {
24812032Speter			usr->space = usr->spc30 = usr->spc60 = usr->spc90 = 0;
24912032Speter			usr->count = 0;
25012032Speter		}
25112032Speter	}
25212032Speter}
25312032Speter
25430262Scharnierstatic void
255180187Sdesusrrehash(void)
25612032Speter{
257180187Sdes	int i;
258180187Sdes	struct user *usr, *usrn;
25912032Speter	struct user *svusr;
260180187Sdes
26112032Speter	svusr = users;
26212032Speter	nusers <<= 1;
26330262Scharnier	if (!(users = (struct user *)calloc(nusers,sizeof(struct user))))
26430262Scharnier		errx(1, "allocate users");
26512032Speter	for (usr = svusr, i = nusers >> 1; --i >= 0; usr++) {
26612032Speter		for (usrn = users + (usr->uid&(nusers - 1)); usrn->name;
26712032Speter		    usrn--) {
26812032Speter			if (usrn <= users)
26912032Speter				usrn = users + nusers;
27012032Speter		}
27112032Speter		*usrn = *usr;
27212032Speter	}
27312032Speter}
27412032Speter
27530262Scharnierstatic struct user *
276180187Sdesuser(uid_t uid)
27712032Speter{
278180187Sdes	struct user *usr;
279180187Sdes	int i;
28012032Speter	struct passwd *pwd;
281180187Sdes
28212032Speter	while (1) {
28312032Speter		for (usr = users + (uid&(nusers - 1)), i = nusers; --i >= 0;
28412032Speter		    usr--) {
28512032Speter			if (!usr->name) {
28612032Speter				usr->uid = uid;
287180187Sdes
28812032Speter				if (!(pwd = getpwuid(uid))) {
28930262Scharnier					if ((usr->name = (char *)malloc(7)))
29012032Speter						sprintf(usr->name,"#%d",uid);
29112032Speter				} else {
29230262Scharnier					if ((usr->name = (char *)
29330262Scharnier					    malloc(strlen(pwd->pw_name) + 1)))
29412032Speter						strcpy(usr->name,pwd->pw_name);
29512032Speter				}
29630262Scharnier				if (!usr->name)
29730262Scharnier					errx(1, "allocate users");
298180187Sdes
29912032Speter				return usr;
300180187Sdes
30112032Speter			} else if (usr->uid == uid)
30212032Speter				return usr;
30312032Speter
30412032Speter			if (usr <= users)
30512032Speter				usr = users + nusers;
30612032Speter		}
30712032Speter		usrrehash();
30812032Speter	}
30912032Speter}
31012032Speter
31130262Scharnierstatic int
312180187Sdescmpusers(const void *v1, const void *v2)
31312032Speter{
31487554Smikeh	const struct user *u1, *u2;
31587554Smikeh	u1 = (const struct user *)v1;
31687554Smikeh	u2 = (const struct user *)v2;
31787554Smikeh
31812032Speter	return u2->space - u1->space;
31912032Speter}
32012032Speter
32112032Speter#define	sortusers(users)	(qsort((users),nusers,sizeof(struct user), \
32212032Speter				    cmpusers))
32312032Speter
32430262Scharnierstatic void
325180187Sdesuses(uid_t uid, daddr_t blks, time_t act)
32612032Speter{
32712032Speter	static time_t today;
328180187Sdes	struct user *usr;
329180187Sdes
33012032Speter	if (!today)
33112032Speter		time(&today);
332180187Sdes
33312032Speter	usr = user(uid);
33412032Speter	usr->count++;
33512032Speter	usr->space += blks;
336180187Sdes
33712032Speter	if (today - act > 90L * 24L * 60L * 60L)
33812032Speter		usr->spc90 += blks;
33912032Speter	if (today - act > 60L * 24L * 60L * 60L)
34012032Speter		usr->spc60 += blks;
34112032Speter	if (today - act > 30L * 24L * 60L * 60L)
34212032Speter		usr->spc30 += blks;
34312032Speter}
34412032Speter
34512032Speter#ifdef	COMPAT
34612032Speter#define	FSZCNT	500
34712032Speter#else
34812032Speter#define	FSZCNT	512
34912032Speter#endif
35012032Speterstruct fsizes {
35112032Speter	struct fsizes *fsz_next;
35212032Speter	daddr_t fsz_first, fsz_last;
35312032Speter	ino_t fsz_count[FSZCNT];
35412032Speter	daddr_t fsz_sz[FSZCNT];
35512032Speter} *fsizes;
35612032Speter
35730262Scharnierstatic void
358180187Sdesinitfsizes(void)
35912032Speter{
360180187Sdes	struct fsizes *fp;
361180187Sdes	int i;
362180187Sdes
36312032Speter	for (fp = fsizes; fp; fp = fp->fsz_next) {
36412032Speter		for (i = FSZCNT; --i >= 0;) {
36512032Speter			fp->fsz_count[i] = 0;
36612032Speter			fp->fsz_sz[i] = 0;
36712032Speter		}
36812032Speter	}
36912032Speter}
37012032Speter
37130262Scharnierstatic void
372180187Sdesdofsizes(int fd, struct fs *super, char *name)
37312032Speter{
37412032Speter	ino_t inode, maxino;
37598542Smckusick	union dinode *dp;
37612032Speter	daddr_t sz, ksz;
37712032Speter	struct fsizes *fp, **fsp;
378180187Sdes	int i;
379180187Sdes
38012032Speter	maxino = super->fs_ncg * super->fs_ipg - 1;
38112032Speter#ifdef	COMPAT
38230262Scharnier	if (!(fsizes = (struct fsizes *)malloc(sizeof(struct fsizes))))
38353764Scharnier		errx(1, "allocate fsize structure");
38412032Speter#endif	/* COMPAT */
38512032Speter	for (inode = 0; inode < maxino; inode++) {
38612032Speter		errno = 0;
38798542Smckusick		if ((dp = get_inode(fd,super,inode))
38812032Speter#ifdef	COMPAT
38998542Smckusick		    && ((DIP(super, dp, di_mode) & IFMT) == IFREG
39098542Smckusick			|| (DIP(super, dp, di_mode) & IFMT) == IFDIR)
39112032Speter#else	/* COMPAT */
39298542Smckusick		    && !isfree(super, dp)
39312032Speter#endif	/* COMPAT */
39412032Speter		    ) {
39598542Smckusick			sz = estimate ? virtualblocks(super, dp) :
39698542Smckusick			    actualblocks(super, dp);
39712032Speter#ifdef	COMPAT
39812032Speter			if (sz >= FSZCNT) {
39912032Speter				fsizes->fsz_count[FSZCNT-1]++;
40012032Speter				fsizes->fsz_sz[FSZCNT-1] += sz;
40112032Speter			} else {
40212032Speter				fsizes->fsz_count[sz]++;
40312032Speter				fsizes->fsz_sz[sz] += sz;
40412032Speter			}
40512032Speter#else	/* COMPAT */
40612032Speter			ksz = SIZE(sz);
40730262Scharnier			for (fsp = &fsizes; (fp = *fsp); fsp = &fp->fsz_next) {
40812032Speter				if (ksz < fp->fsz_last)
40912032Speter					break;
41012032Speter			}
41112032Speter			if (!fp || ksz < fp->fsz_first) {
41212032Speter				if (!(fp = (struct fsizes *)
41330262Scharnier				    malloc(sizeof(struct fsizes))))
41453764Scharnier					errx(1, "allocate fsize structure");
41512032Speter				fp->fsz_next = *fsp;
41612032Speter				*fsp = fp;
41712032Speter				fp->fsz_first = (ksz / FSZCNT) * FSZCNT;
41812032Speter				fp->fsz_last = fp->fsz_first + FSZCNT;
41912032Speter				for (i = FSZCNT; --i >= 0;) {
42012032Speter					fp->fsz_count[i] = 0;
42112032Speter					fp->fsz_sz[i] = 0;
42212032Speter				}
42312032Speter			}
42412032Speter			fp->fsz_count[ksz % FSZCNT]++;
42512032Speter			fp->fsz_sz[ksz % FSZCNT] += sz;
42612032Speter#endif	/* COMPAT */
42712032Speter		} else if (errno) {
42830262Scharnier			err(1, "%s", name);
42912032Speter		}
43012032Speter	}
43112032Speter	sz = 0;
43212032Speter	for (fp = fsizes; fp; fp = fp->fsz_next) {
43312032Speter		for (i = 0; i < FSZCNT; i++) {
43412032Speter			if (fp->fsz_count[i])
43596638Sdes				printf("%jd\t%jd\t%d\n",
43696638Sdes				    (intmax_t)(fp->fsz_first + i),
43796638Sdes				    (intmax_t)fp->fsz_count[i],
43812032Speter				    SIZE(sz += fp->fsz_sz[i]));
43912032Speter		}
44012032Speter	}
44112032Speter}
44212032Speter
44330262Scharnierstatic void
444180187Sdesdouser(int fd, struct fs *super, char *name)
44512032Speter{
44612032Speter	ino_t inode, maxino;
44712032Speter	struct user *usr, *usrs;
44898542Smckusick	union dinode *dp;
449180187Sdes	int n;
450180187Sdes
45112032Speter	maxino = super->fs_ncg * super->fs_ipg - 1;
45212032Speter	for (inode = 0; inode < maxino; inode++) {
45312032Speter		errno = 0;
45498542Smckusick		if ((dp = get_inode(fd,super,inode))
45598542Smckusick		    && !isfree(super, dp))
45698542Smckusick			uses(DIP(super, dp, di_uid),
45798542Smckusick			    estimate ? virtualblocks(super, dp) :
45898542Smckusick				actualblocks(super, dp),
45998542Smckusick			    DIP(super, dp, di_atime));
46012032Speter		else if (errno) {
46130262Scharnier			err(1, "%s", name);
46212032Speter		}
46312032Speter	}
46430262Scharnier	if (!(usrs = (struct user *)malloc(nusers * sizeof(struct user))))
46530262Scharnier		errx(1, "allocate users");
46612032Speter	bcopy(users,usrs,nusers * sizeof(struct user));
46712032Speter	sortusers(usrs);
46812032Speter	for (usr = usrs, n = nusers; --n >= 0 && usr->count; usr++) {
46912032Speter		printf("%5d",SIZE(usr->space));
47012032Speter		if (count)
47187554Smikeh			printf("\t%5ld",usr->count);
47212032Speter		printf("\t%-8s",usr->name);
47312032Speter		if (unused)
47412032Speter			printf("\t%5d\t%5d\t%5d",
47512032Speter			       SIZE(usr->spc30),
47612032Speter			       SIZE(usr->spc60),
47712032Speter			       SIZE(usr->spc90));
47812032Speter		printf("\n");
47912032Speter	}
48012032Speter	free(usrs);
48112032Speter}
48212032Speter
48330262Scharnierstatic void
484180187Sdesdonames(int fd, struct fs *super, char *name)
48512032Speter{
48612032Speter	int c;
48712032Speter	ino_t maxino;
488241015Smdf	uintmax_t inode;
48998542Smckusick	union dinode *dp;
490180187Sdes
49112032Speter	maxino = super->fs_ncg * super->fs_ipg - 1;
49212032Speter	/* first skip the name of the filesystem */
49312032Speter	while ((c = getchar()) != EOF && (c < '0' || c > '9'))
49412032Speter		while ((c = getchar()) != EOF && c != '\n');
49512032Speter	ungetc(c,stdin);
496241015Smdf	while (scanf("%ju", &inode) == 1) {
49787554Smikeh		if (inode > maxino) {
498241015Smdf			warnx("illegal inode %ju", inode);
49912032Speter			return;
50012032Speter		}
50112032Speter		errno = 0;
50298542Smckusick		if ((dp = get_inode(fd,super,inode))
50398542Smckusick		    && !isfree(super, dp)) {
50498542Smckusick			printf("%s\t",user(DIP(super, dp, di_uid))->name);
50512032Speter			/* now skip whitespace */
50612032Speter			while ((c = getchar()) == ' ' || c == '\t');
50712032Speter			/* and print out the remainder of the input line */
50812032Speter			while (c != EOF && c != '\n') {
50912032Speter				putchar(c);
51012032Speter				c = getchar();
51112032Speter			}
51212032Speter			putchar('\n');
51312032Speter		} else {
51412032Speter			if (errno) {
51530262Scharnier				err(1, "%s", name);
51612032Speter			}
51712032Speter			/* skip this line */
51812032Speter			while ((c = getchar()) != EOF && c != '\n');
51912032Speter		}
52012032Speter		if (c == EOF)
52112032Speter			break;
52212032Speter	}
52312032Speter}
52412032Speter
52530262Scharnierstatic void
526180187Sdesusage(void)
52712032Speter{
52812032Speter#ifdef	COMPAT
52930262Scharnier	fprintf(stderr,"usage: quot [-nfcvha] [filesystem ...]\n");
53012032Speter#else	/* COMPAT */
53153764Scharnier	fprintf(stderr,"usage: quot [-acfhknv] [filesystem ...]\n");
53212032Speter#endif	/* COMPAT */
53312032Speter	exit(1);
53412032Speter}
53512032Speter
53698542Smckusick/*
53798542Smckusick * Possible superblock locations ordered from most to least likely.
53898542Smckusick */
53998542Smckusickstatic int sblock_try[] = SBLOCKSEARCH;
54098542Smckusickstatic char superblock[SBLOCKSIZE];
54112032Speter
54230262Scharniervoid
543180187Sdesquot(char *name, char *mp)
54412032Speter{
54598542Smckusick	int i, fd;
54698542Smckusick	struct fs *fs;
547180187Sdes
54887554Smikeh	get_inode(-1, NULL, 0);		/* flush cache */
54912032Speter	inituser();
55012032Speter	initfsizes();
55198542Smckusick	if ((fd = open(name,0)) < 0) {
55230262Scharnier		warn("%s", name);
55312032Speter		close(fd);
55412032Speter		return;
55512032Speter	}
55698542Smckusick	for (i = 0; sblock_try[i] != -1; i++) {
55798542Smckusick		if (lseek(fd, sblock_try[i], 0) != sblock_try[i]) {
55898542Smckusick			close(fd);
55998542Smckusick			return;
56098542Smckusick		}
56198542Smckusick		if (read(fd, superblock, SBLOCKSIZE) != SBLOCKSIZE) {
56298542Smckusick			close(fd);
56398542Smckusick			return;
56498542Smckusick		}
56598542Smckusick		fs = (struct fs *)superblock;
56698542Smckusick		if ((fs->fs_magic == FS_UFS1_MAGIC ||
56798542Smckusick		     (fs->fs_magic == FS_UFS2_MAGIC &&
568114009Stjr		      fs->fs_sblockloc == sblock_try[i])) &&
56998542Smckusick		    fs->fs_bsize <= MAXBSIZE &&
57098542Smckusick		    fs->fs_bsize >= sizeof(struct fs))
57198542Smckusick			break;
57298542Smckusick	}
57398542Smckusick	if (sblock_try[i] == -1) {
57430262Scharnier		warnx("%s: not a BSD filesystem",name);
57512032Speter		close(fd);
57612032Speter		return;
57712032Speter	}
57812032Speter	printf("%s:",name);
57912032Speter	if (mp)
58012032Speter		printf(" (%s)",mp);
58112032Speter	putchar('\n');
58298542Smckusick	(*func)(fd, fs, name);
58312032Speter	close(fd);
58412032Speter}
58512032Speter
58630262Scharnierint
587180187Sdesmain(int argc, char *argv[])
58812032Speter{
58912032Speter	char all = 0;
59012032Speter	struct statfs *mp;
59174071Sps	struct fstab *fs;
59212032Speter	int cnt;
593180187Sdes
59412032Speter	func = douser;
59512032Speter#ifndef	COMPAT
59612032Speter	header = getbsize(&headerlen,&blocksize);
59712032Speter#endif
59812032Speter	while (--argc > 0 && **++argv == '-') {
59912032Speter		while (*++*argv) {
60012032Speter			switch (**argv) {
60112032Speter			case 'n':
60212032Speter				func = donames;
60312032Speter				break;
60412032Speter			case 'c':
60512032Speter				func = dofsizes;
60612032Speter				break;
60712032Speter			case 'a':
60812032Speter				all = 1;
60912032Speter				break;
61012032Speter			case 'f':
61112032Speter				count = 1;
61212032Speter				break;
61312032Speter			case 'h':
61412032Speter				estimate = 1;
61512032Speter				break;
61612032Speter#ifndef	COMPAT
61712032Speter			case 'k':
61812032Speter				blocksize = 1024;
61912032Speter				break;
62012032Speter#endif	/* COMPAT */
62112032Speter			case 'v':
62212032Speter				unused = 1;
62312032Speter				break;
62412032Speter			default:
62512032Speter				usage();
62612032Speter			}
62712032Speter		}
62812032Speter	}
62912032Speter	if (all) {
63012032Speter		cnt = getmntinfo(&mp,MNT_NOWAIT);
63112032Speter		for (; --cnt >= 0; mp++) {
632183018Sed			if (!strncmp(mp->f_fstypename, "ufs", MFSNAMELEN))
633183018Sed				quot(mp->f_mntfromname, mp->f_mntonname);
63412032Speter		}
63512032Speter	}
63674071Sps	while (--argc >= 0) {
63774071Sps		if ((fs = getfsfile(*argv)) != NULL)
63874071Sps			quot(fs->fs_spec, 0);
63974071Sps		else
64074071Sps			quot(*argv,0);
64174071Sps		argv++;
64274071Sps	}
64312032Speter	return 0;
64412032Speter}
645