1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)quot.c 5.1 (Berkeley) 11/11/91"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <ufs/ufs/dinode.h> 20 #include <ufs/ffs/fs.h> 21 #include <fcntl.h> 22 #include <unistd.h> 23 #include <stdio.h> 24 #include <ctype.h> 25 #include <paths.h> 26 27 #define ISIZ (MAXBSIZE/sizeof(struct dinode)) 28 union { 29 struct fs u_sblock; 30 char dummy[SBSIZE]; 31 } sb_un; 32 #define sblock sb_un.u_sblock 33 struct dinode itab[MAXBSIZE/sizeof(struct dinode)]; 34 35 struct du { 36 struct du *next; 37 long blocks; 38 long blocks30; 39 long blocks60; 40 long blocks90; 41 long nfiles; 42 int uid; 43 #define NDU 2048 44 } du[NDU]; 45 int ndu; 46 #define DUHASH 8209 /* smallest prime >= 4 * NDU */ 47 #define HASH(u) ((u) % DUHASH) 48 struct du *duhash[DUHASH]; 49 50 #define TSIZE 500 51 int sizes[TSIZE]; 52 long overflow; 53 54 int nflg; 55 int fflg; 56 int cflg; 57 int vflg; 58 int hflg; 59 long now; 60 61 unsigned ino; 62 63 char *malloc(); 64 char *user_from_uid(); 65 66 main(argc, argv) 67 int argc; 68 char *argv[]; 69 { 70 extern char *optarg; 71 extern int optind; 72 int ch; 73 time_t time(); 74 75 while ((ch = getopt(argc, argv, "cfhnv")) != EOF) 76 switch((char)ch) { 77 case 'c': 78 cflg++; break; 79 case 'f': 80 fflg++; break; 81 case 'h': /* undocumented */ 82 hflg++; break; 83 case 'n': 84 nflg++; break; 85 case 'v': /* undocumented */ 86 vflg++; break; 87 case '?': 88 default: 89 fputs("usage: quot [-cfn] [filesystem ...]\n", stderr); 90 exit(1); 91 } 92 argc -= optind; 93 argv += optind; 94 95 (void)time(&now); 96 setpassent(1); 97 if (argc) 98 for (; *argv; ++argv) { 99 if (check(*argv, (char *)NULL) == 0) 100 report(); 101 } 102 else 103 quotall(); 104 exit(0); 105 } 106 107 #include <sys/dir.h> 108 #include <fstab.h> 109 110 quotall() 111 { 112 register struct fstab *fs; 113 register char *cp; 114 char dev[MAXNAMLEN + 10], *rindex(); 115 116 while (fs = getfsent()) { 117 if (strcmp(fs->fs_vfstype, "ufs") || 118 (strcmp(fs->fs_type, FSTAB_RO) && 119 strcmp(fs->fs_type, FSTAB_RW) && 120 strcmp(fs->fs_type, FSTAB_RQ))) 121 continue; 122 cp = rindex(fs->fs_spec, '/'); 123 if (cp == 0) 124 continue; 125 (void)sprintf(dev, "%s/r%s", _PATH_DEV, cp + 1); 126 if (check(dev, fs->fs_file) == 0) 127 report(); 128 } 129 } 130 131 check(file, fsdir) 132 char *file; 133 char *fsdir; 134 { 135 register int i, j, nfiles; 136 register struct du **dp; 137 daddr_t iblk; 138 long dev_bsize; 139 int c, fd; 140 141 /* 142 * Initialize tables between checks; 143 * because of the qsort done in report() 144 * the hash tables must be rebuilt each time. 145 */ 146 for (i = 0; i < TSIZE; i++) 147 sizes[i] = 0; 148 overflow = 0; 149 for (dp = duhash; dp < &duhash[DUHASH]; dp++) 150 *dp = 0; 151 ndu = 0; 152 fd = open(file, O_RDONLY); 153 if (fd < 0) { 154 fprintf(stderr, "quot: "); 155 perror(file); 156 return (-1); 157 } 158 printf("%s", file); 159 if (fsdir == NULL) { 160 register struct fstab *fs = getfsspec(file); 161 if (fs != NULL) 162 fsdir = fs->fs_file; 163 } 164 if (fsdir != NULL && *fsdir != '\0') 165 printf(" (%s)", fsdir); 166 printf(":\n"); 167 sync(); 168 bread(fd, (long)SBOFF, (char *)&sblock, SBSIZE); 169 dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 170 if (nflg) { 171 if (isdigit(c = getchar())) 172 (void)ungetc(c, stdin); 173 else while (c != '\n' && c != EOF) 174 c = getchar(); 175 } 176 nfiles = sblock.fs_ipg * sblock.fs_ncg; 177 for (ino = 0; ino < nfiles; ) { 178 iblk = fsbtodb(&sblock, itod(&sblock, ino)); 179 bread(fd, iblk * dev_bsize, (char *)itab, (int)sblock.fs_bsize); 180 for (j = 0; j < INOPB(&sblock) && ino < nfiles; j++, ino++) { 181 if (ino < ROOTINO) 182 continue; 183 qacct(&itab[j]); 184 } 185 } 186 close(fd); 187 return (0); 188 } 189 190 qacct(ip) 191 register struct dinode *ip; 192 { 193 register struct du *dp; 194 struct du **hp; 195 long blks, frags, size; 196 int n; 197 static fino; 198 199 if ((ip->di_mode & IFMT) == 0) 200 return; 201 /* 202 * By default, take block count in inode. Otherwise (-h), 203 * take the size field and estimate the blocks allocated. 204 * The latter does not account for holes in files. 205 */ 206 if (!hflg) 207 size = ip->di_blocks / 2; 208 else { 209 blks = lblkno(&sblock, ip->di_size); 210 frags = blks * sblock.fs_frag + 211 numfrags(&sblock, dblksize(&sblock, ip, blks)); 212 size = frags * sblock.fs_fsize / 1024; 213 } 214 if (cflg) { 215 if ((ip->di_mode&IFMT) != IFDIR && (ip->di_mode&IFMT) != IFREG) 216 return; 217 if (size >= TSIZE) { 218 overflow += size; 219 size = TSIZE-1; 220 } 221 sizes[size]++; 222 return; 223 } 224 hp = &duhash[HASH(ip->di_uid)]; 225 for (dp = *hp; dp; dp = dp->next) 226 if (dp->uid == ip->di_uid) 227 break; 228 if (dp == 0) { 229 if (ndu >= NDU) 230 return; 231 dp = &du[ndu++]; 232 dp->next = *hp; 233 *hp = dp; 234 dp->uid = ip->di_uid; 235 dp->nfiles = 0; 236 dp->blocks = 0; 237 dp->blocks30 = 0; 238 dp->blocks60 = 0; 239 dp->blocks90 = 0; 240 } 241 dp->blocks += size; 242 #define DAY (60 * 60 * 24) /* seconds per day */ 243 if (now - ip->di_atime > 30 * DAY) 244 dp->blocks30 += size; 245 if (now - ip->di_atime > 60 * DAY) 246 dp->blocks60 += size; 247 if (now - ip->di_atime > 90 * DAY) 248 dp->blocks90 += size; 249 dp->nfiles++; 250 while (nflg) { 251 register char *np; 252 253 if (fino == 0) 254 if (scanf("%d", &fino) <= 0) 255 return; 256 if (fino > ino) 257 return; 258 if (fino < ino) { 259 while ((n = getchar()) != '\n' && n != EOF) 260 ; 261 fino = 0; 262 continue; 263 } 264 if (np = user_from_uid(dp->uid, 1)) 265 printf("%.7s\t", np); 266 else 267 printf("%u\t", ip->di_uid); 268 while ((n = getchar()) == ' ' || n == '\t') 269 ; 270 putchar(n); 271 while (n != EOF && n != '\n') { 272 n = getchar(); 273 putchar(n); 274 } 275 fino = 0; 276 break; 277 } 278 } 279 280 bread(fd, bno, buf, cnt) 281 long bno; 282 char *buf; 283 { 284 off_t lseek(); 285 286 (void)lseek(fd, bno, L_SET); 287 if (read(fd, buf, cnt) != cnt) { 288 fprintf(stderr, "quot: read error at block %ld\n", bno); 289 exit(1); 290 } 291 } 292 293 qcmp(p1, p2) 294 register struct du *p1, *p2; 295 { 296 char *s1, *s2; 297 298 if (p1->blocks > p2->blocks) 299 return (-1); 300 if (p1->blocks < p2->blocks) 301 return (1); 302 s1 = user_from_uid(p1->uid, 1); 303 if (s1 == 0) 304 return (0); 305 s2 = user_from_uid(p2->uid, 1); 306 if (s2 == 0) 307 return (0); 308 return (strcmp(s1, s2)); 309 } 310 311 report() 312 { 313 register i; 314 register struct du *dp; 315 316 if (nflg) 317 return; 318 if (cflg) { 319 register long t = 0; 320 321 for (i = 0; i < TSIZE - 1; i++) 322 if (sizes[i]) { 323 t += i*sizes[i]; 324 printf("%d\t%d\t%ld\n", i, sizes[i], t); 325 } 326 printf("%d\t%d\t%ld\n", 327 TSIZE - 1, sizes[TSIZE - 1], overflow + t); 328 return; 329 } 330 qsort(du, ndu, sizeof (du[0]), qcmp); 331 for (dp = du; dp < &du[ndu]; dp++) { 332 register char *cp; 333 334 if (dp->blocks == 0) 335 return; 336 printf("%5D\t", dp->blocks); 337 if (fflg) 338 printf("%5D\t", dp->nfiles); 339 if (cp = user_from_uid(dp->uid, 1)) 340 printf("%-8.8s", cp); 341 else 342 printf("#%-8d", dp->uid); 343 if (vflg) 344 printf("\t%5D\t%5D\t%5D", 345 dp->blocks30, dp->blocks60, dp->blocks90); 346 printf("\n"); 347 } 348 } 349