8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / fs.d / ufs / quot / quot.c
blob674c710548daf9f380b6542812193deadcc5c960
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
39 #pragma ident "%Z%%M% %I% %E% SMI"
42 * quot
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <ctype.h>
48 #include <string.h>
49 #include <limits.h>
50 #include <pwd.h>
51 #include <sys/mnttab.h>
52 #include <sys/param.h>
53 #include <sys/types.h>
54 #include <unistd.h>
55 #include <sys/mntent.h>
56 #include <sys/vnode.h>
57 #include <sys/fs/ufs_inode.h>
58 #include <sys/fs/ufs_fs.h>
59 #include <sys/file.h>
60 #include <sys/stat.h>
61 #include <fcntl.h>
63 #define ISIZ (MAXBSIZE/sizeof (struct dinode))
64 static union {
65 struct fs u_sblock;
66 char dummy[SBSIZE];
67 } sb_un;
68 #define sblock sb_un.u_sblock
69 static struct dinode *itab;
71 struct du {
72 struct du *next;
73 long blocks;
74 long blocks30;
75 long blocks60;
76 long blocks90;
77 long nfiles;
78 uid_t uid;
79 char *u_name;
81 static struct du **du;
83 #define UHASH 8209
84 static int ndu;
85 #define HASH(u) ((uint_t)(u) % UHASH)
86 static struct du *duhashtbl[UHASH];
88 #define TSIZE 2048
89 static int sizes[TSIZE];
90 static offset_t overflow;
92 static int nflg;
93 static int fflg;
94 static int cflg;
95 static int vflg;
96 static int hflg;
97 static int aflg;
98 static long now;
100 static unsigned ino;
102 static void usage(void);
103 static void quotall(void);
104 static void qacct(struct dinode *);
105 static void bread(int, diskaddr_t, char *, int);
106 static void report(void);
107 static int getdev(char **);
108 static int check(char *, char *);
109 static struct du *adduid(uid_t);
110 static struct du *lookup(uid_t);
111 static void sortprep(void);
112 static void cleanup(void);
114 static void
115 usage()
117 (void) fprintf(stderr, "ufs usage: quot [-nfcvha] [filesystem ...]\n");
121 main(int argc, char *argv[])
123 int opt;
124 int i;
126 if (argc == 1) {
127 (void) fprintf(stderr,
128 "ufs Usage: quot [-nfcvha] [filesystem ...]\n");
129 return (32);
132 now = time(0);
133 while ((opt = getopt(argc, argv, "nfcvhaV")) != EOF) {
134 switch (opt) {
135 case 'n':
136 nflg++;
137 break;
138 case 'f':
139 fflg++;
140 break;
141 case 'c':
142 cflg++;
143 break;
144 case 'v':
145 vflg++;
146 break;
147 case 'h':
148 hflg++;
149 break;
150 case 'a':
151 aflg++;
152 break;
153 case 'V': /* Print command line */
155 char *opt_text;
156 int opt_count;
158 (void) fprintf(stdout, "quot -F UFS ");
159 for (opt_count = 1; opt_count < argc;
160 opt_count++) {
161 opt_text = argv[opt_count];
162 if (opt_text)
163 (void) fprintf(stdout, " %s ",
164 opt_text);
166 (void) fprintf(stdout, "\n");
168 break;
169 case '?':
170 usage();
171 return (32);
175 if (aflg) {
176 quotall();
179 for (i = optind; i < argc; i++) {
180 if ((getdev(&argv[i]) == 0) &&
181 (check(argv[i], (char *)NULL) == 0)) {
182 report();
183 cleanup();
186 return (0);
189 static void
190 quotall()
192 FILE *fstab;
193 struct mnttab mntp;
194 char *cp;
196 extern char *getfullrawname();
198 fstab = fopen(MNTTAB, "r");
199 if (fstab == NULL) {
200 (void) fprintf(stderr, "quot: no %s file\n", MNTTAB);
201 exit(32);
203 while (getmntent(fstab, &mntp) == NULL) {
204 if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) != 0)
205 continue;
207 if ((cp = getfullrawname(mntp.mnt_special)) == NULL)
208 continue;
210 if (*cp == '\0')
211 continue;
213 if (check(cp, mntp.mnt_mountp) == 0) {
214 report();
215 cleanup();
218 free(cp);
220 (void) fclose(fstab);
223 static int
224 check(char *file, char *fsdir)
226 FILE *fstab;
227 int i, j;
228 int c, fd;
232 * Initialize tables between checks;
233 * because of the qsort done in report()
234 * the hash tables must be rebuilt each time.
236 for (i = 0; i < TSIZE; i++)
237 sizes[i] = 0;
238 overflow = 0LL;
239 ndu = 0;
240 fd = open64(file, O_RDONLY);
241 if (fd < 0) {
242 (void) fprintf(stderr, "quot: ");
243 perror(file);
244 exit(32);
246 (void) printf("%s", file);
247 if (fsdir == NULL) {
248 struct mnttab mntp;
250 fstab = fopen(MNTTAB, "r");
251 if (fstab == NULL) {
252 (void) fprintf(stderr, "quot: no %s file\n", MNTTAB);
253 exit(32);
255 while (getmntent(fstab, &mntp) == NULL) {
256 if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) != 0)
257 continue;
258 if (strcmp(mntp.mnt_special, file) == 0) {
259 fsdir = mntp.mnt_mountp;
260 break;
264 if (fsdir != NULL && *fsdir != '\0')
265 (void) printf(" (%s)", fsdir);
266 (void) printf(":\n");
267 sync();
268 bread(fd, (diskaddr_t)SBLOCK, (char *)&sblock, SBSIZE);
269 if (nflg) {
270 if (isdigit(c = getchar()))
271 (void) ungetc(c, stdin);
272 else while (c != '\n' && c != EOF)
273 c = getchar();
276 itab = (struct dinode *)calloc(sblock.fs_ipg, sizeof (struct dinode));
277 if (itab == NULL) {
278 (void) fprintf(stderr,
279 "not enough memory to allocate tables\n");
280 return (1);
283 ino = 0;
284 for (c = 0; c < sblock.fs_ncg; c++) {
285 bread(fd, (diskaddr_t)fsbtodb(&sblock, cgimin(&sblock, c)),
286 (char *)itab,
287 (int)(sblock.fs_ipg * sizeof (struct dinode)));
288 for (j = 0; j < sblock.fs_ipg; j++, ino++) {
289 if (ino < UFSROOTINO)
290 continue;
291 qacct(&itab[j]);
294 (void) close(fd);
295 return (0);
298 static void
299 qacct(struct dinode *ip)
301 struct du *dp;
302 long blks, frags, size;
303 int n;
304 static int fino;
306 ip->di_mode = ip->di_smode;
307 if (ip->di_suid != UID_LONG) {
308 ip->di_uid = ip->di_suid;
310 if ((ip->di_mode & IFMT) == 0)
311 return;
313 * By default, take block count in inode. Otherwise (-h),
314 * take the size field and estimate the blocks allocated.
315 * The latter does not account for holes in files.
317 if (!hflg)
318 size = ip->di_blocks / 2;
319 else {
320 blks = lblkno(&sblock, ip->di_size);
321 frags = blks * sblock.fs_frag +
322 numfrags(&sblock, dblksize(&sblock, ip, blks));
324 * Must cast to offset_t because for a large file,
325 * frags multiplied by sblock.fs_fsize will not fit in a long.
326 * However, when divided by 1024, the end result will fit in
327 * the 32 bit size variable (40 bit UFS).
329 size = (long)((offset_t)frags * (offset_t)sblock.fs_fsize / 1024);
331 if (cflg) {
332 if ((ip->di_mode&IFMT) != IFDIR && (ip->di_mode&IFMT) != IFREG)
333 return;
334 if (size >= TSIZE) {
335 overflow += (offset_t)size;
336 size = TSIZE-1;
338 sizes[size]++;
339 return;
341 dp = lookup(ip->di_uid);
342 if (dp == NULL)
343 return;
344 dp->blocks += size;
345 #define DAY (60 * 60 * 24) /* seconds per day */
346 if (now - ip->di_atime > 30 * DAY)
347 dp->blocks30 += size;
348 if (now - ip->di_atime > 60 * DAY)
349 dp->blocks60 += size;
350 if (now - ip->di_atime > 90 * DAY)
351 dp->blocks90 += size;
352 dp->nfiles++;
353 while (nflg) {
354 if (fino == 0)
355 if (scanf("%d", &fino) <= 0)
356 return;
357 if (fino > ino)
358 return;
359 if (fino < ino) {
360 while ((n = getchar()) != '\n' && n != EOF)
362 fino = 0;
363 continue;
365 if (dp->u_name)
366 (void) printf("%.7s ", dp->u_name);
367 else
368 (void) printf("%ld ", (long)ip->di_uid);
369 while ((n = getchar()) == ' ' || n == '\t')
371 (void) putchar(n);
372 while (n != EOF && n != '\n') {
373 n = getchar();
374 (void) putchar(n);
376 fino = 0;
377 break;
381 static void
382 bread(int fd, diskaddr_t bno, char *buf, int cnt)
384 int ret;
386 if (llseek(fd, (offset_t)(bno * DEV_BSIZE), SEEK_SET) < 0) {
387 perror("llseek");
388 exit(32);
391 if ((ret = read(fd, buf, cnt)) != cnt) {
392 (void) fprintf(stderr, "quot: read returns %d (cnt = %d)\n",
393 ret, cnt);
394 (void) fprintf(stderr, "quot: read error at block %lld\n", bno);
395 perror("read");
396 exit(32);
400 static int
401 qcmp(const void *arg1, const void *arg2)
403 struct du **p1 = (struct du **)arg1;
404 struct du **p2 = (struct du **)arg2;
405 char *s1, *s2;
407 if ((*p1)->blocks > (*p2)->blocks)
408 return (-1);
409 if ((*p1)->blocks < (*p2)->blocks)
410 return (1);
411 s1 = (*p1)->u_name;
412 if (s1 == NULL)
413 return (0);
414 s2 = (*p2)->u_name;
415 if (s2 == NULL)
416 return (0);
417 return (strcmp(s1, s2));
420 static void
421 report()
423 int i;
424 struct du **dp;
425 int cnt;
427 if (nflg)
428 return;
429 if (cflg) {
430 long t = 0;
432 for (i = 0; i < TSIZE - 1; i++)
433 if (sizes[i]) {
434 t += i*sizes[i];
435 (void) printf("%d %d %ld\n",
436 i, sizes[i], t);
438 if (sizes[TSIZE -1 ])
439 (void) printf("%d %d %lld\n", TSIZE - 1,
440 sizes[TSIZE - 1], overflow + (offset_t)t);
441 return;
443 sortprep();
444 qsort(du, ndu, sizeof (du[0]), qcmp);
445 for (cnt = 0, dp = &du[0]; dp && cnt != ndu; dp++, cnt++) {
446 if ((*dp)->blocks == 0)
447 return;
448 (void) printf("%5ld\t", (*dp)->blocks);
449 if (fflg)
450 (void) printf("%5ld\t", (*dp)->nfiles);
452 if ((*dp)->u_name)
453 (void) printf("%-8s", (*dp)->u_name);
454 else
455 (void) printf("#%-8ld", (long)(*dp)->uid);
456 if (vflg)
457 (void) printf("\t%5ld\t%5ld\t%5ld",
458 (*dp)->blocks30, (*dp)->blocks60, (*dp)->blocks90);
459 (void) printf("\n");
465 static int
466 getdev(char **devpp)
468 struct stat64 statb;
469 FILE *fstab;
470 struct mnttab mntp;
471 char *cp; /* Pointer to raw device name */
473 extern char *getfullrawname();
475 if (stat64(*devpp, &statb) < 0) {
476 perror(*devpp);
477 exit(32);
479 if ((statb.st_mode & S_IFMT) == S_IFCHR)
480 return (0);
481 if ((statb.st_mode & S_IFMT) == S_IFBLK) {
482 /* If we can't get the raw name, keep the block name */
483 if ((cp = getfullrawname(*devpp)) != NULL)
484 *devpp = strdup(cp);
485 return (0);
487 fstab = fopen(MNTTAB, "r");
488 if (fstab == NULL) {
489 (void) fprintf(stderr, "quot: no %s file\n", MNTTAB);
490 exit(32);
492 while (getmntent(fstab, &mntp) == NULL) {
493 if (strcmp(mntp.mnt_mountp, *devpp) == 0) {
494 if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) != 0) {
495 (void) fprintf(stderr,
496 "quot: %s not ufs filesystem\n",
497 *devpp);
498 exit(32);
500 /* If we can't get the raw name, use the block name */
501 if ((cp = getfullrawname(mntp.mnt_special)) == NULL)
502 cp = mntp.mnt_special;
503 *devpp = strdup(cp);
504 (void) fclose(fstab);
505 return (0);
508 (void) fclose(fstab);
509 (void) fprintf(stderr, "quot: %s doesn't appear to be a filesystem.\n",
510 *devpp);
511 usage();
512 exit(32);
513 /* NOTREACHED */
516 static struct du *
517 lookup(uid_t uid)
519 struct passwd *pwp;
520 struct du *up;
522 for (up = duhashtbl[HASH(uid)]; up != NULL; up = up->next) {
523 if (up->uid == uid)
524 return (up);
527 pwp = getpwuid(uid);
529 up = adduid(uid);
530 if (up && pwp) {
531 up->u_name = strdup(pwp->pw_name);
533 return (up);
536 static struct du *
537 adduid(uid_t uid)
539 struct du *up, **uhp;
541 up = (struct du *)calloc(1, sizeof (struct du));
542 if (up == NULL) {
543 (void) fprintf(stderr,
544 "out of memory for du structures\n");
545 exit(32);
548 uhp = &duhashtbl[HASH(uid)];
549 up->next = *uhp;
550 *uhp = up;
551 up->uid = uid;
552 up->u_name = NULL;
553 ndu++;
554 return (up);
557 static void
558 sortprep()
560 struct du **dp, *ep;
561 struct du **hp;
562 int i, cnt = 0;
564 dp = NULL;
566 dp = (struct du **)calloc(ndu, sizeof (struct du **));
567 if (dp == NULL) {
568 (void) fprintf(stderr,
569 "out of memory for du structures\n");
570 exit(32);
573 for (hp = duhashtbl, i = 0; i != UHASH; i++) {
574 if (hp[i] == NULL)
575 continue;
577 for (ep = hp[i]; ep; ep = ep->next) {
578 dp[cnt++] = ep;
581 du = dp;
584 static void
585 cleanup()
587 int i;
588 struct du *ep, *next;
591 * Release memory from hash table and du
594 if (du) {
595 free(du);
596 du = NULL;
600 for (i = 0; i != UHASH; i++) {
601 if (duhashtbl[i] == NULL)
602 continue;
603 ep = duhashtbl[i];
604 while (ep) {
605 next = ep->next;
606 if (ep->u_name) {
607 free(ep->u_name);
609 free(ep);
610 ep = next;
612 duhashtbl[i] = NULL;