1 #ifndef lint 2 static char *sccsid = "@(#)quot.c 4.12 (Berkeley) 87/02/23"; 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 long dev_bsize = 1; 50 51 unsigned ino; 52 53 char *malloc(); 54 char *getname(); 55 56 main(argc, argv) 57 int argc; 58 char *argv[]; 59 { 60 register int n; 61 62 now = time(0); 63 argc--, argv++; 64 while (argc > 0 && argv[0][0] == '-') { 65 register char *cp; 66 67 for (cp = &argv[0][1]; *cp; cp++) 68 switch (*cp) { 69 case 'n': 70 nflg++; break; 71 case 'f': 72 fflg++; break; 73 case 'c': 74 cflg++; break; 75 case 'v': 76 vflg++; break; 77 case 'h': 78 hflg++; break; 79 default: 80 fprintf(stderr, 81 "usage: quot [ -nfcvh ] [ device ... ]\n"); 82 exit(1); 83 } 84 argc--, argv++; 85 } 86 if (argc == 0) 87 quotall(); 88 while (argc-- > 0) 89 if (check(*argv++, (char *)NULL) == 0) 90 report(); 91 exit (0); 92 } 93 94 #include <fstab.h> 95 96 quotall() 97 { 98 register struct fstab *fs; 99 register char *cp; 100 char dev[80], *rindex(); 101 102 if (setfsent() == 0) { 103 fprintf(stderr, "quot: no %s file\n", FSTAB); 104 exit(1); 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 sprintf(dev, "/dev/r%s", cp + 1); 115 if (check(dev, fs->fs_file) == 0) 116 report(); 117 } 118 endfsent(); 119 } 120 121 check(file, fsdir) 122 char *file; 123 char *fsdir; 124 { 125 register int i, j, nfiles; 126 register struct du **dp; 127 daddr_t iblk; 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, SBOFF, (char *)&sblock, SBSIZE); 158 dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 159 if (nflg) { 160 if (isdigit(c = getchar())) 161 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, (char *)itab, 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 ", np); 255 else 256 printf("%d ", 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 unsigned bno; 271 char *buf; 272 { 273 274 lseek(fd, (long)bno * dev_bsize, L_SET); 275 if (read(fd, buf, cnt) != cnt) { 276 fprintf(stderr, "quot: read error at block %u\n", bno); 277 exit(1); 278 } 279 } 280 281 qcmp(p1, p2) 282 register struct du *p1, *p2; 283 { 284 char *s1, *s2; 285 286 if (p1->blocks > p2->blocks) 287 return (-1); 288 if (p1->blocks < p2->blocks) 289 return (1); 290 s1 = getname(p1->uid); 291 if (s1 == 0) 292 return (0); 293 s2 = getname(p2->uid); 294 if (s2 == 0) 295 return (0); 296 return (strcmp(s1, s2)); 297 } 298 299 report() 300 { 301 register i; 302 register struct du *dp; 303 304 if (nflg) 305 return; 306 if (cflg) { 307 register long t = 0; 308 309 for (i = 0; i < TSIZE - 1; i++) 310 if (sizes[i]) { 311 t += i*sizes[i]; 312 printf("%d %d %D\n", i, sizes[i], t); 313 } 314 printf("%d %d %D\n", 315 TSIZE - 1, sizes[TSIZE - 1], overflow + t); 316 return; 317 } 318 qsort(du, ndu, sizeof (du[0]), qcmp); 319 for (dp = du; dp < &du[ndu]; dp++) { 320 register char *cp; 321 322 if (dp->blocks == 0) 323 return; 324 printf("%5D\t", dp->blocks); 325 if (fflg) 326 printf("%5D\t", dp->nfiles); 327 if (cp = getname(dp->uid)) 328 printf("%-8.8s", cp); 329 else 330 printf("#%-8d", dp->uid); 331 if (vflg) 332 printf("\t%5D\t%5D\t%5D", 333 dp->blocks30, dp->blocks60, dp->blocks90); 334 printf("\n"); 335 } 336 } 337 338 /* rest should be done with nameserver or database */ 339 340 #include <pwd.h> 341 #include <grp.h> 342 #include <utmp.h> 343 344 struct utmp utmp; 345 #define NMAX (sizeof (utmp.ut_name)) 346 #define SCPYN(a, b) strncpy(a, b, NMAX) 347 348 #define NUID 64 /* power of 2 */ 349 #define UIDMASK 0x3f 350 351 struct ncache { 352 int uid; 353 char name[NMAX+1]; 354 } nc[NUID]; 355 char outrangename[NMAX+1]; 356 int outrangeuid = -1; 357 358 char * 359 getname(uid) 360 { 361 register struct passwd *pw; 362 struct passwd *getpwent(); 363 extern int _pw_stayopen; 364 register int cp; 365 366 _pw_stayopen = 1; 367 cp = uid & UIDMASK; 368 if (uid >= 0 && nc[cp].uid == uid && nc[cp].name[0]) 369 return (nc[cp].name); 370 pw = getpwuid(uid); 371 if (!pw) 372 return (0); 373 nc[cp].uid = uid; 374 SCPYN(nc[cp].name, pw->pw_name); 375 return (nc[cp].name); 376 } 377