]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - quota/report.c
progs: clean up all remaining xfs*h includes
[thirdparty/xfsprogs-dev.git] / quota / report.c
1 /*
2 * Copyright (c) 2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
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
7 * published by the Free Software Foundation.
8 *
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.
13 *
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
17 */
18
19 #include "xfs/command.h"
20 #include <sys/types.h>
21 #include <pwd.h>
22 #include <grp.h>
23 #include <utmp.h>
24 #include "init.h"
25 #include "quota.h"
26
27 static cmdinfo_t dump_cmd;
28 static cmdinfo_t report_cmd;
29
30 static void
31 dump_help(void)
32 {
33 dump_cmd.args = _("[-gpu] [-f file]");
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
45 static void
46 report_help(void)
47 {
48 report_cmd.args = _("[-bir] [-gpu] [-ahntLNU] [-f file]");
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"
61 " -n -- skip identifier-to-name translations, just report IDs\n"
62 " -N -- suppress the header from the output\n"
63 " -t -- terse output format, hides rows which are all zero\n"
64 " -L -- lower ID bound to report on\n"
65 " -U -- upper ID bound to report on\n"
66 " -g -- report group usage and quota information\n"
67 " -p -- report project usage and quota information\n"
68 " -u -- report user usage and quota information\n"
69 " -b -- report blocks-used information only\n"
70 " -i -- report inodes-used information only\n"
71 " -r -- report realtime-blocks-used information only\n"
72 "\n"));
73 }
74
75 static void
76 dump_file(
77 FILE *fp,
78 uint id,
79 uint type,
80 char *dev)
81 {
82 fs_disk_quota_t d;
83
84 if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0) {
85 if (errno != ENOENT && errno != ENOSYS && errno != ESRCH)
86 perror("XFS_GETQUOTA");
87 return;
88 }
89 if (!d.d_blk_softlimit && !d.d_blk_hardlimit &&
90 !d.d_ino_softlimit && !d.d_ino_hardlimit &&
91 !d.d_rtb_softlimit && !d.d_rtb_hardlimit)
92 return;
93 fprintf(fp, "fs = %s\n", dev);
94 /* this branch is for backward compatibility reasons */
95 if (d.d_rtb_softlimit || d.d_rtb_hardlimit)
96 fprintf(fp, "%-10d %7llu %7llu %7llu %7llu %7llu %7llu\n", id,
97 (unsigned long long)d.d_blk_softlimit,
98 (unsigned long long)d.d_blk_hardlimit,
99 (unsigned long long)d.d_ino_softlimit,
100 (unsigned long long)d.d_ino_hardlimit,
101 (unsigned long long)d.d_rtb_softlimit,
102 (unsigned long long)d.d_rtb_hardlimit);
103 else
104 fprintf(fp, "%-10d %7llu %7llu %7llu %7llu\n", id,
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 }
110
111 static void
112 dump_limits_any_type(
113 FILE *fp,
114 uint type,
115 char *dir,
116 uint lower,
117 uint upper)
118 {
119 fs_path_t *mount;
120 uint id;
121
122 if ((mount = fs_table_lookup(dir, FS_MOUNT_POINT)) == NULL) {
123 exitcode = 1;
124 fprintf(stderr, "%s: cannot find mount point %s\n",
125 progname, dir);
126 return;
127 }
128
129 if (upper) {
130 for (id = lower; id <= upper; id++)
131 dump_file(fp, id, type, mount->fs_name);
132 return;
133 }
134
135 switch (type) {
136 case XFS_GROUP_QUOTA: {
137 struct group *g;
138 setgrent();
139 while ((g = getgrent()) != NULL)
140 dump_file(fp, g->gr_gid, type, mount->fs_name);
141 endgrent();
142 break;
143 }
144 case XFS_PROJ_QUOTA: {
145 struct fs_project *p;
146 setprent();
147 while ((p = getprent()) != NULL)
148 dump_file(fp, p->pr_prid, type, mount->fs_name);
149 endprent();
150 break;
151 }
152 case XFS_USER_QUOTA: {
153 struct passwd *u;
154 setpwent();
155 while ((u = getpwent()) != NULL)
156 dump_file(fp, u->pw_uid, type, mount->fs_name);
157 endpwent();
158 break;
159 }
160 }
161 }
162
163 static int
164 dump_f(
165 int argc,
166 char **argv)
167 {
168 FILE *fp;
169 char *fname = NULL;
170 uint lower = 0, upper = 0;
171 int c, type = XFS_USER_QUOTA;
172
173 while ((c = getopt(argc, argv, "f:gpuL:U:")) != EOF) {
174 switch(c) {
175 case 'f':
176 fname = optarg;
177 break;
178 case 'g':
179 type = XFS_GROUP_QUOTA;
180 break;
181 case 'p':
182 type = XFS_PROJ_QUOTA;
183 break;
184 case 'u':
185 type = XFS_USER_QUOTA;
186 break;
187 case 'L':
188 lower = (uint)atoi(optarg);
189 break;
190 case 'U':
191 upper = (uint)atoi(optarg);
192 break;
193 default:
194 return command_usage(&dump_cmd);
195 }
196 }
197
198 if (argc != optind)
199 return command_usage(&dump_cmd);
200
201 if ((fp = fopen_write_secure(fname)) == NULL)
202 return 0;
203
204 dump_limits_any_type(fp, type, fs_path->fs_dir, lower, upper);
205
206 if (fname)
207 fclose(fp);
208
209 return 0;
210 }
211
212 static void
213 report_header(
214 FILE *fp,
215 uint form,
216 uint type,
217 fs_path_t *mount,
218 int flags)
219 {
220 char *typename = type_to_string(type);
221 char scratch[64];
222 uint i, count;
223
224 if (flags & NO_HEADER_FLAG)
225 return;
226
227 /* line 1 */
228 fprintf(fp, _("%s quota on %s (%s)\n"),
229 typename, mount->fs_dir, mount->fs_name);
230
231 /* line 2 */
232 for (i = 0; i < 10; i++)
233 fputc(' ', fp);
234 if (form & XFS_BLOCK_QUOTA)
235 fprintf(fp, (flags & HUMAN_FLAG) ?
236 "%13c %s %13c" : "%20c %s %20c",
237 ' ', form_to_string(XFS_BLOCK_QUOTA), ' ');
238 if (form & XFS_INODE_QUOTA)
239 fprintf(fp, (flags & HUMAN_FLAG) ?
240 "%13c %s %13c" : "%20c %s %20c",
241 ' ', form_to_string(XFS_INODE_QUOTA), ' ');
242 if (form & XFS_RTBLOCK_QUOTA)
243 fprintf(fp, (flags & HUMAN_FLAG) ?
244 "%9c %s %9c" : "%15c %s %15c",
245 ' ', form_to_string(XFS_RTBLOCK_QUOTA), ' ');
246 fputc('\n', fp);
247
248 /* line 3 */
249 snprintf(scratch, sizeof(scratch), "%s ID", typename);
250 fprintf(fp, "%-10s ", scratch);
251 if (form & XFS_BLOCK_QUOTA)
252 fprintf(fp, (flags & HUMAN_FLAG) ?
253 _(" Used Soft Hard Warn/Grace ") :
254 _(" Used Soft Hard Warn/Grace "));
255 if (form & XFS_INODE_QUOTA)
256 fprintf(fp, (flags & HUMAN_FLAG) ?
257 _(" Used Soft Hard Warn/Grace ") :
258 _(" Used Soft Hard Warn/ Grace "));
259 if (form & XFS_RTBLOCK_QUOTA)
260 fprintf(fp, (flags & HUMAN_FLAG) ?
261 _(" Used Soft Hard Warn/Grace ") :
262 _(" Used Soft Hard Warn/Grace "));
263 fputc('\n', fp);
264
265 /* line 4 */
266 for (i = 0; i < 10; i++)
267 fputc('-', fp);
268 fputc(' ', fp);
269 count = (flags & HUMAN_FLAG) ? 33 : 50;
270 if (form & XFS_BLOCK_QUOTA) {
271 for (i = 0; i < count; i++)
272 fputc('-', fp);
273 fputc(' ', fp);
274 }
275 if (form & XFS_INODE_QUOTA) {
276 for (i = 0; i < count; i++)
277 fputc('-', fp);
278 fputc(' ', fp);
279 }
280 if (form & XFS_RTBLOCK_QUOTA) {
281 for (i = 0; i < count; i++)
282 fputc('-', fp);
283 fputc(' ', fp);
284 }
285 fputc('\n', fp);
286 }
287
288 static int
289 report_mount(
290 FILE *fp,
291 __uint32_t id,
292 char *name,
293 uint form,
294 uint type,
295 fs_path_t *mount,
296 uint flags)
297 {
298 fs_disk_quota_t d;
299 char *dev = mount->fs_name;
300 char c[8], h[8], s[8];
301 uint qflags;
302 int count;
303
304 if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0) {
305 if (errno != ENOENT && errno != ENOSYS && errno != ESRCH)
306 perror("XFS_GETQUOTA");
307 return 0;
308 }
309
310 if (flags & TERSE_FLAG) {
311 count = 0;
312 if ((form & XFS_BLOCK_QUOTA) && d.d_bcount)
313 count++;
314 if ((form & XFS_INODE_QUOTA) && d.d_icount)
315 count++;
316 if ((form & XFS_RTBLOCK_QUOTA) && d.d_rtbcount)
317 count++;
318 if (!count)
319 return 0;
320 }
321
322 if (!(flags & NO_HEADER_FLAG))
323 report_header(fp, form, type, mount, flags);
324
325 fprintf(fp, "%-10s", name);
326 if (form & XFS_BLOCK_QUOTA) {
327 qflags = (flags & HUMAN_FLAG);
328 if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit)
329 qflags |= LIMIT_FLAG;
330 if (d.d_blk_softlimit && d.d_bcount > d.d_blk_softlimit)
331 qflags |= QUOTA_FLAG;
332 if (flags & HUMAN_FLAG)
333 fprintf(fp, " %6s %6s %6s %02d %8s",
334 bbs_to_string(d.d_bcount, c, sizeof(c)),
335 bbs_to_string(d.d_blk_softlimit, s, sizeof(s)),
336 bbs_to_string(d.d_blk_hardlimit, h, sizeof(h)),
337 d.d_bwarns,
338 time_to_string(d.d_btimer, qflags));
339 else
340 fprintf(fp, " %10llu %10llu %10llu %02d %9s",
341 (unsigned long long)d.d_bcount >> 1,
342 (unsigned long long)d.d_blk_softlimit >> 1,
343 (unsigned long long)d.d_blk_hardlimit >> 1,
344 d.d_bwarns,
345 time_to_string(d.d_btimer, qflags));
346 }
347 if (form & XFS_INODE_QUOTA) {
348 qflags = (flags & HUMAN_FLAG);
349 if (d.d_ino_hardlimit && d.d_icount > d.d_ino_hardlimit)
350 qflags |= LIMIT_FLAG;
351 if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
352 qflags |= QUOTA_FLAG;
353 if (flags & HUMAN_FLAG)
354 fprintf(fp, " %6s %6s %6s %02d %8s",
355 num_to_string(d.d_icount, c, sizeof(c)),
356 num_to_string(d.d_ino_softlimit, s, sizeof(s)),
357 num_to_string(d.d_ino_hardlimit, h, sizeof(h)),
358 d.d_iwarns,
359 time_to_string(d.d_itimer, qflags));
360 else
361 fprintf(fp, " %10llu %10llu %10llu %02d %9s",
362 (unsigned long long)d.d_icount,
363 (unsigned long long)d.d_ino_softlimit,
364 (unsigned long long)d.d_ino_hardlimit,
365 d.d_iwarns,
366 time_to_string(d.d_itimer, qflags));
367 }
368 if (form & XFS_RTBLOCK_QUOTA) {
369 qflags = (flags & HUMAN_FLAG);
370 if (d.d_rtb_hardlimit && d.d_rtbcount > d.d_rtb_hardlimit)
371 qflags |= LIMIT_FLAG;
372 if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
373 qflags |= QUOTA_FLAG;
374 if (flags & HUMAN_FLAG)
375 fprintf(fp, " %6s %6s %6s %02d %8s",
376 bbs_to_string(d.d_rtbcount, c, sizeof(c)),
377 bbs_to_string(d.d_rtb_softlimit, s, sizeof(s)),
378 bbs_to_string(d.d_rtb_hardlimit, h, sizeof(h)),
379 d.d_rtbwarns,
380 time_to_string(d.d_rtbtimer, qflags));
381 else
382 fprintf(fp, " %10llu %10llu %10llu %02d %9s",
383 (unsigned long long)d.d_rtbcount >> 1,
384 (unsigned long long)d.d_rtb_softlimit >> 1,
385 (unsigned long long)d.d_rtb_hardlimit >> 1,
386 d.d_rtbwarns,
387 time_to_string(d.d_rtbtimer, qflags));
388 }
389 fputc('\n', fp);
390 return 1;
391 }
392
393 static void
394 report_user_mount(
395 FILE *fp,
396 uint form,
397 fs_path_t *mount,
398 uint lower,
399 uint upper,
400 uint flags)
401 {
402 struct passwd *u;
403 char n[NMAX];
404 uint id;
405
406 if (upper) { /* identifier range specified */
407 for (id = lower; id <= upper; id++) {
408 snprintf(n, sizeof(n)-1, "#%u", id);
409 if (report_mount(fp, id, n,
410 form, XFS_USER_QUOTA, mount, flags))
411 flags |= NO_HEADER_FLAG;
412 }
413 } else {
414 setpwent();
415 while ((u = getpwent()) != NULL) {
416 if (flags & NO_LOOKUP_FLAG)
417 snprintf(n, sizeof(n)-1, "#%u", u->pw_uid);
418 else
419 strncpy(n, u->pw_name, sizeof(n)-1);
420 if (report_mount(fp, u->pw_uid, n,
421 form, XFS_USER_QUOTA, mount, flags))
422 flags |= NO_HEADER_FLAG;
423 }
424 endpwent();
425 }
426
427 if (flags & NO_HEADER_FLAG)
428 fputc('\n', fp);
429 }
430
431 static void
432 report_group_mount(
433 FILE *fp,
434 uint form,
435 fs_path_t *mount,
436 uint lower,
437 uint upper,
438 uint flags)
439 {
440 struct group *g;
441 char n[NMAX];
442 uint id;
443
444 if (upper) { /* identifier range specified */
445 for (id = lower; id <= upper; id++) {
446 snprintf(n, sizeof(n)-1, "#%u", id);
447 if (report_mount(fp, id, n,
448 form, XFS_GROUP_QUOTA, mount, flags))
449 flags |= NO_HEADER_FLAG;
450 }
451 } else {
452 setgrent();
453 while ((g = getgrent()) != NULL) {
454 if (flags & NO_LOOKUP_FLAG)
455 snprintf(n, sizeof(n)-1, "#%u", g->gr_gid);
456 else
457 strncpy(n, g->gr_name, sizeof(n)-1);
458 if (report_mount(fp, g->gr_gid, n,
459 form, XFS_GROUP_QUOTA, mount, flags))
460 flags |= NO_HEADER_FLAG;
461 }
462 }
463 if (flags & NO_HEADER_FLAG)
464 fputc('\n', fp);
465 endgrent();
466 }
467
468 static void
469 report_project_mount(
470 FILE *fp,
471 uint form,
472 fs_path_t *mount,
473 uint lower,
474 uint upper,
475 uint flags)
476 {
477 fs_project_t *p;
478 char n[NMAX];
479 uint id;
480
481 if (upper) { /* identifier range specified */
482 for (id = lower; id <= upper; id++) {
483 snprintf(n, sizeof(n)-1, "#%u", id);
484 if (report_mount(fp, id, n,
485 form, XFS_PROJ_QUOTA, mount, flags))
486 flags |= NO_HEADER_FLAG;
487 }
488 } else {
489 setprent();
490 while ((p = getprent()) != NULL) {
491 if (flags & NO_LOOKUP_FLAG)
492 snprintf(n, sizeof(n)-1, "#%u",
493 (unsigned int)p->pr_prid);
494 else
495 strncpy(n, p->pr_name, sizeof(n)-1);
496 if (report_mount(fp, p->pr_prid, n,
497 form, XFS_PROJ_QUOTA, mount, flags))
498 flags |= NO_HEADER_FLAG;
499 }
500 endprent();
501 }
502
503 if (flags & NO_HEADER_FLAG)
504 fputc('\n', fp);
505 }
506
507 static void
508 report_any_type(
509 FILE *fp,
510 uint form,
511 uint type,
512 char *dir,
513 uint lower,
514 uint upper,
515 uint flags)
516 {
517 fs_cursor_t cursor;
518 fs_path_t *mount;
519
520 if (type & XFS_USER_QUOTA) {
521 fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor);
522 while ((mount = fs_cursor_next_entry(&cursor))) {
523 if (xfsquotactl(XFS_QSYNC, mount->fs_name,
524 XFS_USER_QUOTA, 0, NULL) < 0
525 && errno != ENOENT && errno != ENOSYS)
526 perror("XFS_QSYNC user quota");
527 report_user_mount(fp, form, mount,
528 lower, upper, flags);
529 }
530 }
531 if (type & XFS_GROUP_QUOTA) {
532 fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor);
533 while ((mount = fs_cursor_next_entry(&cursor))) {
534 if (xfsquotactl(XFS_QSYNC, mount->fs_name,
535 XFS_GROUP_QUOTA, 0, NULL) < 0
536 && errno != ENOENT && errno != ENOSYS)
537 perror("XFS_QSYNC group quota");
538 report_group_mount(fp, form, mount,
539 lower, upper, flags);
540 }
541 }
542 if (type & XFS_PROJ_QUOTA) {
543 fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor);
544 while ((mount = fs_cursor_next_entry(&cursor))) {
545 if (xfsquotactl(XFS_QSYNC, mount->fs_name,
546 XFS_PROJ_QUOTA, 0, NULL) < 0
547 && errno != ENOENT && errno != ENOSYS)
548 perror("XFS_QSYNC proj quota");
549 report_project_mount(fp, form, mount,
550 lower, upper, flags);
551 }
552 }
553 }
554
555 static int
556 report_f(
557 int argc,
558 char **argv)
559 {
560 FILE *fp = NULL;
561 char *fname = NULL;
562 uint lower = 0, upper = 0;
563 int c, flags = 0, type = 0, form = 0;
564
565 while ((c = getopt(argc, argv, "abf:ghiL:NnprtuU:")) != EOF) {
566 switch (c) {
567 case 'f':
568 fname = optarg;
569 break;
570 case 'b':
571 form |= XFS_BLOCK_QUOTA;
572 break;
573 case 'i':
574 form |= XFS_INODE_QUOTA;
575 break;
576 case 'r':
577 form |= XFS_RTBLOCK_QUOTA;
578 break;
579 case 'g':
580 type |= XFS_GROUP_QUOTA;
581 break;
582 case 'p':
583 type |= XFS_PROJ_QUOTA;
584 break;
585 case 'u':
586 type |= XFS_USER_QUOTA;
587 break;
588 case 'a':
589 flags |= ALL_MOUNTS_FLAG;
590 break;
591 case 'h':
592 flags |= HUMAN_FLAG;
593 break;
594 case 'n':
595 flags |= NO_LOOKUP_FLAG;
596 break;
597 case 'N':
598 flags |= NO_HEADER_FLAG;
599 break;
600 case 't':
601 flags |= TERSE_FLAG;
602 break;
603 case 'L':
604 lower = (uint)atoi(optarg);
605 break;
606 case 'U':
607 upper = (uint)atoi(optarg);
608 break;
609 default:
610 return command_usage(&report_cmd);
611 }
612 }
613
614 if (!form)
615 form = XFS_BLOCK_QUOTA;
616
617 if (!type)
618 type = XFS_USER_QUOTA | XFS_GROUP_QUOTA | XFS_PROJ_QUOTA;
619
620 if ((fp = fopen_write_secure(fname)) == NULL)
621 return 0;
622
623 if (argc == optind) {
624 if (flags & ALL_MOUNTS_FLAG)
625 report_any_type(fp, form, type, NULL,
626 lower, upper, flags);
627 else if (fs_path && (fs_path->fs_flags & FS_MOUNT_POINT))
628 report_any_type(fp, form, type, fs_path->fs_dir,
629 lower, upper, flags);
630 } else while (argc > optind) {
631 report_any_type(fp, form, type, argv[optind++],
632 lower, upper, flags);
633 }
634
635 if (fname)
636 fclose(fp);
637 return 0;
638 }
639
640 void
641 report_init(void)
642 {
643 dump_cmd.name = "dump";
644 dump_cmd.cfunc = dump_f;
645 dump_cmd.argmin = 0;
646 dump_cmd.argmax = -1;
647 dump_cmd.args = _("[-gpu] [-f file]");
648 dump_cmd.oneline = _("dump quota information for backup utilities");
649 dump_cmd.help = dump_help;
650
651 report_cmd.name = "report";
652 report_cmd.altname = "repquota";
653 report_cmd.cfunc = report_f;
654 report_cmd.argmin = 0;
655 report_cmd.argmax = -1;
656 report_cmd.flags = CMD_FLAG_GLOBAL;
657 report_cmd.args = _("[-bir] [-gpu] [-ahnt] [-f file]");
658 report_cmd.oneline = _("report filesystem quota information");
659 report_cmd.help = report_help;
660
661 if (expert) {
662 add_command(&dump_cmd);
663 add_command(&report_cmd);
664 }
665 }