2 * Copyright (c) 1980, 1990 Regents of the University of California.
3 * Copyright (C) 2000, 2001 Silicon Graphics, Inc. [SGI]
6 * [Extensions to support XFS are copyright SGI]
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met: 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 2.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution. 3. All advertising
15 * materials mentioning features or use of this software must display the
16 * following acknowledgement: This product includes software developed by the
17 * University of California, Berkeley and its contributors. 4. Neither the
18 * name of the University nor the names of its contributors may be used to
19 * endorse or promote products derived from this software without specific
20 * prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
23 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
26 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include <sys/param.h>
39 #include <sys/ioctl.h>
59 __uint64_t sizes[TSIZE];
74 static void mounttable(void);
75 static char *idname(__uint32_t, int);
76 static void report(const char *, char *, int);
77 static void creport(const char *, char *);
79 static void usage(void)
81 errstr(_("Usage: %s [-acfugvViTq] [filesystem...]\n"), progname);
85 int main(int argc, char **argv)
90 progname = basename(argv[0]);
92 while ((c = getopt(argc, argv, "acfguvVTq")) != -1) {
128 if ((aflag && optind != argc) || (!aflag && optind == argc))
130 if (!uflag && !gflag)
132 if (init_mounts_scan(aflag ? 0 : argc - optind, argv + optind, (iflag ? MS_NO_AUTOFS : 0)) < 0)
139 static void mounttable(void)
144 while ((mntp = get_next_mount())) {
145 /* Currently, only XFS is implemented... */
146 if (strcmp(mntp->mnt_type, MNTTYPE_XFS) == 0) {
147 checkXFS(mntp->mnt_fsname, mntp->mnt_dir);
150 /* ...additional filesystems types here. */
153 if (cflag) creport(mntp->mnt_fsname, mntp->mnt_dir);
154 if (!cflag && uflag) report(mntp->mnt_fsname, mntp->mnt_dir, 0);
155 if (!cflag && gflag) report(mntp->mnt_fsname, mntp->mnt_dir, 1);
160 static int qcmp(du_t * p1, du_t * p2)
162 if (p1->blocks > p2->blocks)
164 if (p1->blocks < p2->blocks)
168 else if (p1->id < p2->id)
173 static void creport(const char *file, char *fsdir)
178 printf(_("%s (%s):\n"), file, fsdir);
179 for (i = 0; i < TSIZE - 1; i++)
182 printf(_("%d\t%llu\t%llu\n"), i,
183 (unsigned long long) sizes[i],
184 (unsigned long long) t);
186 printf(_("%d\t%llu\t%llu\n"), TSIZE - 1,
187 (unsigned long long) sizes[TSIZE - 1],
188 (unsigned long long) (overflow + t));
191 static void report(const char *file, char *fsdir, int type)
195 printf(_("%s (%s) %s:\n"), file, fsdir, type? "groups" : "users");
197 qsort(du[type], ndu[type], sizeof(du[type][0]), (int (*)(const void *, const void *))qcmp);
198 for (dp = du[type]; dp < &du[type][ndu[type]]; dp++) {
203 printf(_("%8llu "), (unsigned long long) dp->blocks);
205 printf(_("%8llu "), (unsigned long long) dp->nfiles);
206 if ((cp = idname(dp->id, type)) != NULL) {
210 printf(_("%-8.8s"), cp);
212 printf(_("#%-7d"), dp->id);
214 printf(_(" %8llu %8llu %8llu"),
215 (unsigned long long) dp->blocks30,
216 (unsigned long long) dp->blocks60,
217 (unsigned long long) dp->blocks90);
222 static idcache_t *getnextent(int type, __uint32_t id, int byid)
226 static idcache_t idc;
228 if (type) { /* /etc/group */
229 if ((gr = byid? getgrgid(id) : getgrent()) == NULL)
232 strncpy(idc.name, gr->gr_name, UT_NAMESIZE);
236 if ((pw = byid? getpwuid(id) : getpwent()) == NULL)
239 strncpy(idc.name, pw->pw_name, UT_NAMESIZE);
243 static char *idname(__uint32_t id, int type)
245 idcache_t *ncp, *idp;
246 static idcache_t nc[2][NID];
247 static int entriesleft[2] = { NID, NID };
249 /* check cache for name first */
250 ncp = &nc[type][id & IDMASK];
251 if (ncp->id == id && ncp->name[0])
253 if (entriesleft[type]) {
255 * If we haven't gone through the passwd/group file
256 * then fill the cache while seaching for name.
257 * This lets us run through passwd/group serially.
259 if (entriesleft[type] == NID)
260 type? setgrent() : setpwent();
261 while (((idp = getnextent(type, id, 0)) != NULL) && entriesleft[type]) {
263 ncp = &nc[type][idp->id & IDMASK];
264 if (ncp->name[0] == '\0' || idp->id == id)
265 memcpy(ncp, idp, sizeof(idcache_t));
269 type? endgrent() : endpwent();
270 entriesleft[type] = 0;
271 ncp = &nc[type][id & IDMASK];
274 /* Not cached - do it the slow way & insert into cache */
275 if ((idp = getnextent(type, id, 1)) == NULL)
277 memcpy(ncp, idp, sizeof(idcache_t));
282 * === XFS specific code follows ===
285 static void acctXFS(xfs_bstat_t *p)
292 if ((p->bs_mode & S_IFMT) == 0)
294 size = howmany((p->bs_blocks * p->bs_blksize), 0x400ULL);
297 if (!(S_ISDIR(p->bs_mode) || S_ISREG(p->bs_mode)))
306 for (i = 0; i < 2; i++) {
307 id = (i == 0)? p->bs_uid : p->bs_gid;
308 hp = &duhash[i][id % DUHASH];
309 for (dp = *hp; dp; dp = dp->next)
315 dp = &du[i][(ndu[i]++)];
327 if (now - p->bs_atime.tv_sec > 30 * SEC24HR)
328 dp->blocks30 += size;
329 if (now - p->bs_atime.tv_sec > 60 * SEC24HR)
330 dp->blocks60 += size;
331 if (now - p->bs_atime.tv_sec > 90 * SEC24HR)
332 dp->blocks90 += size;
337 static void checkXFS(const char *file, char *fsdir)
339 xfs_fsop_bulkreq_t bulkreq;
349 * Initialize tables between checks; because of the qsort
350 * in report() the hash tables must be rebuilt each time.
352 for (sts = 0; sts < TSIZE; sts++)
355 for (i = 0; i < 2; i++)
356 for (dp = duhash[i]; dp < &duhash[i][DUHASH]; dp++)
360 fsfd = open(fsdir, O_RDONLY);
362 errstr(_("cannot open %s: %s\n"), fsdir, strerror(errno));
367 buf = (xfs_bstat_t *) smalloc(NBSTAT * sizeof(xfs_bstat_t));
368 memset(buf, 0, NBSTAT * sizeof(xfs_bstat_t));
370 bulkreq.lastip = &last;
371 bulkreq.icount = NBSTAT;
372 bulkreq.ubuffer = buf;
373 bulkreq.ocount = &count;
375 while ((sts = ioctl(fsfd, XFS_IOC_FSBULKSTAT, &bulkreq)) == 0) {
378 for (i = 0; i < count; i++)
382 errstr(_("XFS_IOC_FSBULKSTAT ioctl failed: %s\n"),