]>
Commit | Line | Data |
---|---|---|
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 | ||
27 | static cmdinfo_t dump_cmd; | |
28 | static cmdinfo_t report_cmd; | |
29 | ||
30 | static void | |
31 | dump_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 | ||
45 | static void | |
46 | report_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 | 76 | static int |
5aead01d NS |
77 | dump_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 | ||
134 | static void | |
135 | dump_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 | ||
200 | static int | |
201 | dump_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 | ||
257 | static void | |
258 | report_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 | ||
333 | static int | |
334 | report_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 | ||
478 | static void | |
479 | report_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 | ||
520 | static void | |
521 | report_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 | ||
561 | static void | |
562 | report_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 | ||
613 | static void | |
614 | report_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 | ||
667 | static int | |
668 | report_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 | ||
761 | void | |
762 | report_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 | } |