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