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