]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - quota/report.c
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2005 Silicon Graphics, Inc.
15 static cmdinfo_t dump_cmd
;
16 static cmdinfo_t report_cmd
;
23 " create a backup file which contains quota limits information\n"
24 " -g -- dump out group quota limits\n"
25 " -p -- dump out project quota limits\n"
26 " -u -- dump out user quota limits (default)\n"
27 " -L -- lower ID bound to dump\n"
28 " -U -- upper ID bound to dump\n"
29 " -f -- write the dump out to the specified file\n"
38 " report used space and inodes, and quota limits, for a filesystem\n"
41 " (reports inode usage for all groups, in an easy-to-read format)\n"
42 " This command is the equivalent of the traditional repquota command, which\n"
43 " prints a summary of the disk usage and quotas for the current filesystem,\n"
44 " or all filesystems.\n"
45 " -a -- report for all mounted filesystems with quota enabled\n"
46 " -h -- report in a human-readable format\n"
47 " -n -- skip identifier-to-name translations, just report IDs\n"
48 " -N -- suppress the header from the output\n"
49 " -t -- terse output format, hides rows which are all zero\n"
50 " -L -- lower ID bound to report on\n"
51 " -U -- upper ID bound to report on\n"
52 " -l -- look up names for IDs in lower-upper range\n"
53 " -g -- report group usage and quota information\n"
54 " -p -- report project usage and quota information\n"
55 " -u -- report user usage and quota information\n"
56 " -b -- report blocks-used information only\n"
57 " -i -- report inodes-used information only\n"
58 " -r -- report realtime-blocks-used information only\n"
64 struct fs_disk_quota
*d
,
72 if (flags
& GETNEXTQUOTA_FLAG
)
73 cmd
= XFS_GETNEXTQUOTA
;
77 /* Fall back silently if XFS_GETNEXTQUOTA fails, warn on XFS_GETQUOTA */
78 if (xfsquotactl(cmd
, dev
, type
, id
, (void *)d
) < 0) {
79 if (errno
!= ENOENT
&& errno
!= ENOSYS
&& errno
!= ESRCH
&&
81 perror("XFS_GETQUOTA");
85 /* Did kernelspace wrap? */
95 struct fs_disk_quota
*d
,
98 if (!d
->d_blk_softlimit
&& !d
->d_blk_hardlimit
&&
99 !d
->d_ino_softlimit
&& !d
->d_ino_hardlimit
&&
100 !d
->d_rtb_softlimit
&& !d
->d_rtb_hardlimit
)
102 fprintf(fp
, "fs = %s\n", dev
);
103 /* this branch is for backward compatibility reasons */
104 if (d
->d_rtb_softlimit
|| d
->d_rtb_hardlimit
)
105 fprintf(fp
, "%-10d %7llu %7llu %7llu %7llu %7llu %7llu\n",
107 (unsigned long long)d
->d_blk_softlimit
,
108 (unsigned long long)d
->d_blk_hardlimit
,
109 (unsigned long long)d
->d_ino_softlimit
,
110 (unsigned long long)d
->d_ino_hardlimit
,
111 (unsigned long long)d
->d_rtb_softlimit
,
112 (unsigned long long)d
->d_rtb_hardlimit
);
114 fprintf(fp
, "%-10d %7llu %7llu %7llu %7llu\n",
116 (unsigned long long)d
->d_blk_softlimit
,
117 (unsigned long long)d
->d_blk_hardlimit
,
118 (unsigned long long)d
->d_ino_softlimit
,
119 (unsigned long long)d
->d_ino_hardlimit
);
125 dump_limits_any_type(
133 struct fs_disk_quota d
;
134 uint id
= lower
, flags
= 0;
136 if ((mount
= fs_table_lookup(dir
, FS_MOUNT_POINT
)) == NULL
) {
138 fprintf(stderr
, "%s: cannot find mount point %s\n",
143 while (get_dquot(&d
, id
, type
, mount
->fs_name
,
144 flags
| GETNEXTQUOTA_FLAG
) &&
145 !(upper
&& (d
.d_id
> upper
))) {
146 dump_file(fp
, &d
, mount
->fs_name
);
148 flags
|= GETNEXTQUOTA_FLAG
;
151 if (flags
& GETNEXTQUOTA_FLAG
)
154 /* Otherwise fall back to iterating over each uid/gid/prjid */
156 case XFS_GROUP_QUOTA
: {
159 while ((g
= getgrent()) != NULL
) {
160 if (get_dquot(&d
, g
->gr_gid
, type
,
161 mount
->fs_name
, 0) &&
162 !(lower
&& (d
.d_id
< lower
)) &&
163 !(upper
&& (d
.d_id
> upper
)))
164 dump_file(fp
, &d
, mount
->fs_name
);
169 case XFS_PROJ_QUOTA
: {
170 struct fs_project
*p
;
172 while ((p
= getprent()) != NULL
) {
173 if (get_dquot(&d
, p
->pr_prid
, type
,
174 mount
->fs_name
, 0) &&
175 !(lower
&& (d
.d_id
< lower
)) &&
176 !(upper
&& (d
.d_id
> upper
)))
177 dump_file(fp
, &d
, mount
->fs_name
);
182 case XFS_USER_QUOTA
: {
185 while ((u
= getpwent()) != NULL
) {
186 if (get_dquot(&d
, u
->pw_uid
, type
,
187 mount
->fs_name
, 0) &&
188 !(lower
&& (d
.d_id
< lower
)) &&
189 !(upper
&& (d
.d_id
> upper
)))
190 dump_file(fp
, &d
, mount
->fs_name
);
205 uint lower
= 0, upper
= 0;
208 while ((c
= getopt(argc
, argv
, "f:gpuL:U:")) != EOF
) {
214 type
|= XFS_GROUP_QUOTA
;
217 type
|= XFS_PROJ_QUOTA
;
220 type
|= XFS_USER_QUOTA
;
223 lower
= (uint
)atoi(optarg
);
226 upper
= (uint
)atoi(optarg
);
229 return command_usage(&dump_cmd
);
234 return command_usage(&dump_cmd
);
237 type
= XFS_USER_QUOTA
;
238 } else if (type
!= XFS_GROUP_QUOTA
&&
239 type
!= XFS_PROJ_QUOTA
&&
240 type
!= XFS_USER_QUOTA
) {
241 return command_usage(&dump_cmd
);
244 if ((fp
= fopen_write_secure(fname
)) == NULL
)
247 dump_limits_any_type(fp
, type
, fs_path
->fs_dir
, lower
, upper
);
263 char *typename
= type_to_string(type
);
267 if (flags
& NO_HEADER_FLAG
)
271 fprintf(fp
, _("%s quota on %s (%s)\n"),
272 typename
, mount
->fs_dir
, mount
->fs_name
);
275 for (i
= 0; i
< 10; i
++)
277 if (form
& XFS_BLOCK_QUOTA
)
278 fprintf(fp
, (flags
& HUMAN_FLAG
) ?
279 "%13c %s %13c" : "%20c %s %20c",
280 ' ', form_to_string(XFS_BLOCK_QUOTA
), ' ');
281 if (form
& XFS_INODE_QUOTA
)
282 fprintf(fp
, (flags
& HUMAN_FLAG
) ?
283 "%13c %s %13c" : "%20c %s %20c",
284 ' ', form_to_string(XFS_INODE_QUOTA
), ' ');
285 if (form
& XFS_RTBLOCK_QUOTA
)
286 fprintf(fp
, (flags
& HUMAN_FLAG
) ?
287 "%9c %s %9c" : "%15c %s %15c",
288 ' ', form_to_string(XFS_RTBLOCK_QUOTA
), ' ');
292 snprintf(scratch
, sizeof(scratch
), "%s ID", typename
);
293 fprintf(fp
, "%-10s ", scratch
);
294 if (form
& XFS_BLOCK_QUOTA
)
295 fprintf(fp
, (flags
& HUMAN_FLAG
) ?
296 _(" Used Soft Hard Warn/Grace ") :
297 _(" Used Soft Hard Warn/Grace "));
298 if (form
& XFS_INODE_QUOTA
)
299 fprintf(fp
, (flags
& HUMAN_FLAG
) ?
300 _(" Used Soft Hard Warn/Grace ") :
301 _(" Used Soft Hard Warn/ Grace "));
302 if (form
& XFS_RTBLOCK_QUOTA
)
303 fprintf(fp
, (flags
& HUMAN_FLAG
) ?
304 _(" Used Soft Hard Warn/Grace ") :
305 _(" Used Soft Hard Warn/Grace "));
309 for (i
= 0; i
< 10; i
++)
312 count
= (flags
& HUMAN_FLAG
) ? 33 : 50;
313 if (form
& XFS_BLOCK_QUOTA
) {
314 for (i
= 0; i
< count
; i
++)
318 if (form
& XFS_INODE_QUOTA
) {
319 for (i
= 0; i
< count
; i
++)
323 if (form
& XFS_RTBLOCK_QUOTA
) {
324 for (i
= 0; i
< count
; i
++)
334 struct fs_disk_quota
*d
,
342 char c
[8], h
[8], s
[8];
346 if (flags
& TERSE_FLAG
) {
348 if ((form
& XFS_BLOCK_QUOTA
) && d
->d_bcount
)
350 if ((form
& XFS_INODE_QUOTA
) && d
->d_icount
)
352 if ((form
& XFS_RTBLOCK_QUOTA
) && d
->d_rtbcount
)
358 if (!(flags
& NO_HEADER_FLAG
))
359 report_header(fp
, form
, type
, mount
, flags
);
361 if (flags
& NO_LOOKUP_FLAG
) {
362 fprintf(fp
, "#%-10u", d
->d_id
);
365 if (type
== XFS_USER_QUOTA
) {
366 struct passwd
*u
= getpwuid(d
->d_id
);
369 } else if (type
== XFS_GROUP_QUOTA
) {
370 struct group
*g
= getgrgid(d
->d_id
);
373 } else if (type
== XFS_PROJ_QUOTA
) {
374 fs_project_t
*p
= getprprid(d
->d_id
);
379 /* If no name is found, print the id #num instead of (null) */
381 fprintf(fp
, "%-10s", name
);
383 fprintf(fp
, "#%-9u", d
->d_id
);
386 if (form
& XFS_BLOCK_QUOTA
) {
387 timer
= decode_timer(d
, d
->d_btimer
, d
->d_btimer_hi
);
388 qflags
= (flags
& HUMAN_FLAG
);
389 if (d
->d_blk_hardlimit
&& d
->d_bcount
> d
->d_blk_hardlimit
)
390 qflags
|= LIMIT_FLAG
;
391 if (d
->d_blk_softlimit
&& d
->d_bcount
> d
->d_blk_softlimit
)
392 qflags
|= QUOTA_FLAG
;
393 if (flags
& HUMAN_FLAG
)
394 fprintf(fp
, " %6s %6s %6s %02d %8s",
395 bbs_to_string(d
->d_bcount
, c
, sizeof(c
)),
396 bbs_to_string(d
->d_blk_softlimit
, s
, sizeof(s
)),
397 bbs_to_string(d
->d_blk_hardlimit
, h
, sizeof(h
)),
399 time_to_string(timer
, qflags
));
401 fprintf(fp
, " %10llu %10llu %10llu %02d %9s",
402 (unsigned long long)d
->d_bcount
>> 1,
403 (unsigned long long)d
->d_blk_softlimit
>> 1,
404 (unsigned long long)d
->d_blk_hardlimit
>> 1,
406 time_to_string(timer
, qflags
));
408 if (form
& XFS_INODE_QUOTA
) {
409 timer
= decode_timer(d
, d
->d_itimer
, d
->d_itimer_hi
);
410 qflags
= (flags
& HUMAN_FLAG
);
411 if (d
->d_ino_hardlimit
&& d
->d_icount
> d
->d_ino_hardlimit
)
412 qflags
|= LIMIT_FLAG
;
413 if (d
->d_ino_softlimit
&& d
->d_icount
> d
->d_ino_softlimit
)
414 qflags
|= QUOTA_FLAG
;
415 if (flags
& HUMAN_FLAG
)
416 fprintf(fp
, " %6s %6s %6s %02d %8s",
417 num_to_string(d
->d_icount
, c
, sizeof(c
)),
418 num_to_string(d
->d_ino_softlimit
, s
, sizeof(s
)),
419 num_to_string(d
->d_ino_hardlimit
, h
, sizeof(h
)),
421 time_to_string(timer
, qflags
));
423 fprintf(fp
, " %10llu %10llu %10llu %02d %9s",
424 (unsigned long long)d
->d_icount
,
425 (unsigned long long)d
->d_ino_softlimit
,
426 (unsigned long long)d
->d_ino_hardlimit
,
428 time_to_string(timer
, qflags
));
430 if (form
& XFS_RTBLOCK_QUOTA
) {
431 timer
= decode_timer(d
, d
->d_rtbtimer
, d
->d_rtbtimer_hi
);
432 qflags
= (flags
& HUMAN_FLAG
);
433 if (d
->d_rtb_hardlimit
&& d
->d_rtbcount
> d
->d_rtb_hardlimit
)
434 qflags
|= LIMIT_FLAG
;
435 if (d
->d_rtb_softlimit
&& d
->d_rtbcount
> d
->d_rtb_softlimit
)
436 qflags
|= QUOTA_FLAG
;
437 if (flags
& HUMAN_FLAG
)
438 fprintf(fp
, " %6s %6s %6s %02d %8s",
439 bbs_to_string(d
->d_rtbcount
, c
, sizeof(c
)),
440 bbs_to_string(d
->d_rtb_softlimit
, s
, sizeof(s
)),
441 bbs_to_string(d
->d_rtb_hardlimit
, h
, sizeof(h
)),
443 time_to_string(timer
, qflags
));
445 fprintf(fp
, " %10llu %10llu %10llu %02d %9s",
446 (unsigned long long)d
->d_rtbcount
>> 1,
447 (unsigned long long)d
->d_rtb_softlimit
>> 1,
448 (unsigned long long)d
->d_rtb_hardlimit
>> 1,
450 time_to_string(timer
, qflags
));
466 struct fs_disk_quota d
;
469 while (get_dquot(&d
, id
, XFS_USER_QUOTA
, mount
->fs_name
,
470 flags
| GETNEXTQUOTA_FLAG
) &&
471 !(upper
&& (d
.d_id
> upper
))) {
472 report_mount(fp
, &d
, NULL
, form
, XFS_USER_QUOTA
, mount
, flags
);
474 flags
|= GETNEXTQUOTA_FLAG
;
475 flags
|= NO_HEADER_FLAG
;
478 /* No GETNEXTQUOTA support, iterate over all from password file */
479 if (!(flags
& GETNEXTQUOTA_FLAG
)) {
481 while ((u
= getpwent()) != NULL
) {
482 if (get_dquot(&d
, u
->pw_uid
, XFS_USER_QUOTA
,
483 mount
->fs_name
, flags
) &&
484 !(lower
&& (d
.d_id
< lower
)) &&
485 !(upper
&& (d
.d_id
> upper
))) {
486 report_mount(fp
, &d
, u
->pw_name
, form
,
487 XFS_USER_QUOTA
, mount
, flags
);
488 flags
|= NO_HEADER_FLAG
;
494 if (flags
& NO_HEADER_FLAG
)
508 struct fs_disk_quota d
;
511 while (get_dquot(&d
, id
, XFS_GROUP_QUOTA
, mount
->fs_name
,
512 flags
| GETNEXTQUOTA_FLAG
) &&
513 !(upper
&& (d
.d_id
> upper
))) {
514 report_mount(fp
, &d
, NULL
, form
, XFS_GROUP_QUOTA
, mount
, flags
);
516 flags
|= GETNEXTQUOTA_FLAG
;
517 flags
|= NO_HEADER_FLAG
;
520 /* No GETNEXTQUOTA support, iterate over all from password file */
521 if (!(flags
& GETNEXTQUOTA_FLAG
)) {
523 while ((g
= getgrent()) != NULL
) {
524 if (get_dquot(&d
, g
->gr_gid
, XFS_GROUP_QUOTA
,
525 mount
->fs_name
, flags
) &&
526 !(lower
&& (d
.d_id
< lower
)) &&
527 !(upper
&& (d
.d_id
> upper
))) {
528 report_mount(fp
, &d
, g
->gr_name
, form
,
529 XFS_GROUP_QUOTA
, mount
, flags
);
530 flags
|= NO_HEADER_FLAG
;
534 if (flags
& NO_HEADER_FLAG
)
540 report_project_mount(
549 struct fs_disk_quota d
;
552 while (get_dquot(&d
, id
, XFS_PROJ_QUOTA
, mount
->fs_name
,
553 flags
| GETNEXTQUOTA_FLAG
) &&
554 !(upper
&& (d
.d_id
> upper
))) {
555 report_mount(fp
, &d
, NULL
, form
, XFS_PROJ_QUOTA
, mount
, flags
);
557 flags
|= GETNEXTQUOTA_FLAG
;
558 flags
|= NO_HEADER_FLAG
;
561 /* No GETNEXTQUOTA support, iterate over all */
562 if (!(flags
& GETNEXTQUOTA_FLAG
)) {
565 * Print default project quota, even if projid 0
568 if (get_dquot(&d
, 0, XFS_PROJ_QUOTA
, mount
->fs_name
,
570 !(lower
&& (d
.d_id
< lower
)) &&
571 !(upper
&& (d
.d_id
> upper
))) {
572 report_mount(fp
, &d
, NULL
, form
, XFS_PROJ_QUOTA
,
574 flags
|= NO_HEADER_FLAG
;
579 while ((p
= getprent()) != NULL
) {
580 if (get_dquot(&d
, p
->pr_prid
, XFS_PROJ_QUOTA
,
581 mount
->fs_name
, flags
) &&
582 !(lower
&& (d
.d_id
< lower
)) &&
583 !(upper
&& (d
.d_id
> upper
))) {
584 report_mount(fp
, &d
, p
->pr_name
, form
,
585 XFS_PROJ_QUOTA
, mount
, flags
);
586 flags
|= NO_HEADER_FLAG
;
592 if (flags
& NO_HEADER_FLAG
)
609 if (type
& XFS_USER_QUOTA
) {
610 fs_cursor_initialise(dir
, FS_MOUNT_POINT
, &cursor
);
611 while ((mount
= fs_cursor_next_entry(&cursor
))) {
612 if (!foreign_allowed
&& (mount
->fs_flags
& FS_FOREIGN
))
614 if (xfsquotactl(XFS_QSYNC
, mount
->fs_name
,
615 XFS_USER_QUOTA
, 0, NULL
) < 0
616 && errno
!= ENOENT
&& errno
!= ENOSYS
)
617 perror("XFS_QSYNC user quota");
618 report_user_mount(fp
, form
, mount
,
619 lower
, upper
, flags
);
622 if (type
& XFS_GROUP_QUOTA
) {
623 fs_cursor_initialise(dir
, FS_MOUNT_POINT
, &cursor
);
624 while ((mount
= fs_cursor_next_entry(&cursor
))) {
625 if (!foreign_allowed
&& (mount
->fs_flags
& FS_FOREIGN
))
627 if (xfsquotactl(XFS_QSYNC
, mount
->fs_name
,
628 XFS_GROUP_QUOTA
, 0, NULL
) < 0
629 && errno
!= ENOENT
&& errno
!= ENOSYS
)
630 perror("XFS_QSYNC group quota");
631 report_group_mount(fp
, form
, mount
,
632 lower
, upper
, flags
);
635 if (type
& XFS_PROJ_QUOTA
) {
636 fs_cursor_initialise(dir
, FS_MOUNT_POINT
, &cursor
);
637 while ((mount
= fs_cursor_next_entry(&cursor
))) {
638 if (!foreign_allowed
&& (mount
->fs_flags
& FS_FOREIGN
))
640 if (xfsquotactl(XFS_QSYNC
, mount
->fs_name
,
641 XFS_PROJ_QUOTA
, 0, NULL
) < 0
642 && errno
!= ENOENT
&& errno
!= ENOSYS
)
643 perror("XFS_QSYNC proj quota");
644 report_project_mount(fp
, form
, mount
,
645 lower
, upper
, flags
);
657 uint lower
= 0, upper
= 0;
659 int c
, flags
= 0, type
= 0, form
= 0;
661 while ((c
= getopt(argc
, argv
, "abdf:ghilL:NnprtuU:")) != EOF
) {
667 form
|= XFS_BLOCK_QUOTA
;
670 form
|= XFS_INODE_QUOTA
;
673 form
|= XFS_RTBLOCK_QUOTA
;
676 type
|= XFS_GROUP_QUOTA
;
679 type
|= XFS_PROJ_QUOTA
;
682 type
|= XFS_USER_QUOTA
;
685 flags
|= ALL_MOUNTS_FLAG
;
691 flags
|= NO_LOOKUP_FLAG
;
694 flags
|= NO_HEADER_FLAG
;
700 lower
= (uint
)atoi(optarg
);
701 flags
|= NO_LOOKUP_FLAG
;
704 upper
= (uint
)atoi(optarg
);
705 flags
|= NO_LOOKUP_FLAG
;
711 return command_usage(&report_cmd
);
716 form
= XFS_BLOCK_QUOTA
;
719 type
= XFS_USER_QUOTA
| XFS_GROUP_QUOTA
| XFS_PROJ_QUOTA
;
722 flags
&= ~NO_LOOKUP_FLAG
;
724 if ((fp
= fopen_write_secure(fname
)) == NULL
)
727 if (argc
== optind
) {
728 if (flags
& ALL_MOUNTS_FLAG
)
729 report_any_type(fp
, form
, type
, NULL
,
730 lower
, upper
, flags
);
731 else if (fs_path
&& (fs_path
->fs_flags
& FS_MOUNT_POINT
))
732 report_any_type(fp
, form
, type
, fs_path
->fs_dir
,
733 lower
, upper
, flags
);
734 } else while (argc
> optind
) {
735 report_any_type(fp
, form
, type
, argv
[optind
++],
736 lower
, upper
, flags
);
747 dump_cmd
.name
= "dump";
748 dump_cmd
.cfunc
= dump_f
;
750 dump_cmd
.argmax
= -1;
751 dump_cmd
.args
= _("[-g|-p|-u] [-LU] [-f file]");
752 dump_cmd
.oneline
= _("dump quota information for backup utilities");
753 dump_cmd
.help
= dump_help
;
754 dump_cmd
.flags
= CMD_FLAG_FOREIGN_OK
;
756 report_cmd
.name
= "report";
757 report_cmd
.altname
= "repquota";
758 report_cmd
.cfunc
= report_f
;
759 report_cmd
.argmin
= 0;
760 report_cmd
.argmax
= -1;
761 report_cmd
.args
= _("[-bir] [-gpu] [-ahntlLNU] [-f file]");
762 report_cmd
.oneline
= _("report filesystem quota information");
763 report_cmd
.help
= report_help
;
764 report_cmd
.flags
= CMD_FLAG_ONESHOT
| CMD_FLAG_FOREIGN_OK
;
767 add_command(&dump_cmd
);
768 add_command(&report_cmd
);