]>
Commit | Line | Data |
---|---|---|
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 | ||
15 | static cmdinfo_t dump_cmd; | |
16 | static cmdinfo_t report_cmd; | |
17 | ||
18 | static void | |
19 | dump_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 | ||
33 | static void | |
34 | report_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 |
62 | static int |
63 | get_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 | ||
92 | static int | |
93 | dump_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 | ||
124 | static void | |
125 | dump_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 | ||
198 | static int | |
199 | dump_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 | ||
255 | static void | |
256 | report_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 | ||
331 | static int | |
332 | report_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 | ||
456 | static void | |
457 | report_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 | ||
498 | static void | |
499 | report_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 | ||
539 | static void | |
540 | report_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 | ||
596 | static void | |
597 | report_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 | ||
650 | static int | |
651 | report_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 | ||
744 | void | |
745 | report_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 | } |