2 * Copyright (c) 2005 Silicon Graphics, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
38 static __uint64_t sizes
[TSIZE
];
39 static __uint64_t overflow
;
43 static du_t du
[3][NDU
];
44 static du_t
*duhash
[3][DUHASH
];
45 static int ndu
[3]; /* #usr/grp/prj */
50 static cmdinfo_t quot_cmd
;
57 " display a summary of filesystem ownership\n"
59 " -a -- summarise for all local XFS filesystem mount points\n"
60 " -c -- display three columns giving file size in kilobytes, number of files\n"
61 " of that size, and cumulative total of kilobytes in that size or\n"
62 " smaller file. The last row is used as an overflow bucket and is the\n"
63 " total of all files greater than 500 kilobytes.\n"
64 " -v -- display three columns containing the number of kilobytes not\n"
65 " accessed in the last 30, 60, and 90 days.\n"
66 " -g -- display group summary\n"
67 " -p -- display project summary\n"
68 " -u -- display user summary\n"
69 " -b -- display number of blocks used\n"
70 " -i -- display number of inodes used\n"
71 " -r -- display number of realtime blocks used\n"
72 " -n -- skip identifier-to-name translations, just report IDs\n"
73 " -N -- suppress the initial header\n"
74 " -f -- send output to a file\n"
75 " The (optional) user/group/project can be specified either by name or by\n"
76 " number (i.e. uid/gid/projid).\n"
90 if ((p
->bs_mode
& S_IFMT
) == 0)
92 size
= howmany((p
->bs_blocks
* p
->bs_blksize
), 0x400ULL
);
94 if (flags
& HISTOGRAM_FLAG
) {
95 if (!(S_ISDIR(p
->bs_mode
) || S_ISREG(p
->bs_mode
)))
104 for (i
= 0; i
< 3; i
++) {
105 id
= (i
== 0) ? p
->bs_uid
: ((i
== 1) ?
106 p
->bs_gid
: bstat_get_projid(p
));
107 hp
= &duhash
[i
][id
% DUHASH
];
108 for (dp
= *hp
; dp
; dp
= dp
->next
)
114 dp
= &du
[i
][(ndu
[i
]++)];
126 if (now
- p
->bs_atime
.tv_sec
> 30 * (60*60*24))
127 dp
->blocks30
+= size
;
128 if (now
- p
->bs_atime
.tv_sec
> 60 * (60*60*24))
129 dp
->blocks60
+= size
;
130 if (now
- p
->bs_atime
.tv_sec
> 90 * (60*60*24))
131 dp
->blocks90
+= size
;
141 xfs_fsop_bulkreq_t bulkreq
;
149 * Initialize tables between checks; because of the qsort
150 * in report() the hash tables must be rebuilt each time.
152 for (sts
= 0; sts
< TSIZE
; sts
++)
155 for (i
= 0; i
< 3; i
++)
156 for (dp
= duhash
[i
]; dp
< &duhash
[i
][DUHASH
]; dp
++)
158 ndu
[0] = ndu
[1] = ndu
[2] = 0;
160 fsfd
= open(fsdir
, O_RDONLY
);
166 buf
= (xfs_bstat_t
*)calloc(NBSTAT
, sizeof(xfs_bstat_t
));
173 bulkreq
.lastip
= &last
;
174 bulkreq
.icount
= NBSTAT
;
175 bulkreq
.ubuffer
= buf
;
176 bulkreq
.ocount
= &count
;
178 while ((sts
= xfsctl(fsdir
, fsfd
, XFS_IOC_FSBULKSTAT
, &bulkreq
)) == 0) {
181 for (i
= 0; i
< count
; i
++)
182 quot_bulkstat_add(&buf
[i
], flags
);
185 perror("XFS_IOC_FSBULKSTAT"),
195 if (p1
->blocks
> p2
->blocks
)
197 if (p1
->blocks
< p2
->blocks
)
201 else if (p1
->id
< p2
->id
)
206 typedef char *(*idtoname_t
)(__uint32_t
);
209 quot_report_mount_any_type(
221 fprintf(fp
, _("%s (%s) %s:\n"),
222 mount
->fs_name
, mount
->fs_dir
, type_to_string(type
));
223 qsort(dp
, count
, sizeof(dp
[0]),
224 (int (*)(const void *, const void *))qcompare
);
225 for (; dp
< &dp
[count
]; dp
++) {
228 fprintf(fp
, "%8llu ", (unsigned long long) dp
->blocks
);
229 if (form
& XFS_INODE_QUOTA
)
230 fprintf(fp
, "%8llu ",
231 (unsigned long long) dp
->nfiles
);
232 if (!(flags
& NO_LOOKUP_FLAG
) &&
233 ((cp
= (names
)(dp
->id
)) != NULL
))
234 fprintf(fp
, "%-8.8s", cp
);
236 fprintf(fp
, "#%-7d", dp
->id
);
237 if (flags
& VERBOSE_FLAG
)
238 fprintf(fp
, " %8llu %8llu %8llu",
239 (unsigned long long) dp
->blocks30
,
240 (unsigned long long) dp
->blocks60
,
241 (unsigned long long) dp
->blocks90
);
255 case XFS_GROUP_QUOTA
:
256 quot_report_mount_any_type(fp
, du
[1], ndu
[1], gid_to_name
,
257 form
, type
, mount
, flags
);
260 quot_report_mount_any_type(fp
, du
[2], ndu
[2], prid_to_name
,
261 form
, type
, mount
, flags
);
264 quot_report_mount_any_type(fp
, du
[0], ndu
[0], uid_to_name
,
265 form
, type
, mount
, flags
);
281 fs_cursor_initialise(dir
, FS_MOUNT_POINT
, &cursor
);
282 while ((mount
= fs_cursor_next_entry(&cursor
))) {
283 quot_bulkstat_mount(mount
->fs_dir
, flags
);
284 quot_report_mount(fp
, form
, type
, mount
, flags
);
289 quot_histogram_mount(
297 fprintf(fp
, _("%s (%s):\n"), mount
->fs_name
, mount
->fs_dir
);
299 for (i
= 0; i
< TSIZE
- 1; i
++)
302 fprintf(fp
, _("%d\t%llu\t%llu\n"), i
,
303 (unsigned long long) sizes
[i
],
304 (unsigned long long) t
);
306 fprintf(fp
, _("%d\t%llu\t%llu\n"), TSIZE
- 1,
307 (unsigned long long) sizes
[TSIZE
- 1],
308 (unsigned long long) (overflow
+ t
));
320 fs_cursor_initialise(dir
, FS_MOUNT_POINT
, &cursor
);
321 while ((mount
= fs_cursor_next_entry(&cursor
))) {
322 quot_bulkstat_mount(mount
->fs_dir
, flags
);
323 quot_histogram_mount(fp
, mount
, flags
);
335 if (flags
& HISTOGRAM_FLAG
)
336 quot_histogram(fp
, dir
, flags
);
338 quot_report(fp
, form
, type
, dir
, flags
);
348 int c
, flags
= 0, type
= 0, form
= 0;
350 while ((c
= getopt(argc
, argv
, "abcf:ghinpruv")) != EOF
) {
356 form
|= XFS_BLOCK_QUOTA
;
359 form
|= XFS_INODE_QUOTA
;
362 form
|= XFS_RTBLOCK_QUOTA
;
365 type
|= XFS_GROUP_QUOTA
;
368 type
|= XFS_PROJ_QUOTA
;
371 type
|= XFS_USER_QUOTA
;
374 flags
|= ALL_MOUNTS_FLAG
;
377 flags
|= HISTOGRAM_FLAG
;
380 flags
|= NO_LOOKUP_FLAG
;
383 flags
|= VERBOSE_FLAG
;
386 return command_usage("_cmd
);
391 form
= XFS_BLOCK_QUOTA
;
394 type
= XFS_USER_QUOTA
;
395 } else if (type
!= XFS_GROUP_QUOTA
&&
396 type
!= XFS_PROJ_QUOTA
&&
397 type
!= XFS_USER_QUOTA
) {
398 return command_usage("_cmd
);
401 if ((fp
= fopen_write_secure(fname
)) == NULL
)
404 if (argc
== optind
) {
405 if (flags
& ALL_MOUNTS_FLAG
)
406 quot_any_type(fp
, form
, type
, NULL
, flags
);
407 else if (fs_path
->fs_flags
& FS_MOUNT_POINT
)
408 quot_any_type(fp
, form
, type
, fs_path
->fs_dir
, flags
);
409 } else while (argc
> optind
) {
410 quot_any_type(fp
, form
, type
, argv
[optind
++], flags
);
421 quot_cmd
.name
= "quot";
422 quot_cmd
.cfunc
= quot_f
;
424 quot_cmd
.argmax
= -1;
425 quot_cmd
.args
= _("[-bir] [-g|-p|-u] [-acv] [-f file]");
426 quot_cmd
.oneline
= _("summarize filesystem ownership");
427 quot_cmd
.help
= quot_help
;
430 add_command("_cmd
);