]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - quota/report.c
Initial version of xfs quota utility. Knows how to do user/group/project quota,...
[thirdparty/xfsprogs-dev.git] / quota / report.c
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
39 static cmdinfo_t dump_cmd;
40 static cmdinfo_t report_cmd;
41
42 static void
43 dump_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
57 static void
58 report_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"
73 " -n -- suppress the header from the output\n"
74 " -t -- terse output format, hides rows which are all zero\n"
75 " -g -- report group usage and quota information\n"
76 " -p -- report project usage and quota information\n"
77 " -u -- report user usage and quota information\n"
78 " -b -- report blocks-used information only\n"
79 " -i -- report inodes-used information only\n"
80 " -r -- report realtime-blocks-used information only\n"
81 "\n"));
82 }
83
84 static void
85 dump_file(
86 FILE *fp,
87 uint id,
88 uint type,
89 char *dev)
90 {
91 fs_disk_quota_t d;
92
93 if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0)
94 return;
95 fprintf(fp, "fs = %s\n", dev);
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 }
104
105 static void
106 dump_limits_any_type(
107 FILE *fp,
108 uint type,
109 char *dir)
110 {
111 fs_path_t *mount;
112
113 if ((mount = fs_table_lookup(dir, FS_MOUNT_POINT)) == NULL) {
114 fprintf(stderr, "%s: cannot find mount point %s\n",
115 progname, dir);
116 return;
117 }
118
119 switch (type) {
120 case XFS_GROUP_QUOTA: {
121 struct group *g;
122 setgrent();
123 while ((g = getgrent()) != NULL)
124 dump_file(fp, g->gr_gid, type, mount->fs_name);
125 endgrent();
126 break;
127 }
128 case XFS_PROJ_QUOTA: {
129 struct fs_project *p;
130 setprent();
131 while ((p = getprent()) != NULL)
132 dump_file(fp, p->pr_prid, type, mount->fs_name);
133 endprent();
134 break;
135 }
136 case XFS_USER_QUOTA: {
137 struct passwd *u;
138 setpwent();
139 while ((u = getpwent()) != NULL)
140 dump_file(fp, u->pw_uid, type, mount->fs_name);
141 endpwent();
142 break;
143 }
144 }
145 }
146
147 static int
148 dump_f(
149 int argc,
150 char **argv)
151 {
152 FILE *fp;
153 char *fname = NULL;
154 int c, type = XFS_USER_QUOTA;
155
156 while ((c = getopt(argc, argv, "f:gpu")) != EOF) {
157 switch(c) {
158 case 'f':
159 fname = optarg;
160 break;
161 case 'g':
162 type = XFS_GROUP_QUOTA;
163 break;
164 case 'p':
165 type = XFS_PROJ_QUOTA;
166 break;
167 case 'u':
168 type = XFS_USER_QUOTA;
169 break;
170 default:
171 return command_usage(&dump_cmd);
172 }
173 }
174
175 if (argc != optind)
176 return command_usage(&dump_cmd);
177
178 if ((fp = fopen_write_secure(fname)) == NULL)
179 return 0;
180
181 dump_limits_any_type(fp, type, fs_path->fs_dir);
182
183 if (fname)
184 fclose(fp);
185
186 return 0;
187 }
188
189 static void
190 report_header(
191 FILE *fp,
192 uint form,
193 uint type,
194 fs_path_t *mount,
195 int flags)
196 {
197 char *typename = type_to_string(type);
198 char scratch[64];
199 uint i, count;
200
201 if (flags & NO_HEADER_FLAG)
202 return;
203
204 /* line 1 */
205 fprintf(fp, _("%s quota on %s (%s)\n"),
206 typename, mount->fs_dir, mount->fs_name);
207
208 /* line 2 */
209 for (i = 0; i < 10; i++)
210 fputc(' ', fp);
211 if (form & XFS_BLOCK_QUOTA)
212 fprintf(fp, (flags & HUMAN_FLAG) ?
213 "%13c %s %13c" : "%20c %s %20c",
214 ' ', form_to_string(XFS_BLOCK_QUOTA), ' ');
215 if (form & XFS_INODE_QUOTA)
216 fprintf(fp, (flags & HUMAN_FLAG) ?
217 "%13c %s %13c" : "%20c %s %20c",
218 ' ', form_to_string(XFS_INODE_QUOTA), ' ');
219 if (form & XFS_RTBLOCK_QUOTA)
220 fprintf(fp, (flags & HUMAN_FLAG) ?
221 "%9c %s %9c" : "%15c %s %15c",
222 ' ', form_to_string(XFS_RTBLOCK_QUOTA), ' ');
223 fputc('\n', fp);
224
225 /* line 3 */
226 snprintf(scratch, sizeof(scratch), "%s ID", typename);
227 fprintf(fp, "%-10s ", scratch);
228 if (form & XFS_BLOCK_QUOTA)
229 fprintf(fp, (flags & HUMAN_FLAG) ?
230 _(" Used Soft Hard Warn/Grace ") :
231 _(" Used Soft Hard Warn/Grace "));
232 if (form & XFS_INODE_QUOTA)
233 fprintf(fp, (flags & HUMAN_FLAG) ?
234 _(" Used Soft Hard Warn/Grace ") :
235 _(" Used Soft Hard Warn/ Grace "));
236 if (form & XFS_RTBLOCK_QUOTA)
237 fprintf(fp, (flags & HUMAN_FLAG) ?
238 _(" Used Soft Hard Warn/Grace ") :
239 _(" Used Soft Hard Warn/Grace "));
240 fputc('\n', fp);
241
242 /* line 4 */
243 for (i = 0; i < 10; i++)
244 fputc('-', fp);
245 fputc(' ', fp);
246 count = (flags & HUMAN_FLAG) ? 33 : 50;
247 if (form & XFS_BLOCK_QUOTA) {
248 for (i = 0; i < count; i++)
249 fputc('-', fp);
250 fputc(' ', fp);
251 }
252 if (form & XFS_INODE_QUOTA) {
253 for (i = 0; i < count; i++)
254 fputc('-', fp);
255 fputc(' ', fp);
256 }
257 if (form & XFS_RTBLOCK_QUOTA) {
258 for (i = 0; i < count; i++)
259 fputc('-', fp);
260 fputc(' ', fp);
261 }
262 fputc('\n', fp);
263 }
264
265 static int
266 report_mount(
267 FILE *fp,
268 __uint32_t id,
269 char *name,
270 uint form,
271 uint type,
272 fs_path_t *mount,
273 uint flags)
274 {
275 fs_disk_quota_t d;
276 char *dev = mount->fs_name;
277 char c[8], h[8], s[8];
278 uint qflags;
279 int count;
280
281 if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0)
282 return 0;
283
284 if (flags & TERSE_FLAG) {
285 count = 0;
286 if ((form & XFS_BLOCK_QUOTA) && d.d_bcount)
287 count++;
288 if ((form & XFS_INODE_QUOTA) && d.d_icount)
289 count++;
290 if ((form & XFS_RTBLOCK_QUOTA) && d.d_rtbcount)
291 count++;
292 if (!count)
293 return 0;
294 }
295
296 if (!(flags & NO_HEADER_FLAG))
297 report_header(fp, form, type, mount, flags);
298
299 fprintf(fp, "%-10s", name);
300 if (form & XFS_BLOCK_QUOTA) {
301 qflags = (flags & HUMAN_FLAG);
302 if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit)
303 qflags |= LIMIT_FLAG;
304 if (d.d_blk_softlimit && d.d_bcount > d.d_blk_softlimit)
305 qflags |= QUOTA_FLAG;
306 if (flags & HUMAN_FLAG)
307 fprintf(fp, " %6s %6s %6s %02d %8s",
308 bbs_to_string(d.d_bcount, c, sizeof(c)),
309 bbs_to_string(d.d_blk_softlimit, s, sizeof(s)),
310 bbs_to_string(d.d_blk_hardlimit, h, sizeof(h)),
311 d.d_bwarns,
312 time_to_string(d.d_btimer, qflags));
313 else
314 fprintf(fp, " %10llu %10llu %10llu %02d %9s",
315 (unsigned long long)d.d_bcount >> 1,
316 (unsigned long long)d.d_blk_softlimit >> 1,
317 (unsigned long long)d.d_blk_hardlimit >> 1,
318 d.d_bwarns,
319 time_to_string(d.d_btimer, qflags));
320 }
321 if (form & XFS_INODE_QUOTA) {
322 qflags = (flags & HUMAN_FLAG);
323 if (d.d_ino_hardlimit && d.d_icount > d.d_ino_hardlimit)
324 qflags |= LIMIT_FLAG;
325 if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
326 qflags |= QUOTA_FLAG;
327 if (flags & HUMAN_FLAG)
328 fprintf(fp, " %6s %6s %6s %02d %8s",
329 num_to_string(d.d_icount, c, sizeof(c)),
330 num_to_string(d.d_ino_softlimit, s, sizeof(s)),
331 num_to_string(d.d_ino_hardlimit, h, sizeof(h)),
332 d.d_iwarns,
333 time_to_string(d.d_itimer, qflags));
334 else
335 fprintf(fp, " %10llu %10llu %10llu %02d %9s",
336 (unsigned long long)d.d_icount,
337 (unsigned long long)d.d_ino_softlimit,
338 (unsigned long long)d.d_ino_hardlimit,
339 d.d_iwarns,
340 time_to_string(d.d_itimer, qflags));
341 }
342 if (form & XFS_RTBLOCK_QUOTA) {
343 qflags = (flags & HUMAN_FLAG);
344 if (d.d_rtb_hardlimit && d.d_rtbcount > d.d_rtb_hardlimit)
345 qflags |= LIMIT_FLAG;
346 if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
347 qflags |= QUOTA_FLAG;
348 if (flags & HUMAN_FLAG)
349 fprintf(fp, " %6s %6s %6s %02d %8s",
350 bbs_to_string(d.d_rtbcount, c, sizeof(c)),
351 bbs_to_string(d.d_rtb_softlimit, s, sizeof(s)),
352 bbs_to_string(d.d_rtb_hardlimit, h, sizeof(h)),
353 d.d_rtbwarns,
354 time_to_string(d.d_rtbtimer, qflags));
355 else
356 fprintf(fp, " %10llu %10llu %10llu %02d %9s",
357 (unsigned long long)d.d_rtbcount >> 1,
358 (unsigned long long)d.d_rtb_softlimit >> 1,
359 (unsigned long long)d.d_rtb_hardlimit >> 1,
360 d.d_rtbwarns,
361 time_to_string(d.d_rtbtimer, qflags));
362 }
363 fputc('\n', fp);
364 return 1;
365 }
366
367 static void
368 report_user_mount(
369 FILE *fp,
370 uint form,
371 fs_path_t *mount,
372 uint flags)
373 {
374 struct passwd *u;
375
376 setpwent();
377 while ((u = getpwent()) != NULL)
378 if (report_mount(fp, u->pw_uid, u->pw_name,
379 form, XFS_USER_QUOTA, mount, flags))
380 flags |= NO_HEADER_FLAG;
381 if (flags & NO_HEADER_FLAG)
382 fputc('\n', fp);
383 endpwent();
384 }
385
386 static void
387 report_group_mount(
388 FILE *fp,
389 uint form,
390 fs_path_t *mount,
391 uint flags)
392 {
393 struct group *g;
394
395 setgrent();
396 while ((g = getgrent()) != NULL)
397 if (report_mount(fp, g->gr_gid, g->gr_name,
398 form, XFS_GROUP_QUOTA, mount, flags))
399 flags |= NO_HEADER_FLAG;
400 if (flags & NO_HEADER_FLAG)
401 fputc('\n', fp);
402 endgrent();
403 }
404
405 static void
406 report_project_mount(
407 FILE *fp,
408 uint form,
409 fs_path_t *mount,
410 uint flags)
411 {
412 fs_project_t *p;
413
414 setprent();
415 while ((p = getprent()) != NULL)
416 if (report_mount(fp, p->pr_prid, p->pr_name,
417 form, XFS_PROJ_QUOTA, mount, flags))
418 flags |= NO_HEADER_FLAG;
419 if (flags & NO_HEADER_FLAG)
420 fputc('\n', fp);
421 endprent();
422 }
423
424 static void
425 report_any_type(
426 FILE *fp,
427 uint form,
428 uint type,
429 char *dir,
430 uint flags)
431 {
432 fs_cursor_t cursor;
433 fs_path_t *mount;
434
435 if (type & XFS_USER_QUOTA) {
436 fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor);
437 while ((mount = fs_cursor_next_entry(&cursor)))
438 report_user_mount(fp, form, mount, flags);
439 }
440 if (type & XFS_GROUP_QUOTA) {
441 fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor);
442 while ((mount = fs_cursor_next_entry(&cursor)))
443 report_group_mount(fp, form, mount, flags);
444 }
445 if (type & XFS_PROJ_QUOTA) {
446 fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor);
447 while ((mount = fs_cursor_next_entry(&cursor)))
448 report_project_mount(fp, form, mount, flags);
449 }
450 }
451
452 static int
453 report_f(
454 int argc,
455 char **argv)
456 {
457 FILE *fp = NULL;
458 char *fname = NULL;
459 int c, flags = 0, type = 0, form = 0;
460
461 while ((c = getopt(argc, argv, "abf:hgniprtu")) != EOF) {
462 switch (c) {
463 case 'f':
464 fname = optarg;
465 break;
466 case 'b':
467 form |= XFS_BLOCK_QUOTA;
468 break;
469 case 'i':
470 form |= XFS_INODE_QUOTA;
471 break;
472 case 'r':
473 form |= XFS_RTBLOCK_QUOTA;
474 break;
475 case 'g':
476 type |= XFS_GROUP_QUOTA;
477 break;
478 case 'p':
479 type |= XFS_PROJ_QUOTA;
480 break;
481 case 'u':
482 type |= XFS_USER_QUOTA;
483 break;
484 case 'a':
485 flags |= ALL_MOUNTS_FLAG;
486 break;
487 case 'h':
488 flags |= HUMAN_FLAG;
489 break;
490 case 'n':
491 flags |= NO_HEADER_FLAG;
492 break;
493 case 't':
494 flags |= TERSE_FLAG;
495 break;
496 default:
497 return command_usage(&report_cmd);
498 }
499 }
500
501 if (!form)
502 form = XFS_BLOCK_QUOTA;
503
504 if (!type)
505 type = XFS_USER_QUOTA | XFS_GROUP_QUOTA | XFS_PROJ_QUOTA;
506
507 if ((fp = fopen_write_secure(fname)) == NULL)
508 return 0;
509
510 if (argc == optind)
511 report_any_type(fp, form, type, (flags & ALL_MOUNTS_FLAG) ?
512 NULL : fs_path->fs_dir, flags);
513 else while (argc > optind)
514 report_any_type(fp, form, type, argv[optind++], flags);
515
516 if (fname)
517 fclose(fp);
518 return 0;
519 }
520
521 void
522 report_init(void)
523 {
524 dump_cmd.name = _("dump");
525 dump_cmd.cfunc = dump_f;
526 dump_cmd.argmin = 0;
527 dump_cmd.argmax = -1;
528 dump_cmd.args = _("[-gpu] [-f file]");
529 dump_cmd.oneline = _("dump quota information for backup utilities");
530 dump_cmd.help = dump_help;
531
532 report_cmd.name = _("report");
533 report_cmd.altname = _("repquota");
534 report_cmd.cfunc = report_f;
535 report_cmd.argmin = 0;
536 report_cmd.argmax = -1;
537 report_cmd.args = _("[-bir] [-gpu] [-ahnt] [-f file]");
538 report_cmd.oneline = _("report filesystem quota information");
539 report_cmd.help = report_help;
540
541 if (expert) {
542 add_command(&dump_cmd);
543 add_command(&report_cmd);
544 }
545 }