]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - quota/report.c
xfs_quota: apply -L/-U range limits in uid/gid/pid loops
[thirdparty/xfsprogs-dev.git] / quota / report.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 */
6 #include <stdbool.h>
7 #include "command.h"
8 #include <sys/types.h>
9 #include <pwd.h>
10 #include <grp.h>
11 #include <utmp.h>
12 #include "init.h"
13 #include "quota.h"
14
15 static cmdinfo_t dump_cmd;
16 static cmdinfo_t report_cmd;
17
18 static void
19 dump_help(void)
20 {
21 printf(_(
22 "\n"
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"
30 "\n"));
31 }
32
33 static void
34 report_help(void)
35 {
36 printf(_(
37 "\n"
38 " report used space and inodes, and quota limits, for a filesystem\n"
39 " Example:\n"
40 " 'report -igh'\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"
59 "\n"));
60 }
61
62 static int
63 get_dquot(
64 struct fs_disk_quota *d,
65 uint id,
66 uint type,
67 char *dev,
68 int flags)
69 {
70 int cmd;
71
72 if (flags & GETNEXTQUOTA_FLAG)
73 cmd = XFS_GETNEXTQUOTA;
74 else
75 cmd = XFS_GETQUOTA;
76
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 &&
80 cmd == XFS_GETQUOTA)
81 perror("XFS_GETQUOTA");
82 return 0;
83 }
84
85 /* Did kernelspace wrap? */
86 if (d->d_id < id)
87 return 0;
88
89 return 1;
90 }
91
92 static int
93 dump_file(
94 FILE *fp,
95 struct fs_disk_quota *d,
96 char *dev)
97 {
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)
101 return 1;
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",
106 d->d_id,
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);
113 else
114 fprintf(fp, "%-10d %7llu %7llu %7llu %7llu\n",
115 d->d_id,
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);
120
121 return 1;
122 }
123
124 static void
125 dump_limits_any_type(
126 FILE *fp,
127 uint type,
128 char *dir,
129 uint lower,
130 uint upper)
131 {
132 fs_path_t *mount;
133 struct fs_disk_quota d;
134 uint id = lower, flags = 0;
135
136 if ((mount = fs_table_lookup(dir, FS_MOUNT_POINT)) == NULL) {
137 exitcode = 1;
138 fprintf(stderr, "%s: cannot find mount point %s\n",
139 progname, dir);
140 return;
141 }
142
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);
147 id = d.d_id + 1;
148 flags |= GETNEXTQUOTA_FLAG;
149 }
150
151 if (flags & GETNEXTQUOTA_FLAG)
152 return;
153
154 /* Otherwise fall back to iterating over each uid/gid/prjid */
155 switch (type) {
156 case XFS_GROUP_QUOTA: {
157 struct group *g;
158 setgrent();
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);
165 }
166 endgrent();
167 break;
168 }
169 case XFS_PROJ_QUOTA: {
170 struct fs_project *p;
171 setprent();
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);
178 }
179 endprent();
180 break;
181 }
182 case XFS_USER_QUOTA: {
183 struct passwd *u;
184 setpwent();
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);
191 }
192 endpwent();
193 break;
194 }
195 }
196 }
197
198 static int
199 dump_f(
200 int argc,
201 char **argv)
202 {
203 FILE *fp;
204 char *fname = NULL;
205 uint lower = 0, upper = 0;
206 int c, type = 0;
207
208 while ((c = getopt(argc, argv, "f:gpuL:U:")) != EOF) {
209 switch(c) {
210 case 'f':
211 fname = optarg;
212 break;
213 case 'g':
214 type |= XFS_GROUP_QUOTA;
215 break;
216 case 'p':
217 type |= XFS_PROJ_QUOTA;
218 break;
219 case 'u':
220 type |= XFS_USER_QUOTA;
221 break;
222 case 'L':
223 lower = (uint)atoi(optarg);
224 break;
225 case 'U':
226 upper = (uint)atoi(optarg);
227 break;
228 default:
229 return command_usage(&dump_cmd);
230 }
231 }
232
233 if (argc != optind)
234 return command_usage(&dump_cmd);
235
236 if (!type) {
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);
242 }
243
244 if ((fp = fopen_write_secure(fname)) == NULL)
245 return 0;
246
247 dump_limits_any_type(fp, type, fs_path->fs_dir, lower, upper);
248
249 if (fname)
250 fclose(fp);
251
252 return 0;
253 }
254
255 static void
256 report_header(
257 FILE *fp,
258 uint form,
259 uint type,
260 fs_path_t *mount,
261 int flags)
262 {
263 char *typename = type_to_string(type);
264 char scratch[64];
265 uint i, count;
266
267 if (flags & NO_HEADER_FLAG)
268 return;
269
270 /* line 1 */
271 fprintf(fp, _("%s quota on %s (%s)\n"),
272 typename, mount->fs_dir, mount->fs_name);
273
274 /* line 2 */
275 for (i = 0; i < 10; i++)
276 fputc(' ', fp);
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), ' ');
289 fputc('\n', fp);
290
291 /* line 3 */
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 "));
306 fputc('\n', fp);
307
308 /* line 4 */
309 for (i = 0; i < 10; i++)
310 fputc('-', fp);
311 fputc(' ', fp);
312 count = (flags & HUMAN_FLAG) ? 33 : 50;
313 if (form & XFS_BLOCK_QUOTA) {
314 for (i = 0; i < count; i++)
315 fputc('-', fp);
316 fputc(' ', fp);
317 }
318 if (form & XFS_INODE_QUOTA) {
319 for (i = 0; i < count; i++)
320 fputc('-', fp);
321 fputc(' ', fp);
322 }
323 if (form & XFS_RTBLOCK_QUOTA) {
324 for (i = 0; i < count; i++)
325 fputc('-', fp);
326 fputc(' ', fp);
327 }
328 fputc('\n', fp);
329 }
330
331 static int
332 report_mount(
333 FILE *fp,
334 struct fs_disk_quota *d,
335 char *name,
336 uint form,
337 uint type,
338 fs_path_t *mount,
339 uint flags)
340 {
341 time64_t timer;
342 char c[8], h[8], s[8];
343 uint qflags;
344 int count;
345
346 if (flags & TERSE_FLAG) {
347 count = 0;
348 if ((form & XFS_BLOCK_QUOTA) && d->d_bcount)
349 count++;
350 if ((form & XFS_INODE_QUOTA) && d->d_icount)
351 count++;
352 if ((form & XFS_RTBLOCK_QUOTA) && d->d_rtbcount)
353 count++;
354 if (!count)
355 return 0;
356 }
357
358 if (!(flags & NO_HEADER_FLAG))
359 report_header(fp, form, type, mount, flags);
360
361 if (flags & NO_LOOKUP_FLAG) {
362 fprintf(fp, "#%-10u", d->d_id);
363 } else {
364 if (name == NULL) {
365 if (type == XFS_USER_QUOTA) {
366 struct passwd *u = getpwuid(d->d_id);
367 if (u)
368 name = u->pw_name;
369 } else if (type == XFS_GROUP_QUOTA) {
370 struct group *g = getgrgid(d->d_id);
371 if (g)
372 name = g->gr_name;
373 } else if (type == XFS_PROJ_QUOTA) {
374 fs_project_t *p = getprprid(d->d_id);
375 if (p)
376 name = p->pr_name;
377 }
378 }
379 /* If no name is found, print the id #num instead of (null) */
380 if (name != NULL)
381 fprintf(fp, "%-10s", name);
382 else
383 fprintf(fp, "#%-9u", d->d_id);
384 }
385
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)),
398 d->d_bwarns,
399 time_to_string(timer, qflags));
400 else
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,
405 d->d_bwarns,
406 time_to_string(timer, qflags));
407 }
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)),
420 d->d_iwarns,
421 time_to_string(timer, qflags));
422 else
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,
427 d->d_iwarns,
428 time_to_string(timer, qflags));
429 }
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)),
442 d->d_rtbwarns,
443 time_to_string(timer, qflags));
444 else
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,
449 d->d_rtbwarns,
450 time_to_string(timer, qflags));
451 }
452 fputc('\n', fp);
453 return 1;
454 }
455
456 static void
457 report_user_mount(
458 FILE *fp,
459 uint form,
460 fs_path_t *mount,
461 uint lower,
462 uint upper,
463 uint flags)
464 {
465 struct passwd *u;
466 struct fs_disk_quota d;
467 uint id = lower;
468
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);
473 id = d.d_id + 1;
474 flags |= GETNEXTQUOTA_FLAG;
475 flags |= NO_HEADER_FLAG;
476 }
477
478 /* No GETNEXTQUOTA support, iterate over all from password file */
479 if (!(flags & GETNEXTQUOTA_FLAG)) {
480 setpwent();
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;
489 }
490 }
491 endpwent();
492 }
493
494 if (flags & NO_HEADER_FLAG)
495 fputc('\n', fp);
496 }
497
498 static void
499 report_group_mount(
500 FILE *fp,
501 uint form,
502 fs_path_t *mount,
503 uint lower,
504 uint upper,
505 uint flags)
506 {
507 struct group *g;
508 struct fs_disk_quota d;
509 uint id = lower;
510
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);
515 id = d.d_id + 1;
516 flags |= GETNEXTQUOTA_FLAG;
517 flags |= NO_HEADER_FLAG;
518 }
519
520 /* No GETNEXTQUOTA support, iterate over all from password file */
521 if (!(flags & GETNEXTQUOTA_FLAG)) {
522 setgrent();
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;
531 }
532 }
533 }
534 if (flags & NO_HEADER_FLAG)
535 fputc('\n', fp);
536 endgrent();
537 }
538
539 static void
540 report_project_mount(
541 FILE *fp,
542 uint form,
543 fs_path_t *mount,
544 uint lower,
545 uint upper,
546 uint flags)
547 {
548 fs_project_t *p;
549 struct fs_disk_quota d;
550 uint id = lower;
551
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);
556 id = d.d_id + 1;
557 flags |= GETNEXTQUOTA_FLAG;
558 flags |= NO_HEADER_FLAG;
559 }
560
561 /* No GETNEXTQUOTA support, iterate over all */
562 if (!(flags & GETNEXTQUOTA_FLAG)) {
563 if (!getprprid(0)) {
564 /*
565 * Print default project quota, even if projid 0
566 * isn't defined
567 */
568 if (get_dquot(&d, 0, XFS_PROJ_QUOTA, mount->fs_name,
569 flags) &&
570 !(lower && (d.d_id < lower)) &&
571 !(upper && (d.d_id > upper))) {
572 report_mount(fp, &d, NULL, form, XFS_PROJ_QUOTA,
573 mount, flags);
574 flags |= NO_HEADER_FLAG;
575 }
576 }
577
578 setprent();
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;
587 }
588 }
589 endprent();
590 }
591
592 if (flags & NO_HEADER_FLAG)
593 fputc('\n', fp);
594 }
595
596 static void
597 report_any_type(
598 FILE *fp,
599 uint form,
600 uint type,
601 char *dir,
602 uint lower,
603 uint upper,
604 uint flags)
605 {
606 fs_cursor_t cursor;
607 fs_path_t *mount;
608
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))
613 continue;
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);
620 }
621 }
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))
626 continue;
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);
633 }
634 }
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))
639 continue;
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);
646 }
647 }
648 }
649
650 static int
651 report_f(
652 int argc,
653 char **argv)
654 {
655 FILE *fp = NULL;
656 char *fname = NULL;
657 uint lower = 0, upper = 0;
658 bool lookup = false;
659 int c, flags = 0, type = 0, form = 0;
660
661 while ((c = getopt(argc, argv, "abdf:ghilL:NnprtuU:")) != EOF) {
662 switch (c) {
663 case 'f':
664 fname = optarg;
665 break;
666 case 'b':
667 form |= XFS_BLOCK_QUOTA;
668 break;
669 case 'i':
670 form |= XFS_INODE_QUOTA;
671 break;
672 case 'r':
673 form |= XFS_RTBLOCK_QUOTA;
674 break;
675 case 'g':
676 type |= XFS_GROUP_QUOTA;
677 break;
678 case 'p':
679 type |= XFS_PROJ_QUOTA;
680 break;
681 case 'u':
682 type |= XFS_USER_QUOTA;
683 break;
684 case 'a':
685 flags |= ALL_MOUNTS_FLAG;
686 break;
687 case 'h':
688 flags |= HUMAN_FLAG;
689 break;
690 case 'n':
691 flags |= NO_LOOKUP_FLAG;
692 break;
693 case 'N':
694 flags |= NO_HEADER_FLAG;
695 break;
696 case 't':
697 flags |= TERSE_FLAG;
698 break;
699 case 'L':
700 lower = (uint)atoi(optarg);
701 flags |= NO_LOOKUP_FLAG;
702 break;
703 case 'U':
704 upper = (uint)atoi(optarg);
705 flags |= NO_LOOKUP_FLAG;
706 break;
707 case 'l':
708 lookup = true;
709 break;
710 default:
711 return command_usage(&report_cmd);
712 }
713 }
714
715 if (!form)
716 form = XFS_BLOCK_QUOTA;
717
718 if (!type)
719 type = XFS_USER_QUOTA | XFS_GROUP_QUOTA | XFS_PROJ_QUOTA;
720
721 if (lookup)
722 flags &= ~NO_LOOKUP_FLAG;
723
724 if ((fp = fopen_write_secure(fname)) == NULL)
725 return 0;
726
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);
737 }
738
739 if (fname)
740 fclose(fp);
741 return 0;
742 }
743
744 void
745 report_init(void)
746 {
747 dump_cmd.name = "dump";
748 dump_cmd.cfunc = dump_f;
749 dump_cmd.argmin = 0;
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;
755
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;
765
766 if (expert) {
767 add_command(&dump_cmd);
768 add_command(&report_cmd);
769 }
770 }