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