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]
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
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
39 #pragma ident "%Z%%M% %I% %E% SMI"
51 #include <sys/mnttab.h>
52 #include <sys/param.h>
53 #include <sys/types.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>
63 #define ISIZ (MAXBSIZE/sizeof (struct dinode))
68 #define sblock sb_un.u_sblock
69 static struct dinode
*itab
;
81 static struct du
**du
;
85 #define HASH(u) ((uint_t)(u) % UHASH)
86 static struct du
*duhashtbl
[UHASH
];
89 static int sizes
[TSIZE
];
90 static offset_t overflow
;
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);
117 (void) fprintf(stderr
, "ufs usage: quot [-nfcvha] [filesystem ...]\n");
121 main(int argc
, char *argv
[])
127 (void) fprintf(stderr
,
128 "ufs Usage: quot [-nfcvha] [filesystem ...]\n");
133 while ((opt
= getopt(argc
, argv
, "nfcvhaV")) != EOF
) {
153 case 'V': /* Print command line */
158 (void) fprintf(stdout
, "quot -F UFS ");
159 for (opt_count
= 1; opt_count
< argc
;
161 opt_text
= argv
[opt_count
];
163 (void) fprintf(stdout
, " %s ",
166 (void) fprintf(stdout
, "\n");
179 for (i
= optind
; i
< argc
; i
++) {
180 if ((getdev(&argv
[i
]) == 0) &&
181 (check(argv
[i
], (char *)NULL
) == 0)) {
196 extern char *getfullrawname();
198 fstab
= fopen(MNTTAB
, "r");
200 (void) fprintf(stderr
, "quot: no %s file\n", MNTTAB
);
203 while (getmntent(fstab
, &mntp
) == NULL
) {
204 if (strcmp(mntp
.mnt_fstype
, MNTTYPE_UFS
) != 0)
207 if ((cp
= getfullrawname(mntp
.mnt_special
)) == NULL
)
213 if (check(cp
, mntp
.mnt_mountp
) == 0) {
220 (void) fclose(fstab
);
224 check(char *file
, char *fsdir
)
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
++)
240 fd
= open64(file
, O_RDONLY
);
242 (void) fprintf(stderr
, "quot: ");
246 (void) printf("%s", file
);
250 fstab
= fopen(MNTTAB
, "r");
252 (void) fprintf(stderr
, "quot: no %s file\n", MNTTAB
);
255 while (getmntent(fstab
, &mntp
) == NULL
) {
256 if (strcmp(mntp
.mnt_fstype
, MNTTYPE_UFS
) != 0)
258 if (strcmp(mntp
.mnt_special
, file
) == 0) {
259 fsdir
= mntp
.mnt_mountp
;
264 if (fsdir
!= NULL
&& *fsdir
!= '\0')
265 (void) printf(" (%s)", fsdir
);
266 (void) printf(":\n");
268 bread(fd
, (diskaddr_t
)SBLOCK
, (char *)&sblock
, SBSIZE
);
270 if (isdigit(c
= getchar()))
271 (void) ungetc(c
, stdin
);
272 else while (c
!= '\n' && c
!= EOF
)
276 itab
= (struct dinode
*)calloc(sblock
.fs_ipg
, sizeof (struct dinode
));
278 (void) fprintf(stderr
,
279 "not enough memory to allocate tables\n");
284 for (c
= 0; c
< sblock
.fs_ncg
; c
++) {
285 bread(fd
, (diskaddr_t
)fsbtodb(&sblock
, cgimin(&sblock
, c
)),
287 (int)(sblock
.fs_ipg
* sizeof (struct dinode
)));
288 for (j
= 0; j
< sblock
.fs_ipg
; j
++, ino
++) {
289 if (ino
< UFSROOTINO
)
299 qacct(struct dinode
*ip
)
302 long blks
, frags
, size
;
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)
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.
318 size
= ip
->di_blocks
/ 2;
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);
332 if ((ip
->di_mode
&IFMT
) != IFDIR
&& (ip
->di_mode
&IFMT
) != IFREG
)
335 overflow
+= (offset_t
)size
;
341 dp
= lookup(ip
->di_uid
);
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
;
355 if (scanf("%d", &fino
) <= 0)
360 while ((n
= getchar()) != '\n' && n
!= EOF
)
366 (void) printf("%.7s ", dp
->u_name
);
368 (void) printf("%ld ", (long)ip
->di_uid
);
369 while ((n
= getchar()) == ' ' || n
== '\t')
372 while (n
!= EOF
&& n
!= '\n') {
382 bread(int fd
, diskaddr_t bno
, char *buf
, int cnt
)
386 if (llseek(fd
, (offset_t
)(bno
* DEV_BSIZE
), SEEK_SET
) < 0) {
391 if ((ret
= read(fd
, buf
, cnt
)) != cnt
) {
392 (void) fprintf(stderr
, "quot: read returns %d (cnt = %d)\n",
394 (void) fprintf(stderr
, "quot: read error at block %lld\n", bno
);
401 qcmp(const void *arg1
, const void *arg2
)
403 struct du
**p1
= (struct du
**)arg1
;
404 struct du
**p2
= (struct du
**)arg2
;
407 if ((*p1
)->blocks
> (*p2
)->blocks
)
409 if ((*p1
)->blocks
< (*p2
)->blocks
)
417 return (strcmp(s1
, s2
));
432 for (i
= 0; i
< TSIZE
- 1; i
++)
435 (void) printf("%d %d %ld\n",
438 if (sizes
[TSIZE
-1 ])
439 (void) printf("%d %d %lld\n", TSIZE
- 1,
440 sizes
[TSIZE
- 1], overflow
+ (offset_t
)t
);
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)
448 (void) printf("%5ld\t", (*dp
)->blocks
);
450 (void) printf("%5ld\t", (*dp
)->nfiles
);
453 (void) printf("%-8s", (*dp
)->u_name
);
455 (void) printf("#%-8ld", (long)(*dp
)->uid
);
457 (void) printf("\t%5ld\t%5ld\t%5ld",
458 (*dp
)->blocks30
, (*dp
)->blocks60
, (*dp
)->blocks90
);
471 char *cp
; /* Pointer to raw device name */
473 extern char *getfullrawname();
475 if (stat64(*devpp
, &statb
) < 0) {
479 if ((statb
.st_mode
& S_IFMT
) == S_IFCHR
)
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
)
487 fstab
= fopen(MNTTAB
, "r");
489 (void) fprintf(stderr
, "quot: no %s file\n", MNTTAB
);
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",
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
;
504 (void) fclose(fstab
);
508 (void) fclose(fstab
);
509 (void) fprintf(stderr
, "quot: %s doesn't appear to be a filesystem.\n",
522 for (up
= duhashtbl
[HASH(uid
)]; up
!= NULL
; up
= up
->next
) {
531 up
->u_name
= strdup(pwp
->pw_name
);
539 struct du
*up
, **uhp
;
541 up
= (struct du
*)calloc(1, sizeof (struct du
));
543 (void) fprintf(stderr
,
544 "out of memory for du structures\n");
548 uhp
= &duhashtbl
[HASH(uid
)];
566 dp
= (struct du
**)calloc(ndu
, sizeof (struct du
**));
568 (void) fprintf(stderr
,
569 "out of memory for du structures\n");
573 for (hp
= duhashtbl
, i
= 0; i
!= UHASH
; i
++) {
577 for (ep
= hp
[i
]; ep
; ep
= ep
->next
) {
588 struct du
*ep
, *next
;
591 * Release memory from hash table and du
600 for (i
= 0; i
!= UHASH
; i
++) {
601 if (duhashtbl
[i
] == NULL
)