quot.c revision 28160
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 3328160Sjkhstatic char rcsid[] = "$Id: quot.c,v 1.5 1997/02/22 16:12:39 peter Exp $"; 3412032Speter#endif /* not lint */ 3512032Speter 3612032Speter#include <sys/param.h> 3712032Speter#include <sys/mount.h> 3812032Speter#include <sys/time.h> 3912032Speter#include <ufs/ffs/fs.h> 4012032Speter#include <ufs/ufs/quota.h> 4112032Speter#include <ufs/ufs/inode.h> 4212032Speter 4312032Speter#include <stdio.h> 4412032Speter#include <stdlib.h> 4512032Speter#include <string.h> 4612032Speter#include <errno.h> 4712032Speter#include <pwd.h> 4812032Speter 4912032Speter/* some flags of what to do: */ 5012032Speterstatic char estimate; 5112032Speterstatic char count; 5212032Speterstatic char unused; 5312032Speterstatic int (*func)(); 5412032Speterstatic long blocksize; 5512032Speterstatic char *header; 5612032Speterstatic int headerlen; 5712032Speter 5812032Speter/* 5912032Speter * Original BSD quot doesn't round to number of frags/blocks, 6012032Speter * doesn't account for indirection blocks and gets it totally 6112032Speter * wrong if the size is a multiple of the blocksize. 6212032Speter * The new code always counts the number of 512 byte blocks 6312032Speter * instead of the number of kilobytes and converts them to 6412032Speter * kByte when done (on request). 6512032Speter */ 6612032Speter#ifdef COMPAT 6712032Speter#define SIZE(n) (n) 6812032Speter#else 6912032Speter#define SIZE(n) (((n) * 512 + blocksize - 1)/blocksize) 7012032Speter#endif 7112032Speter 7212032Speter#define INOCNT(fs) ((fs)->fs_ipg) 7312032Speter#define INOSZ(fs) (sizeof(struct dinode) * INOCNT(fs)) 7412032Speter 7512032Speterstatic struct dinode *get_inode(fd,super,ino) 7612032Speter struct fs *super; 7712032Speter ino_t ino; 7812032Speter{ 7912032Speter static struct dinode *ip; 8012032Speter static ino_t last; 8112032Speter 8212032Speter if (fd < 0) { /* flush cache */ 8312032Speter if (ip) { 8412032Speter free(ip); 8512032Speter ip = 0; 8612032Speter } 8712032Speter return 0; 8812032Speter } 8912032Speter 9012032Speter if (!ip || ino < last || ino >= last + INOCNT(super)) { 9112032Speter if (!ip 9212032Speter && !(ip = (struct dinode *)malloc(INOSZ(super)))) { 9312032Speter perror("allocate inodes"); 9412032Speter exit(1); 9512032Speter } 9612032Speter last = (ino / INOCNT(super)) * INOCNT(super); 9728160Sjkh if (lseek(fd, (off_t)ino_to_fsba(super, last) << super->fs_fshift, 0) < (off_t)0 9812032Speter || read(fd,ip,INOSZ(super)) != INOSZ(super)) { 9912032Speter perror("read inodes"); 10012032Speter exit(1); 10112032Speter } 10212032Speter } 10312032Speter 10412032Speter return ip + ino % INOCNT(super); 10512032Speter} 10612032Speter 10712032Speter#ifdef COMPAT 10812032Speter#define actualblocks(super,ip) ((ip)->di_blocks/2) 10912032Speter#else 11012032Speter#define actualblocks(super,ip) ((ip)->di_blocks) 11112032Speter#endif 11212032Speter 11312032Speterstatic virtualblocks(super,ip) 11412032Speter struct fs *super; 11512032Speter struct dinode *ip; 11612032Speter{ 11712032Speter register off_t nblk, sz; 11812032Speter 11912032Speter sz = ip->di_size; 12012032Speter#ifdef COMPAT 12112032Speter if (lblkno(super,sz) >= NDADDR) { 12212032Speter nblk = blkroundup(super,sz); 12312032Speter if (sz == nblk) 12412032Speter nblk += super->fs_bsize; 12512032Speter } 12612032Speter 12712032Speter return sz / 1024; 12812032Speter 12912032Speter#else /* COMPAT */ 13012032Speter 13112032Speter if (lblkno(super,sz) >= NDADDR) { 13212032Speter nblk = blkroundup(super,sz); 13312032Speter sz = lblkno(super,nblk); 13412032Speter sz = (sz - NDADDR + NINDIR(super) - 1) / NINDIR(super); 13512032Speter while (sz > 0) { 13612032Speter nblk += sz * super->fs_bsize; 13712032Speter /* sz - 1 rounded up */ 13812032Speter sz = (sz - 1 + NINDIR(super) - 1) / NINDIR(super); 13912032Speter } 14012032Speter } else 14112032Speter nblk = fragroundup(super,sz); 14212032Speter 14312032Speter return nblk / 512; 14412032Speter#endif /* COMPAT */ 14512032Speter} 14612032Speter 14712032Speterstatic isfree(ip) 14812032Speter struct dinode *ip; 14912032Speter{ 15012032Speter#ifdef COMPAT 15112032Speter return (ip->di_mode&IFMT) == 0; 15212032Speter#else /* COMPAT */ 15312032Speter 15412032Speter switch (ip->di_mode&IFMT) { 15512032Speter case IFIFO: 15612032Speter case IFLNK: /* should check FASTSYMLINK? */ 15712032Speter case IFDIR: 15812032Speter case IFREG: 15912032Speter return 0; 16012032Speter default: 16112032Speter return 1; 16212032Speter } 16312032Speter#endif 16412032Speter} 16512032Speter 16612032Speterstatic struct user { 16712032Speter uid_t uid; 16812032Speter char *name; 16912032Speter daddr_t space; 17012032Speter long count; 17112032Speter daddr_t spc30; 17212032Speter daddr_t spc60; 17312032Speter daddr_t spc90; 17412032Speter} *users; 17512032Speterstatic int nusers; 17612032Speter 17712032Speterstatic inituser() 17812032Speter{ 17912032Speter register i; 18012032Speter register struct user *usr; 18112032Speter 18212032Speter if (!nusers) { 18312032Speter nusers = 8; 18412032Speter if (!(users = 18512032Speter (struct user *)calloc(nusers,sizeof(struct user)))) { 18612032Speter perror("allocate users"); 18712032Speter exit(1); 18812032Speter } 18912032Speter } else { 19012032Speter for (usr = users, i = nusers; --i >= 0; usr++) { 19112032Speter usr->space = usr->spc30 = usr->spc60 = usr->spc90 = 0; 19212032Speter usr->count = 0; 19312032Speter } 19412032Speter } 19512032Speter} 19612032Speter 19712032Speterstatic usrrehash() 19812032Speter{ 19912032Speter register i; 20012032Speter register struct user *usr, *usrn; 20112032Speter struct user *svusr; 20212032Speter 20312032Speter svusr = users; 20412032Speter nusers <<= 1; 20512032Speter if (!(users = (struct user *)calloc(nusers,sizeof(struct user)))) { 20612032Speter perror("allocate users"); 20712032Speter exit(1); 20812032Speter } 20912032Speter for (usr = svusr, i = nusers >> 1; --i >= 0; usr++) { 21012032Speter for (usrn = users + (usr->uid&(nusers - 1)); usrn->name; 21112032Speter usrn--) { 21212032Speter if (usrn <= users) 21312032Speter usrn = users + nusers; 21412032Speter } 21512032Speter *usrn = *usr; 21612032Speter } 21712032Speter} 21812032Speter 21912032Speterstatic struct user *user(uid) 22012032Speter uid_t uid; 22112032Speter{ 22212032Speter register struct user *usr; 22312032Speter register i; 22412032Speter struct passwd *pwd; 22512032Speter 22612032Speter while (1) { 22712032Speter for (usr = users + (uid&(nusers - 1)), i = nusers; --i >= 0; 22812032Speter usr--) { 22912032Speter if (!usr->name) { 23012032Speter usr->uid = uid; 23112032Speter 23212032Speter if (!(pwd = getpwuid(uid))) { 23312032Speter if (usr->name = (char *)malloc(7)) 23412032Speter sprintf(usr->name,"#%d",uid); 23512032Speter } else { 23612032Speter if (usr->name = (char *) 23712032Speter malloc(strlen(pwd->pw_name) + 1)) 23812032Speter strcpy(usr->name,pwd->pw_name); 23912032Speter } 24012032Speter if (!usr->name) { 24112032Speter perror("allocate users"); 24212032Speter exit(1); 24312032Speter } 24412032Speter 24512032Speter return usr; 24612032Speter 24712032Speter } else if (usr->uid == uid) 24812032Speter return usr; 24912032Speter 25012032Speter if (usr <= users) 25112032Speter usr = users + nusers; 25212032Speter } 25312032Speter usrrehash(); 25412032Speter } 25512032Speter} 25612032Speter 25712032Speterstatic cmpusers(u1,u2) 25812032Speter struct user *u1, *u2; 25912032Speter{ 26012032Speter return u2->space - u1->space; 26112032Speter} 26212032Speter 26312032Speter#define sortusers(users) (qsort((users),nusers,sizeof(struct user), \ 26412032Speter cmpusers)) 26512032Speter 26612032Speterstatic uses(uid,blks,act) 26712032Speter uid_t uid; 26812032Speter daddr_t blks; 26912032Speter time_t act; 27012032Speter{ 27112032Speter static time_t today; 27212032Speter register struct user *usr; 27312032Speter 27412032Speter if (!today) 27512032Speter time(&today); 27612032Speter 27712032Speter usr = user(uid); 27812032Speter usr->count++; 27912032Speter usr->space += blks; 28012032Speter 28112032Speter if (today - act > 90L * 24L * 60L * 60L) 28212032Speter usr->spc90 += blks; 28312032Speter if (today - act > 60L * 24L * 60L * 60L) 28412032Speter usr->spc60 += blks; 28512032Speter if (today - act > 30L * 24L * 60L * 60L) 28612032Speter usr->spc30 += blks; 28712032Speter} 28812032Speter 28912032Speter#ifdef COMPAT 29012032Speter#define FSZCNT 500 29112032Speter#else 29212032Speter#define FSZCNT 512 29312032Speter#endif 29412032Speterstruct fsizes { 29512032Speter struct fsizes *fsz_next; 29612032Speter daddr_t fsz_first, fsz_last; 29712032Speter ino_t fsz_count[FSZCNT]; 29812032Speter daddr_t fsz_sz[FSZCNT]; 29912032Speter} *fsizes; 30012032Speter 30112032Speterstatic initfsizes() 30212032Speter{ 30312032Speter register struct fsizes *fp; 30412032Speter register i; 30512032Speter 30612032Speter for (fp = fsizes; fp; fp = fp->fsz_next) { 30712032Speter for (i = FSZCNT; --i >= 0;) { 30812032Speter fp->fsz_count[i] = 0; 30912032Speter fp->fsz_sz[i] = 0; 31012032Speter } 31112032Speter } 31212032Speter} 31312032Speter 31412032Speterstatic dofsizes(fd,super,name) 31512032Speter struct fs *super; 31612032Speter char *name; 31712032Speter{ 31812032Speter ino_t inode, maxino; 31912032Speter struct dinode *ip; 32012032Speter daddr_t sz, ksz; 32112032Speter struct fsizes *fp, **fsp; 32212032Speter register i; 32312032Speter 32412032Speter maxino = super->fs_ncg * super->fs_ipg - 1; 32512032Speter#ifdef COMPAT 32612032Speter if (!(fsizes = (struct fsizes *)malloc(sizeof(struct fsizes)))) { 32712032Speter perror("alloc fsize structure"); 32812032Speter exit(1); 32912032Speter } 33012032Speter#endif /* COMPAT */ 33112032Speter for (inode = 0; inode < maxino; inode++) { 33212032Speter errno = 0; 33312032Speter if ((ip = get_inode(fd,super,inode)) 33412032Speter#ifdef COMPAT 33512032Speter && ((ip->di_mode&IFMT) == IFREG 33612032Speter || (ip->di_mode&IFMT) == IFDIR) 33712032Speter#else /* COMPAT */ 33812032Speter && !isfree(ip) 33912032Speter#endif /* COMPAT */ 34012032Speter ) { 34112032Speter sz = estimate ? virtualblocks(super,ip) : 34212032Speter actualblocks(super,ip); 34312032Speter#ifdef COMPAT 34412032Speter if (sz >= FSZCNT) { 34512032Speter fsizes->fsz_count[FSZCNT-1]++; 34612032Speter fsizes->fsz_sz[FSZCNT-1] += sz; 34712032Speter } else { 34812032Speter fsizes->fsz_count[sz]++; 34912032Speter fsizes->fsz_sz[sz] += sz; 35012032Speter } 35112032Speter#else /* COMPAT */ 35212032Speter ksz = SIZE(sz); 35312032Speter for (fsp = &fsizes; fp = *fsp; fsp = &fp->fsz_next) { 35412032Speter if (ksz < fp->fsz_last) 35512032Speter break; 35612032Speter } 35712032Speter if (!fp || ksz < fp->fsz_first) { 35812032Speter if (!(fp = (struct fsizes *) 35912032Speter malloc(sizeof(struct fsizes)))) { 36012032Speter perror("alloc fsize structure"); 36112032Speter exit(1); 36212032Speter } 36312032Speter fp->fsz_next = *fsp; 36412032Speter *fsp = fp; 36512032Speter fp->fsz_first = (ksz / FSZCNT) * FSZCNT; 36612032Speter fp->fsz_last = fp->fsz_first + FSZCNT; 36712032Speter for (i = FSZCNT; --i >= 0;) { 36812032Speter fp->fsz_count[i] = 0; 36912032Speter fp->fsz_sz[i] = 0; 37012032Speter } 37112032Speter } 37212032Speter fp->fsz_count[ksz % FSZCNT]++; 37312032Speter fp->fsz_sz[ksz % FSZCNT] += sz; 37412032Speter#endif /* COMPAT */ 37512032Speter } else if (errno) { 37612032Speter perror(name); 37712032Speter exit(1); 37812032Speter } 37912032Speter } 38012032Speter sz = 0; 38112032Speter for (fp = fsizes; fp; fp = fp->fsz_next) { 38212032Speter for (i = 0; i < FSZCNT; i++) { 38312032Speter if (fp->fsz_count[i]) 38412032Speter printf("%d\t%d\t%d\n",fp->fsz_first + i, 38512032Speter fp->fsz_count[i], 38612032Speter SIZE(sz += fp->fsz_sz[i])); 38712032Speter } 38812032Speter } 38912032Speter} 39012032Speter 39112032Speterstatic douser(fd,super,name) 39212032Speter struct fs *super; 39312032Speter char *name; 39412032Speter{ 39512032Speter ino_t inode, maxino; 39612032Speter struct user *usr, *usrs; 39712032Speter struct dinode *ip; 39812032Speter register n; 39912032Speter 40012032Speter maxino = super->fs_ncg * super->fs_ipg - 1; 40112032Speter for (inode = 0; inode < maxino; inode++) { 40212032Speter errno = 0; 40312032Speter if ((ip = get_inode(fd,super,inode)) 40412032Speter && !isfree(ip)) 40512032Speter uses(ip->di_uid, 40612032Speter estimate ? virtualblocks(super,ip) : 40712032Speter actualblocks(super,ip), 40812032Speter ip->di_atime); 40912032Speter else if (errno) { 41012032Speter perror(name); 41112032Speter exit(1); 41212032Speter } 41312032Speter } 41412032Speter if (!(usrs = (struct user *)malloc(nusers * sizeof(struct user)))) { 41512032Speter perror("allocate users"); 41612032Speter exit(1); 41712032Speter } 41812032Speter bcopy(users,usrs,nusers * sizeof(struct user)); 41912032Speter sortusers(usrs); 42012032Speter for (usr = usrs, n = nusers; --n >= 0 && usr->count; usr++) { 42112032Speter printf("%5d",SIZE(usr->space)); 42212032Speter if (count) 42312032Speter printf("\t%5d",usr->count); 42412032Speter printf("\t%-8s",usr->name); 42512032Speter if (unused) 42612032Speter printf("\t%5d\t%5d\t%5d", 42712032Speter SIZE(usr->spc30), 42812032Speter SIZE(usr->spc60), 42912032Speter SIZE(usr->spc90)); 43012032Speter printf("\n"); 43112032Speter } 43212032Speter free(usrs); 43312032Speter} 43412032Speter 43512032Speterstatic donames(fd,super,name) 43612032Speter struct fs *super; 43712032Speter char *name; 43812032Speter{ 43912032Speter int c; 44012032Speter ino_t inode, inode1; 44112032Speter ino_t maxino; 44212032Speter struct dinode *ip; 44312032Speter 44412032Speter maxino = super->fs_ncg * super->fs_ipg - 1; 44512032Speter /* first skip the name of the filesystem */ 44612032Speter while ((c = getchar()) != EOF && (c < '0' || c > '9')) 44712032Speter while ((c = getchar()) != EOF && c != '\n'); 44812032Speter ungetc(c,stdin); 44912032Speter inode1 = -1; 45012032Speter while (scanf("%d",&inode) == 1) { 45112032Speter if (inode < 0 || inode > maxino) { 45212032Speter fprintf(stderr,"illegal inode %d\n",inode); 45312032Speter return; 45412032Speter } 45512032Speter errno = 0; 45612032Speter if ((ip = get_inode(fd,super,inode)) 45712032Speter && !isfree(ip)) { 45812032Speter printf("%s\t",user(ip->di_uid)->name); 45912032Speter /* now skip whitespace */ 46012032Speter while ((c = getchar()) == ' ' || c == '\t'); 46112032Speter /* and print out the remainder of the input line */ 46212032Speter while (c != EOF && c != '\n') { 46312032Speter putchar(c); 46412032Speter c = getchar(); 46512032Speter } 46612032Speter putchar('\n'); 46712032Speter inode1 = inode; 46812032Speter } else { 46912032Speter if (errno) { 47012032Speter perror(name); 47112032Speter exit(1); 47212032Speter } 47312032Speter /* skip this line */ 47412032Speter while ((c = getchar()) != EOF && c != '\n'); 47512032Speter } 47612032Speter if (c == EOF) 47712032Speter break; 47812032Speter } 47912032Speter} 48012032Speter 48112032Speterstatic usage() 48212032Speter{ 48312032Speter#ifdef COMPAT 48412032Speter fprintf(stderr,"Usage: quot [-nfcvha] [filesystem ...]\n"); 48512032Speter#else /* COMPAT */ 48612032Speter fprintf(stderr,"Usage: quot [ -acfhknv ] [ filesystem ... ]\n"); 48712032Speter#endif /* COMPAT */ 48812032Speter exit(1); 48912032Speter} 49012032Speter 49112032Speterstatic char superblock[SBSIZE]; 49212032Speter 49312032Speterquot(name,mp) 49412032Speter char *name, *mp; 49512032Speter{ 49612032Speter int fd; 49712032Speter 49812032Speter get_inode(-1); /* flush cache */ 49912032Speter inituser(); 50012032Speter initfsizes(); 50112032Speter if ((fd = open(name,0)) < 0 50212032Speter || lseek(fd,SBOFF,0) != SBOFF 50312032Speter || read(fd,superblock,SBSIZE) != SBSIZE) { 50412032Speter perror(name); 50512032Speter close(fd); 50612032Speter return; 50712032Speter } 50812032Speter if (((struct fs *)superblock)->fs_magic != FS_MAGIC) { 50912032Speter fprintf(stderr,"%s: not a BSD filesystem\n",name); 51012032Speter close(fd); 51112032Speter return; 51212032Speter } 51312032Speter printf("%s:",name); 51412032Speter if (mp) 51512032Speter printf(" (%s)",mp); 51612032Speter putchar('\n'); 51712032Speter (*func)(fd,superblock,name); 51812032Speter close(fd); 51912032Speter} 52012032Speter 52112032Speterint main(argc,argv) 52212032Speter char **argv; 52312032Speter{ 52412032Speter int fd; 52512032Speter char all = 0; 52612032Speter FILE *fp; 52712032Speter struct statfs *mp; 52812038Speter struct vfsconf vfc, *vfsp; 52912032Speter char dev[MNAMELEN + 1]; 53012032Speter char *nm; 53112032Speter int cnt; 53212032Speter 53312032Speter func = douser; 53412032Speter#ifndef COMPAT 53512032Speter header = getbsize(&headerlen,&blocksize); 53612032Speter#endif 53712032Speter while (--argc > 0 && **++argv == '-') { 53812032Speter while (*++*argv) { 53912032Speter switch (**argv) { 54012032Speter case 'n': 54112032Speter func = donames; 54212032Speter break; 54312032Speter case 'c': 54412032Speter func = dofsizes; 54512032Speter break; 54612032Speter case 'a': 54712032Speter all = 1; 54812032Speter break; 54912032Speter case 'f': 55012032Speter count = 1; 55112032Speter break; 55212032Speter case 'h': 55312032Speter estimate = 1; 55412032Speter break; 55512032Speter#ifndef COMPAT 55612032Speter case 'k': 55712032Speter blocksize = 1024; 55812032Speter break; 55912032Speter#endif /* COMPAT */ 56012032Speter case 'v': 56112032Speter unused = 1; 56212032Speter break; 56312032Speter default: 56412032Speter usage(); 56512032Speter } 56612032Speter } 56712032Speter } 56812032Speter if (all) { 56912032Speter cnt = getmntinfo(&mp,MNT_NOWAIT); 57012038Speter vfsp = getvfsbyname("ufs"); 57112038Speter if (vfsp == NULL) { 57212038Speter fprintf(stderr, "cannot find ufs/ffs filesystem type!\n"); 57312038Speter exit(1); 57412038Speter } 57512032Speter for (; --cnt >= 0; mp++) { 57612038Speter if (mp->f_type == vfsp->vfc_index) { 57712032Speter if (nm = strrchr(mp->f_mntfromname,'/')) { 57812032Speter sprintf(dev,"/dev/r%s",nm + 1); 57912032Speter nm = dev; 58012032Speter } else 58112032Speter nm = mp->f_mntfromname; 58212032Speter quot(nm,mp->f_mntonname); 58312032Speter } 58412032Speter } 58512032Speter } 58612032Speter while (--argc >= 0) 58712032Speter quot(*argv++,0); 58812032Speter return 0; 58912032Speter} 590