]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - quota/state.c
libxcmd: don't check generic library commands
[thirdparty/xfsprogs-dev.git] / quota / state.c
CommitLineData
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"
5aead01d
NS
20#include "init.h"
21#include "quota.h"
22
23static cmdinfo_t off_cmd;
24static cmdinfo_t state_cmd;
25static cmdinfo_t enable_cmd;
26static cmdinfo_t disable_cmd;
27static cmdinfo_t remove_cmd;
28
29static void
30off_help(void)
31{
32 printf(_(
33"\n"
34" turn filesystem quota off, both accounting and enforcement\n"
35"\n"
36" Example:\n"
37" 'off -uv' (switch off user quota on the current filesystem)\n"
38" This command is the equivalent of the traditional quotaoff command,\n"
39" which disables quota completely on a mounted filesystem.\n"
40" Note that there is no 'on' command - for XFS filesystems (with the\n"
41" exception of the root filesystem on IRIX) quota can only be enabled\n"
42" at mount time, through the use of one of the quota mount options.\n"
43"\n"
44" The state command is useful for displaying the current state. Using\n"
45" the -v (verbose) option with the 'off' command will display the quota\n"
46" state for the affected filesystem once the operation is complete.\n"
47" The affected quota type is -g (groups), -p (projects) or -u (users)\n"
48" and defaults to user quota (multiple types can be specified).\n"
49"\n"));
50}
51
52static void
53state_help(void)
54{
55 printf(_(
56"\n"
57" query the state of quota on the current filesystem\n"
58"\n"
59" This is a verbose status command, reporting whether or not accounting\n"
60" and/or enforcement are enabled for a filesystem, which inodes are in\n"
61" use as the quota state inodes, and how many extents and blocks are\n"
62" presently being used to hold that information.\n"
63" The quota type is specified via -g (groups), -p (projects) or -u (users)\n"
64" and defaults to user quota (multiple types can be specified).\n"
65"\n"));
66}
67
68static void
69enable_help(void)
70{
71 printf(_(
72"\n"
73" enable quota enforcement on a filesystem\n"
74"\n"
75" If a filesystem is mounted and has quota accounting enabled, but not\n"
76" quota enforcement, enforcement can be enabled with this command.\n"
77" With the -v (verbose) option, the status of the filesystem will be\n"
78" reported after the operation is complete.\n"
79" The affected quota type is -g (groups), -p (projects) or -u (users)\n"
80" and defaults to user quota (multiple types can be specified).\n"
81"\n"));
82}
83
84static void
85disable_help(void)
86{
87 printf(_(
88"\n"
89" disable quota enforcement on a filesystem\n"
90"\n"
91" If a filesystem is mounted and is currently enforcing quota, this\n"
92" provides a mechanism to switch off the enforcement, but continue to\n"
93" perform used space (and used inodes) accounting.\n"
94" The affected quota type is -g (groups), -p (projects) or -u (users).\n"
95"\n"));
96}
97
98static void
99remove_help(void)
100{
101 printf(_(
102"\n"
103" remove any space being used by the quota subsystem\n"
104"\n"
105" Once quota has been switched 'off' on a filesystem, the space that\n"
106" was allocated to holding quota metadata can be freed via this command.\n"
107" The affected quota type is -g (groups), -p (projects) or -u (users)\n"
108" and defaults to user quota (multiple types can be specified).\n"
109"\n"));
110}
111
112static void
113state_qfilestat(
bb92709f
ES
114 FILE *fp,
115 struct fs_path *mount,
116 uint type,
117 struct fs_qfilestatv *qfs,
118 int accounting,
119 int enforcing)
5aead01d
NS
120{
121 fprintf(fp, _("%s quota state on %s (%s)\n"), type_to_string(type),
122 mount->fs_dir, mount->fs_name);
123 fprintf(fp, _(" Accounting: %s\n"), accounting ? _("ON") : _("OFF"));
124 fprintf(fp, _(" Enforcement: %s\n"), enforcing ? _("ON") : _("OFF"));
06065b12
AE
125 if (qfs->qfs_ino != (__u64) -1)
126 fprintf(fp, _(" Inode: #%llu (%llu blocks, %lu extents)\n"),
127 (unsigned long long)qfs->qfs_ino,
128 (unsigned long long)qfs->qfs_nblks,
129 (unsigned long)qfs->qfs_nextents);
130 else
131 fprintf(fp, _(" Inode: N/A\n"));
5aead01d
NS
132}
133
134static void
135state_timelimit(
136 FILE *fp,
137 uint form,
138 __uint32_t timelimit)
139{
140 fprintf(fp, _("%s grace time: %s\n"),
141 form_to_string(form),
142 time_to_string(timelimit, VERBOSE_FLAG | ABSOLUTE_FLAG));
143}
144
bb92709f
ES
145/*
146 * fs_quota_stat holds a subset of fs_quota_statv; this copies
147 * the smaller into the larger, leaving any not-present fields
148 * empty. This is so the same reporting function can be used
149 * for both XFS_GETQSTAT and XFS_GETQSTATV results.
150 */
151static void
152state_stat_to_statv(
153 struct fs_quota_stat *s,
154 struct fs_quota_statv *sv)
155{
156 memset(sv, 0, sizeof(struct fs_quota_statv));
157
158 /* shared information */
159 sv->qs_version = s->qs_version;
160 sv->qs_flags = s->qs_flags;
161 sv->qs_incoredqs = s->qs_incoredqs;
162 sv->qs_btimelimit = s->qs_btimelimit;
163 sv->qs_itimelimit = s->qs_itimelimit;
164 sv->qs_rtbtimelimit = s->qs_rtbtimelimit;
165 sv->qs_bwarnlimit = s->qs_bwarnlimit;
166 sv->qs_iwarnlimit = s->qs_iwarnlimit;
167
168 /* Always room for uquota */
169 sv->qs_uquota.qfs_ino = s->qs_uquota.qfs_ino;
170 sv->qs_uquota.qfs_nblks = s->qs_uquota.qfs_nblks;
171 sv->qs_uquota.qfs_nextents = s->qs_uquota.qfs_nextents;
172
173 /*
174 * If we are here, XFS_GETQSTATV failed and XFS_GETQSTAT passed;
175 * that is a very strong hint that we're on a kernel which predates
176 * the on-disk pquota inode; both were added in v3.12. So, we do
177 * some tricksy determination here.
178 * gs_gquota may hold either group quota inode info, or project
179 * quota if that is used instead; which one it actually holds depends
180 * on the quota flags. (If neither is set, neither is used)
181 */
182 if (s->qs_flags & XFS_QUOTA_GDQ_ACCT) {
183 /* gs_gquota holds group quota info */
184 sv->qs_gquota.qfs_ino = s->qs_gquota.qfs_ino;
185 sv->qs_gquota.qfs_nblks = s->qs_gquota.qfs_nblks;
186 sv->qs_gquota.qfs_nextents = s->qs_gquota.qfs_nextents;
187 } else if (s->qs_flags & XFS_QUOTA_PDQ_ACCT) {
188 /* gs_gquota actually holds project quota info */
189 sv->qs_pquota.qfs_ino = s->qs_gquota.qfs_ino;
190 sv->qs_pquota.qfs_nblks = s->qs_gquota.qfs_nblks;
191 sv->qs_pquota.qfs_nextents = s->qs_gquota.qfs_nextents;
192 }
193}
194
5aead01d
NS
195static void
196state_quotafile_mount(
bb92709f
ES
197 FILE *fp,
198 uint type,
199 struct fs_path *mount,
200 uint flags)
5aead01d 201{
bb92709f
ES
202 struct fs_quota_stat s;
203 struct fs_quota_statv sv;
204 char *dev = mount->fs_name;
205
206 sv.qs_version = FS_QSTATV_VERSION1;
207
208 if (xfsquotactl(XFS_GETQSTATV, dev, type, 0, (void *)&sv) < 0) {
209 if (xfsquotactl(XFS_GETQSTAT, dev, type, 0, (void *)&s) < 0) {
210 if (flags & VERBOSE_FLAG)
211 fprintf(fp,
212 _("%s quota are not enabled on %s\n"),
213 type_to_string(type), dev);
214 return;
215 }
216 state_stat_to_statv(&s, &sv);
5aead01d
NS
217 }
218
219 if (type & XFS_USER_QUOTA)
bb92709f
ES
220 state_qfilestat(fp, mount, XFS_USER_QUOTA, &sv.qs_uquota,
221 sv.qs_flags & XFS_QUOTA_UDQ_ACCT,
222 sv.qs_flags & XFS_QUOTA_UDQ_ENFD);
5aead01d 223 if (type & XFS_GROUP_QUOTA)
bb92709f
ES
224 state_qfilestat(fp, mount, XFS_GROUP_QUOTA, &sv.qs_gquota,
225 sv.qs_flags & XFS_QUOTA_GDQ_ACCT,
226 sv.qs_flags & XFS_QUOTA_GDQ_ENFD);
5aead01d 227 if (type & XFS_PROJ_QUOTA)
bb92709f
ES
228 state_qfilestat(fp, mount, XFS_PROJ_QUOTA, &sv.qs_pquota,
229 sv.qs_flags & XFS_QUOTA_PDQ_ACCT,
230 sv.qs_flags & XFS_QUOTA_PDQ_ENFD);
5aead01d 231
bb92709f
ES
232 state_timelimit(fp, XFS_BLOCK_QUOTA, sv.qs_btimelimit);
233 state_timelimit(fp, XFS_INODE_QUOTA, sv.qs_itimelimit);
234 state_timelimit(fp, XFS_RTBLOCK_QUOTA, sv.qs_rtbtimelimit);
5aead01d
NS
235}
236
237static void
238state_quotafile(
239 FILE *fp,
240 uint type,
241 char *dir,
242 uint flags)
243{
244 fs_cursor_t cursor;
245 fs_path_t *mount;
246
247 fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor);
248 while ((mount = fs_cursor_next_entry(&cursor)))
249 state_quotafile_mount(fp, type, mount, flags);
250}
251
252static int
253state_f(
254 int argc,
255 char **argv)
256{
257 FILE *fp = NULL;
258 char *fname = NULL;
259 int c, flags = 0, type = 0;
260
261 while ((c = getopt(argc, argv, "af:gpuv")) != EOF) {
262 switch (c) {
263 case 'a':
264 flags |= ALL_MOUNTS_FLAG;
265 break;
266 case 'f':
267 fname = optarg;
268 break;
269 case 'g':
270 type |= XFS_GROUP_QUOTA;
271 break;
272 case 'p':
273 type |= XFS_PROJ_QUOTA;
274 break;
275 case 'u':
276 type |= XFS_USER_QUOTA;
277 break;
278 case 'v':
279 flags |= VERBOSE_FLAG;
280 break;
281 default:
282 return command_usage(&state_cmd);
283 }
284 }
285
286 if (argc != optind)
287 return command_usage(&state_cmd);
288
289 if ((fp = fopen_write_secure(fname)) == NULL)
290 return 0;
291
292 if (!type)
293 type = XFS_USER_QUOTA | XFS_GROUP_QUOTA | XFS_PROJ_QUOTA;
294
fa13a00f
NS
295 if (flags & ALL_MOUNTS_FLAG)
296 state_quotafile(fp, type, NULL, flags);
04418c59 297 else if (fs_path && fs_path->fs_flags & FS_MOUNT_POINT)
fa13a00f 298 state_quotafile(fp, type, fs_path->fs_dir, flags);
5aead01d
NS
299
300 if (fname)
301 fclose(fp);
302 return 0;
303}
304
305static void
306enable_enforcement(
307 char *dir,
308 uint type,
309 uint qflags,
310 uint flags)
311{
312 fs_path_t *mount;
5aead01d
NS
313
314 mount = fs_table_lookup(dir, FS_MOUNT_POINT);
315 if (!mount) {
e3210fd8 316 exitcode = 1;
5aead01d
NS
317 fprintf(stderr, "%s: unknown mount point %s\n", progname, dir);
318 return;
319 }
320 dir = mount->fs_name;
79ac1ae4 321 if (xfsquotactl(XFS_QUOTAON, dir, type, 0, (void *)&qflags) < 0)
5aead01d
NS
322 perror("XFS_QUOTAON");
323 else if (flags & VERBOSE_FLAG)
324 state_quotafile_mount(stdout, type, mount, flags);
325}
326
327static void
328disable_enforcement(
329 char *dir,
330 uint type,
331 uint qflags,
332 uint flags)
333{
334 fs_path_t *mount;
5aead01d
NS
335
336 mount = fs_table_lookup(dir, FS_MOUNT_POINT);
337 if (!mount) {
e3210fd8 338 exitcode = 1;
5aead01d
NS
339 fprintf(stderr, "%s: unknown mount point %s\n", progname, dir);
340 return;
341 }
342 dir = mount->fs_name;
79ac1ae4 343 if (xfsquotactl(XFS_QUOTAOFF, dir, type, 0, (void *)&qflags) < 0)
5aead01d
NS
344 perror("XFS_QUOTAOFF");
345 else if (flags & VERBOSE_FLAG)
346 state_quotafile_mount(stdout, type, mount, flags);
347}
348
349static void
350quotaoff(
351 char *dir,
352 uint type,
353 uint qflags,
354 uint flags)
355{
356 fs_path_t *mount;
5aead01d
NS
357
358 mount = fs_table_lookup(dir, FS_MOUNT_POINT);
359 if (!mount) {
e3210fd8 360 exitcode = 1;
5aead01d
NS
361 fprintf(stderr, "%s: unknown mount point %s\n", progname, dir);
362 return;
363 }
364 dir = mount->fs_name;
79ac1ae4 365 if (xfsquotactl(XFS_QUOTAOFF, dir, type, 0, (void *)&qflags) < 0)
5aead01d
NS
366 perror("XFS_QUOTAOFF");
367 else if (flags & VERBOSE_FLAG)
368 state_quotafile_mount(stdout, type, mount, flags);
369}
370
79ac1ae4
DD
371static int
372remove_qtype_extents(
373 char *dir,
374 uint type)
375{
376 int error = 0;
377
378 if ((error = xfsquotactl(XFS_QUOTARM, dir, type, 0, (void *)&type)) < 0)
379 perror("XFS_QUOTARM");
380 return error;
381}
382
5aead01d
NS
383static void
384remove_extents(
385 char *dir,
386 uint type,
5aead01d
NS
387 uint flags)
388{
389 fs_path_t *mount;
5aead01d
NS
390
391 mount = fs_table_lookup(dir, FS_MOUNT_POINT);
392 if (!mount) {
e3210fd8 393 exitcode = 1;
5aead01d
NS
394 fprintf(stderr, "%s: unknown mount point %s\n", progname, dir);
395 return;
396 }
397 dir = mount->fs_name;
79ac1ae4 398 if (type & XFS_USER_QUOTA) {
f8149110 399 if (remove_qtype_extents(dir, XFS_USER_QUOTA) < 0)
79ac1ae4
DD
400 return;
401 }
402 if (type & XFS_GROUP_QUOTA) {
f8149110 403 if (remove_qtype_extents(dir, XFS_GROUP_QUOTA) < 0)
79ac1ae4
DD
404 return;
405 } else if (type & XFS_PROJ_QUOTA) {
f8149110 406 if (remove_qtype_extents(dir, XFS_PROJ_QUOTA) < 0)
79ac1ae4
DD
407 return;
408 }
409 if (flags & VERBOSE_FLAG)
5aead01d
NS
410 state_quotafile_mount(stdout, type, mount, flags);
411}
412
413static int
414enable_f(
415 int argc,
416 char **argv)
417{
418 int c, flags = 0, qflags = 0, type = 0;
419
420 while ((c = getopt(argc, argv, "gpuv")) != EOF) {
421 switch (c) {
422 case 'g':
423 type |= XFS_GROUP_QUOTA;
424 qflags |= XFS_QUOTA_GDQ_ACCT | XFS_QUOTA_GDQ_ENFD;
425 break;
426 case 'p':
427 type |= XFS_PROJ_QUOTA;
428 qflags |= XFS_QUOTA_PDQ_ACCT | XFS_QUOTA_PDQ_ENFD;
429 break;
430 case 'u':
431 type |= XFS_USER_QUOTA;
432 qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD;
433 break;
434 case 'v':
435 flags |= VERBOSE_FLAG;
436 break;
437 default:
438 return command_usage(&enable_cmd);
439 }
440 }
441
442 if (argc != optind)
443 return command_usage(&enable_cmd);
444
79ac1ae4 445 if (!type) {
5aead01d
NS
446 type |= XFS_USER_QUOTA;
447 qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD;
448 }
449
fa13a00f
NS
450 if (fs_path->fs_flags & FS_MOUNT_POINT)
451 enable_enforcement(fs_path->fs_dir, type, qflags, flags);
5aead01d
NS
452 return 0;
453}
454
455static int
456disable_f(
457 int argc,
458 char **argv)
459{
460 int c, flags = 0, qflags = 0, type = 0;
461
462 while ((c = getopt(argc, argv, "gpuv")) != EOF) {
463 switch (c) {
464 case 'g':
465 type |= XFS_GROUP_QUOTA;
79ac1ae4 466 qflags |= XFS_QUOTA_GDQ_ENFD;
5aead01d
NS
467 break;
468 case 'p':
469 type |= XFS_PROJ_QUOTA;
79ac1ae4 470 qflags |= XFS_QUOTA_PDQ_ENFD;
5aead01d
NS
471 break;
472 case 'u':
473 type |= XFS_USER_QUOTA;
79ac1ae4 474 qflags |= XFS_QUOTA_UDQ_ENFD;
5aead01d
NS
475 break;
476 case 'v':
477 flags |= VERBOSE_FLAG;
478 break;
479 default:
480 return command_usage(&disable_cmd);
481 }
482 }
483
484 if (argc != optind)
485 return command_usage(&disable_cmd);
486
79ac1ae4 487 if (!type) {
5aead01d 488 type |= XFS_USER_QUOTA;
79ac1ae4 489 qflags |= XFS_QUOTA_UDQ_ENFD;
5aead01d
NS
490 }
491
fa13a00f
NS
492 if (fs_path->fs_flags & FS_MOUNT_POINT)
493 disable_enforcement(fs_path->fs_dir, type, qflags, flags);
5aead01d
NS
494 return 0;
495}
496
497static int
498off_f(
499 int argc,
500 char **argv)
501{
502 int c, flags = 0, qflags = 0, type = 0;
503
504 while ((c = getopt(argc, argv, "gpuv")) != EOF) {
505 switch (c) {
506 case 'g':
507 type |= XFS_GROUP_QUOTA;
508 qflags |= XFS_QUOTA_GDQ_ACCT | XFS_QUOTA_GDQ_ENFD;
509 break;
510 case 'p':
511 type |= XFS_PROJ_QUOTA;
512 qflags |= XFS_QUOTA_PDQ_ACCT | XFS_QUOTA_PDQ_ENFD;
513 break;
514 case 'u':
515 type |= XFS_USER_QUOTA;
516 qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD;
517 break;
518 case 'v':
519 flags |= VERBOSE_FLAG;
520 break;
521 default:
522 return command_usage(&off_cmd);
523 }
524 }
525
526 if (argc != optind)
527 return command_usage(&off_cmd);
528
79ac1ae4 529 if (!type) {
5aead01d
NS
530 type |= XFS_USER_QUOTA;
531 qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD;
532 }
533
fa13a00f
NS
534 if (fs_path->fs_flags & FS_MOUNT_POINT)
535 quotaoff(fs_path->fs_dir, type, qflags, flags);
5aead01d
NS
536 return 0;
537}
538
539static int
540remove_f(
541 int argc,
542 char **argv)
543{
79ac1ae4 544 int c, flags = 0, type = 0;
5aead01d
NS
545
546 while ((c = getopt(argc, argv, "gpuv")) != EOF) {
547 switch (c) {
548 case 'g':
549 type |= XFS_GROUP_QUOTA;
5aead01d
NS
550 break;
551 case 'p':
552 type |= XFS_PROJ_QUOTA;
5aead01d
NS
553 break;
554 case 'u':
555 type |= XFS_USER_QUOTA;
5aead01d
NS
556 break;
557 case 'v':
558 flags |= VERBOSE_FLAG;
559 break;
560 default:
561 return command_usage(&remove_cmd);
562 }
563 }
564
565 if (argc != optind)
566 return command_usage(&remove_cmd);
567
79ac1ae4 568 if (!type) {
5aead01d 569 type |= XFS_USER_QUOTA;
5aead01d
NS
570 }
571
fa13a00f 572 if (fs_path->fs_flags & FS_MOUNT_POINT)
79ac1ae4 573 remove_extents(fs_path->fs_dir, type, flags);
5aead01d
NS
574 return 0;
575}
576
577void
578state_init(void)
579{
ad765595 580 off_cmd.name = "off";
5aead01d
NS
581 off_cmd.cfunc = off_f;
582 off_cmd.argmin = 0;
583 off_cmd.argmax = -1;
584 off_cmd.args = _("[-gpu] [-v]");
585 off_cmd.oneline = _("permanently switch quota off for a path");
586 off_cmd.help = off_help;
587
ad765595 588 state_cmd.name = "state";
5aead01d
NS
589 state_cmd.cfunc = state_f;
590 state_cmd.argmin = 0;
591 state_cmd.argmax = -1;
62790d19 592 state_cmd.args = _("[-gpu] [-a] [-v] [-f file]");
5aead01d
NS
593 state_cmd.oneline = _("get overall quota state information");
594 state_cmd.help = state_help;
29647c8d 595 state_cmd.flags = CMD_FLAG_FOREIGN_OK;
5aead01d 596
ad765595 597 enable_cmd.name = "enable";
5aead01d
NS
598 enable_cmd.cfunc = enable_f;
599 enable_cmd.argmin = 0;
600 enable_cmd.argmax = -1;
601 enable_cmd.args = _("[-gpu] [-v]");
602 enable_cmd.oneline = _("enable quota enforcement");
603 enable_cmd.help = enable_help;
604
ad765595 605 disable_cmd.name = "disable";
5aead01d
NS
606 disable_cmd.cfunc = disable_f;
607 disable_cmd.argmin = 0;
608 disable_cmd.argmax = -1;
609 disable_cmd.args = _("[-gpu] [-v]");
610 disable_cmd.oneline = _("disable quota enforcement");
611 disable_cmd.help = disable_help;
612
ad765595 613 remove_cmd.name = "remove";
5aead01d
NS
614 remove_cmd.cfunc = remove_f;
615 remove_cmd.argmin = 0;
616 remove_cmd.argmax = -1;
617 remove_cmd.args = _("[-gpu] [-v]");
618 remove_cmd.oneline = _("remove quota extents from a filesystem");
619 remove_cmd.help = remove_help;
620
621 if (expert) {
622 add_command(&off_cmd);
623 add_command(&state_cmd);
624 add_command(&enable_cmd);
625 add_command(&disable_cmd);
626 add_command(&remove_cmd);
627 }
628}