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