1*87ba0e2aSchs /* $NetBSD: quot.c,v 1.35 2022/11/17 06:40:41 chs Exp $ */
202132669Sws
366ffc9f8Sws /*
466ffc9f8Sws * Copyright (C) 1991, 1994 Wolfgang Solfrank.
566ffc9f8Sws * Copyright (C) 1991, 1994 TooLs GmbH.
666ffc9f8Sws * All rights reserved.
766ffc9f8Sws *
866ffc9f8Sws * Redistribution and use in source and binary forms, with or without
966ffc9f8Sws * modification, are permitted provided that the following conditions
1066ffc9f8Sws * are met:
1166ffc9f8Sws * 1. Redistributions of source code must retain the above copyright
1266ffc9f8Sws * notice, this list of conditions and the following disclaimer.
1366ffc9f8Sws * 2. Redistributions in binary form must reproduce the above copyright
1466ffc9f8Sws * notice, this list of conditions and the following disclaimer in the
1566ffc9f8Sws * documentation and/or other materials provided with the distribution.
1666ffc9f8Sws * 3. All advertising materials mentioning features or use of this software
1766ffc9f8Sws * must display the following acknowledgement:
1866ffc9f8Sws * This product includes software developed by TooLs GmbH.
1966ffc9f8Sws * 4. The name of TooLs GmbH may not be used to endorse or promote products
2066ffc9f8Sws * derived from this software without specific prior written permission.
2166ffc9f8Sws *
2266ffc9f8Sws * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
2366ffc9f8Sws * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2466ffc9f8Sws * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2566ffc9f8Sws * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2666ffc9f8Sws * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2766ffc9f8Sws * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2866ffc9f8Sws * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2966ffc9f8Sws * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
3066ffc9f8Sws * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
3166ffc9f8Sws * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3266ffc9f8Sws */
335b9674ecScgd
34d07d0944Slukem #include <sys/cdefs.h>
355b9674ecScgd #ifndef lint
36*87ba0e2aSchs __RCSID("$NetBSD: quot.c,v 1.35 2022/11/17 06:40:41 chs Exp $");
375b9674ecScgd #endif /* not lint */
385b9674ecScgd
394417e586Scgd #include <sys/param.h>
404417e586Scgd #include <sys/mount.h>
414417e586Scgd #include <sys/time.h>
4242614ed3Sfvdl #include <ufs/ufs/dinode.h>
43e5bc90f4Sfvdl #include <ufs/ffs/fs.h>
444417e586Scgd
45de441420Slukem #include <err.h>
46d07d0944Slukem #include <errno.h>
47d07d0944Slukem #include <fcntl.h>
48d07d0944Slukem #include <pwd.h>
4966ffc9f8Sws #include <stdio.h>
5066ffc9f8Sws #include <stdlib.h>
5166ffc9f8Sws #include <string.h>
5230cdcc3bSmrg #include <unistd.h>
5366ffc9f8Sws
5466ffc9f8Sws /* some flags of what to do: */
5566ffc9f8Sws static char estimate;
5666ffc9f8Sws static char count;
5766ffc9f8Sws static char unused;
58e73fcb71Schristos static void (*func)(int, struct fs *, const char *);
5966ffc9f8Sws static long blocksize;
6066ffc9f8Sws static char *header;
6166ffc9f8Sws
625b9674ecScgd /*
635b9674ecScgd * Original BSD quot doesn't round to number of frags/blocks,
645b9674ecScgd * doesn't account for indirection blocks and gets it totally
655b9674ecScgd * wrong if the size is a multiple of the blocksize.
6602132669Sws * The new code always counts the number of DEV_BSIZE byte blocks
675b9674ecScgd * instead of the number of kilobytes and converts them to
685b9674ecScgd * kByte when done (on request).
695b9674ecScgd */
7066ffc9f8Sws #ifdef COMPAT
71c960d1daSmycroft #define SIZE(n) ((long long)(n))
7266ffc9f8Sws #else
73c960d1daSmycroft #define SIZE(n) howmany((long long)(n) * DEV_BSIZE, (long long)blocksize)
7466ffc9f8Sws #endif
7566ffc9f8Sws
7666ffc9f8Sws #define INOCNT(fs) ((fs)->fs_ipg)
7742614ed3Sfvdl #define INOSZ(fs) \
7842614ed3Sfvdl (((fs)->fs_magic == FS_UFS1_MAGIC ? sizeof(struct ufs1_dinode) : \
7942614ed3Sfvdl sizeof(struct ufs2_dinode)) * INOCNT(fs))
8042614ed3Sfvdl
8142614ed3Sfvdl union dinode {
8242614ed3Sfvdl struct ufs1_dinode dp1;
8342614ed3Sfvdl struct ufs2_dinode dp2;
8442614ed3Sfvdl };
8542614ed3Sfvdl #define DIP(fs, dp, field) \
8642614ed3Sfvdl (((fs)->fs_magic == FS_UFS1_MAGIC) ? \
8742614ed3Sfvdl (dp)->dp1.di_##field : (dp)->dp2.di_##field)
8842614ed3Sfvdl
8966ffc9f8Sws
90e73fcb71Schristos static int cmpusers(const void *, const void *);
91e73fcb71Schristos static void dofsizes(int, struct fs *, const char *);
92e73fcb71Schristos static void donames(int, struct fs *, const char *);
93e73fcb71Schristos static void douser(int, struct fs *, const char *);
94e73fcb71Schristos static union dinode *get_inode(int, struct fs *, ino_t);
95e73fcb71Schristos static void ffs_oldfscompat(struct fs *);
96e73fcb71Schristos static void initfsizes(void);
97e73fcb71Schristos static void inituser(void);
98e73fcb71Schristos static int isfree(struct fs *, union dinode *);
99e73fcb71Schristos static void quot(const char *, const char *);
100e73fcb71Schristos static void usage(void) __attribute__((__noreturn__));
101e73fcb71Schristos static struct user *user(uid_t);
102e73fcb71Schristos static void uses(uid_t, daddr_t, time_t);
103e73fcb71Schristos static void usrrehash(void);
104e73fcb71Schristos static int virtualblocks(struct fs *, union dinode *);
105d07d0944Slukem
106d07d0944Slukem
10742614ed3Sfvdl static union dinode *
get_inode(int fd,struct fs * super,ino_t ino)108e73fcb71Schristos get_inode(int fd, struct fs *super, ino_t ino)
10966ffc9f8Sws {
11042614ed3Sfvdl static char *ipbuf;
11166ffc9f8Sws static ino_t last;
11266ffc9f8Sws
11366ffc9f8Sws if (fd < 0) { /* flush cache */
11442614ed3Sfvdl if (ipbuf) {
11542614ed3Sfvdl free(ipbuf);
11642614ed3Sfvdl ipbuf = NULL;
11766ffc9f8Sws }
11866ffc9f8Sws return 0;
11966ffc9f8Sws }
12066ffc9f8Sws
12142614ed3Sfvdl if (!ipbuf || ino < last || ino >= last + INOCNT(super)) {
12242614ed3Sfvdl if (!ipbuf
12342614ed3Sfvdl && !(ipbuf = malloc(INOSZ(super))))
124de441420Slukem errx(1, "allocate inodes");
12566ffc9f8Sws last = (ino / INOCNT(super)) * INOCNT(super);
12602132669Sws if (lseek(fd,
12702132669Sws (off_t)ino_to_fsba(super, last) << super->fs_fshift,
12811f8dfe5Smycroft 0) < 0 ||
129e73fcb71Schristos read(fd, ipbuf, INOSZ(super)) != (ssize_t)INOSZ(super))
130de441420Slukem errx(1, "read inodes");
13166ffc9f8Sws }
13266ffc9f8Sws
13342614ed3Sfvdl if (super->fs_magic == FS_UFS1_MAGIC)
13442614ed3Sfvdl return ((union dinode *)
13542614ed3Sfvdl &((struct ufs1_dinode *)ipbuf)[ino % INOCNT(super)]);
13642614ed3Sfvdl return ((union dinode *)
13742614ed3Sfvdl &((struct ufs2_dinode *)ipbuf)[ino % INOCNT(super)]);
13866ffc9f8Sws }
13966ffc9f8Sws
14066ffc9f8Sws #ifdef COMPAT
141e73fcb71Schristos #define actualblocks(fs, dp) (int)(DIP(fs, dp, blocks) / 2)
14266ffc9f8Sws #else
143e73fcb71Schristos #define actualblocks(fs, dp) (int)(DIP(fs, dp, blocks))
14466ffc9f8Sws #endif
14566ffc9f8Sws
14602132669Sws static int
virtualblocks(struct fs * super,union dinode * dp)147e73fcb71Schristos virtualblocks(struct fs *super, union dinode *dp)
14866ffc9f8Sws {
149de441420Slukem off_t nblk, sz;
15066ffc9f8Sws
15142614ed3Sfvdl sz = DIP(super, dp, size);
15266ffc9f8Sws #ifdef COMPAT
153e1610ba4Sdholland if (ffs_lblkno(super, sz) >= UFS_NDADDR) {
154e1610ba4Sdholland nblk = ffs_blkroundup(super, sz);
15566ffc9f8Sws if (sz == nblk)
15666ffc9f8Sws nblk += super->fs_bsize;
15766ffc9f8Sws }
15866ffc9f8Sws
15966ffc9f8Sws return sz / 1024;
16066ffc9f8Sws #else /* COMPAT */
16166ffc9f8Sws
162e1610ba4Sdholland if (ffs_lblkno(super, sz) >= UFS_NDADDR) {
163e1610ba4Sdholland nblk = ffs_blkroundup(super, sz);
164e1610ba4Sdholland sz = ffs_lblkno(super, nblk);
165f1333577Sdholland sz = howmany(sz - UFS_NDADDR, FFS_NINDIR(super));
16666ffc9f8Sws while (sz > 0) {
16766ffc9f8Sws nblk += sz * super->fs_bsize;
16802132669Sws /* One block on this level is in the inode itself */
169f1333577Sdholland sz = howmany(sz - 1, FFS_NINDIR(super));
17066ffc9f8Sws }
17166ffc9f8Sws } else
172e1610ba4Sdholland nblk = ffs_fragroundup(super, sz);
17366ffc9f8Sws
17402132669Sws return nblk / DEV_BSIZE;
17566ffc9f8Sws #endif /* COMPAT */
17666ffc9f8Sws }
17766ffc9f8Sws
17802132669Sws static int
isfree(fs,dp)17942614ed3Sfvdl isfree(fs, dp)
18042614ed3Sfvdl struct fs *fs;
18142614ed3Sfvdl union dinode *dp;
18266ffc9f8Sws {
18366ffc9f8Sws #ifdef COMPAT
18442614ed3Sfvdl return (DIP(fs, dp, mode) & IFMT) == 0;
18566ffc9f8Sws #else /* COMPAT */
18642614ed3Sfvdl switch (DIP(fs, dp, mode) & IFMT) {
18766ffc9f8Sws case IFIFO:
18866ffc9f8Sws case IFLNK: /* should check FASTSYMLINK? */
18966ffc9f8Sws case IFDIR:
19066ffc9f8Sws case IFREG:
19166ffc9f8Sws return 0;
19266ffc9f8Sws default:
19366ffc9f8Sws return 1;
19466ffc9f8Sws }
19566ffc9f8Sws #endif
19666ffc9f8Sws }
19766ffc9f8Sws
19866ffc9f8Sws static struct user {
19966ffc9f8Sws uid_t uid;
20066ffc9f8Sws char *name;
20166ffc9f8Sws daddr_t space;
20266ffc9f8Sws long count;
20366ffc9f8Sws daddr_t spc30;
20466ffc9f8Sws daddr_t spc60;
20566ffc9f8Sws daddr_t spc90;
20666ffc9f8Sws } *users;
20766ffc9f8Sws static int nusers;
20866ffc9f8Sws
20902132669Sws static void
inituser(void)210e73fcb71Schristos inituser(void)
21166ffc9f8Sws {
212de441420Slukem int i;
213de441420Slukem struct user *usr;
21466ffc9f8Sws
21566ffc9f8Sws if (!nusers) {
21666ffc9f8Sws nusers = 8;
217e73fcb71Schristos if (!(users = calloc(nusers, sizeof(*users))))
218e73fcb71Schristos err(1, "allocate users");
21966ffc9f8Sws } else {
22066ffc9f8Sws for (usr = users, i = nusers; --i >= 0; usr++) {
22166ffc9f8Sws usr->space = usr->spc30 = usr->spc60 = usr->spc90 = 0;
22266ffc9f8Sws usr->count = 0;
22366ffc9f8Sws }
22466ffc9f8Sws }
22566ffc9f8Sws }
22666ffc9f8Sws
22702132669Sws static void
usrrehash(void)228e73fcb71Schristos usrrehash(void)
22966ffc9f8Sws {
230de441420Slukem int i;
231de441420Slukem struct user *usr, *usrn;
23266ffc9f8Sws struct user *svusr;
23366ffc9f8Sws
23466ffc9f8Sws svusr = users;
23566ffc9f8Sws nusers <<= 1;
236e73fcb71Schristos if (!(users = calloc(nusers, sizeof(*users))))
237e73fcb71Schristos err(1, "allocate users");
23866ffc9f8Sws for (usr = svusr, i = nusers >> 1; --i >= 0; usr++) {
23902132669Sws for (usrn = users + (usr->uid&(nusers - 1));
24002132669Sws usrn->name;
2415b9674ecScgd usrn--) {
24266ffc9f8Sws if (usrn <= users)
24366ffc9f8Sws usrn = users + nusers;
24466ffc9f8Sws }
24566ffc9f8Sws *usrn = *usr;
24666ffc9f8Sws }
24766ffc9f8Sws }
24866ffc9f8Sws
24902132669Sws static struct user *
user(uid_t uid)250e73fcb71Schristos user(uid_t uid)
25166ffc9f8Sws {
252de441420Slukem struct user *usr;
253de441420Slukem int i;
25466ffc9f8Sws struct passwd *pwd;
25566ffc9f8Sws
256e73fcb71Schristos for (;;) {
25702132669Sws for (usr = users + (uid & (nusers - 1)), i = nusers;
25802132669Sws --i >= 0;
2595b9674ecScgd usr--) {
26066ffc9f8Sws if (!usr->name) {
26166ffc9f8Sws usr->uid = uid;
26266ffc9f8Sws
263e73fcb71Schristos if (!(pwd = getpwuid(uid)))
264e73fcb71Schristos asprintf(&usr->name, "#%u", uid);
265e73fcb71Schristos else
266e73fcb71Schristos asprintf(&usr->name, "%s",
267e73fcb71Schristos pwd->pw_name);
268de441420Slukem if (!usr->name)
269de441420Slukem errx(1, "allocate users");
27066ffc9f8Sws return usr;
27166ffc9f8Sws } else if (usr->uid == uid)
27266ffc9f8Sws return usr;
27366ffc9f8Sws
27466ffc9f8Sws if (usr <= users)
27566ffc9f8Sws usr = users + nusers;
27666ffc9f8Sws }
27766ffc9f8Sws usrrehash();
27866ffc9f8Sws }
27966ffc9f8Sws }
28066ffc9f8Sws
28102132669Sws static int
cmpusers(u1,u2)28202132669Sws cmpusers(u1, u2)
283d07d0944Slukem const void *u1, *u2;
28466ffc9f8Sws {
2854d2da769Slukem return ((const struct user *)u2)->space - ((const struct user *)u1)->space;
28666ffc9f8Sws }
2875b9674ecScgd
2885b9674ecScgd #define sortusers(users) (qsort((users), nusers, sizeof(struct user), \
2895b9674ecScgd cmpusers))
29066ffc9f8Sws
29102132669Sws static void
uses(uid,blks,act)29202132669Sws uses(uid, blks, act)
29366ffc9f8Sws uid_t uid;
29466ffc9f8Sws daddr_t blks;
29566ffc9f8Sws time_t act;
29666ffc9f8Sws {
29766ffc9f8Sws static time_t today;
298de441420Slukem struct user *usr;
29966ffc9f8Sws
30066ffc9f8Sws if (!today)
30166ffc9f8Sws time(&today);
30266ffc9f8Sws
30366ffc9f8Sws usr = user(uid);
30466ffc9f8Sws usr->count++;
30566ffc9f8Sws usr->space += blks;
30666ffc9f8Sws
30766ffc9f8Sws if (today - act > 90L * 24L * 60L * 60L)
30866ffc9f8Sws usr->spc90 += blks;
30966ffc9f8Sws if (today - act > 60L * 24L * 60L * 60L)
31066ffc9f8Sws usr->spc60 += blks;
31166ffc9f8Sws if (today - act > 30L * 24L * 60L * 60L)
31266ffc9f8Sws usr->spc30 += blks;
31366ffc9f8Sws }
31466ffc9f8Sws
31566ffc9f8Sws #ifdef COMPAT
31666ffc9f8Sws #define FSZCNT 500
31766ffc9f8Sws #else
31866ffc9f8Sws #define FSZCNT 512
31966ffc9f8Sws #endif
32066ffc9f8Sws struct fsizes {
32166ffc9f8Sws struct fsizes *fsz_next;
32266ffc9f8Sws daddr_t fsz_first, fsz_last;
32366ffc9f8Sws ino_t fsz_count[FSZCNT];
32466ffc9f8Sws daddr_t fsz_sz[FSZCNT];
32566ffc9f8Sws } *fsizes;
32666ffc9f8Sws
32702132669Sws static void
initfsizes()32802132669Sws initfsizes()
32966ffc9f8Sws {
330de441420Slukem struct fsizes *fp;
331de441420Slukem int i;
33266ffc9f8Sws
33366ffc9f8Sws for (fp = fsizes; fp; fp = fp->fsz_next) {
33466ffc9f8Sws for (i = FSZCNT; --i >= 0;) {
33566ffc9f8Sws fp->fsz_count[i] = 0;
33666ffc9f8Sws fp->fsz_sz[i] = 0;
33766ffc9f8Sws }
33866ffc9f8Sws }
33966ffc9f8Sws }
34066ffc9f8Sws
34102132669Sws static void
dofsizes(int fd,struct fs * super,const char * name)342e73fcb71Schristos dofsizes(int fd, struct fs *super, const char *name)
34366ffc9f8Sws {
34466ffc9f8Sws ino_t inode, maxino;
34542614ed3Sfvdl union dinode *dp;
34666ffc9f8Sws daddr_t sz, ksz;
34766ffc9f8Sws struct fsizes *fp, **fsp;
348de441420Slukem int i;
34966ffc9f8Sws
35066ffc9f8Sws maxino = super->fs_ncg * super->fs_ipg - 1;
35166ffc9f8Sws #ifdef COMPAT
352e73fcb71Schristos if (!(fsizes = malloc(sizeof(*fsizes))))
353e73fcb71Schristos err(1, "alloc fsize structure");
35466ffc9f8Sws #endif /* COMPAT */
35566ffc9f8Sws for (inode = 0; inode < maxino; inode++) {
35666ffc9f8Sws errno = 0;
35742614ed3Sfvdl if ((dp = get_inode(fd, super, inode))
35866ffc9f8Sws #ifdef COMPAT
35942614ed3Sfvdl && ((DIP(super, dp, mode) & IFMT) == IFREG
36042614ed3Sfvdl || (DIP(dp, mode) & IFMT) == IFDIR)
36166ffc9f8Sws #else /* COMPAT */
36242614ed3Sfvdl && !isfree(super, dp)
36366ffc9f8Sws #endif /* COMPAT */
36466ffc9f8Sws ) {
36542614ed3Sfvdl sz = estimate ? virtualblocks(super, dp) :
36642614ed3Sfvdl actualblocks(super, dp);
36766ffc9f8Sws #ifdef COMPAT
36866ffc9f8Sws if (sz >= FSZCNT) {
36966ffc9f8Sws fsizes->fsz_count[FSZCNT-1]++;
37066ffc9f8Sws fsizes->fsz_sz[FSZCNT-1] += sz;
37166ffc9f8Sws } else {
37266ffc9f8Sws fsizes->fsz_count[sz]++;
37366ffc9f8Sws fsizes->fsz_sz[sz] += sz;
37466ffc9f8Sws }
37566ffc9f8Sws #else /* COMPAT */
37666ffc9f8Sws ksz = SIZE(sz);
377d07d0944Slukem for (fsp = &fsizes; (fp = *fsp) != NULL;
378d07d0944Slukem fsp = &fp->fsz_next) {
37966ffc9f8Sws if (ksz < fp->fsz_last)
38066ffc9f8Sws break;
38166ffc9f8Sws }
38266ffc9f8Sws if (!fp || ksz < fp->fsz_first) {
383e73fcb71Schristos if (!(fp = malloc(sizeof(*fp))))
384e73fcb71Schristos err(1, "alloc fsize structure");
38566ffc9f8Sws fp->fsz_next = *fsp;
38666ffc9f8Sws *fsp = fp;
38766ffc9f8Sws fp->fsz_first = (ksz / FSZCNT) * FSZCNT;
38866ffc9f8Sws fp->fsz_last = fp->fsz_first + FSZCNT;
38966ffc9f8Sws for (i = FSZCNT; --i >= 0;) {
39066ffc9f8Sws fp->fsz_count[i] = 0;
39166ffc9f8Sws fp->fsz_sz[i] = 0;
39266ffc9f8Sws }
39366ffc9f8Sws }
39466ffc9f8Sws fp->fsz_count[ksz % FSZCNT]++;
39566ffc9f8Sws fp->fsz_sz[ksz % FSZCNT] += sz;
39666ffc9f8Sws #endif /* COMPAT */
397de441420Slukem } else if (errno)
398de441420Slukem errx(1, "%s", name);
39966ffc9f8Sws }
40066ffc9f8Sws sz = 0;
40166ffc9f8Sws for (fp = fsizes; fp; fp = fp->fsz_next) {
40266ffc9f8Sws for (i = 0; i < FSZCNT; i++) {
40366ffc9f8Sws if (fp->fsz_count[i])
404c960d1daSmycroft printf("%ld\t%ld\t%lld\n",
405d07d0944Slukem (long)(fp->fsz_first + i),
406d07d0944Slukem (long)fp->fsz_count[i],
407357cd619Smycroft SIZE(sz += fp->fsz_sz[i]));
40866ffc9f8Sws }
40966ffc9f8Sws }
41066ffc9f8Sws }
41166ffc9f8Sws
41202132669Sws static void
douser(int fd,struct fs * super,const char * name)413e73fcb71Schristos douser(int fd, struct fs *super, const char *name)
41466ffc9f8Sws {
41566ffc9f8Sws ino_t inode, maxino;
41666ffc9f8Sws struct user *usr, *usrs;
41742614ed3Sfvdl union dinode *dp;
418de441420Slukem int n;
41966ffc9f8Sws
42066ffc9f8Sws maxino = super->fs_ncg * super->fs_ipg - 1;
42166ffc9f8Sws for (inode = 0; inode < maxino; inode++) {
42266ffc9f8Sws errno = 0;
42342614ed3Sfvdl if ((dp = get_inode(fd, super, inode))
42442614ed3Sfvdl && !isfree(super, dp))
42542614ed3Sfvdl uses(DIP(super, dp, uid),
42642614ed3Sfvdl estimate ? virtualblocks(super, dp) :
42742614ed3Sfvdl actualblocks(super, dp), DIP(super, dp, atime));
428de441420Slukem else if (errno)
429de441420Slukem errx(1, "%s", name);
43066ffc9f8Sws }
431e73fcb71Schristos if (!(usrs = calloc(nusers, sizeof(*usrs))))
432de441420Slukem errx(1, "allocate users");
433e73fcb71Schristos memmove(usrs, users, nusers * sizeof(*usrs));
43466ffc9f8Sws sortusers(usrs);
43566ffc9f8Sws for (usr = usrs, n = nusers; --n >= 0 && usr->count; usr++) {
436c960d1daSmycroft printf("%5lld", SIZE(usr->space));
43766ffc9f8Sws if (count)
438357cd619Smycroft printf("\t%5ld", usr->count);
43966ffc9f8Sws printf("\t%-8s", usr->name);
44066ffc9f8Sws if (unused)
441c960d1daSmycroft printf("\t%5lld\t%5lld\t%5lld",
44211f8dfe5Smycroft SIZE(usr->spc30), SIZE(usr->spc60),
44366ffc9f8Sws SIZE(usr->spc90));
44466ffc9f8Sws printf("\n");
44566ffc9f8Sws }
44666ffc9f8Sws free(usrs);
44766ffc9f8Sws }
44866ffc9f8Sws
44902132669Sws static void
donames(int fd,struct fs * super,const char * name)450e73fcb71Schristos donames(int fd, struct fs *super, const char *name)
45166ffc9f8Sws {
45266ffc9f8Sws int c;
4530a77b69aSchristos ino_t inode;
4540a77b69aSchristos #ifdef COMPAT
4550a77b69aSchristos ino_t inode1 = -1;
4560a77b69aSchristos #endif
45766ffc9f8Sws ino_t maxino;
45842614ed3Sfvdl union dinode *dp;
45966ffc9f8Sws
46066ffc9f8Sws maxino = super->fs_ncg * super->fs_ipg - 1;
46166ffc9f8Sws /* first skip the name of the filesystem */
46266ffc9f8Sws while ((c = getchar()) != EOF && (c < '0' || c > '9'))
46366ffc9f8Sws while ((c = getchar()) != EOF && c != '\n');
46466ffc9f8Sws ungetc(c, stdin);
465ed574610Skent while (scanf("%" SCNu64, &inode) == 1) {
4664d2da769Slukem if (inode > maxino) {
46702132669Sws #ifndef COMPAT
468ed574610Skent warnx("invalid inode %" PRIu64, inode);
46902132669Sws #endif
47066ffc9f8Sws return;
47166ffc9f8Sws }
47202132669Sws #ifdef COMPAT
47302132669Sws if (inode < inode1)
47402132669Sws continue;
47502132669Sws #endif
47666ffc9f8Sws errno = 0;
47742614ed3Sfvdl if ((dp = get_inode(fd, super, inode))
47842614ed3Sfvdl && !isfree(super, dp)) {
47942614ed3Sfvdl printf("%s\t", user(DIP(super, dp, uid))->name);
48066ffc9f8Sws /* now skip whitespace */
48166ffc9f8Sws while ((c = getchar()) == ' ' || c == '\t');
48266ffc9f8Sws /* and print out the remainder of the input line */
48366ffc9f8Sws while (c != EOF && c != '\n') {
48466ffc9f8Sws putchar(c);
48566ffc9f8Sws c = getchar();
48666ffc9f8Sws }
48766ffc9f8Sws putchar('\n');
4880a77b69aSchristos #ifdef COMPAT
48966ffc9f8Sws inode1 = inode;
4900a77b69aSchristos #endif
49166ffc9f8Sws } else {
492de441420Slukem if (errno)
493de441420Slukem errx(1, "%s", name);
49466ffc9f8Sws /* skip this line */
495e73fcb71Schristos while ((c = getchar()) != EOF && c != '\n')
496e73fcb71Schristos continue;
49766ffc9f8Sws }
49866ffc9f8Sws if (c == EOF)
49966ffc9f8Sws break;
50066ffc9f8Sws }
50166ffc9f8Sws }
50266ffc9f8Sws
50302132669Sws static void
usage(void)504e73fcb71Schristos usage(void)
50566ffc9f8Sws {
506e73fcb71Schristos const char *p = getprogname();
50766ffc9f8Sws #ifdef COMPAT
508e73fcb71Schristos fprintf(stderr, "Usage: %s [-nfcvha] [<filesystem> ...]\n", p);
50966ffc9f8Sws #else /* COMPAT */
510e73fcb71Schristos fprintf(stderr, "Usage: %s [ -acfhknv ] [<filesystem> ... ]\n", p);
51166ffc9f8Sws #endif /* COMPAT */
51266ffc9f8Sws exit(1);
51366ffc9f8Sws }
51466ffc9f8Sws
51502132669Sws /*
51602132669Sws * Sanity checks for old file systems.
51702132669Sws * Stolen from <sys/lib/libsa/ufs.c>
51802132669Sws */
51902132669Sws static void
ffs_oldfscompat(struct fs * fs)520e73fcb71Schristos ffs_oldfscompat(struct fs *fs)
52102132669Sws {
52202132669Sws int i;
52302132669Sws
524f0b8f9c1Smartin if (fs->fs_magic == FS_UFS1_MAGIC &&
525f0b8f9c1Smartin fs->fs_old_inodefmt < FS_44INODEFMT) {
52642614ed3Sfvdl quad_t sizepb = fs->fs_bsize;
52742614ed3Sfvdl
528dcd34a91Sdholland fs->fs_maxfilesize = fs->fs_bsize * UFS_NDADDR - 1;
529dcd34a91Sdholland for (i = 0; i < UFS_NIADDR; i++) {
530f1333577Sdholland sizepb *= FFS_NINDIR(fs);
53142614ed3Sfvdl fs->fs_maxfilesize += sizepb;
53202132669Sws }
53342614ed3Sfvdl fs->fs_qbmask = ~fs->fs_bmask;
53442614ed3Sfvdl fs->fs_qfmask = ~fs->fs_fmask;
53542614ed3Sfvdl }
53642614ed3Sfvdl }
53742614ed3Sfvdl
53842614ed3Sfvdl /*
53942614ed3Sfvdl * Possible superblock locations ordered from most to least likely.
54042614ed3Sfvdl */
54142614ed3Sfvdl static int sblock_try[] = SBLOCKSEARCH;
54242614ed3Sfvdl static char superblock[SBLOCKSIZE];
54342614ed3Sfvdl
54402132669Sws
545e73fcb71Schristos static void
quot(const char * name,const char * mp)546e73fcb71Schristos quot(const char *name, const char *mp)
54766ffc9f8Sws {
54842614ed3Sfvdl int fd, i;
54942614ed3Sfvdl struct fs *fs;
550a78ca723Sdsl int sbloc;
55166ffc9f8Sws
552d07d0944Slukem get_inode(-1, 0, 0); /* flush cache */
55366ffc9f8Sws inituser();
55466ffc9f8Sws initfsizes();
55542614ed3Sfvdl if ((fd = open(name, 0)) < 0) {
556507e5c88Smrg warn("%s", name);
55766ffc9f8Sws return;
55866ffc9f8Sws }
55942614ed3Sfvdl
560a78ca723Sdsl for (i = 0; ; i++) {
561a78ca723Sdsl sbloc = sblock_try[i];
562a78ca723Sdsl if (sbloc == -1) {
563de441420Slukem warnx("%s: not a BSD filesystem", name);
56466ffc9f8Sws close(fd);
56566ffc9f8Sws return;
56666ffc9f8Sws }
567a78ca723Sdsl if (pread(fd, superblock, SBLOCKSIZE, sbloc) != SBLOCKSIZE)
568a78ca723Sdsl continue;
569a78ca723Sdsl fs = (struct fs *)superblock;
570a78ca723Sdsl
571a78ca723Sdsl if (fs->fs_magic != FS_UFS1_MAGIC &&
572*87ba0e2aSchs fs->fs_magic != FS_UFS2_MAGIC &&
573*87ba0e2aSchs fs->fs_magic != FS_UFS2EA_MAGIC)
574a78ca723Sdsl continue;
575a78ca723Sdsl
576893680a0Sdsl if (fs->fs_magic == FS_UFS2_MAGIC
577*87ba0e2aSchs || fs->fs_magic == FS_UFS2EA_MAGIC
578893680a0Sdsl || fs->fs_old_flags & FS_FLAGS_UPDATED) {
579a78ca723Sdsl /* Not the main superblock */
580a78ca723Sdsl if (fs->fs_sblockloc != sbloc)
581a78ca723Sdsl continue;
582a78ca723Sdsl } else {
583a78ca723Sdsl /* might be a first alt. id blocksize 64k */
584a78ca723Sdsl if (sbloc == SBLOCK_UFS2)
585a78ca723Sdsl continue;
586a78ca723Sdsl }
587a78ca723Sdsl
588a78ca723Sdsl if (fs->fs_bsize > MAXBSIZE ||
589e73fcb71Schristos (size_t)fs->fs_bsize < sizeof(struct fs))
590a78ca723Sdsl continue;
591a78ca723Sdsl break;
592a78ca723Sdsl }
593a78ca723Sdsl
594d07d0944Slukem ffs_oldfscompat((struct fs *)superblock);
59566ffc9f8Sws printf("%s:", name);
59666ffc9f8Sws if (mp)
59766ffc9f8Sws printf(" (%s)", mp);
59866ffc9f8Sws putchar('\n');
59942614ed3Sfvdl (*func)(fd, fs, name);
60066ffc9f8Sws close(fd);
60166ffc9f8Sws }
60266ffc9f8Sws
60302132669Sws int
main(int argc,char ** argv)604e73fcb71Schristos main(int argc, char **argv)
60566ffc9f8Sws {
60666ffc9f8Sws char all = 0;
6076bd1d6d4Schristos struct statvfs *mp;
60866ffc9f8Sws char dev[MNAMELEN + 1];
60966ffc9f8Sws char *nm;
61066ffc9f8Sws int cnt;
61166ffc9f8Sws
61266ffc9f8Sws func = douser;
61366ffc9f8Sws #ifndef COMPAT
614ae46649fSsimonb header = getbsize(NULL, &blocksize);
61566ffc9f8Sws #endif
61666ffc9f8Sws while (--argc > 0 && **++argv == '-') {
61766ffc9f8Sws while (*++*argv) {
61866ffc9f8Sws switch (**argv) {
61966ffc9f8Sws case 'n':
62066ffc9f8Sws func = donames;
62166ffc9f8Sws break;
62266ffc9f8Sws case 'c':
62366ffc9f8Sws func = dofsizes;
62466ffc9f8Sws break;
62566ffc9f8Sws case 'a':
62666ffc9f8Sws all = 1;
62766ffc9f8Sws break;
62866ffc9f8Sws case 'f':
62966ffc9f8Sws count = 1;
63066ffc9f8Sws break;
63166ffc9f8Sws case 'h':
63266ffc9f8Sws estimate = 1;
63366ffc9f8Sws break;
63466ffc9f8Sws #ifndef COMPAT
63566ffc9f8Sws case 'k':
63666ffc9f8Sws blocksize = 1024;
63766ffc9f8Sws break;
63866ffc9f8Sws #endif /* COMPAT */
63966ffc9f8Sws case 'v':
64066ffc9f8Sws unused = 1;
64166ffc9f8Sws break;
64266ffc9f8Sws default:
64366ffc9f8Sws usage();
64466ffc9f8Sws }
64566ffc9f8Sws }
64666ffc9f8Sws }
64766ffc9f8Sws if (all) {
64866ffc9f8Sws cnt = getmntinfo(&mp, MNT_NOWAIT);
64966ffc9f8Sws for (; --cnt >= 0; mp++) {
65063bf90c6Schristos if (!strncmp(mp->f_fstypename, MOUNT_FFS,
65163bf90c6Schristos sizeof(mp->f_fstypename))) {
652d07d0944Slukem if ((nm =
653d07d0944Slukem strrchr(mp->f_mntfromname, '/')) != NULL) {
654e73fcb71Schristos snprintf(dev, sizeof(dev), "/dev/r%s",
655e73fcb71Schristos nm + 1);
65666ffc9f8Sws nm = dev;
65766ffc9f8Sws } else
65866ffc9f8Sws nm = mp->f_mntfromname;
65966ffc9f8Sws quot(nm, mp->f_mntonname);
66066ffc9f8Sws }
66166ffc9f8Sws }
66266ffc9f8Sws }
66366ffc9f8Sws while (--argc >= 0)
66466ffc9f8Sws quot(*argv++, 0);
66566ffc9f8Sws return 0;
66666ffc9f8Sws }
667