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