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