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