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