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