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