]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - quota/report.c
xfsprogs: Release v6.7.0
[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
NS
65 uint id,
66 uint type,
6a9a085e
ES
67 char *dev,
68 int flags)
5aead01d 69{
6a9a085e
ES
70 int cmd;
71
72 if (flags & GETNEXTQUOTA_FLAG)
73 cmd = XFS_GETNEXTQUOTA;
74 else
75 cmd = XFS_GETQUOTA;
5aead01d 76
52e81d72 77 /* Fall back silently if XFS_GETNEXTQUOTA fails, warn on XFS_GETQUOTA */
f103166a 78 if (xfsquotactl(cmd, dev, type, id, (void *)d) < 0) {
52e81d72
ZL
79 if (errno != ENOENT && errno != ENOSYS && errno != ESRCH &&
80 cmd == XFS_GETQUOTA)
ec4cd312 81 perror("XFS_GETQUOTA");
6a9a085e 82 return 0;
ec4cd312 83 }
cc15c8cc 84
6c007276
AA
85 /* Did kernelspace wrap? */
86 if (d->d_id < id)
87 return 0;
ebd6aa8b 88
f103166a
AA
89 return 1;
90}
91
92static int
93dump_file(
94 FILE *fp,
2c1e7aef
AA
95 struct fs_disk_quota *d,
96 char *dev)
f103166a 97{
2c1e7aef
AA
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)
6a9a085e 101 return 1;
5aead01d 102 fprintf(fp, "fs = %s\n", dev);
1774874a 103 /* this branch is for backward compatibility reasons */
2c1e7aef 104 if (d->d_rtb_softlimit || d->d_rtb_hardlimit)
cc15c8cc 105 fprintf(fp, "%-10d %7llu %7llu %7llu %7llu %7llu %7llu\n",
2c1e7aef
AA
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);
1774874a 113 else
cc15c8cc 114 fprintf(fp, "%-10d %7llu %7llu %7llu %7llu\n",
2c1e7aef
AA
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);
6a9a085e
ES
120
121 return 1;
5aead01d
NS
122}
123
124static void
125dump_limits_any_type(
126 FILE *fp,
127 uint type,
1774874a
NS
128 char *dir,
129 uint lower,
130 uint upper)
5aead01d
NS
131{
132 fs_path_t *mount;
2c1e7aef 133 struct fs_disk_quota d;
6c007276 134 uint id = lower, flags = 0;
5aead01d
NS
135
136 if ((mount = fs_table_lookup(dir, FS_MOUNT_POINT)) == NULL) {
e3210fd8 137 exitcode = 1;
5aead01d
NS
138 fprintf(stderr, "%s: cannot find mount point %s\n",
139 progname, dir);
140 return;
141 }
142
6c007276
AA
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;
1774874a
NS
149 }
150
6c007276 151 if (flags & GETNEXTQUOTA_FLAG)
6a9a085e 152 return;
6a9a085e
ES
153
154 /* Otherwise fall back to iterating over each uid/gid/prjid */
5aead01d
NS
155 switch (type) {
156 case XFS_GROUP_QUOTA: {
157 struct group *g;
158 setgrent();
2c1e7aef 159 while ((g = getgrent()) != NULL) {
f2fde322
AA
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);
2c1e7aef 165 }
5aead01d
NS
166 endgrent();
167 break;
168 }
169 case XFS_PROJ_QUOTA: {
170 struct fs_project *p;
171 setprent();
2c1e7aef 172 while ((p = getprent()) != NULL) {
f2fde322
AA
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);
2c1e7aef 178 }
5aead01d
NS
179 endprent();
180 break;
181 }
182 case XFS_USER_QUOTA: {
183 struct passwd *u;
184 setpwent();
2c1e7aef 185 while ((u = getpwent()) != NULL) {
f2fde322
AA
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);
2c1e7aef 191 }
5aead01d
NS
192 endpwent();
193 break;
194 }
195 }
196}
197
198static int
199dump_f(
200 int argc,
201 char **argv)
202{
203 FILE *fp;
204 char *fname = NULL;
1774874a 205 uint lower = 0, upper = 0;
c614d3bf 206 int c, type = 0;
5aead01d 207
1774874a 208 while ((c = getopt(argc, argv, "f:gpuL:U:")) != EOF) {
5aead01d
NS
209 switch(c) {
210 case 'f':
211 fname = optarg;
212 break;
213 case 'g':
c614d3bf 214 type |= XFS_GROUP_QUOTA;
5aead01d
NS
215 break;
216 case 'p':
c614d3bf 217 type |= XFS_PROJ_QUOTA;
5aead01d
NS
218 break;
219 case 'u':
c614d3bf 220 type |= XFS_USER_QUOTA;
5aead01d 221 break;
1774874a
NS
222 case 'L':
223 lower = (uint)atoi(optarg);
224 break;
225 case 'U':
226 upper = (uint)atoi(optarg);
227 break;
5aead01d
NS
228 default:
229 return command_usage(&dump_cmd);
230 }
231 }
232
233 if (argc != optind)
234 return command_usage(&dump_cmd);
235
c614d3bf
ZL
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
5aead01d
NS
244 if ((fp = fopen_write_secure(fname)) == NULL)
245 return 0;
246
1774874a 247 dump_limits_any_type(fp, type, fs_path->fs_dir, lower, upper);
5aead01d
NS
248
249 if (fname)
250 fclose(fp);
251
252 return 0;
253}
254
255static void
256report_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
331static int
332report_mount(
333 FILE *fp,
79e65174 334 struct fs_disk_quota *d,
5aead01d
NS
335 char *name,
336 uint form,
337 uint type,
338 fs_path_t *mount,
339 uint flags)
340{
219285ad 341 time64_t timer;
5aead01d
NS
342 char c[8], h[8], s[8];
343 uint qflags;
344 int count;
6a9a085e 345
5aead01d
NS
346 if (flags & TERSE_FLAG) {
347 count = 0;
79e65174 348 if ((form & XFS_BLOCK_QUOTA) && d->d_bcount)
5aead01d 349 count++;
79e65174 350 if ((form & XFS_INODE_QUOTA) && d->d_icount)
5aead01d 351 count++;
79e65174 352 if ((form & XFS_RTBLOCK_QUOTA) && d->d_rtbcount)
5aead01d
NS
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
85dcd9a0 361 if (flags & NO_LOOKUP_FLAG) {
79e65174 362 fprintf(fp, "#%-10u", d->d_id);
85dcd9a0
ES
363 } else {
364 if (name == NULL) {
365 if (type == XFS_USER_QUOTA) {
79e65174 366 struct passwd *u = getpwuid(d->d_id);
85dcd9a0
ES
367 if (u)
368 name = u->pw_name;
369 } else if (type == XFS_GROUP_QUOTA) {
79e65174 370 struct group *g = getgrgid(d->d_id);
85dcd9a0
ES
371 if (g)
372 name = g->gr_name;
373 } else if (type == XFS_PROJ_QUOTA) {
79e65174 374 fs_project_t *p = getprprid(d->d_id);
85dcd9a0
ES
375 if (p)
376 name = p->pr_name;
377 }
378 }
3d607a11
ZL
379 /* If no name is found, print the id #num instead of (null) */
380 if (name != NULL)
381 fprintf(fp, "%-10s", name);
382 else
79e65174 383 fprintf(fp, "#%-9u", d->d_id);
85dcd9a0 384 }
a265445e 385
5aead01d 386 if (form & XFS_BLOCK_QUOTA) {
79e65174 387 timer = decode_timer(d, d->d_btimer, d->d_btimer_hi);
5aead01d 388 qflags = (flags & HUMAN_FLAG);
79e65174 389 if (d->d_blk_hardlimit && d->d_bcount > d->d_blk_hardlimit)
5aead01d 390 qflags |= LIMIT_FLAG;
79e65174 391 if (d->d_blk_softlimit && d->d_bcount > d->d_blk_softlimit)
5aead01d
NS
392 qflags |= QUOTA_FLAG;
393 if (flags & HUMAN_FLAG)
394 fprintf(fp, " %6s %6s %6s %02d %8s",
79e65174
AA
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,
219285ad 399 time_to_string(timer, qflags));
5aead01d
NS
400 else
401 fprintf(fp, " %10llu %10llu %10llu %02d %9s",
79e65174
AA
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,
219285ad 406 time_to_string(timer, qflags));
5aead01d
NS
407 }
408 if (form & XFS_INODE_QUOTA) {
79e65174 409 timer = decode_timer(d, d->d_itimer, d->d_itimer_hi);
5aead01d 410 qflags = (flags & HUMAN_FLAG);
79e65174 411 if (d->d_ino_hardlimit && d->d_icount > d->d_ino_hardlimit)
5aead01d 412 qflags |= LIMIT_FLAG;
79e65174 413 if (d->d_ino_softlimit && d->d_icount > d->d_ino_softlimit)
5aead01d
NS
414 qflags |= QUOTA_FLAG;
415 if (flags & HUMAN_FLAG)
416 fprintf(fp, " %6s %6s %6s %02d %8s",
79e65174
AA
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,
219285ad 421 time_to_string(timer, qflags));
5aead01d
NS
422 else
423 fprintf(fp, " %10llu %10llu %10llu %02d %9s",
79e65174
AA
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,
219285ad 428 time_to_string(timer, qflags));
5aead01d
NS
429 }
430 if (form & XFS_RTBLOCK_QUOTA) {
79e65174 431 timer = decode_timer(d, d->d_rtbtimer, d->d_rtbtimer_hi);
5aead01d 432 qflags = (flags & HUMAN_FLAG);
79e65174 433 if (d->d_rtb_hardlimit && d->d_rtbcount > d->d_rtb_hardlimit)
5aead01d 434 qflags |= LIMIT_FLAG;
79e65174 435 if (d->d_rtb_softlimit && d->d_rtbcount > d->d_rtb_softlimit)
5aead01d
NS
436 qflags |= QUOTA_FLAG;
437 if (flags & HUMAN_FLAG)
438 fprintf(fp, " %6s %6s %6s %02d %8s",
79e65174
AA
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,
219285ad 443 time_to_string(timer, qflags));
5aead01d
NS
444 else
445 fprintf(fp, " %10llu %10llu %10llu %02d %9s",
79e65174
AA
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,
219285ad 450 time_to_string(timer, qflags));
5aead01d
NS
451 }
452 fputc('\n', fp);
453 return 1;
454}
455
456static void
457report_user_mount(
458 FILE *fp,
459 uint form,
460 fs_path_t *mount,
1774874a
NS
461 uint lower,
462 uint upper,
5aead01d
NS
463 uint flags)
464{
1774874a 465 struct passwd *u;
79e65174 466 struct fs_disk_quota d;
6c007276 467 uint id = lower;
1774874a 468
6c007276
AA
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;
6a9a085e
ES
474 flags |= GETNEXTQUOTA_FLAG;
475 flags |= NO_HEADER_FLAG;
6c007276
AA
476 }
477
478 /* No GETNEXTQUOTA support, iterate over all from password file */
479 if (!(flags & GETNEXTQUOTA_FLAG)) {
1774874a
NS
480 setpwent();
481 while ((u = getpwent()) != NULL) {
6c007276 482 if (get_dquot(&d, u->pw_uid, XFS_USER_QUOTA,
f2fde322
AA
483 mount->fs_name, flags) &&
484 !(lower && (d.d_id < lower)) &&
485 !(upper && (d.d_id > upper))) {
79e65174
AA
486 report_mount(fp, &d, u->pw_name, form,
487 XFS_USER_QUOTA, mount, flags);
1774874a 488 flags |= NO_HEADER_FLAG;
79e65174 489 }
1774874a
NS
490 }
491 endpwent();
492 }
5aead01d 493
5aead01d
NS
494 if (flags & NO_HEADER_FLAG)
495 fputc('\n', fp);
5aead01d
NS
496}
497
498static void
499report_group_mount(
500 FILE *fp,
501 uint form,
502 fs_path_t *mount,
1774874a
NS
503 uint lower,
504 uint upper,
5aead01d
NS
505 uint flags)
506{
1774874a 507 struct group *g;
79e65174 508 struct fs_disk_quota d;
6c007276 509 uint id = lower;
1774874a 510
6c007276
AA
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;
6a9a085e
ES
516 flags |= GETNEXTQUOTA_FLAG;
517 flags |= NO_HEADER_FLAG;
6c007276
AA
518 }
519
520 /* No GETNEXTQUOTA support, iterate over all from password file */
521 if (!(flags & GETNEXTQUOTA_FLAG)) {
1774874a
NS
522 setgrent();
523 while ((g = getgrent()) != NULL) {
6c007276 524 if (get_dquot(&d, g->gr_gid, XFS_GROUP_QUOTA,
f2fde322
AA
525 mount->fs_name, flags) &&
526 !(lower && (d.d_id < lower)) &&
527 !(upper && (d.d_id > upper))) {
79e65174
AA
528 report_mount(fp, &d, g->gr_name, form,
529 XFS_GROUP_QUOTA, mount, flags);
1774874a 530 flags |= NO_HEADER_FLAG;
79e65174 531 }
1774874a
NS
532 }
533 }
5aead01d
NS
534 if (flags & NO_HEADER_FLAG)
535 fputc('\n', fp);
536 endgrent();
537}
538
539static void
540report_project_mount(
541 FILE *fp,
542 uint form,
543 fs_path_t *mount,
1774874a
NS
544 uint lower,
545 uint upper,
5aead01d
NS
546 uint flags)
547{
548 fs_project_t *p;
79e65174 549 struct fs_disk_quota d;
6c007276 550 uint id = lower;
1774874a 551
6c007276
AA
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;
6a9a085e
ES
557 flags |= GETNEXTQUOTA_FLAG;
558 flags |= NO_HEADER_FLAG;
6c007276
AA
559 }
560
561 /* No GETNEXTQUOTA support, iterate over all */
562 if (!(flags & GETNEXTQUOTA_FLAG)) {
3d607a11
ZL
563 if (!getprprid(0)) {
564 /*
565 * Print default project quota, even if projid 0
566 * isn't defined
567 */
6c007276 568 if (get_dquot(&d, 0, XFS_PROJ_QUOTA, mount->fs_name,
f2fde322
AA
569 flags) &&
570 !(lower && (d.d_id < lower)) &&
571 !(upper && (d.d_id > upper))) {
79e65174
AA
572 report_mount(fp, &d, NULL, form, XFS_PROJ_QUOTA,
573 mount, flags);
a8b6f527 574 flags |= NO_HEADER_FLAG;
79e65174 575 }
3d607a11
ZL
576 }
577
1774874a
NS
578 setprent();
579 while ((p = getprent()) != NULL) {
6c007276 580 if (get_dquot(&d, p->pr_prid, XFS_PROJ_QUOTA,
f2fde322
AA
581 mount->fs_name, flags) &&
582 !(lower && (d.d_id < lower)) &&
583 !(upper && (d.d_id > upper))) {
79e65174
AA
584 report_mount(fp, &d, p->pr_name, form,
585 XFS_PROJ_QUOTA, mount, flags);
1774874a 586 flags |= NO_HEADER_FLAG;
79e65174 587 }
1774874a
NS
588 }
589 endprent();
590 }
5aead01d 591
5aead01d
NS
592 if (flags & NO_HEADER_FLAG)
593 fputc('\n', fp);
5aead01d
NS
594}
595
596static void
597report_any_type(
598 FILE *fp,
599 uint form,
600 uint type,
601 char *dir,
1774874a
NS
602 uint lower,
603 uint upper,
5aead01d
NS
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);
546bedf4 611 while ((mount = fs_cursor_next_entry(&cursor))) {
29647c8d
BD
612 if (!foreign_allowed && (mount->fs_flags & FS_FOREIGN))
613 continue;
ec4cd312
AM
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");
1774874a
NS
618 report_user_mount(fp, form, mount,
619 lower, upper, flags);
546bedf4 620 }
5aead01d
NS
621 }
622 if (type & XFS_GROUP_QUOTA) {
623 fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor);
546bedf4 624 while ((mount = fs_cursor_next_entry(&cursor))) {
29647c8d
BD
625 if (!foreign_allowed && (mount->fs_flags & FS_FOREIGN))
626 continue;
ec4cd312
AM
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");
1774874a
NS
631 report_group_mount(fp, form, mount,
632 lower, upper, flags);
546bedf4 633 }
5aead01d
NS
634 }
635 if (type & XFS_PROJ_QUOTA) {
636 fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor);
546bedf4 637 while ((mount = fs_cursor_next_entry(&cursor))) {
29647c8d
BD
638 if (!foreign_allowed && (mount->fs_flags & FS_FOREIGN))
639 continue;
ec4cd312
AM
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");
1774874a
NS
644 report_project_mount(fp, form, mount,
645 lower, upper, flags);
546bedf4 646 }
5aead01d
NS
647 }
648}
649
650static int
651report_f(
652 int argc,
653 char **argv)
654{
655 FILE *fp = NULL;
fa13a00f 656 char *fname = NULL;
1774874a 657 uint lower = 0, upper = 0;
85dcd9a0 658 bool lookup = false;
5aead01d
NS
659 int c, flags = 0, type = 0, form = 0;
660
85dcd9a0 661 while ((c = getopt(argc, argv, "abdf:ghilL:NnprtuU:")) != EOF) {
5aead01d
NS
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':
1774874a
NS
691 flags |= NO_LOOKUP_FLAG;
692 break;
693 case 'N':
5aead01d
NS
694 flags |= NO_HEADER_FLAG;
695 break;
696 case 't':
697 flags |= TERSE_FLAG;
698 break;
1774874a
NS
699 case 'L':
700 lower = (uint)atoi(optarg);
85dcd9a0 701 flags |= NO_LOOKUP_FLAG;
1774874a
NS
702 break;
703 case 'U':
704 upper = (uint)atoi(optarg);
85dcd9a0
ES
705 flags |= NO_LOOKUP_FLAG;
706 break;
707 case 'l':
708 lookup = true;
1774874a 709 break;
5aead01d
NS
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
85dcd9a0
ES
721 if (lookup)
722 flags &= ~NO_LOOKUP_FLAG;
723
5aead01d
NS
724 if ((fp = fopen_write_secure(fname)) == NULL)
725 return 0;
726
fa13a00f
NS
727 if (argc == optind) {
728 if (flags & ALL_MOUNTS_FLAG)
729 report_any_type(fp, form, type, NULL,
730 lower, upper, flags);
a14d4093 731 else if (fs_path && (fs_path->fs_flags & FS_MOUNT_POINT))
fa13a00f
NS
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);
1774874a 737 }
5aead01d
NS
738
739 if (fname)
740 fclose(fp);
741 return 0;
742}
743
744void
745report_init(void)
746{
ad765595 747 dump_cmd.name = "dump";
5aead01d
NS
748 dump_cmd.cfunc = dump_f;
749 dump_cmd.argmin = 0;
750 dump_cmd.argmax = -1;
069610ec 751 dump_cmd.args = _("[-g|-p|-u] [-LU] [-f file]");
5aead01d
NS
752 dump_cmd.oneline = _("dump quota information for backup utilities");
753 dump_cmd.help = dump_help;
29647c8d 754 dump_cmd.flags = CMD_FLAG_FOREIGN_OK;
5aead01d 755
ad765595
AM
756 report_cmd.name = "report";
757 report_cmd.altname = "repquota";
5aead01d
NS
758 report_cmd.cfunc = report_f;
759 report_cmd.argmin = 0;
760 report_cmd.argmax = -1;
069610ec 761 report_cmd.args = _("[-bir] [-gpu] [-ahntlLNU] [-f file]");
5aead01d
NS
762 report_cmd.oneline = _("report filesystem quota information");
763 report_cmd.help = report_help;
7a9b7314 764 report_cmd.flags = CMD_FLAG_ONESHOT | CMD_FLAG_FOREIGN_OK;
5aead01d
NS
765
766 if (expert) {
767 add_command(&dump_cmd);
768 add_command(&report_cmd);
769 }
770}