]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - quota/report.c
xfs_quota: separate get_dquot() and dump_file()
[thirdparty/xfsprogs-dev.git] / quota / report.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
5aead01d 2/*
da23017d
NS
3 * Copyright (c) 2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5aead01d 5 */
29647c8d 6#include <stdbool.h>
6b803e5a 7#include "command.h"
904e8060 8#include <sys/types.h>
5aead01d
NS
9#include <pwd.h>
10#include <grp.h>
ce8d0b3a 11#include <utmp.h>
5aead01d
NS
12#include "init.h"
13#include "quota.h"
14
15static cmdinfo_t dump_cmd;
16static cmdinfo_t report_cmd;
17
18static void
19dump_help(void)
20{
5aead01d
NS
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"
069610ec
ES
27" -L -- lower ID bound to dump\n"
28" -U -- upper ID bound to dump\n"
5aead01d
NS
29" -f -- write the dump out to the specified file\n"
30"\n"));
31}
32
33static void
34report_help(void)
35{
5aead01d
NS
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"
1774874a
NS
47" -n -- skip identifier-to-name translations, just report IDs\n"
48" -N -- suppress the header from the output\n"
5aead01d 49" -t -- terse output format, hides rows which are all zero\n"
bb76b4b3 50" -L -- lower ID bound to report on\n"
ff1f79a7 51" -U -- upper ID bound to report on\n"
85dcd9a0 52" -l -- look up names for IDs in lower-upper range\n"
5aead01d
NS
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
f103166a
AA
62static int
63get_dquot(
64 struct fs_disk_quota *d,
5aead01d 65 uint id,
cc15c8cc 66 uint *oid,
5aead01d 67 uint type,
6a9a085e
ES
68 char *dev,
69 int flags)
5aead01d 70{
6a9a085e
ES
71 int cmd;
72
73 if (flags & GETNEXTQUOTA_FLAG)
74 cmd = XFS_GETNEXTQUOTA;
75 else
76 cmd = XFS_GETQUOTA;
5aead01d 77
52e81d72 78 /* Fall back silently if XFS_GETNEXTQUOTA fails, warn on XFS_GETQUOTA */
f103166a 79 if (xfsquotactl(cmd, dev, type, id, (void *)d) < 0) {
52e81d72
ZL
80 if (errno != ENOENT && errno != ENOSYS && errno != ESRCH &&
81 cmd == XFS_GETQUOTA)
ec4cd312 82 perror("XFS_GETQUOTA");
6a9a085e 83 return 0;
ec4cd312 84 }
cc15c8cc 85
c89be81f 86 if (oid) {
f103166a 87 *oid = d->d_id;
c89be81f
ES
88 /* Did kernelspace wrap? */
89 if (*oid < id)
90 return 0;
91 }
ebd6aa8b 92
f103166a
AA
93 return 1;
94}
95
96static int
97dump_file(
98 FILE *fp,
2c1e7aef
AA
99 struct fs_disk_quota *d,
100 char *dev)
f103166a 101{
2c1e7aef
AA
102 if (!d->d_blk_softlimit && !d->d_blk_hardlimit &&
103 !d->d_ino_softlimit && !d->d_ino_hardlimit &&
104 !d->d_rtb_softlimit && !d->d_rtb_hardlimit)
6a9a085e 105 return 1;
5aead01d 106 fprintf(fp, "fs = %s\n", dev);
1774874a 107 /* this branch is for backward compatibility reasons */
2c1e7aef 108 if (d->d_rtb_softlimit || d->d_rtb_hardlimit)
cc15c8cc 109 fprintf(fp, "%-10d %7llu %7llu %7llu %7llu %7llu %7llu\n",
2c1e7aef
AA
110 d->d_id,
111 (unsigned long long)d->d_blk_softlimit,
112 (unsigned long long)d->d_blk_hardlimit,
113 (unsigned long long)d->d_ino_softlimit,
114 (unsigned long long)d->d_ino_hardlimit,
115 (unsigned long long)d->d_rtb_softlimit,
116 (unsigned long long)d->d_rtb_hardlimit);
1774874a 117 else
cc15c8cc 118 fprintf(fp, "%-10d %7llu %7llu %7llu %7llu\n",
2c1e7aef
AA
119 d->d_id,
120 (unsigned long long)d->d_blk_softlimit,
121 (unsigned long long)d->d_blk_hardlimit,
122 (unsigned long long)d->d_ino_softlimit,
123 (unsigned long long)d->d_ino_hardlimit);
6a9a085e
ES
124
125 return 1;
5aead01d
NS
126}
127
128static void
129dump_limits_any_type(
130 FILE *fp,
131 uint type,
1774874a
NS
132 char *dir,
133 uint lower,
134 uint upper)
5aead01d
NS
135{
136 fs_path_t *mount;
2c1e7aef 137 struct fs_disk_quota d;
6a9a085e 138 uint id = 0, oid;
5aead01d
NS
139
140 if ((mount = fs_table_lookup(dir, FS_MOUNT_POINT)) == NULL) {
e3210fd8 141 exitcode = 1;
5aead01d
NS
142 fprintf(stderr, "%s: cannot find mount point %s\n",
143 progname, dir);
144 return;
145 }
146
6a9a085e 147 /* Range was specified; query everything in it */
1774874a 148 if (upper) {
2c1e7aef
AA
149 for (id = lower; id <= upper; id++) {
150 get_dquot(&d, id, &oid, type, mount->fs_name, 0);
151 dump_file(fp, &d, mount->fs_name);
152 }
1774874a
NS
153 return;
154 }
155
6a9a085e 156 /* Use GETNEXTQUOTA if it's available */
2c1e7aef
AA
157 if (get_dquot(&d, id, &oid, type, mount->fs_name, GETNEXTQUOTA_FLAG)) {
158 dump_file(fp, &d, mount->fs_name);
6a9a085e 159 id = oid + 1;
2c1e7aef
AA
160 while (get_dquot(&d, id, &oid, type, mount->fs_name,
161 GETNEXTQUOTA_FLAG)) {
162 dump_file(fp, &d, mount->fs_name);
6a9a085e 163 id = oid + 1;
2c1e7aef 164 }
6a9a085e 165 return;
2c1e7aef 166 }
6a9a085e
ES
167
168 /* Otherwise fall back to iterating over each uid/gid/prjid */
5aead01d
NS
169 switch (type) {
170 case XFS_GROUP_QUOTA: {
171 struct group *g;
172 setgrent();
2c1e7aef
AA
173 while ((g = getgrent()) != NULL) {
174 get_dquot(&d, g->gr_gid, NULL, type,
175 mount->fs_name, 0);
176 dump_file(fp, &d, mount->fs_name);
177 }
5aead01d
NS
178 endgrent();
179 break;
180 }
181 case XFS_PROJ_QUOTA: {
182 struct fs_project *p;
183 setprent();
2c1e7aef
AA
184 while ((p = getprent()) != NULL) {
185 get_dquot(&d, p->pr_prid, NULL, type,
186 mount->fs_name, 0);
187 dump_file(fp, &d, mount->fs_name);
188 }
5aead01d
NS
189 endprent();
190 break;
191 }
192 case XFS_USER_QUOTA: {
193 struct passwd *u;
194 setpwent();
2c1e7aef
AA
195 while ((u = getpwent()) != NULL) {
196 get_dquot(&d, u->pw_uid, NULL, type,
197 mount->fs_name, 0);
198 dump_file(fp, &d, mount->fs_name);
199 }
5aead01d
NS
200 endpwent();
201 break;
202 }
203 }
204}
205
206static int
207dump_f(
208 int argc,
209 char **argv)
210{
211 FILE *fp;
212 char *fname = NULL;
1774874a 213 uint lower = 0, upper = 0;
c614d3bf 214 int c, type = 0;
5aead01d 215
1774874a 216 while ((c = getopt(argc, argv, "f:gpuL:U:")) != EOF) {
5aead01d
NS
217 switch(c) {
218 case 'f':
219 fname = optarg;
220 break;
221 case 'g':
c614d3bf 222 type |= XFS_GROUP_QUOTA;
5aead01d
NS
223 break;
224 case 'p':
c614d3bf 225 type |= XFS_PROJ_QUOTA;
5aead01d
NS
226 break;
227 case 'u':
c614d3bf 228 type |= XFS_USER_QUOTA;
5aead01d 229 break;
1774874a
NS
230 case 'L':
231 lower = (uint)atoi(optarg);
232 break;
233 case 'U':
234 upper = (uint)atoi(optarg);
235 break;
5aead01d
NS
236 default:
237 return command_usage(&dump_cmd);
238 }
239 }
240
241 if (argc != optind)
242 return command_usage(&dump_cmd);
243
c614d3bf
ZL
244 if (!type) {
245 type = XFS_USER_QUOTA;
246 } else if (type != XFS_GROUP_QUOTA &&
247 type != XFS_PROJ_QUOTA &&
248 type != XFS_USER_QUOTA) {
249 return command_usage(&dump_cmd);
250 }
251
5aead01d
NS
252 if ((fp = fopen_write_secure(fname)) == NULL)
253 return 0;
254
1774874a 255 dump_limits_any_type(fp, type, fs_path->fs_dir, lower, upper);
5aead01d
NS
256
257 if (fname)
258 fclose(fp);
259
260 return 0;
261}
262
263static void
264report_header(
265 FILE *fp,
266 uint form,
267 uint type,
268 fs_path_t *mount,
269 int flags)
270{
271 char *typename = type_to_string(type);
272 char scratch[64];
273 uint i, count;
274
275 if (flags & NO_HEADER_FLAG)
276 return;
277
278 /* line 1 */
279 fprintf(fp, _("%s quota on %s (%s)\n"),
280 typename, mount->fs_dir, mount->fs_name);
281
282 /* line 2 */
283 for (i = 0; i < 10; i++)
284 fputc(' ', fp);
285 if (form & XFS_BLOCK_QUOTA)
286 fprintf(fp, (flags & HUMAN_FLAG) ?
287 "%13c %s %13c" : "%20c %s %20c",
288 ' ', form_to_string(XFS_BLOCK_QUOTA), ' ');
289 if (form & XFS_INODE_QUOTA)
290 fprintf(fp, (flags & HUMAN_FLAG) ?
291 "%13c %s %13c" : "%20c %s %20c",
292 ' ', form_to_string(XFS_INODE_QUOTA), ' ');
293 if (form & XFS_RTBLOCK_QUOTA)
294 fprintf(fp, (flags & HUMAN_FLAG) ?
295 "%9c %s %9c" : "%15c %s %15c",
296 ' ', form_to_string(XFS_RTBLOCK_QUOTA), ' ');
297 fputc('\n', fp);
298
299 /* line 3 */
300 snprintf(scratch, sizeof(scratch), "%s ID", typename);
301 fprintf(fp, "%-10s ", scratch);
302 if (form & XFS_BLOCK_QUOTA)
303 fprintf(fp, (flags & HUMAN_FLAG) ?
304 _(" Used Soft Hard Warn/Grace ") :
305 _(" Used Soft Hard Warn/Grace "));
306 if (form & XFS_INODE_QUOTA)
307 fprintf(fp, (flags & HUMAN_FLAG) ?
308 _(" Used Soft Hard Warn/Grace ") :
309 _(" Used Soft Hard Warn/ Grace "));
310 if (form & XFS_RTBLOCK_QUOTA)
311 fprintf(fp, (flags & HUMAN_FLAG) ?
312 _(" Used Soft Hard Warn/Grace ") :
313 _(" Used Soft Hard Warn/Grace "));
314 fputc('\n', fp);
315
316 /* line 4 */
317 for (i = 0; i < 10; i++)
318 fputc('-', fp);
319 fputc(' ', fp);
320 count = (flags & HUMAN_FLAG) ? 33 : 50;
321 if (form & XFS_BLOCK_QUOTA) {
322 for (i = 0; i < count; i++)
323 fputc('-', fp);
324 fputc(' ', fp);
325 }
326 if (form & XFS_INODE_QUOTA) {
327 for (i = 0; i < count; i++)
328 fputc('-', fp);
329 fputc(' ', fp);
330 }
331 if (form & XFS_RTBLOCK_QUOTA) {
332 for (i = 0; i < count; i++)
333 fputc('-', fp);
334 fputc(' ', fp);
335 }
336 fputc('\n', fp);
337}
338
339static int
340report_mount(
341 FILE *fp,
14f8b681 342 uint32_t id,
5aead01d 343 char *name,
14f8b681 344 uint32_t *oid,
5aead01d
NS
345 uint form,
346 uint type,
347 fs_path_t *mount,
348 uint flags)
349{
350 fs_disk_quota_t d;
219285ad 351 time64_t timer;
5aead01d
NS
352 char c[8], h[8], s[8];
353 uint qflags;
354 int count;
6a9a085e 355
f103166a 356 if (!get_dquot(&d, id, oid, type, mount->fs_name, flags))
5aead01d 357 return 0;
ebd6aa8b 358
5aead01d
NS
359 if (flags & TERSE_FLAG) {
360 count = 0;
361 if ((form & XFS_BLOCK_QUOTA) && d.d_bcount)
362 count++;
363 if ((form & XFS_INODE_QUOTA) && d.d_icount)
364 count++;
365 if ((form & XFS_RTBLOCK_QUOTA) && d.d_rtbcount)
366 count++;
367 if (!count)
368 return 0;
369 }
370
371 if (!(flags & NO_HEADER_FLAG))
372 report_header(fp, form, type, mount, flags);
373
85dcd9a0 374 if (flags & NO_LOOKUP_FLAG) {
cc15c8cc 375 fprintf(fp, "#%-10u", d.d_id);
85dcd9a0
ES
376 } else {
377 if (name == NULL) {
378 if (type == XFS_USER_QUOTA) {
cc15c8cc 379 struct passwd *u = getpwuid(d.d_id);
85dcd9a0
ES
380 if (u)
381 name = u->pw_name;
382 } else if (type == XFS_GROUP_QUOTA) {
cc15c8cc 383 struct group *g = getgrgid(d.d_id);
85dcd9a0
ES
384 if (g)
385 name = g->gr_name;
386 } else if (type == XFS_PROJ_QUOTA) {
cc15c8cc 387 fs_project_t *p = getprprid(d.d_id);
85dcd9a0
ES
388 if (p)
389 name = p->pr_name;
390 }
391 }
3d607a11
ZL
392 /* If no name is found, print the id #num instead of (null) */
393 if (name != NULL)
394 fprintf(fp, "%-10s", name);
395 else
396 fprintf(fp, "#%-9u", d.d_id);
85dcd9a0 397 }
a265445e 398
5aead01d 399 if (form & XFS_BLOCK_QUOTA) {
f3eb31d9 400 timer = decode_timer(&d, d.d_btimer, d.d_btimer_hi);
5aead01d
NS
401 qflags = (flags & HUMAN_FLAG);
402 if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit)
403 qflags |= LIMIT_FLAG;
404 if (d.d_blk_softlimit && d.d_bcount > d.d_blk_softlimit)
405 qflags |= QUOTA_FLAG;
406 if (flags & HUMAN_FLAG)
407 fprintf(fp, " %6s %6s %6s %02d %8s",
408 bbs_to_string(d.d_bcount, c, sizeof(c)),
409 bbs_to_string(d.d_blk_softlimit, s, sizeof(s)),
410 bbs_to_string(d.d_blk_hardlimit, h, sizeof(h)),
411 d.d_bwarns,
219285ad 412 time_to_string(timer, qflags));
5aead01d
NS
413 else
414 fprintf(fp, " %10llu %10llu %10llu %02d %9s",
415 (unsigned long long)d.d_bcount >> 1,
416 (unsigned long long)d.d_blk_softlimit >> 1,
417 (unsigned long long)d.d_blk_hardlimit >> 1,
418 d.d_bwarns,
219285ad 419 time_to_string(timer, qflags));
5aead01d
NS
420 }
421 if (form & XFS_INODE_QUOTA) {
f3eb31d9 422 timer = decode_timer(&d, d.d_itimer, d.d_itimer_hi);
5aead01d
NS
423 qflags = (flags & HUMAN_FLAG);
424 if (d.d_ino_hardlimit && d.d_icount > d.d_ino_hardlimit)
425 qflags |= LIMIT_FLAG;
426 if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
427 qflags |= QUOTA_FLAG;
428 if (flags & HUMAN_FLAG)
429 fprintf(fp, " %6s %6s %6s %02d %8s",
430 num_to_string(d.d_icount, c, sizeof(c)),
431 num_to_string(d.d_ino_softlimit, s, sizeof(s)),
432 num_to_string(d.d_ino_hardlimit, h, sizeof(h)),
433 d.d_iwarns,
219285ad 434 time_to_string(timer, qflags));
5aead01d
NS
435 else
436 fprintf(fp, " %10llu %10llu %10llu %02d %9s",
437 (unsigned long long)d.d_icount,
438 (unsigned long long)d.d_ino_softlimit,
439 (unsigned long long)d.d_ino_hardlimit,
440 d.d_iwarns,
219285ad 441 time_to_string(timer, qflags));
5aead01d
NS
442 }
443 if (form & XFS_RTBLOCK_QUOTA) {
f3eb31d9 444 timer = decode_timer(&d, d.d_rtbtimer, d.d_rtbtimer_hi);
5aead01d
NS
445 qflags = (flags & HUMAN_FLAG);
446 if (d.d_rtb_hardlimit && d.d_rtbcount > d.d_rtb_hardlimit)
447 qflags |= LIMIT_FLAG;
448 if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
449 qflags |= QUOTA_FLAG;
450 if (flags & HUMAN_FLAG)
451 fprintf(fp, " %6s %6s %6s %02d %8s",
452 bbs_to_string(d.d_rtbcount, c, sizeof(c)),
453 bbs_to_string(d.d_rtb_softlimit, s, sizeof(s)),
454 bbs_to_string(d.d_rtb_hardlimit, h, sizeof(h)),
455 d.d_rtbwarns,
219285ad 456 time_to_string(timer, qflags));
5aead01d
NS
457 else
458 fprintf(fp, " %10llu %10llu %10llu %02d %9s",
459 (unsigned long long)d.d_rtbcount >> 1,
460 (unsigned long long)d.d_rtb_softlimit >> 1,
461 (unsigned long long)d.d_rtb_hardlimit >> 1,
462 d.d_rtbwarns,
219285ad 463 time_to_string(timer, qflags));
5aead01d
NS
464 }
465 fputc('\n', fp);
466 return 1;
467}
468
469static void
470report_user_mount(
471 FILE *fp,
472 uint form,
473 fs_path_t *mount,
1774874a
NS
474 uint lower,
475 uint upper,
5aead01d
NS
476 uint flags)
477{
1774874a 478 struct passwd *u;
6a9a085e 479 uint id = 0, oid;
1774874a
NS
480
481 if (upper) { /* identifier range specified */
57cc6e78 482 for (id = lower; id <= upper; id++) {
cc15c8cc 483 if (report_mount(fp, id, NULL, NULL,
1774874a
NS
484 form, XFS_USER_QUOTA, mount, flags))
485 flags |= NO_HEADER_FLAG;
486 }
6a9a085e
ES
487 } else if (report_mount(fp, id, NULL, &oid, form,
488 XFS_USER_QUOTA, mount,
489 flags|GETNEXTQUOTA_FLAG)) {
490 id = oid + 1;
491 flags |= GETNEXTQUOTA_FLAG;
492 flags |= NO_HEADER_FLAG;
493 while (report_mount(fp, id, NULL, &oid, form, XFS_USER_QUOTA,
494 mount, flags)) {
495 id = oid + 1;
496 }
1774874a
NS
497 } else {
498 setpwent();
499 while ((u = getpwent()) != NULL) {
cc15c8cc 500 if (report_mount(fp, u->pw_uid, u->pw_name, NULL,
1774874a
NS
501 form, XFS_USER_QUOTA, mount, flags))
502 flags |= NO_HEADER_FLAG;
503 }
504 endpwent();
505 }
5aead01d 506
5aead01d
NS
507 if (flags & NO_HEADER_FLAG)
508 fputc('\n', fp);
5aead01d
NS
509}
510
511static void
512report_group_mount(
513 FILE *fp,
514 uint form,
515 fs_path_t *mount,
1774874a
NS
516 uint lower,
517 uint upper,
5aead01d
NS
518 uint flags)
519{
1774874a 520 struct group *g;
6a9a085e 521 uint id = 0, oid;
1774874a
NS
522
523 if (upper) { /* identifier range specified */
57cc6e78 524 for (id = lower; id <= upper; id++) {
cc15c8cc 525 if (report_mount(fp, id, NULL, NULL,
1774874a
NS
526 form, XFS_GROUP_QUOTA, mount, flags))
527 flags |= NO_HEADER_FLAG;
528 }
6a9a085e
ES
529 } else if (report_mount(fp, id, NULL, &oid, form,
530 XFS_GROUP_QUOTA, mount,
531 flags|GETNEXTQUOTA_FLAG)) {
532 id = oid + 1;
533 flags |= GETNEXTQUOTA_FLAG;
534 flags |= NO_HEADER_FLAG;
535 while (report_mount(fp, id, NULL, &oid, form, XFS_GROUP_QUOTA,
536 mount, flags)) {
537 id = oid + 1;
538 }
1774874a
NS
539 } else {
540 setgrent();
541 while ((g = getgrent()) != NULL) {
cc15c8cc 542 if (report_mount(fp, g->gr_gid, g->gr_name, NULL,
1774874a
NS
543 form, XFS_GROUP_QUOTA, mount, flags))
544 flags |= NO_HEADER_FLAG;
545 }
546 }
5aead01d
NS
547 if (flags & NO_HEADER_FLAG)
548 fputc('\n', fp);
549 endgrent();
550}
551
552static void
553report_project_mount(
554 FILE *fp,
555 uint form,
556 fs_path_t *mount,
1774874a
NS
557 uint lower,
558 uint upper,
5aead01d
NS
559 uint flags)
560{
561 fs_project_t *p;
6a9a085e 562 uint id = 0, oid;
1774874a
NS
563
564 if (upper) { /* identifier range specified */
57cc6e78 565 for (id = lower; id <= upper; id++) {
cc15c8cc 566 if (report_mount(fp, id, NULL, NULL,
1774874a
NS
567 form, XFS_PROJ_QUOTA, mount, flags))
568 flags |= NO_HEADER_FLAG;
569 }
6a9a085e
ES
570 } else if (report_mount(fp, id, NULL, &oid, form,
571 XFS_PROJ_QUOTA, mount,
572 flags|GETNEXTQUOTA_FLAG)) {
573 id = oid + 1;
574 flags |= GETNEXTQUOTA_FLAG;
575 flags |= NO_HEADER_FLAG;
576 while (report_mount(fp, id, NULL, &oid, form, XFS_PROJ_QUOTA,
577 mount, flags)) {
578 id = oid + 1;
579 }
1774874a 580 } else {
3d607a11
ZL
581 if (!getprprid(0)) {
582 /*
583 * Print default project quota, even if projid 0
584 * isn't defined
585 */
a8b6f527
ES
586 if (report_mount(fp, 0, NULL, NULL,
587 form, XFS_PROJ_QUOTA, mount, flags))
588 flags |= NO_HEADER_FLAG;
3d607a11
ZL
589 }
590
1774874a
NS
591 setprent();
592 while ((p = getprent()) != NULL) {
cc15c8cc 593 if (report_mount(fp, p->pr_prid, p->pr_name, NULL,
1774874a
NS
594 form, XFS_PROJ_QUOTA, mount, flags))
595 flags |= NO_HEADER_FLAG;
596 }
597 endprent();
598 }
5aead01d 599
5aead01d
NS
600 if (flags & NO_HEADER_FLAG)
601 fputc('\n', fp);
5aead01d
NS
602}
603
604static void
605report_any_type(
606 FILE *fp,
607 uint form,
608 uint type,
609 char *dir,
1774874a
NS
610 uint lower,
611 uint upper,
5aead01d
NS
612 uint flags)
613{
614 fs_cursor_t cursor;
615 fs_path_t *mount;
616
617 if (type & XFS_USER_QUOTA) {
618 fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor);
546bedf4 619 while ((mount = fs_cursor_next_entry(&cursor))) {
29647c8d
BD
620 if (!foreign_allowed && (mount->fs_flags & FS_FOREIGN))
621 continue;
ec4cd312
AM
622 if (xfsquotactl(XFS_QSYNC, mount->fs_name,
623 XFS_USER_QUOTA, 0, NULL) < 0
624 && errno != ENOENT && errno != ENOSYS)
625 perror("XFS_QSYNC user quota");
1774874a
NS
626 report_user_mount(fp, form, mount,
627 lower, upper, flags);
546bedf4 628 }
5aead01d
NS
629 }
630 if (type & XFS_GROUP_QUOTA) {
631 fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor);
546bedf4 632 while ((mount = fs_cursor_next_entry(&cursor))) {
29647c8d
BD
633 if (!foreign_allowed && (mount->fs_flags & FS_FOREIGN))
634 continue;
ec4cd312
AM
635 if (xfsquotactl(XFS_QSYNC, mount->fs_name,
636 XFS_GROUP_QUOTA, 0, NULL) < 0
637 && errno != ENOENT && errno != ENOSYS)
638 perror("XFS_QSYNC group quota");
1774874a
NS
639 report_group_mount(fp, form, mount,
640 lower, upper, flags);
546bedf4 641 }
5aead01d
NS
642 }
643 if (type & XFS_PROJ_QUOTA) {
644 fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor);
546bedf4 645 while ((mount = fs_cursor_next_entry(&cursor))) {
29647c8d
BD
646 if (!foreign_allowed && (mount->fs_flags & FS_FOREIGN))
647 continue;
ec4cd312
AM
648 if (xfsquotactl(XFS_QSYNC, mount->fs_name,
649 XFS_PROJ_QUOTA, 0, NULL) < 0
650 && errno != ENOENT && errno != ENOSYS)
651 perror("XFS_QSYNC proj quota");
1774874a
NS
652 report_project_mount(fp, form, mount,
653 lower, upper, flags);
546bedf4 654 }
5aead01d
NS
655 }
656}
657
658static int
659report_f(
660 int argc,
661 char **argv)
662{
663 FILE *fp = NULL;
fa13a00f 664 char *fname = NULL;
1774874a 665 uint lower = 0, upper = 0;
85dcd9a0 666 bool lookup = false;
5aead01d
NS
667 int c, flags = 0, type = 0, form = 0;
668
85dcd9a0 669 while ((c = getopt(argc, argv, "abdf:ghilL:NnprtuU:")) != EOF) {
5aead01d
NS
670 switch (c) {
671 case 'f':
672 fname = optarg;
673 break;
674 case 'b':
675 form |= XFS_BLOCK_QUOTA;
676 break;
677 case 'i':
678 form |= XFS_INODE_QUOTA;
679 break;
680 case 'r':
681 form |= XFS_RTBLOCK_QUOTA;
682 break;
683 case 'g':
684 type |= XFS_GROUP_QUOTA;
685 break;
686 case 'p':
687 type |= XFS_PROJ_QUOTA;
688 break;
689 case 'u':
690 type |= XFS_USER_QUOTA;
691 break;
692 case 'a':
693 flags |= ALL_MOUNTS_FLAG;
694 break;
695 case 'h':
696 flags |= HUMAN_FLAG;
697 break;
698 case 'n':
1774874a
NS
699 flags |= NO_LOOKUP_FLAG;
700 break;
701 case 'N':
5aead01d
NS
702 flags |= NO_HEADER_FLAG;
703 break;
704 case 't':
705 flags |= TERSE_FLAG;
706 break;
1774874a
NS
707 case 'L':
708 lower = (uint)atoi(optarg);
85dcd9a0 709 flags |= NO_LOOKUP_FLAG;
1774874a
NS
710 break;
711 case 'U':
712 upper = (uint)atoi(optarg);
85dcd9a0
ES
713 flags |= NO_LOOKUP_FLAG;
714 break;
715 case 'l':
716 lookup = true;
1774874a 717 break;
5aead01d
NS
718 default:
719 return command_usage(&report_cmd);
720 }
721 }
722
723 if (!form)
724 form = XFS_BLOCK_QUOTA;
725
726 if (!type)
727 type = XFS_USER_QUOTA | XFS_GROUP_QUOTA | XFS_PROJ_QUOTA;
728
85dcd9a0
ES
729 if (lookup)
730 flags &= ~NO_LOOKUP_FLAG;
731
5aead01d
NS
732 if ((fp = fopen_write_secure(fname)) == NULL)
733 return 0;
734
fa13a00f
NS
735 if (argc == optind) {
736 if (flags & ALL_MOUNTS_FLAG)
737 report_any_type(fp, form, type, NULL,
738 lower, upper, flags);
a14d4093 739 else if (fs_path && (fs_path->fs_flags & FS_MOUNT_POINT))
fa13a00f
NS
740 report_any_type(fp, form, type, fs_path->fs_dir,
741 lower, upper, flags);
742 } else while (argc > optind) {
743 report_any_type(fp, form, type, argv[optind++],
744 lower, upper, flags);
1774874a 745 }
5aead01d
NS
746
747 if (fname)
748 fclose(fp);
749 return 0;
750}
751
752void
753report_init(void)
754{
ad765595 755 dump_cmd.name = "dump";
5aead01d
NS
756 dump_cmd.cfunc = dump_f;
757 dump_cmd.argmin = 0;
758 dump_cmd.argmax = -1;
069610ec 759 dump_cmd.args = _("[-g|-p|-u] [-LU] [-f file]");
5aead01d
NS
760 dump_cmd.oneline = _("dump quota information for backup utilities");
761 dump_cmd.help = dump_help;
29647c8d 762 dump_cmd.flags = CMD_FLAG_FOREIGN_OK;
5aead01d 763
ad765595
AM
764 report_cmd.name = "report";
765 report_cmd.altname = "repquota";
5aead01d
NS
766 report_cmd.cfunc = report_f;
767 report_cmd.argmin = 0;
768 report_cmd.argmax = -1;
069610ec 769 report_cmd.args = _("[-bir] [-gpu] [-ahntlLNU] [-f file]");
5aead01d
NS
770 report_cmd.oneline = _("report filesystem quota information");
771 report_cmd.help = report_help;
7a9b7314 772 report_cmd.flags = CMD_FLAG_ONESHOT | CMD_FLAG_FOREIGN_OK;
5aead01d
NS
773
774 if (expert) {
775 add_command(&dump_cmd);
776 add_command(&report_cmd);
777 }
778}