quot.c revision 108458
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
3212032Speter#ifndef lint
3330262Scharnierstatic const char rcsid[] =
3450479Speter  "$FreeBSD: head/usr.sbin/quot/quot.c 108458 2002-12-30 18:21:47Z mike $";
3512032Speter#endif /* not lint */
3612032Speter
3712032Speter#include <sys/param.h>
3896638Sdes#include <sys/stdint.h>
3912032Speter#include <sys/mount.h>
4096479Sphk#include <sys/disklabel.h>
4112032Speter#include <sys/time.h>
4298542Smckusick#include <ufs/ufs/dinode.h>
4312032Speter#include <ufs/ffs/fs.h>
4412032Speter
4530262Scharnier#include <err.h>
4630262Scharnier#include <fcntl.h>
4774071Sps#include <fstab.h>
4830262Scharnier#include <errno.h>
4969793Sobrien#include <paths.h>
5030262Scharnier#include <pwd.h>
5112032Speter#include <stdio.h>
5212032Speter#include <stdlib.h>
5312032Speter#include <string.h>
5430262Scharnier#include <unistd.h>
5512032Speter
5612032Speter/* some flags of what to do: */
5712032Speterstatic char estimate;
5812032Speterstatic char count;
5912032Speterstatic char unused;
6087554Smikehstatic void (*func)(int, struct fs *, char *);
6112032Speterstatic long blocksize;
6212032Speterstatic char *header;
63108458Smikestatic int headerlen;
6412032Speter
6598542Smckusickstatic union dinode *get_inode(int, struct fs *, ino_t);
6698542Smckusickstatic int	virtualblocks(struct fs *, union dinode *);
6798542Smckusickstatic int	isfree(struct fs *, union dinode *);
6887554Smikehstatic void	inituser(void);
6987554Smikehstatic void	usrrehash(void);
7087554Smikehstatic struct user *user(uid_t);
7187554Smikehstatic int	cmpusers(const void *, const void *);
7287554Smikehstatic void	uses(uid_t, daddr_t, time_t);
7387554Smikehstatic void	initfsizes(void);
7487554Smikehstatic void	dofsizes(int, struct fs *, char *);
7587554Smikehstatic void	douser(int, struct fs *, char *);
7687554Smikehstatic void	donames(int, struct fs *, char *);
7787554Smikehstatic void	usage(void);
7887554Smikehstatic void	quot(char *, char *);
7987554Smikeh
8012032Speter/*
8112032Speter * Original BSD quot doesn't round to number of frags/blocks,
8212032Speter * doesn't account for indirection blocks and gets it totally
8312032Speter * wrong if the	size is a multiple of the blocksize.
8412032Speter * The new code always counts the number of 512 byte blocks
8512032Speter * instead of the number of kilobytes and converts them	to
8612032Speter * kByte when done (on request).
8741727Sdillon *
8841727Sdillon * Due to the size of modern disks, we must cast intermediate
8941727Sdillon * values to 64 bits to prevent potential overflows.
9012032Speter */
9112032Speter#ifdef	COMPAT
9212032Speter#define	SIZE(n)	(n)
9312032Speter#else
9441727Sdillon#define	SIZE(n) ((int)(((quad_t)(n) * 512 + blocksize - 1)/blocksize))
9512032Speter#endif
9612032Speter
9712032Speter#define	INOCNT(fs)	((fs)->fs_ipg)
9898542Smckusick#define	INOSZ(fs) \
9998542Smckusick	(((fs)->fs_magic == FS_UFS1_MAGIC ? sizeof(struct ufs1_dinode) : \
10098542Smckusick	sizeof(struct ufs2_dinode)) * INOCNT(fs))
10112032Speter
10298542Smckusickunion dinode {
10398542Smckusick	struct ufs1_dinode dp1;
10498542Smckusick	struct ufs2_dinode dp2;
10598542Smckusick};
10698542Smckusick#define	DIP(fs, dp, field) \
10798542Smckusick	(((fs)->fs_magic == FS_UFS1_MAGIC) ? \
10898542Smckusick	(dp)->dp1.field : (dp)->dp2.field)
10998542Smckusick
11098542Smckusickstatic union dinode *
11130262Scharnierget_inode(fd,super,ino)
11287554Smikeh	int fd;
11312032Speter	struct fs *super;
11412032Speter	ino_t ino;
11512032Speter{
11698542Smckusick	static caddr_t ipbuf;
11712032Speter	static ino_t last;
11812032Speter
11912032Speter	if (fd < 0) {		/* flush cache */
12098542Smckusick		if (ipbuf) {
12198542Smckusick			free(ipbuf);
12298542Smckusick			ipbuf = 0;
12312032Speter		}
12412032Speter		return 0;
12512032Speter	}
12612032Speter
12798542Smckusick	if (!ipbuf || ino < last || ino >= last + INOCNT(super)) {
12898542Smckusick		if (!ipbuf
12998542Smckusick		    && !(ipbuf = malloc(INOSZ(super))))
13030262Scharnier			errx(1, "allocate inodes");
13112032Speter		last = (ino / INOCNT(super)) * INOCNT(super);
13228160Sjkh		if (lseek(fd, (off_t)ino_to_fsba(super, last) << super->fs_fshift, 0) < (off_t)0
13398542Smckusick		    || read(fd, ipbuf, INOSZ(super)) != (ssize_t)INOSZ(super))
13430262Scharnier			err(1, "read inodes");
13512032Speter	}
13612032Speter
13798542Smckusick	if (super->fs_magic == FS_UFS1_MAGIC)
13898542Smckusick		return ((union dinode *)
13998542Smckusick		    &((struct ufs1_dinode *)ipbuf)[ino % INOCNT(super)]);
14098542Smckusick	return ((union dinode *)
14198542Smckusick	    &((struct ufs2_dinode *)ipbuf)[ino % INOCNT(super)]);
14212032Speter}
14312032Speter
14412032Speter#ifdef	COMPAT
14598542Smckusick#define	actualblocks(fs, dp)	(DIP(fs, dp, di_blocks) / 2)
14612032Speter#else
14798542Smckusick#define	actualblocks(fs, dp)	DIP(fs, dp, di_blocks)
14812032Speter#endif
14912032Speter
15098542Smckusickstatic int virtualblocks(super, dp)
15112032Speter	struct fs *super;
15298542Smckusick	union dinode *dp;
15312032Speter{
15412032Speter	register off_t nblk, sz;
15512032Speter
15698542Smckusick	sz = DIP(super, dp, di_size);
15712032Speter#ifdef	COMPAT
15812032Speter	if (lblkno(super,sz) >= NDADDR) {
15912032Speter		nblk = blkroundup(super,sz);
16012032Speter		if (sz == nblk)
16112032Speter			nblk += super->fs_bsize;
16212032Speter	}
16312032Speter
16412032Speter	return sz / 1024;
16512032Speter
16612032Speter#else	/* COMPAT */
16712032Speter
16812032Speter	if (lblkno(super,sz) >= NDADDR) {
16912032Speter		nblk = blkroundup(super,sz);
17012032Speter		sz = lblkno(super,nblk);
17112032Speter		sz = (sz - NDADDR + NINDIR(super) - 1) / NINDIR(super);
17212032Speter		while (sz > 0) {
17312032Speter			nblk += sz * super->fs_bsize;
17412032Speter			/* sz - 1 rounded up */
17512032Speter			sz = (sz - 1 + NINDIR(super) - 1) / NINDIR(super);
17612032Speter		}
17712032Speter	} else
17812032Speter		nblk = fragroundup(super,sz);
17912032Speter
18012032Speter	return nblk / 512;
18112032Speter#endif	/* COMPAT */
18212032Speter}
18312032Speter
18430262Scharnierstatic int
18598542Smckusickisfree(super, dp)
18698542Smckusick	struct fs *super;
18798542Smckusick	union dinode *dp;
18812032Speter{
18912032Speter#ifdef	COMPAT
19098542Smckusick	return (DIP(super, dp, di_mode) & IFMT) == 0;
19112032Speter#else	/* COMPAT */
19212032Speter
19398542Smckusick	switch (DIP(super, dp, di_mode) & IFMT) {
19412032Speter	case IFIFO:
19512032Speter	case IFLNK:		/* should check FASTSYMLINK? */
19612032Speter	case IFDIR:
19712032Speter	case IFREG:
19812032Speter		return 0;
19912032Speter	default:
20012032Speter		return 1;
20112032Speter	}
20212032Speter#endif
20312032Speter}
20412032Speter
20512032Speterstatic struct user {
20612032Speter	uid_t uid;
20712032Speter	char *name;
20812032Speter	daddr_t space;
20912032Speter	long count;
21012032Speter	daddr_t spc30;
21112032Speter	daddr_t spc60;
21212032Speter	daddr_t spc90;
21312032Speter} *users;
21412032Speterstatic int nusers;
21512032Speter
21630262Scharnierstatic void
21730262Scharnierinituser()
21812032Speter{
21987554Smikeh	register int i;
22012032Speter	register struct user *usr;
22112032Speter
22212032Speter	if (!nusers) {
22312032Speter		nusers = 8;
22412032Speter		if (!(users =
22530262Scharnier		    (struct user *)calloc(nusers,sizeof(struct user))))
22630262Scharnier			errx(1, "allocate users");
22712032Speter	} else {
22812032Speter		for (usr = users, i = nusers; --i >= 0; usr++) {
22912032Speter			usr->space = usr->spc30 = usr->spc60 = usr->spc90 = 0;
23012032Speter			usr->count = 0;
23112032Speter		}
23212032Speter	}
23312032Speter}
23412032Speter
23530262Scharnierstatic void
23630262Scharnierusrrehash()
23712032Speter{
23887554Smikeh	register int i;
23912032Speter	register struct user *usr, *usrn;
24012032Speter	struct user *svusr;
24112032Speter
24212032Speter	svusr = users;
24312032Speter	nusers <<= 1;
24430262Scharnier	if (!(users = (struct user *)calloc(nusers,sizeof(struct user))))
24530262Scharnier		errx(1, "allocate users");
24612032Speter	for (usr = svusr, i = nusers >> 1; --i >= 0; usr++) {
24712032Speter		for (usrn = users + (usr->uid&(nusers - 1)); usrn->name;
24812032Speter		    usrn--) {
24912032Speter			if (usrn <= users)
25012032Speter				usrn = users + nusers;
25112032Speter		}
25212032Speter		*usrn = *usr;
25312032Speter	}
25412032Speter}
25512032Speter
25630262Scharnierstatic struct user *
25730262Scharnieruser(uid)
25812032Speter	uid_t uid;
25912032Speter{
26012032Speter	register struct user *usr;
26187554Smikeh	register int i;
26212032Speter	struct passwd *pwd;
26312032Speter
26412032Speter	while (1) {
26512032Speter		for (usr = users + (uid&(nusers - 1)), i = nusers; --i >= 0;
26612032Speter		    usr--) {
26712032Speter			if (!usr->name) {
26812032Speter				usr->uid = uid;
26912032Speter
27012032Speter				if (!(pwd = getpwuid(uid))) {
27130262Scharnier					if ((usr->name = (char *)malloc(7)))
27212032Speter						sprintf(usr->name,"#%d",uid);
27312032Speter				} else {
27430262Scharnier					if ((usr->name = (char *)
27530262Scharnier					    malloc(strlen(pwd->pw_name) + 1)))
27612032Speter						strcpy(usr->name,pwd->pw_name);
27712032Speter				}
27830262Scharnier				if (!usr->name)
27930262Scharnier					errx(1, "allocate users");
28012032Speter
28112032Speter				return usr;
28212032Speter
28312032Speter			} else if (usr->uid == uid)
28412032Speter				return usr;
28512032Speter
28612032Speter			if (usr <= users)
28712032Speter				usr = users + nusers;
28812032Speter		}
28912032Speter		usrrehash();
29012032Speter	}
29112032Speter}
29212032Speter
29330262Scharnierstatic int
29487554Smikehcmpusers(v1,v2)
29587554Smikeh	const void *v1, *v2;
29612032Speter{
29787554Smikeh	const struct user *u1, *u2;
29887554Smikeh	u1 = (const struct user *)v1;
29987554Smikeh	u2 = (const struct user *)v2;
30087554Smikeh
30112032Speter	return u2->space - u1->space;
30212032Speter}
30312032Speter
30412032Speter#define	sortusers(users)	(qsort((users),nusers,sizeof(struct user), \
30512032Speter				    cmpusers))
30612032Speter
30730262Scharnierstatic void
30830262Scharnieruses(uid,blks,act)
30912032Speter	uid_t uid;
31012032Speter	daddr_t blks;
31112032Speter	time_t act;
31212032Speter{
31312032Speter	static time_t today;
31412032Speter	register struct user *usr;
31512032Speter
31612032Speter	if (!today)
31712032Speter		time(&today);
31812032Speter
31912032Speter	usr = user(uid);
32012032Speter	usr->count++;
32112032Speter	usr->space += blks;
32212032Speter
32312032Speter	if (today - act > 90L * 24L * 60L * 60L)
32412032Speter		usr->spc90 += blks;
32512032Speter	if (today - act > 60L * 24L * 60L * 60L)
32612032Speter		usr->spc60 += blks;
32712032Speter	if (today - act > 30L * 24L * 60L * 60L)
32812032Speter		usr->spc30 += blks;
32912032Speter}
33012032Speter
33112032Speter#ifdef	COMPAT
33212032Speter#define	FSZCNT	500
33312032Speter#else
33412032Speter#define	FSZCNT	512
33512032Speter#endif
33612032Speterstruct fsizes {
33712032Speter	struct fsizes *fsz_next;
33812032Speter	daddr_t fsz_first, fsz_last;
33912032Speter	ino_t fsz_count[FSZCNT];
34012032Speter	daddr_t fsz_sz[FSZCNT];
34112032Speter} *fsizes;
34212032Speter
34330262Scharnierstatic void
34430262Scharnierinitfsizes()
34512032Speter{
34612032Speter	register struct fsizes *fp;
34787554Smikeh	register int i;
34812032Speter
34912032Speter	for (fp = fsizes; fp; fp = fp->fsz_next) {
35012032Speter		for (i = FSZCNT; --i >= 0;) {
35112032Speter			fp->fsz_count[i] = 0;
35212032Speter			fp->fsz_sz[i] = 0;
35312032Speter		}
35412032Speter	}
35512032Speter}
35612032Speter
35730262Scharnierstatic void
35898542Smckusickdofsizes(fd, super, name)
35987554Smikeh	int fd;
36012032Speter	struct fs *super;
36112032Speter	char *name;
36212032Speter{
36312032Speter	ino_t inode, maxino;
36498542Smckusick	union dinode *dp;
36512032Speter	daddr_t sz, ksz;
36612032Speter	struct fsizes *fp, **fsp;
36787554Smikeh	register int i;
36812032Speter
36912032Speter	maxino = super->fs_ncg * super->fs_ipg - 1;
37012032Speter#ifdef	COMPAT
37130262Scharnier	if (!(fsizes = (struct fsizes *)malloc(sizeof(struct fsizes))))
37253764Scharnier		errx(1, "allocate fsize structure");
37312032Speter#endif	/* COMPAT */
37412032Speter	for (inode = 0; inode < maxino; inode++) {
37512032Speter		errno = 0;
37698542Smckusick		if ((dp = get_inode(fd,super,inode))
37712032Speter#ifdef	COMPAT
37898542Smckusick		    && ((DIP(super, dp, di_mode) & IFMT) == IFREG
37998542Smckusick			|| (DIP(super, dp, di_mode) & IFMT) == IFDIR)
38012032Speter#else	/* COMPAT */
38198542Smckusick		    && !isfree(super, dp)
38212032Speter#endif	/* COMPAT */
38312032Speter		    ) {
38498542Smckusick			sz = estimate ? virtualblocks(super, dp) :
38598542Smckusick			    actualblocks(super, dp);
38612032Speter#ifdef	COMPAT
38712032Speter			if (sz >= FSZCNT) {
38812032Speter				fsizes->fsz_count[FSZCNT-1]++;
38912032Speter				fsizes->fsz_sz[FSZCNT-1] += sz;
39012032Speter			} else {
39112032Speter				fsizes->fsz_count[sz]++;
39212032Speter				fsizes->fsz_sz[sz] += sz;
39312032Speter			}
39412032Speter#else	/* COMPAT */
39512032Speter			ksz = SIZE(sz);
39630262Scharnier			for (fsp = &fsizes; (fp = *fsp); fsp = &fp->fsz_next) {
39712032Speter				if (ksz < fp->fsz_last)
39812032Speter					break;
39912032Speter			}
40012032Speter			if (!fp || ksz < fp->fsz_first) {
40112032Speter				if (!(fp = (struct fsizes *)
40230262Scharnier				    malloc(sizeof(struct fsizes))))
40353764Scharnier					errx(1, "allocate fsize structure");
40412032Speter				fp->fsz_next = *fsp;
40512032Speter				*fsp = fp;
40612032Speter				fp->fsz_first = (ksz / FSZCNT) * FSZCNT;
40712032Speter				fp->fsz_last = fp->fsz_first + FSZCNT;
40812032Speter				for (i = FSZCNT; --i >= 0;) {
40912032Speter					fp->fsz_count[i] = 0;
41012032Speter					fp->fsz_sz[i] = 0;
41112032Speter				}
41212032Speter			}
41312032Speter			fp->fsz_count[ksz % FSZCNT]++;
41412032Speter			fp->fsz_sz[ksz % FSZCNT] += sz;
41512032Speter#endif	/* COMPAT */
41612032Speter		} else if (errno) {
41730262Scharnier			err(1, "%s", name);
41812032Speter		}
41912032Speter	}
42012032Speter	sz = 0;
42112032Speter	for (fp = fsizes; fp; fp = fp->fsz_next) {
42212032Speter		for (i = 0; i < FSZCNT; i++) {
42312032Speter			if (fp->fsz_count[i])
42496638Sdes				printf("%jd\t%jd\t%d\n",
42596638Sdes				    (intmax_t)(fp->fsz_first + i),
42696638Sdes				    (intmax_t)fp->fsz_count[i],
42712032Speter				    SIZE(sz += fp->fsz_sz[i]));
42812032Speter		}
42912032Speter	}
43012032Speter}
43112032Speter
43230262Scharnierstatic void
43398542Smckusickdouser(fd, super, name)
43487554Smikeh	int fd;
43512032Speter	struct fs *super;
43612032Speter	char *name;
43712032Speter{
43812032Speter	ino_t inode, maxino;
43912032Speter	struct user *usr, *usrs;
44098542Smckusick	union dinode *dp;
44187554Smikeh	register int n;
44212032Speter
44312032Speter	maxino = super->fs_ncg * super->fs_ipg - 1;
44412032Speter	for (inode = 0; inode < maxino; inode++) {
44512032Speter		errno = 0;
44698542Smckusick		if ((dp = get_inode(fd,super,inode))
44798542Smckusick		    && !isfree(super, dp))
44898542Smckusick			uses(DIP(super, dp, di_uid),
44998542Smckusick			    estimate ? virtualblocks(super, dp) :
45098542Smckusick				actualblocks(super, dp),
45198542Smckusick			    DIP(super, dp, di_atime));
45212032Speter		else if (errno) {
45330262Scharnier			err(1, "%s", name);
45412032Speter		}
45512032Speter	}
45630262Scharnier	if (!(usrs = (struct user *)malloc(nusers * sizeof(struct user))))
45730262Scharnier		errx(1, "allocate users");
45812032Speter	bcopy(users,usrs,nusers * sizeof(struct user));
45912032Speter	sortusers(usrs);
46012032Speter	for (usr = usrs, n = nusers; --n >= 0 && usr->count; usr++) {
46112032Speter		printf("%5d",SIZE(usr->space));
46212032Speter		if (count)
46387554Smikeh			printf("\t%5ld",usr->count);
46412032Speter		printf("\t%-8s",usr->name);
46512032Speter		if (unused)
46612032Speter			printf("\t%5d\t%5d\t%5d",
46712032Speter			       SIZE(usr->spc30),
46812032Speter			       SIZE(usr->spc60),
46912032Speter			       SIZE(usr->spc90));
47012032Speter		printf("\n");
47112032Speter	}
47212032Speter	free(usrs);
47312032Speter}
47412032Speter
47530262Scharnierstatic void
47698542Smckusickdonames(fd, super, name)
47787554Smikeh	int fd;
47812032Speter	struct fs *super;
47912032Speter	char *name;
48012032Speter{
48112032Speter	int c;
48212032Speter	ino_t inode, inode1;
48312032Speter	ino_t maxino;
48498542Smckusick	union dinode *dp;
48512032Speter
48612032Speter	maxino = super->fs_ncg * super->fs_ipg - 1;
48712032Speter	/* first skip the name of the filesystem */
48812032Speter	while ((c = getchar()) != EOF && (c < '0' || c > '9'))
48912032Speter		while ((c = getchar()) != EOF && c != '\n');
49012032Speter	ungetc(c,stdin);
49112032Speter	inode1 = -1;
49287554Smikeh	while (scanf("%u",&inode) == 1) {
49387554Smikeh		if (inode > maxino) {
49430262Scharnier			warnx("illegal inode %d",inode);
49512032Speter			return;
49612032Speter		}
49712032Speter		errno = 0;
49898542Smckusick		if ((dp = get_inode(fd,super,inode))
49998542Smckusick		    && !isfree(super, dp)) {
50098542Smckusick			printf("%s\t",user(DIP(super, dp, di_uid))->name);
50112032Speter			/* now skip whitespace */
50212032Speter			while ((c = getchar()) == ' ' || c == '\t');
50312032Speter			/* and print out the remainder of the input line */
50412032Speter			while (c != EOF && c != '\n') {
50512032Speter				putchar(c);
50612032Speter				c = getchar();
50712032Speter			}
50812032Speter			putchar('\n');
50912032Speter			inode1 = inode;
51012032Speter		} else {
51112032Speter			if (errno) {
51230262Scharnier				err(1, "%s", name);
51312032Speter			}
51412032Speter			/* skip this line */
51512032Speter			while ((c = getchar()) != EOF && c != '\n');
51612032Speter		}
51712032Speter		if (c == EOF)
51812032Speter			break;
51912032Speter	}
52012032Speter}
52112032Speter
52230262Scharnierstatic void
52330262Scharnierusage()
52412032Speter{
52512032Speter#ifdef	COMPAT
52630262Scharnier	fprintf(stderr,"usage: quot [-nfcvha] [filesystem ...]\n");
52712032Speter#else	/* COMPAT */
52853764Scharnier	fprintf(stderr,"usage: quot [-acfhknv] [filesystem ...]\n");
52912032Speter#endif	/* COMPAT */
53012032Speter	exit(1);
53112032Speter}
53212032Speter
53398542Smckusick/*
53498542Smckusick * Possible superblock locations ordered from most to least likely.
53598542Smckusick */
53698542Smckusickstatic int sblock_try[] = SBLOCKSEARCH;
53798542Smckusickstatic char superblock[SBLOCKSIZE];
53812032Speter
53930262Scharniervoid
54012032Speterquot(name,mp)
54112032Speter	char *name, *mp;
54212032Speter{
54398542Smckusick	int i, fd;
54498542Smckusick	struct fs *fs;
54512032Speter
54687554Smikeh	get_inode(-1, NULL, 0);		/* flush cache */
54712032Speter	inituser();
54812032Speter	initfsizes();
54998542Smckusick	if ((fd = open(name,0)) < 0) {
55030262Scharnier		warn("%s", name);
55112032Speter		close(fd);
55212032Speter		return;
55312032Speter	}
55498542Smckusick	for (i = 0; sblock_try[i] != -1; i++) {
55598542Smckusick		if (lseek(fd, sblock_try[i], 0) != sblock_try[i]) {
55698542Smckusick			close(fd);
55798542Smckusick			return;
55898542Smckusick		}
55998542Smckusick		if (read(fd, superblock, SBLOCKSIZE) != SBLOCKSIZE) {
56098542Smckusick			close(fd);
56198542Smckusick			return;
56298542Smckusick		}
56398542Smckusick		fs = (struct fs *)superblock;
56498542Smckusick		if ((fs->fs_magic == FS_UFS1_MAGIC ||
56598542Smckusick		     (fs->fs_magic == FS_UFS2_MAGIC &&
56698542Smckusick		      fs->fs_sblockloc == numfrags(fs, sblock_try[i]))) &&
56798542Smckusick		    fs->fs_bsize <= MAXBSIZE &&
56898542Smckusick		    fs->fs_bsize >= sizeof(struct fs))
56998542Smckusick			break;
57098542Smckusick	}
57198542Smckusick	if (sblock_try[i] == -1) {
57230262Scharnier		warnx("%s: not a BSD filesystem",name);
57312032Speter		close(fd);
57412032Speter		return;
57512032Speter	}
57612032Speter	printf("%s:",name);
57712032Speter	if (mp)
57812032Speter		printf(" (%s)",mp);
57912032Speter	putchar('\n');
58098542Smckusick	(*func)(fd, fs, name);
58112032Speter	close(fd);
58212032Speter}
58312032Speter
58430262Scharnierint
58530262Scharniermain(argc,argv)
58687554Smikeh	int argc;
58712032Speter	char **argv;
58812032Speter{
58912032Speter	char all = 0;
59012032Speter	struct statfs *mp;
59174071Sps	struct fstab *fs;
59212032Speter	char dev[MNAMELEN + 1];
59312032Speter	char *nm;
59412032Speter	int cnt;
59512032Speter
59612032Speter	func = douser;
59712032Speter#ifndef	COMPAT
59812032Speter	header = getbsize(&headerlen,&blocksize);
59912032Speter#endif
60012032Speter	while (--argc > 0 && **++argv == '-') {
60112032Speter		while (*++*argv) {
60212032Speter			switch (**argv) {
60312032Speter			case 'n':
60412032Speter				func = donames;
60512032Speter				break;
60612032Speter			case 'c':
60712032Speter				func = dofsizes;
60812032Speter				break;
60912032Speter			case 'a':
61012032Speter				all = 1;
61112032Speter				break;
61212032Speter			case 'f':
61312032Speter				count = 1;
61412032Speter				break;
61512032Speter			case 'h':
61612032Speter				estimate = 1;
61712032Speter				break;
61812032Speter#ifndef	COMPAT
61912032Speter			case 'k':
62012032Speter				blocksize = 1024;
62112032Speter				break;
62212032Speter#endif	/* COMPAT */
62312032Speter			case 'v':
62412032Speter				unused = 1;
62512032Speter				break;
62612032Speter			default:
62712032Speter				usage();
62812032Speter			}
62912032Speter		}
63012032Speter	}
63112032Speter	if (all) {
63212032Speter		cnt = getmntinfo(&mp,MNT_NOWAIT);
63312032Speter		for (; --cnt >= 0; mp++) {
63432595Sbde			if (!strncmp(mp->f_fstypename, "ufs", MFSNAMELEN)) {
63530262Scharnier				if ((nm = strrchr(mp->f_mntfromname,'/'))) {
63669793Sobrien					sprintf(dev,"%s%s",_PATH_DEV,nm + 1);
63712032Speter					nm = dev;
63812032Speter				} else
63912032Speter					nm = mp->f_mntfromname;
64012032Speter				quot(nm,mp->f_mntonname);
64112032Speter			}
64212032Speter		}
64312032Speter	}
64474071Sps	while (--argc >= 0) {
64574071Sps		if ((fs = getfsfile(*argv)) != NULL)
64674071Sps			quot(fs->fs_spec, 0);
64774071Sps		else
64874071Sps			quot(*argv,0);
64974071Sps		argv++;
65074071Sps	}
65112032Speter	return 0;
65212032Speter}
653