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
19 #include <xfs/command.h>
37 static __uint64_t sizes
[TSIZE
];
38 static __uint64_t overflow
;
42 static du_t du
[3][NDU
];
43 static du_t
*duhash
[3][DUHASH
];
44 static int ndu
[3]; /* #usr/grp/prj */
49 static cmdinfo_t quot_cmd
;
56 " display a summary of filesystem ownership\n"
58 " -a -- summarise for all local XFS filesystem mount points\n"
59 " -c -- display three columns giving file size in kilobytes, number of files\n"
60 " of that size, and cumulative total of kilobytes in that size or\n"
61 " smaller file. The last row is used as an overflow bucket and is the\n"
62 " total of all files greater than 500 kilobytes.\n"
63 " -v -- display three columns containing the number of kilobytes not\n"
64 " accessed in the last 30, 60, and 90 days.\n"
65 " -g -- display group summary\n"
66 " -p -- display project summary\n"
67 " -u -- display user summary\n"
68 " -b -- display number of blocks used\n"
69 " -i -- display number of inodes used\n"
70 " -r -- display number of realtime blocks used\n"
71 " -n -- skip identifier-to-name translations, just report IDs\n"
72 " -N -- suppress the initial header\n"
73 " -f -- send output to a file\n"
74 " The (optional) user/group/project can be specified either by name or by\n"
75 " number (i.e. uid/gid/projid).\n"
89 if ((p
->bs_mode
& S_IFMT
) == 0)
91 size
= howmany((p
->bs_blocks
* p
->bs_blksize
), 0x400ULL
);
93 if (flags
& HISTOGRAM_FLAG
) {
94 if (!(S_ISDIR(p
->bs_mode
) || S_ISREG(p
->bs_mode
)))
103 for (i
= 0; i
< 3; i
++) {
104 id
= (i
== 0) ? p
->bs_uid
: ((i
== 1) ?
105 p
->bs_gid
: bstat_get_projid(p
));
106 hp
= &duhash
[i
][id
% DUHASH
];
107 for (dp
= *hp
; dp
; dp
= dp
->next
)
113 dp
= &du
[i
][(ndu
[i
]++)];
125 if (now
- p
->bs_atime
.tv_sec
> 30 * (60*60*24))
126 dp
->blocks30
+= size
;
127 if (now
- p
->bs_atime
.tv_sec
> 60 * (60*60*24))
128 dp
->blocks60
+= size
;
129 if (now
- p
->bs_atime
.tv_sec
> 90 * (60*60*24))
130 dp
->blocks90
+= size
;
140 xfs_fsop_bulkreq_t bulkreq
;
148 * Initialize tables between checks; because of the qsort
149 * in report() the hash tables must be rebuilt each time.
151 for (sts
= 0; sts
< TSIZE
; sts
++)
154 for (i
= 0; i
< 3; i
++)
155 for (dp
= duhash
[i
]; dp
< &duhash
[i
][DUHASH
]; dp
++)
157 ndu
[0] = ndu
[1] = ndu
[2] = 0;
159 fsfd
= open(fsdir
, O_RDONLY
);
165 buf
= (xfs_bstat_t
*)calloc(NBSTAT
, sizeof(xfs_bstat_t
));
172 bulkreq
.lastip
= &last
;
173 bulkreq
.icount
= NBSTAT
;
174 bulkreq
.ubuffer
= buf
;
175 bulkreq
.ocount
= &count
;
177 while ((sts
= xfsctl(fsdir
, fsfd
, XFS_IOC_FSBULKSTAT
, &bulkreq
)) == 0) {
180 for (i
= 0; i
< count
; i
++)
181 quot_bulkstat_add(&buf
[i
], flags
);
184 perror("XFS_IOC_FSBULKSTAT"),
194 if (p1
->blocks
> p2
->blocks
)
196 if (p1
->blocks
< p2
->blocks
)
200 else if (p1
->id
< p2
->id
)
205 typedef char *(*idtoname_t
)(__uint32_t
);
208 quot_report_mount_any_type(
220 fprintf(fp
, _("%s (%s) %s:\n"),
221 mount
->fs_name
, mount
->fs_dir
, type_to_string(type
));
222 qsort(dp
, count
, sizeof(dp
[0]),
223 (int (*)(const void *, const void *))qcompare
);
224 for (; dp
< &dp
[count
]; dp
++) {
227 fprintf(fp
, "%8llu ", (unsigned long long) dp
->blocks
);
228 if (form
& XFS_INODE_QUOTA
)
229 fprintf(fp
, "%8llu ",
230 (unsigned long long) dp
->nfiles
);
231 if (!(flags
& NO_LOOKUP_FLAG
) &&
232 ((cp
= (names
)(dp
->id
)) != NULL
))
233 fprintf(fp
, "%-8.8s", cp
);
235 fprintf(fp
, "#%-7d", dp
->id
);
236 if (flags
& VERBOSE_FLAG
)
237 fprintf(fp
, " %8llu %8llu %8llu",
238 (unsigned long long) dp
->blocks30
,
239 (unsigned long long) dp
->blocks60
,
240 (unsigned long long) dp
->blocks90
);
254 case XFS_GROUP_QUOTA
:
255 quot_report_mount_any_type(fp
, du
[1], ndu
[1], gid_to_name
,
256 form
, type
, mount
, flags
);
259 quot_report_mount_any_type(fp
, du
[2], ndu
[2], prid_to_name
,
260 form
, type
, mount
, flags
);
263 quot_report_mount_any_type(fp
, du
[0], ndu
[0], uid_to_name
,
264 form
, type
, mount
, flags
);
280 fs_cursor_initialise(dir
, FS_MOUNT_POINT
, &cursor
);
281 while ((mount
= fs_cursor_next_entry(&cursor
))) {
282 quot_bulkstat_mount(mount
->fs_dir
, flags
);
283 quot_report_mount(fp
, form
, type
, mount
, flags
);
288 quot_histogram_mount(
296 fprintf(fp
, _("%s (%s):\n"), mount
->fs_name
, mount
->fs_dir
);
298 for (i
= 0; i
< TSIZE
- 1; i
++)
301 fprintf(fp
, _("%d\t%llu\t%llu\n"), i
,
302 (unsigned long long) sizes
[i
],
303 (unsigned long long) t
);
305 fprintf(fp
, _("%d\t%llu\t%llu\n"), TSIZE
- 1,
306 (unsigned long long) sizes
[TSIZE
- 1],
307 (unsigned long long) (overflow
+ t
));
319 fs_cursor_initialise(dir
, FS_MOUNT_POINT
, &cursor
);
320 while ((mount
= fs_cursor_next_entry(&cursor
))) {
321 quot_bulkstat_mount(mount
->fs_dir
, flags
);
322 quot_histogram_mount(fp
, mount
, flags
);
334 if (flags
& HISTOGRAM_FLAG
)
335 quot_histogram(fp
, dir
, flags
);
337 quot_report(fp
, form
, type
, dir
, flags
);
347 int c
, flags
= 0, type
= 0, form
= 0;
349 while ((c
= getopt(argc
, argv
, "abcf:ghinpruv")) != EOF
) {
355 form
|= XFS_BLOCK_QUOTA
;
358 form
|= XFS_INODE_QUOTA
;
361 form
|= XFS_RTBLOCK_QUOTA
;
364 type
= XFS_GROUP_QUOTA
;
367 type
= XFS_PROJ_QUOTA
;
370 type
= XFS_USER_QUOTA
;
373 flags
|= ALL_MOUNTS_FLAG
;
376 flags
|= HISTOGRAM_FLAG
;
379 flags
|= NO_LOOKUP_FLAG
;
382 flags
|= VERBOSE_FLAG
;
385 return command_usage("_cmd
);
390 form
= XFS_BLOCK_QUOTA
;
393 type
= XFS_USER_QUOTA
;
395 if ((fp
= fopen_write_secure(fname
)) == NULL
)
398 if (argc
== optind
) {
399 if (flags
& ALL_MOUNTS_FLAG
)
400 quot_any_type(fp
, form
, type
, NULL
, flags
);
401 else if (fs_path
->fs_flags
& FS_MOUNT_POINT
)
402 quot_any_type(fp
, form
, type
, fs_path
->fs_dir
, flags
);
403 } else while (argc
> optind
) {
404 quot_any_type(fp
, form
, type
, argv
[optind
++], flags
);
415 quot_cmd
.name
= "quot";
416 quot_cmd
.cfunc
= quot_f
;
418 quot_cmd
.argmax
= -1;
419 quot_cmd
.args
= _("[-bir] [-gpu] [-acv] [-f file]");
420 quot_cmd
.oneline
= _("summarize filesystem ownership");
421 quot_cmd
.help
= quot_help
;
424 add_command("_cmd
);