2 * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
33 #include <xfs/command.h>
51 static __uint64_t sizes
[TSIZE
];
52 static __uint64_t overflow
;
56 static du_t du
[3][NDU
];
57 static du_t
*duhash
[3][DUHASH
];
58 static int ndu
[3]; /* #usr/grp/prj */
63 static cmdinfo_t quot_cmd
;
70 " display a summary of filesystem ownership\n"
72 " -a -- summarise for all local XFS filesystem mount points\n"
73 " -c -- display three columns giving file size in kilobytes, number of files\n"
74 " of that size, and cumulative total of kilobytes in that size or\n"
75 " smaller file. The last row is used as an overflow bucket and is the\n"
76 " total of all files greater than 500 kilobytes.\n"
77 " -v -- display three columns containing the number of kilobytes not\n"
78 " accessed in the last 30, 60, and 90 days.\n"
79 " -g -- display group summary\n"
80 " -p -- display project summary\n"
81 " -u -- display user summary\n"
82 " -b -- display number of blocks used\n"
83 " -i -- display number of inodes used\n"
84 " -r -- display number of realtime blocks used\n"
85 " -n -- suppress the initial header\n"
86 " -f -- send output to a file\n"
87 " The (optional) user/group/project can be specified either by name or by\n"
88 " number (i.e. uid/gid/projid).\n"
102 if ((p
->bs_mode
& S_IFMT
) == 0)
104 size
= howmany((p
->bs_blocks
* p
->bs_blksize
), 0x400ULL
);
106 if (flags
& HISTOGRAM_FLAG
) {
107 if (!(S_ISDIR(p
->bs_mode
) || S_ISREG(p
->bs_mode
)))
116 for (i
= 0; i
< 3; i
++) {
117 id
= (i
== 0) ? p
->bs_uid
: ((i
== 1) ?
118 p
->bs_gid
: p
->bs_projid
);
119 hp
= &duhash
[i
][id
% DUHASH
];
120 for (dp
= *hp
; dp
; dp
= dp
->next
)
126 dp
= &du
[i
][(ndu
[i
]++)];
138 if (now
- p
->bs_atime
.tv_sec
> 30 * (60*60*24))
139 dp
->blocks30
+= size
;
140 if (now
- p
->bs_atime
.tv_sec
> 60 * (60*60*24))
141 dp
->blocks60
+= size
;
142 if (now
- p
->bs_atime
.tv_sec
> 90 * (60*60*24))
143 dp
->blocks90
+= size
;
153 xfs_fsop_bulkreq_t bulkreq
;
161 * Initialize tables between checks; because of the qsort
162 * in report() the hash tables must be rebuilt each time.
164 for (sts
= 0; sts
< TSIZE
; sts
++)
167 for (i
= 0; i
< 3; i
++)
168 for (dp
= duhash
[i
]; dp
< &duhash
[i
][DUHASH
]; dp
++)
170 ndu
[0] = ndu
[1] = ndu
[2] = 0;
172 fsfd
= open(fsdir
, O_RDONLY
);
178 buf
= (xfs_bstat_t
*)calloc(NBSTAT
, sizeof(xfs_bstat_t
));
184 bulkreq
.lastip
= &last
;
185 bulkreq
.icount
= NBSTAT
;
186 bulkreq
.ubuffer
= buf
;
187 bulkreq
.ocount
= &count
;
189 while ((sts
= xfsctl(fsdir
, fsfd
, XFS_IOC_FSBULKSTAT
, &bulkreq
)) == 0) {
192 for (i
= 0; i
< count
; i
++)
193 quot_bulkstat_add(&buf
[i
], flags
);
196 perror("XFS_IOC_FSBULKSTAT"),
206 if (p1
->blocks
> p2
->blocks
)
208 if (p1
->blocks
< p2
->blocks
)
212 else if (p1
->id
< p2
->id
)
217 typedef char *(*idtoname_t
)(__uint32_t
);
220 quot_report_mount_any_type(
232 fprintf(fp
, _("%s (%s) %s:\n"),
233 mount
->fs_name
, mount
->fs_dir
, type_to_string(type
));
234 qsort(dp
, count
, sizeof(dp
[0]),
235 (int (*)(const void *, const void *))qcompare
);
236 for (; dp
< &dp
[count
]; dp
++) {
239 fprintf(fp
, "%8llu ", (unsigned long long) dp
->blocks
);
240 if (form
& XFS_INODE_QUOTA
)
241 fprintf(fp
, "%8llu ",
242 (unsigned long long) dp
->nfiles
);
243 if ((cp
= (names
)(dp
->id
)) != NULL
)
244 fprintf(fp
, "%-8.8s", cp
);
246 fprintf(fp
, "#%-7d", dp
->id
);
247 if (flags
& VERBOSE_FLAG
)
248 fprintf(fp
, " %8llu %8llu %8llu",
249 (unsigned long long) dp
->blocks30
,
250 (unsigned long long) dp
->blocks60
,
251 (unsigned long long) dp
->blocks90
);
265 case XFS_GROUP_QUOTA
:
266 quot_report_mount_any_type(fp
, du
[1], ndu
[1], gid_to_name
,
267 form
, type
, mount
, flags
);
270 quot_report_mount_any_type(fp
, du
[2], ndu
[2], prid_to_name
,
271 form
, type
, mount
, flags
);
274 quot_report_mount_any_type(fp
, du
[0], ndu
[0], uid_to_name
,
275 form
, type
, mount
, flags
);
291 fs_cursor_initialise(dir
, FS_MOUNT_POINT
, &cursor
);
292 while ((mount
= fs_cursor_next_entry(&cursor
))) {
293 quot_bulkstat_mount(mount
->fs_dir
, flags
);
294 quot_report_mount(fp
, form
, type
, mount
, flags
);
299 quot_histogram_mount(
307 fprintf(fp
, _("%s (%s):\n"), mount
->fs_name
, mount
->fs_dir
);
309 for (i
= 0; i
< TSIZE
- 1; i
++)
312 fprintf(fp
, _("%d\t%llu\t%llu\n"), i
,
313 (unsigned long long) sizes
[i
],
314 (unsigned long long) t
);
316 fprintf(fp
, _("%d\t%llu\t%llu\n"), TSIZE
- 1,
317 (unsigned long long) sizes
[TSIZE
- 1],
318 (unsigned long long) (overflow
+ t
));
330 fs_cursor_initialise(dir
, FS_MOUNT_POINT
, &cursor
);
331 while ((mount
= fs_cursor_next_entry(&cursor
))) {
332 quot_bulkstat_mount(mount
->fs_dir
, flags
);
333 quot_histogram_mount(fp
, mount
, flags
);
345 if (flags
& HISTOGRAM_FLAG
)
346 quot_histogram(fp
, dir
, flags
);
348 quot_report(fp
, form
, type
, dir
, flags
);
358 int c
, flags
= 0, type
= 0, form
= 0;
360 while ((c
= getopt(argc
, argv
, "abcf:hgipruv")) != EOF
) {
366 form
|= XFS_BLOCK_QUOTA
;
369 form
|= XFS_INODE_QUOTA
;
372 form
|= XFS_RTBLOCK_QUOTA
;
375 type
= XFS_GROUP_QUOTA
;
378 type
= XFS_PROJ_QUOTA
;
381 type
= XFS_USER_QUOTA
;
384 flags
|= ALL_MOUNTS_FLAG
;
387 flags
|= HISTOGRAM_FLAG
;
390 flags
|= VERBOSE_FLAG
;
393 return command_usage("_cmd
);
398 form
= XFS_BLOCK_QUOTA
;
401 type
= XFS_USER_QUOTA
;
403 if ((fp
= fopen_write_secure(fname
)) == NULL
)
407 quot_any_type(fp
, form
, type
, (flags
& ALL_MOUNTS_FLAG
) ?
408 NULL
: fs_path
->fs_dir
, flags
);
409 else while (argc
> optind
)
410 quot_any_type(fp
, form
, type
, argv
[optind
++], flags
);
420 quot_cmd
.name
= _("quot");
421 quot_cmd
.cfunc
= quot_f
;
423 quot_cmd
.argmax
= -1;
424 quot_cmd
.args
= _("[-bir] [-gpu] [-acv] [-f file]");
425 quot_cmd
.oneline
= _("summarize filesystem ownership");
426 quot_cmd
.help
= quot_help
;
429 add_command("_cmd
);