expand bitmaps to 256 bits
[unix-history] / usr / src / usr.sbin / quot / quot.c
CommitLineData
ebdf2361 1/*-
7c3ccde2
KB
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
ebdf2361
KB
4 *
5 * %sccs.include.proprietary.c%
6 */
7
8#ifndef lint
7c3ccde2
KB
9static char copyright[] =
10"@(#) Copyright (c) 1991, 1993\n\
11 The Regents of the University of California. All rights reserved.\n";
ebdf2361
KB
12#endif /* not lint */
13
b47543fa 14#ifndef lint
a4d097e6 15static char sccsid[] = "@(#)quot.c 8.4 (Berkeley) %G%";
ebdf2361 16#endif /* not lint */
6430f2d0 17
bea492ce 18#include <sys/param.h>
249eea8a 19#include <sys/time.h>
3e6ca7df
KM
20#include <sys/stat.h>
21#include <sys/mount.h>
1032f6ad
KB
22#include <ufs/ufs/dinode.h>
23#include <ufs/ffs/fs.h>
249eea8a 24
8ebbce3e
KB
25#include <fcntl.h>
26#include <unistd.h>
b712d94e
KB
27#include <stdio.h>
28#include <ctype.h>
29#include <paths.h>
bea492ce 30
f6910205 31#define ISIZ (MAXBSIZE/sizeof(struct dinode))
f6910205
KM
32union {
33 struct fs u_sblock;
34 char dummy[SBSIZE];
35} sb_un;
36#define sblock sb_un.u_sblock
37struct dinode itab[MAXBSIZE/sizeof(struct dinode)];
359e6e11
SL
38
39struct du {
40 struct du *next;
bea492ce 41 long blocks;
359e6e11
SL
42 long blocks30;
43 long blocks60;
44 long blocks90;
bea492ce
BJ
45 long nfiles;
46 int uid;
359e6e11
SL
47#define NDU 2048
48} du[NDU];
49int ndu;
50#define DUHASH 8209 /* smallest prime >= 4 * NDU */
51#define HASH(u) ((u) % DUHASH)
52struct du *duhash[DUHASH];
53
bea492ce
BJ
54#define TSIZE 500
55int sizes[TSIZE];
56long overflow;
57
58int nflg;
59int fflg;
60int cflg;
6430f2d0 61int vflg;
f6910205 62int hflg;
249eea8a 63struct timeval now;
bea492ce 64
bea492ce 65unsigned ino;
bea492ce 66
74708eda 67char *user_from_uid();
bea492ce
BJ
68
69main(argc, argv)
359e6e11
SL
70 int argc;
71 char *argv[];
bea492ce 72{
84cfb8d9
KB
73 extern char *optarg;
74 extern int optind;
75 int ch;
84cfb8d9
KB
76
77 while ((ch = getopt(argc, argv, "cfhnv")) != EOF)
78 switch((char)ch) {
79 case 'c':
80 cflg++; break;
81 case 'f':
82 fflg++; break;
83 case 'h': /* undocumented */
84 hflg++; break;
85 case 'n':
86 nflg++; break;
87 case 'v': /* undocumented */
88 vflg++; break;
89 case '?':
90 default:
91 fputs("usage: quot [-cfn] [filesystem ...]\n", stderr);
92 exit(1);
93 }
94 argc -= optind;
95 argv += optind;
96
249eea8a 97 (void)gettimeofday(&now, NULL);
e6fecf21 98 setpassent(1);
84cfb8d9
KB
99 if (argc)
100 for (; *argv; ++argv) {
101 if (check(*argv, (char *)NULL) == 0)
102 report();
103 }
104 else
359e6e11 105 quotall();
84cfb8d9 106 exit(0);
359e6e11
SL
107}
108
84cfb8d9 109#include <sys/dir.h>
359e6e11
SL
110#include <fstab.h>
111
112quotall()
113{
114 register struct fstab *fs;
115 register char *cp;
84cfb8d9 116 char dev[MAXNAMLEN + 10], *rindex();
359e6e11 117
359e6e11 118 while (fs = getfsent()) {
baf18142
KM
119 if (strcmp(fs->fs_vfstype, "ufs") ||
120 (strcmp(fs->fs_type, FSTAB_RO) &&
359e6e11 121 strcmp(fs->fs_type, FSTAB_RW) &&
baf18142 122 strcmp(fs->fs_type, FSTAB_RQ)))
359e6e11
SL
123 continue;
124 cp = rindex(fs->fs_spec, '/');
125 if (cp == 0)
126 continue;
a4d097e6 127 (void)snprintf(dev, sizeof(dev), "%sr%s", _PATH_DEV, cp + 1);
619bf80a 128 if (check(dev, fs->fs_file) == 0)
359e6e11 129 report();
bea492ce 130 }
bea492ce
BJ
131}
132
619bf80a 133check(file, fsdir)
359e6e11 134 char *file;
619bf80a 135 char *fsdir;
bea492ce 136{
359e6e11
SL
137 register int i, j, nfiles;
138 register struct du **dp;
f6910205 139 daddr_t iblk;
84cfb8d9 140 long dev_bsize;
359e6e11 141 int c, fd;
3e6ca7df
KM
142 struct stat sb;
143 struct statfs sfs;
144#define FNBSZ 128
145 char filebuf[FNBSZ];
bea492ce 146
359e6e11 147 /*
249eea8a
KB
148 * Initialize tables between checks; because of the qsort done in
149 * report() the hash tables must be rebuilt each time.
359e6e11
SL
150 */
151 for (i = 0; i < TSIZE; i++)
152 sizes[i] = 0;
153 overflow = 0;
154 for (dp = duhash; dp < &duhash[DUHASH]; dp++)
155 *dp = 0;
156 ndu = 0;
3e6ca7df
KM
157 /*
158 * Make sure "file" refers to a char special file.
159 * Convert if necessary. Also make sure we have an fsdir.
160 */
161 if (stat(file, &sb) < 0) {
162 fprintf(stderr, "quot: ");
163 perror(file);
164 return (-1);
165 }
166 /*
167 * User specified "file".
168 * Attempt to come up with the appropriate char special file
169 * and a mount point.
170 */
171 if (fsdir == NULL) {
172 register struct fstab *fs;
173 int len = strlen(_PATH_DEV);
174
175 strcpy(filebuf, _PATH_DEV);
176 if (S_ISCHR(sb.st_mode)) {
177 if (strncmp(_PATH_DEV, file, len) == 0 &&
178 file[len] == 'r') {
179 strncpy(&filebuf[len], &file[len+1], FNBSZ-6);
180 fs = getfsspec(filebuf);
181 if (fs != NULL)
182 fsdir = fs->fs_file;
183 }
184 } else {
185 if (S_ISBLK(sb.st_mode)) {
186 fs = getfsspec(file);
187 if (fs != NULL)
188 fsdir = fs->fs_file;
189 } else {
190 if (statfs(file, &sfs) == 0) {
191 file = sfs.f_mntfromname;
192 fsdir = sfs.f_mntonname;
193 }
194 }
195 if (strncmp(_PATH_DEV, file, len) == 0) {
196 filebuf[len] = 'r';
197 strncpy(&filebuf[len+1], &file[len], FNBSZ-7);
198 file = filebuf;
199 }
200 }
201 }
359e6e11
SL
202 fd = open(file, O_RDONLY);
203 if (fd < 0) {
204 fprintf(stderr, "quot: ");
205 perror(file);
b47543fa 206 return (-1);
bea492ce 207 }
619bf80a
S
208 printf("%s", file);
209 if (fsdir == NULL) {
210 register struct fstab *fs = getfsspec(file);
211 if (fs != NULL)
212 fsdir = fs->fs_file;
213 }
214 if (fsdir != NULL && *fsdir != '\0')
215 printf(" (%s)", fsdir);
216 printf(":\n");
bea492ce 217 sync();
249eea8a 218 bread(fd, (off_t)SBOFF, (char *)&sblock, SBSIZE);
a66ab591 219 dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
bea492ce
BJ
220 if (nflg) {
221 if (isdigit(c = getchar()))
84cfb8d9 222 (void)ungetc(c, stdin);
359e6e11 223 else while (c != '\n' && c != EOF)
bea492ce
BJ
224 c = getchar();
225 }
f6910205
KM
226 nfiles = sblock.fs_ipg * sblock.fs_ncg;
227 for (ino = 0; ino < nfiles; ) {
39e484b3 228 iblk = fsbtodb(&sblock, ino_to_fsba(&sblock, ino));
249eea8a 229 bread(fd, (off_t)iblk * dev_bsize, itab, (int)sblock.fs_bsize);
ed77f19d
KM
230 for (j = 0; j < INOPB(&sblock) && ino < nfiles; j++, ino++) {
231 if (ino < ROOTINO)
f6910205 232 continue;
8ebbce3e 233 qacct(&itab[j]);
bea492ce
BJ
234 }
235 }
359e6e11 236 close(fd);
619bf80a 237 return (0);
bea492ce
BJ
238}
239
8ebbce3e 240qacct(ip)
f6910205 241 register struct dinode *ip;
bea492ce 242{
359e6e11
SL
243 register struct du *dp;
244 struct du **hp;
f6910205 245 long blks, frags, size;
619bf80a 246 int n;
bea492ce
BJ
247 static fino;
248
359e6e11 249 if ((ip->di_mode & IFMT) == 0)
bea492ce 250 return;
359e6e11
SL
251 /*
252 * By default, take block count in inode. Otherwise (-h),
253 * take the size field and estimate the blocks allocated.
254 * The latter does not account for holes in files.
255 */
256 if (!hflg)
81ac5aae 257 size = ip->di_blocks / 2;
359e6e11 258 else {
81ac5aae
KM
259 blks = lblkno(&sblock, ip->di_size);
260 frags = blks * sblock.fs_frag +
261 numfrags(&sblock, dblksize(&sblock, ip, blks));
262 size = frags * sblock.fs_fsize / 1024;
f6910205 263 }
bea492ce 264 if (cflg) {
359e6e11 265 if ((ip->di_mode&IFMT) != IFDIR && (ip->di_mode&IFMT) != IFREG)
bea492ce 266 return;
f6910205
KM
267 if (size >= TSIZE) {
268 overflow += size;
269 size = TSIZE-1;
bea492ce 270 }
f6910205 271 sizes[size]++;
bea492ce
BJ
272 return;
273 }
359e6e11
SL
274 hp = &duhash[HASH(ip->di_uid)];
275 for (dp = *hp; dp; dp = dp->next)
276 if (dp->uid == ip->di_uid)
277 break;
278 if (dp == 0) {
279 if (ndu >= NDU)
280 return;
281 dp = &du[ndu++];
282 dp->next = *hp;
283 *hp = dp;
284 dp->uid = ip->di_uid;
285 dp->nfiles = 0;
286 dp->blocks = 0;
287 dp->blocks30 = 0;
288 dp->blocks60 = 0;
289 dp->blocks90 = 0;
290 }
291 dp->blocks += size;
6430f2d0 292#define DAY (60 * 60 * 24) /* seconds per day */
5389d836 293 if (now.tv_sec - ip->di_atime.ts_sec > 30 * DAY)
359e6e11 294 dp->blocks30 += size;
5389d836 295 if (now.tv_sec - ip->di_atime.ts_sec > 60 * DAY)
359e6e11 296 dp->blocks60 += size;
5389d836 297 if (now.tv_sec - ip->di_atime.ts_sec > 90 * DAY)
359e6e11
SL
298 dp->blocks90 += size;
299 dp->nfiles++;
300 while (nflg) {
301 register char *np;
302
303 if (fino == 0)
304 if (scanf("%d", &fino) <= 0)
bea492ce
BJ
305 return;
306 if (fino > ino)
307 return;
359e6e11
SL
308 if (fino < ino) {
309 while ((n = getchar()) != '\n' && n != EOF)
bea492ce
BJ
310 ;
311 fino = 0;
359e6e11 312 continue;
bea492ce 313 }
74708eda 314 if (np = user_from_uid(dp->uid, 1))
84cfb8d9 315 printf("%.7s\t", np);
bea492ce 316 else
84cfb8d9 317 printf("%u\t", ip->di_uid);
359e6e11 318 while ((n = getchar()) == ' ' || n == '\t')
bea492ce
BJ
319 ;
320 putchar(n);
359e6e11 321 while (n != EOF && n != '\n') {
bea492ce
BJ
322 n = getchar();
323 putchar(n);
324 }
325 fino = 0;
359e6e11 326 break;
bea492ce
BJ
327 }
328}
329
359e6e11 330bread(fd, bno, buf, cnt)
249eea8a 331 int fd, cnt;
2f42a3e4 332 off_t bno;
249eea8a 333 void *buf;
bea492ce 334{
84cfb8d9 335 (void)lseek(fd, bno, L_SET);
359e6e11 336 if (read(fd, buf, cnt) != cnt) {
84cfb8d9 337 fprintf(stderr, "quot: read error at block %ld\n", bno);
bea492ce
BJ
338 exit(1);
339 }
340}
341
342qcmp(p1, p2)
359e6e11 343 register struct du *p1, *p2;
bea492ce 344{
359e6e11
SL
345 char *s1, *s2;
346
bea492ce 347 if (p1->blocks > p2->blocks)
359e6e11 348 return (-1);
bea492ce 349 if (p1->blocks < p2->blocks)
359e6e11 350 return (1);
74708eda 351 s1 = user_from_uid(p1->uid, 1);
359e6e11
SL
352 if (s1 == 0)
353 return (0);
74708eda 354 s2 = user_from_uid(p2->uid, 1);
359e6e11
SL
355 if (s2 == 0)
356 return (0);
357 return (strcmp(s1, s2));
bea492ce
BJ
358}
359
360report()
361{
362 register i;
359e6e11 363 register struct du *dp;
bea492ce
BJ
364
365 if (nflg)
366 return;
367 if (cflg) {
359e6e11
SL
368 register long t = 0;
369
370 for (i = 0; i < TSIZE - 1; i++)
bea492ce
BJ
371 if (sizes[i]) {
372 t += i*sizes[i];
84cfb8d9 373 printf("%d\t%d\t%ld\n", i, sizes[i], t);
bea492ce 374 }
84cfb8d9 375 printf("%d\t%d\t%ld\n",
359e6e11 376 TSIZE - 1, sizes[TSIZE - 1], overflow + t);
bea492ce
BJ
377 return;
378 }
359e6e11
SL
379 qsort(du, ndu, sizeof (du[0]), qcmp);
380 for (dp = du; dp < &du[ndu]; dp++) {
381 register char *cp;
382
383 if (dp->blocks == 0)
bea492ce 384 return;
359e6e11 385 printf("%5D\t", dp->blocks);
bea492ce 386 if (fflg)
359e6e11 387 printf("%5D\t", dp->nfiles);
74708eda 388 if (cp = user_from_uid(dp->uid, 1))
359e6e11 389 printf("%-8.8s", cp);
bea492ce 390 else
359e6e11 391 printf("#%-8d", dp->uid);
6430f2d0
BJ
392 if (vflg)
393 printf("\t%5D\t%5D\t%5D",
359e6e11 394 dp->blocks30, dp->blocks60, dp->blocks90);
6430f2d0 395 printf("\n");
bea492ce
BJ
396 }
397}