rip out mention of default file system, list options in synopsis
[unix-history] / usr / src / usr.sbin / quot / quot.c
CommitLineData
b47543fa 1#ifndef lint
9bd38ba8 2static char *sccsid = "@(#)quot.c 4.13 (Berkeley) 87/10/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;
a66ab591 49long dev_bsize = 1;
bea492ce 50
bea492ce 51unsigned ino;
bea492ce 52
bea492ce 53char *malloc();
359e6e11 54char *getname();
bea492ce
BJ
55
56main(argc, argv)
359e6e11
SL
57 int argc;
58 char *argv[];
bea492ce
BJ
59{
60 register int n;
bea492ce 61
6430f2d0 62 now = time(0);
359e6e11
SL
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++;
bea492ce 85 }
359e6e11
SL
86 if (argc == 0)
87 quotall();
88 while (argc-- > 0)
619bf80a 89 if (check(*argv++, (char *)NULL) == 0)
359e6e11
SL
90 report();
91 exit (0);
92}
93
94#include <fstab.h>
95
96quotall()
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);
6430f2d0 104 exit(1);
bea492ce 105 }
359e6e11
SL
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;
9bd38ba8 114 (void)sprintf(dev, "/dev/r%s", cp + 1);
619bf80a 115 if (check(dev, fs->fs_file) == 0)
359e6e11 116 report();
bea492ce 117 }
359e6e11 118 endfsent();
bea492ce
BJ
119}
120
619bf80a 121check(file, fsdir)
359e6e11 122 char *file;
619bf80a 123 char *fsdir;
bea492ce 124{
359e6e11
SL
125 register int i, j, nfiles;
126 register struct du **dp;
f6910205 127 daddr_t iblk;
359e6e11 128 int c, fd;
bea492ce 129
359e6e11
SL
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);
b47543fa 145 return (-1);
bea492ce 146 }
619bf80a
S
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");
bea492ce 156 sync();
a66ab591
KM
157 bread(fd, SBOFF, (char *)&sblock, SBSIZE);
158 dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
bea492ce
BJ
159 if (nflg) {
160 if (isdigit(c = getchar()))
161 ungetc(c, stdin);
359e6e11 162 else while (c != '\n' && c != EOF)
bea492ce
BJ
163 c = getchar();
164 }
f6910205
KM
165 nfiles = sblock.fs_ipg * sblock.fs_ncg;
166 for (ino = 0; ino < nfiles; ) {
167 iblk = fsbtodb(&sblock, itod(&sblock, ino));
359e6e11 168 bread(fd, iblk, (char *)itab, sblock.fs_bsize);
ed77f19d
KM
169 for (j = 0; j < INOPB(&sblock) && ino < nfiles; j++, ino++) {
170 if (ino < ROOTINO)
f6910205 171 continue;
bea492ce
BJ
172 acct(&itab[j]);
173 }
174 }
359e6e11 175 close(fd);
619bf80a 176 return (0);
bea492ce
BJ
177}
178
179acct(ip)
f6910205 180 register struct dinode *ip;
bea492ce 181{
359e6e11
SL
182 register struct du *dp;
183 struct du **hp;
f6910205 184 long blks, frags, size;
619bf80a 185 int n;
bea492ce
BJ
186 static fino;
187
359e6e11 188 if ((ip->di_mode & IFMT) == 0)
bea492ce 189 return;
359e6e11
SL
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)
81ac5aae 196 size = ip->di_blocks / 2;
359e6e11 197 else {
81ac5aae
KM
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;
f6910205 202 }
bea492ce 203 if (cflg) {
359e6e11 204 if ((ip->di_mode&IFMT) != IFDIR && (ip->di_mode&IFMT) != IFREG)
bea492ce 205 return;
f6910205
KM
206 if (size >= TSIZE) {
207 overflow += size;
208 size = TSIZE-1;
bea492ce 209 }
f6910205 210 sizes[size]++;
bea492ce
BJ
211 return;
212 }
359e6e11
SL
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;
6430f2d0
BJ
231#define DAY (60 * 60 * 24) /* seconds per day */
232 if (now - ip->di_atime > 30 * DAY)
359e6e11 233 dp->blocks30 += size;
6430f2d0 234 if (now - ip->di_atime > 60 * DAY)
359e6e11 235 dp->blocks60 += size;
6430f2d0 236 if (now - ip->di_atime > 90 * DAY)
359e6e11
SL
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)
bea492ce
BJ
244 return;
245 if (fino > ino)
246 return;
359e6e11
SL
247 if (fino < ino) {
248 while ((n = getchar()) != '\n' && n != EOF)
bea492ce
BJ
249 ;
250 fino = 0;
359e6e11 251 continue;
bea492ce 252 }
359e6e11 253 if (np = getname(dp->uid))
bea492ce
BJ
254 printf("%.7s ", np);
255 else
256 printf("%d ", ip->di_uid);
359e6e11 257 while ((n = getchar()) == ' ' || n == '\t')
bea492ce
BJ
258 ;
259 putchar(n);
359e6e11 260 while (n != EOF && n != '\n') {
bea492ce
BJ
261 n = getchar();
262 putchar(n);
263 }
264 fino = 0;
359e6e11 265 break;
bea492ce
BJ
266 }
267}
268
359e6e11
SL
269bread(fd, bno, buf, cnt)
270 unsigned bno;
271 char *buf;
bea492ce
BJ
272{
273
a66ab591 274 lseek(fd, (long)bno * dev_bsize, L_SET);
359e6e11
SL
275 if (read(fd, buf, cnt) != cnt) {
276 fprintf(stderr, "quot: read error at block %u\n", bno);
bea492ce
BJ
277 exit(1);
278 }
279}
280
281qcmp(p1, p2)
359e6e11 282 register struct du *p1, *p2;
bea492ce 283{
359e6e11
SL
284 char *s1, *s2;
285
bea492ce 286 if (p1->blocks > p2->blocks)
359e6e11 287 return (-1);
bea492ce 288 if (p1->blocks < p2->blocks)
359e6e11
SL
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));
bea492ce
BJ
297}
298
299report()
300{
301 register i;
359e6e11 302 register struct du *dp;
bea492ce
BJ
303
304 if (nflg)
305 return;
306 if (cflg) {
359e6e11
SL
307 register long t = 0;
308
309 for (i = 0; i < TSIZE - 1; i++)
bea492ce
BJ
310 if (sizes[i]) {
311 t += i*sizes[i];
312 printf("%d %d %D\n", i, sizes[i], t);
313 }
359e6e11
SL
314 printf("%d %d %D\n",
315 TSIZE - 1, sizes[TSIZE - 1], overflow + t);
bea492ce
BJ
316 return;
317 }
359e6e11
SL
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)
bea492ce 323 return;
359e6e11 324 printf("%5D\t", dp->blocks);
bea492ce 325 if (fflg)
359e6e11
SL
326 printf("%5D\t", dp->nfiles);
327 if (cp = getname(dp->uid))
328 printf("%-8.8s", cp);
bea492ce 329 else
359e6e11 330 printf("#%-8d", dp->uid);
6430f2d0
BJ
331 if (vflg)
332 printf("\t%5D\t%5D\t%5D",
359e6e11 333 dp->blocks30, dp->blocks60, dp->blocks90);
6430f2d0 334 printf("\n");
bea492ce
BJ
335 }
336}
337
e43e6c78
KM
338/* rest should be done with nameserver or database */
339
359e6e11 340#include <pwd.h>
e43e6c78 341#include <grp.h>
359e6e11
SL
342#include <utmp.h>
343
344struct utmp utmp;
359e6e11 345#define NMAX (sizeof (utmp.ut_name))
e43e6c78 346#define SCPYN(a, b) strncpy(a, b, NMAX)
359e6e11 347
e43e6c78
KM
348#define NUID 64 /* power of 2 */
349#define UIDMASK 0x3f
350
351struct ncache {
352 int uid;
353 char name[NMAX+1];
354} nc[NUID];
359e6e11
SL
355char outrangename[NMAX+1];
356int outrangeuid = -1;
357
bea492ce 358char *
359e6e11 359getname(uid)
bea492ce 360{
359e6e11 361 register struct passwd *pw;
359e6e11 362 struct passwd *getpwent();
e43e6c78
KM
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)
359e6e11 372 return (0);
e43e6c78
KM
373 nc[cp].uid = uid;
374 SCPYN(nc[cp].name, pw->pw_name);
375 return (nc[cp].name);
bea492ce 376}