file reorg, pathnames.h
[unix-history] / usr / src / usr.sbin / quot / quot.c
... / ...
CommitLineData
1#ifndef lint
2static char *sccsid = "@(#)quot.c 4.16 (Berkeley) 89/05/15";
3#endif
4
5/*
6 * quot
7 */
8
9#include <sys/param.h>
10#include <sys/inode.h>
11#include <sys/fs.h>
12#include <sys/file.h>
13#include <stdio.h>
14#include <ctype.h>
15#include <paths.h>
16
17#define ISIZ (MAXBSIZE/sizeof(struct dinode))
18union {
19 struct fs u_sblock;
20 char dummy[SBSIZE];
21} sb_un;
22#define sblock sb_un.u_sblock
23struct dinode itab[MAXBSIZE/sizeof(struct dinode)];
24
25struct du {
26 struct du *next;
27 long blocks;
28 long blocks30;
29 long blocks60;
30 long blocks90;
31 long nfiles;
32 int uid;
33#define NDU 2048
34} du[NDU];
35int ndu;
36#define DUHASH 8209 /* smallest prime >= 4 * NDU */
37#define HASH(u) ((u) % DUHASH)
38struct du *duhash[DUHASH];
39
40#define TSIZE 500
41int sizes[TSIZE];
42long overflow;
43
44int nflg;
45int fflg;
46int cflg;
47int vflg;
48int hflg;
49long now;
50
51unsigned ino;
52
53char *malloc();
54char *getname();
55
56main(argc, argv)
57 int argc;
58 char *argv[];
59{
60 extern char *optarg;
61 extern int optind;
62 int ch;
63 time_t time();
64
65 while ((ch = getopt(argc, argv, "cfhnv")) != EOF)
66 switch((char)ch) {
67 case 'c':
68 cflg++; break;
69 case 'f':
70 fflg++; break;
71 case 'h': /* undocumented */
72 hflg++; break;
73 case 'n':
74 nflg++; break;
75 case 'v': /* undocumented */
76 vflg++; break;
77 case '?':
78 default:
79 fputs("usage: quot [-cfn] [filesystem ...]\n", stderr);
80 exit(1);
81 }
82 argc -= optind;
83 argv += optind;
84
85 (void)time(&now);
86 setpassent(1);
87 if (argc)
88 for (; *argv; ++argv) {
89 if (check(*argv, (char *)NULL) == 0)
90 report();
91 }
92 else
93 quotall();
94 exit(0);
95}
96
97#include <sys/dir.h>
98#include <fstab.h>
99
100quotall()
101{
102 register struct fstab *fs;
103 register char *cp;
104 char dev[MAXNAMLEN + 10], *rindex();
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 (void)sprintf(dev, "%s/r%s", _PATH_DEV, cp + 1);
115 if (check(dev, fs->fs_file) == 0)
116 report();
117 }
118}
119
120check(file, fsdir)
121 char *file;
122 char *fsdir;
123{
124 register int i, j, nfiles;
125 register struct du **dp;
126 daddr_t iblk;
127 long dev_bsize;
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, (long)SBOFF, (char *)&sblock, SBSIZE);
158 dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
159 if (nflg) {
160 if (isdigit(c = getchar()))
161 (void)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 * dev_bsize, (char *)itab, (int)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
179acct(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\t", np);
255 else
256 printf("%u\t", 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
269bread(fd, bno, buf, cnt)
270 long bno;
271 char *buf;
272{
273 off_t lseek();
274
275 (void)lseek(fd, bno, L_SET);
276 if (read(fd, buf, cnt) != cnt) {
277 fprintf(stderr, "quot: read error at block %ld\n", bno);
278 exit(1);
279 }
280}
281
282qcmp(p1, p2)
283 register struct du *p1, *p2;
284{
285 char *s1, *s2;
286
287 if (p1->blocks > p2->blocks)
288 return (-1);
289 if (p1->blocks < p2->blocks)
290 return (1);
291 s1 = getname(p1->uid);
292 if (s1 == 0)
293 return (0);
294 s2 = getname(p2->uid);
295 if (s2 == 0)
296 return (0);
297 return (strcmp(s1, s2));
298}
299
300report()
301{
302 register i;
303 register struct du *dp;
304
305 if (nflg)
306 return;
307 if (cflg) {
308 register long t = 0;
309
310 for (i = 0; i < TSIZE - 1; i++)
311 if (sizes[i]) {
312 t += i*sizes[i];
313 printf("%d\t%d\t%ld\n", i, sizes[i], t);
314 }
315 printf("%d\t%d\t%ld\n",
316 TSIZE - 1, sizes[TSIZE - 1], overflow + t);
317 return;
318 }
319 qsort(du, ndu, sizeof (du[0]), qcmp);
320 for (dp = du; dp < &du[ndu]; dp++) {
321 register char *cp;
322
323 if (dp->blocks == 0)
324 return;
325 printf("%5D\t", dp->blocks);
326 if (fflg)
327 printf("%5D\t", dp->nfiles);
328 if (cp = getname(dp->uid))
329 printf("%-8.8s", cp);
330 else
331 printf("#%-8d", dp->uid);
332 if (vflg)
333 printf("\t%5D\t%5D\t%5D",
334 dp->blocks30, dp->blocks60, dp->blocks90);
335 printf("\n");
336 }
337}
338
339/* rest should be done with nameserver or database */
340
341#include <pwd.h>
342#include <grp.h>
343#include <utmp.h>
344
345struct utmp utmp;
346#define NMAX (sizeof (utmp.ut_name))
347#define SCPYN(a, b) strncpy(a, b, NMAX)
348
349#define NUID 64 /* power of 2 */
350#define UIDMASK 0x3f
351
352struct ncache {
353 int uid;
354 char name[NMAX+1];
355} nc[NUID];
356
357char *
358getname(uid)
359{
360 register struct passwd *pw;
361 struct passwd *getpwent();
362 register int cp;
363
364 cp = uid & UIDMASK;
365 if (uid >= 0 && nc[cp].uid == uid && nc[cp].name[0])
366 return (nc[cp].name);
367 pw = getpwuid(uid);
368 if (!pw)
369 return (0);
370 nc[cp].uid = uid;
371 SCPYN(nc[cp].name, pw->pw_name);
372 return (nc[cp].name);
373}