From 153fe8c3bc0f5a2a0b0ff7075fe41d2d0ef10934 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 3 Nov 1995 15:06:04 +0000 Subject: Import NetBSD's quot command, filling the gap in our sources (We only have the man page...) Obtained from: NetBSD; Wolfgang Solfrank / TooLs GmbH. --- usr.sbin/quot/quot.c | 583 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 583 insertions(+) create mode 100644 usr.sbin/quot/quot.c (limited to 'usr.sbin/quot/quot.c') diff --git a/usr.sbin/quot/quot.c b/usr.sbin/quot/quot.c new file mode 100644 index 0000000..e5f2daa --- /dev/null +++ b/usr.sbin/quot/quot.c @@ -0,0 +1,583 @@ +/* + * Copyright (C) 1991, 1994 Wolfgang Solfrank. + * Copyright (C) 1991, 1994 TooLs GmbH. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef lint +static char rcsid[] = "$Id: quot.c,v 1.6.4.1 1995/11/01 00:06:41 jtc Exp $"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* some flags of what to do: */ +static char estimate; +static char count; +static char unused; +static int (*func)(); +static long blocksize; +static char *header; +static int headerlen; + +/* + * Original BSD quot doesn't round to number of frags/blocks, + * doesn't account for indirection blocks and gets it totally + * wrong if the size is a multiple of the blocksize. + * The new code always counts the number of 512 byte blocks + * instead of the number of kilobytes and converts them to + * kByte when done (on request). + */ +#ifdef COMPAT +#define SIZE(n) (n) +#else +#define SIZE(n) (((n) * 512 + blocksize - 1)/blocksize) +#endif + +#define INOCNT(fs) ((fs)->fs_ipg) +#define INOSZ(fs) (sizeof(struct dinode) * INOCNT(fs)) + +static struct dinode *get_inode(fd,super,ino) + struct fs *super; + ino_t ino; +{ + static struct dinode *ip; + static ino_t last; + + if (fd < 0) { /* flush cache */ + if (ip) { + free(ip); + ip = 0; + } + return 0; + } + + if (!ip || ino < last || ino >= last + INOCNT(super)) { + if (!ip + && !(ip = (struct dinode *)malloc(INOSZ(super)))) { + perror("allocate inodes"); + exit(1); + } + last = (ino / INOCNT(super)) * INOCNT(super); + if (lseek(fd,ino_to_fsba(super,last) << super->fs_fshift,0) < 0 + || read(fd,ip,INOSZ(super)) != INOSZ(super)) { + perror("read inodes"); + exit(1); + } + } + + return ip + ino % INOCNT(super); +} + +#ifdef COMPAT +#define actualblocks(super,ip) ((ip)->di_blocks/2) +#else +#define actualblocks(super,ip) ((ip)->di_blocks) +#endif + +static virtualblocks(super,ip) + struct fs *super; + struct dinode *ip; +{ + register off_t nblk, sz; + + sz = ip->di_size; +#ifdef COMPAT + if (lblkno(super,sz) >= NDADDR) { + nblk = blkroundup(super,sz); + if (sz == nblk) + nblk += super->fs_bsize; + } + + return sz / 1024; + +#else /* COMPAT */ + + if (lblkno(super,sz) >= NDADDR) { + nblk = blkroundup(super,sz); + sz = lblkno(super,nblk); + sz = (sz - NDADDR + NINDIR(super) - 1) / NINDIR(super); + while (sz > 0) { + nblk += sz * super->fs_bsize; + /* sz - 1 rounded up */ + sz = (sz - 1 + NINDIR(super) - 1) / NINDIR(super); + } + } else + nblk = fragroundup(super,sz); + + return nblk / 512; +#endif /* COMPAT */ +} + +static isfree(ip) + struct dinode *ip; +{ +#ifdef COMPAT + return (ip->di_mode&IFMT) == 0; +#else /* COMPAT */ + + switch (ip->di_mode&IFMT) { + case IFIFO: + case IFLNK: /* should check FASTSYMLINK? */ + case IFDIR: + case IFREG: + return 0; + default: + return 1; + } +#endif +} + +static struct user { + uid_t uid; + char *name; + daddr_t space; + long count; + daddr_t spc30; + daddr_t spc60; + daddr_t spc90; +} *users; +static int nusers; + +static inituser() +{ + register i; + register struct user *usr; + + if (!nusers) { + nusers = 8; + if (!(users = + (struct user *)calloc(nusers,sizeof(struct user)))) { + perror("allocate users"); + exit(1); + } + } else { + for (usr = users, i = nusers; --i >= 0; usr++) { + usr->space = usr->spc30 = usr->spc60 = usr->spc90 = 0; + usr->count = 0; + } + } +} + +static usrrehash() +{ + register i; + register struct user *usr, *usrn; + struct user *svusr; + + svusr = users; + nusers <<= 1; + if (!(users = (struct user *)calloc(nusers,sizeof(struct user)))) { + perror("allocate users"); + exit(1); + } + for (usr = svusr, i = nusers >> 1; --i >= 0; usr++) { + for (usrn = users + (usr->uid&(nusers - 1)); usrn->name; + usrn--) { + if (usrn <= users) + usrn = users + nusers; + } + *usrn = *usr; + } +} + +static struct user *user(uid) + uid_t uid; +{ + register struct user *usr; + register i; + struct passwd *pwd; + + while (1) { + for (usr = users + (uid&(nusers - 1)), i = nusers; --i >= 0; + usr--) { + if (!usr->name) { + usr->uid = uid; + + if (!(pwd = getpwuid(uid))) { + if (usr->name = (char *)malloc(7)) + sprintf(usr->name,"#%d",uid); + } else { + if (usr->name = (char *) + malloc(strlen(pwd->pw_name) + 1)) + strcpy(usr->name,pwd->pw_name); + } + if (!usr->name) { + perror("allocate users"); + exit(1); + } + + return usr; + + } else if (usr->uid == uid) + return usr; + + if (usr <= users) + usr = users + nusers; + } + usrrehash(); + } +} + +static cmpusers(u1,u2) + struct user *u1, *u2; +{ + return u2->space - u1->space; +} + +#define sortusers(users) (qsort((users),nusers,sizeof(struct user), \ + cmpusers)) + +static uses(uid,blks,act) + uid_t uid; + daddr_t blks; + time_t act; +{ + static time_t today; + register struct user *usr; + + if (!today) + time(&today); + + usr = user(uid); + usr->count++; + usr->space += blks; + + if (today - act > 90L * 24L * 60L * 60L) + usr->spc90 += blks; + if (today - act > 60L * 24L * 60L * 60L) + usr->spc60 += blks; + if (today - act > 30L * 24L * 60L * 60L) + usr->spc30 += blks; +} + +#ifdef COMPAT +#define FSZCNT 500 +#else +#define FSZCNT 512 +#endif +struct fsizes { + struct fsizes *fsz_next; + daddr_t fsz_first, fsz_last; + ino_t fsz_count[FSZCNT]; + daddr_t fsz_sz[FSZCNT]; +} *fsizes; + +static initfsizes() +{ + register struct fsizes *fp; + register i; + + for (fp = fsizes; fp; fp = fp->fsz_next) { + for (i = FSZCNT; --i >= 0;) { + fp->fsz_count[i] = 0; + fp->fsz_sz[i] = 0; + } + } +} + +static dofsizes(fd,super,name) + struct fs *super; + char *name; +{ + ino_t inode, maxino; + struct dinode *ip; + daddr_t sz, ksz; + struct fsizes *fp, **fsp; + register i; + + maxino = super->fs_ncg * super->fs_ipg - 1; +#ifdef COMPAT + if (!(fsizes = (struct fsizes *)malloc(sizeof(struct fsizes)))) { + perror("alloc fsize structure"); + exit(1); + } +#endif /* COMPAT */ + for (inode = 0; inode < maxino; inode++) { + errno = 0; + if ((ip = get_inode(fd,super,inode)) +#ifdef COMPAT + && ((ip->di_mode&IFMT) == IFREG + || (ip->di_mode&IFMT) == IFDIR) +#else /* COMPAT */ + && !isfree(ip) +#endif /* COMPAT */ + ) { + sz = estimate ? virtualblocks(super,ip) : + actualblocks(super,ip); +#ifdef COMPAT + if (sz >= FSZCNT) { + fsizes->fsz_count[FSZCNT-1]++; + fsizes->fsz_sz[FSZCNT-1] += sz; + } else { + fsizes->fsz_count[sz]++; + fsizes->fsz_sz[sz] += sz; + } +#else /* COMPAT */ + ksz = SIZE(sz); + for (fsp = &fsizes; fp = *fsp; fsp = &fp->fsz_next) { + if (ksz < fp->fsz_last) + break; + } + if (!fp || ksz < fp->fsz_first) { + if (!(fp = (struct fsizes *) + malloc(sizeof(struct fsizes)))) { + perror("alloc fsize structure"); + exit(1); + } + fp->fsz_next = *fsp; + *fsp = fp; + fp->fsz_first = (ksz / FSZCNT) * FSZCNT; + fp->fsz_last = fp->fsz_first + FSZCNT; + for (i = FSZCNT; --i >= 0;) { + fp->fsz_count[i] = 0; + fp->fsz_sz[i] = 0; + } + } + fp->fsz_count[ksz % FSZCNT]++; + fp->fsz_sz[ksz % FSZCNT] += sz; +#endif /* COMPAT */ + } else if (errno) { + perror(name); + exit(1); + } + } + sz = 0; + for (fp = fsizes; fp; fp = fp->fsz_next) { + for (i = 0; i < FSZCNT; i++) { + if (fp->fsz_count[i]) + printf("%d\t%d\t%d\n",fp->fsz_first + i, + fp->fsz_count[i], + SIZE(sz += fp->fsz_sz[i])); + } + } +} + +static douser(fd,super,name) + struct fs *super; + char *name; +{ + ino_t inode, maxino; + struct user *usr, *usrs; + struct dinode *ip; + register n; + + maxino = super->fs_ncg * super->fs_ipg - 1; + for (inode = 0; inode < maxino; inode++) { + errno = 0; + if ((ip = get_inode(fd,super,inode)) + && !isfree(ip)) + uses(ip->di_uid, + estimate ? virtualblocks(super,ip) : + actualblocks(super,ip), + ip->di_atime); + else if (errno) { + perror(name); + exit(1); + } + } + if (!(usrs = (struct user *)malloc(nusers * sizeof(struct user)))) { + perror("allocate users"); + exit(1); + } + bcopy(users,usrs,nusers * sizeof(struct user)); + sortusers(usrs); + for (usr = usrs, n = nusers; --n >= 0 && usr->count; usr++) { + printf("%5d",SIZE(usr->space)); + if (count) + printf("\t%5d",usr->count); + printf("\t%-8s",usr->name); + if (unused) + printf("\t%5d\t%5d\t%5d", + SIZE(usr->spc30), + SIZE(usr->spc60), + SIZE(usr->spc90)); + printf("\n"); + } + free(usrs); +} + +static donames(fd,super,name) + struct fs *super; + char *name; +{ + int c; + ino_t inode, inode1; + ino_t maxino; + struct dinode *ip; + + maxino = super->fs_ncg * super->fs_ipg - 1; + /* first skip the name of the filesystem */ + while ((c = getchar()) != EOF && (c < '0' || c > '9')) + while ((c = getchar()) != EOF && c != '\n'); + ungetc(c,stdin); + inode1 = -1; + while (scanf("%d",&inode) == 1) { + if (inode < 0 || inode > maxino) { + fprintf(stderr,"illegal inode %d\n",inode); + return; + } + errno = 0; + if ((ip = get_inode(fd,super,inode)) + && !isfree(ip)) { + printf("%s\t",user(ip->di_uid)->name); + /* now skip whitespace */ + while ((c = getchar()) == ' ' || c == '\t'); + /* and print out the remainder of the input line */ + while (c != EOF && c != '\n') { + putchar(c); + c = getchar(); + } + putchar('\n'); + inode1 = inode; + } else { + if (errno) { + perror(name); + exit(1); + } + /* skip this line */ + while ((c = getchar()) != EOF && c != '\n'); + } + if (c == EOF) + break; + } +} + +static usage() +{ +#ifdef COMPAT + fprintf(stderr,"Usage: quot [-nfcvha] [filesystem ...]\n"); +#else /* COMPAT */ + fprintf(stderr,"Usage: quot [ -acfhknv ] [ filesystem ... ]\n"); +#endif /* COMPAT */ + exit(1); +} + +static char superblock[SBSIZE]; + +quot(name,mp) + char *name, *mp; +{ + int fd; + + get_inode(-1); /* flush cache */ + inituser(); + initfsizes(); + if ((fd = open(name,0)) < 0 + || lseek(fd,SBOFF,0) != SBOFF + || read(fd,superblock,SBSIZE) != SBSIZE) { + perror(name); + close(fd); + return; + } + if (((struct fs *)superblock)->fs_magic != FS_MAGIC) { + fprintf(stderr,"%s: not a BSD filesystem\n",name); + close(fd); + return; + } + printf("%s:",name); + if (mp) + printf(" (%s)",mp); + putchar('\n'); + (*func)(fd,superblock,name); + close(fd); +} + +int main(argc,argv) + char **argv; +{ + int fd; + char all = 0; + FILE *fp; + struct statfs *mp; + char dev[MNAMELEN + 1]; + char *nm; + int cnt; + + func = douser; +#ifndef COMPAT + header = getbsize(&headerlen,&blocksize); +#endif + while (--argc > 0 && **++argv == '-') { + while (*++*argv) { + switch (**argv) { + case 'n': + func = donames; + break; + case 'c': + func = dofsizes; + break; + case 'a': + all = 1; + break; + case 'f': + count = 1; + break; + case 'h': + estimate = 1; + break; +#ifndef COMPAT + case 'k': + blocksize = 1024; + break; +#endif /* COMPAT */ + case 'v': + unused = 1; + break; + default: + usage(); + } + } + } + if (all) { + cnt = getmntinfo(&mp,MNT_NOWAIT); + for (; --cnt >= 0; mp++) { + if (!strncmp(mp->f_fstypename, MOUNT_FFS, MFSNAMELEN)) { + if (nm = strrchr(mp->f_mntfromname,'/')) { + sprintf(dev,"/dev/r%s",nm + 1); + nm = dev; + } else + nm = mp->f_mntfromname; + quot(nm,mp->f_mntonname); + } + } + } + while (--argc >= 0) + quot(*argv++,0); + return 0; +} -- cgit v1.1