]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - quota/edit.c
xfs_scrub: include unicrash.h in unicrash.c
[thirdparty/xfsprogs-dev.git] / quota / edit.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
5aead01d 2/*
da23017d
NS
3 * Copyright (c) 2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5aead01d
NS
5 */
6
7#include <pwd.h>
8#include <grp.h>
9#include <ctype.h>
6b803e5a
CH
10#include "input.h"
11#include "command.h"
5aead01d
NS
12#include "init.h"
13#include "quota.h"
14
15static cmdinfo_t limit_cmd;
16static cmdinfo_t restore_cmd;
17static cmdinfo_t timer_cmd;
18static cmdinfo_t warn_cmd;
19
20static void
21limit_help(void)
22{
23 printf(_(
24"\n"
25" modify quota limits for the specified user\n"
26"\n"
27" Example:\n"
28" 'limit bsoft=100m bhard=110m tanya\n"
29"\n"
30" Changes the soft and/or hard block limits, inode limits and/or realtime\n"
31" block limits that are currently being used for the specified user, group,\n"
32" or project. The filesystem identified by the current path is modified.\n"
33" -d -- set the default values, used the first time a file is created\n"
34" -g -- modify group quota limits\n"
35" -p -- modify project quota limits\n"
36" -u -- modify user quota limits\n"
37" The block limit values can be specified with a units suffix - accepted\n"
38" units are: k (kilobytes), m (megabytes), g (gigabytes), and t (terabytes).\n"
39" The user/group/project can be specified either by name or by number.\n"
40"\n"));
41}
42
43static void
44timer_help(void)
45{
46 printf(_(
47"\n"
1774874a 48" modify quota enforcement timeout for the current filesystem\n"
5aead01d
NS
49"\n"
50" Example:\n"
1774874a
NS
51" 'timer -i 3days'\n"
52" (soft inode limit timer is changed to 3 days)\n"
5aead01d
NS
53"\n"
54" Changes the timeout value associated with the block limits, inode limits\n"
1774874a
NS
55" and/or realtime block limits for all users, groups, or projects on the\n"
56" current filesystem.\n"
5aead01d
NS
57" As soon as a user consumes the amount of space or number of inodes set as\n"
58" the soft limit, a timer is started. If the timer expires and the user is\n"
59" still over the soft limit, the soft limit is enforced as the hard limit.\n"
60" The default timeout is 7 days.\n"
61" -d -- set the default values, used the first time a file is created\n"
62" -g -- modify group quota timer\n"
63" -p -- modify project quota timer\n"
64" -u -- modify user quota timer\n"
65" -b -- modify the blocks-used timer\n"
66" -i -- modify the inodes-used timer\n"
67" -r -- modify the blocks-used timer for the (optional) realtime subvolume\n"
68" The timeout value is specified as a number of seconds, by default.\n"
69" However, a suffix may be used to alternatively specify minutes (m),\n"
70" hours (h), days (d), or weeks (w) - either the full word or the first\n"
71" letter of the word can be used.\n"
5aead01d
NS
72"\n"));
73}
74
75static void
76warn_help(void)
77{
78 printf(_(
79"\n"
80" modify the number of quota warnings sent to the specified user\n"
81"\n"
82" Example:\n"
83" 'warn 2 jimmy'\n"
84" (tell the quota system that two warnings have been sent to user jimmy)\n"
85"\n"
86" Changes the warning count associated with the block limits, inode limits\n"
87" and/or realtime block limits for the specified user, group, or project.\n"
88" When a user has been warned the maximum number of times allowed, the soft\n"
89" limit is enforced as the hard limit. It is intended as an alternative to\n"
90" the timeout system, where the system administrator updates a count of the\n"
91" number of warnings issued to people, and they are penalised if the warnings\n"
92" are ignored.\n"
93" -d -- set maximum warning count, which triggers soft limit enforcement\n"
94" -g -- set group quota warning count\n"
95" -p -- set project quota warning count\n"
96" -u -- set user quota warning count\n"
97" -b -- set the blocks-used warning count\n"
98" -i -- set the inodes-used warning count\n"
99" -r -- set the blocks-used warn count for the (optional) realtime subvolume\n"
100" The user/group/project can be specified either by name or by number.\n"
101"\n"));
102}
103
104static void
105set_limits(
14f8b681 106 uint32_t id,
5aead01d
NS
107 uint type,
108 uint mask,
109 char *dev,
14f8b681
DW
110 uint64_t *bsoft,
111 uint64_t *bhard,
112 uint64_t *isoft,
113 uint64_t *ihard,
114 uint64_t *rtbsoft,
115 uint64_t *rtbhard)
5aead01d
NS
116{
117 fs_disk_quota_t d;
118
119 memset(&d, 0, sizeof(d));
120 d.d_version = FS_DQUOT_VERSION;
121 d.d_id = id;
122 d.d_flags = type;
123 d.d_fieldmask = mask;
124 d.d_blk_hardlimit = *bhard;
125 d.d_blk_softlimit = *bsoft;
126 d.d_ino_hardlimit = *ihard;
127 d.d_ino_softlimit = *isoft;
128 d.d_rtb_hardlimit = *rtbhard;
129 d.d_rtb_softlimit = *rtbsoft;
130
e3210fd8
AM
131 if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
132 exitcode = 1;
5aead01d
NS
133 fprintf(stderr, _("%s: cannot set limits: %s\n"),
134 progname, strerror(errno));
e3210fd8 135 }
5aead01d
NS
136}
137
138static void
139set_user_limits(
140 char *name,
141 uint type,
142 uint mask,
14f8b681
DW
143 uint64_t *bsoft,
144 uint64_t *bhard,
145 uint64_t *isoft,
146 uint64_t *ihard,
147 uint64_t *rtbsoft,
148 uint64_t *rtbhard)
5aead01d
NS
149{
150 uid_t uid = uid_from_string(name);
151
e3210fd8
AM
152 if (uid == -1) {
153 exitcode = 1;
5aead01d
NS
154 fprintf(stderr, _("%s: invalid user name: %s\n"),
155 progname, name);
e3210fd8 156 } else
5aead01d
NS
157 set_limits(uid, type, mask, fs_path->fs_name,
158 bsoft, bhard, isoft, ihard, rtbsoft, rtbhard);
159}
160
161static void
162set_group_limits(
163 char *name,
164 uint type,
165 uint mask,
14f8b681
DW
166 uint64_t *bsoft,
167 uint64_t *bhard,
168 uint64_t *isoft,
169 uint64_t *ihard,
170 uint64_t *rtbsoft,
171 uint64_t *rtbhard)
5aead01d
NS
172{
173 gid_t gid = gid_from_string(name);
174
e3210fd8
AM
175 if (gid == -1) {
176 exitcode = 1;
5aead01d
NS
177 fprintf(stderr, _("%s: invalid group name: %s\n"),
178 progname, name);
e3210fd8 179 } else
5aead01d
NS
180 set_limits(gid, type, mask, fs_path->fs_name,
181 bsoft, bhard, isoft, ihard, rtbsoft, rtbhard);
182}
183
184static void
185set_project_limits(
186 char *name,
187 uint type,
188 uint mask,
14f8b681
DW
189 uint64_t *bsoft,
190 uint64_t *bhard,
191 uint64_t *isoft,
192 uint64_t *ihard,
193 uint64_t *rtbsoft,
194 uint64_t *rtbhard)
5aead01d
NS
195{
196 prid_t prid = prid_from_string(name);
197
e3210fd8
AM
198 if (prid == -1) {
199 exitcode = 1;
5aead01d
NS
200 fprintf(stderr, _("%s: invalid project name: %s\n"),
201 progname, name);
e3210fd8 202 } else
5aead01d
NS
203 set_limits(prid, type, mask, fs_path->fs_name,
204 bsoft, bhard, isoft, ihard, rtbsoft, rtbhard);
205}
206
1774874a 207/* extract number of blocks from an ascii string */
5aead01d 208static int
1774874a 209extractb(
5aead01d
NS
210 char *string,
211 const char *prefix,
212 int length,
213 uint blocksize,
214 uint sectorsize,
14f8b681 215 uint64_t *value)
5aead01d 216{
7fd39587 217 long long v;
5aead01d
NS
218 char *s = string;
219
220 if (strncmp(string, prefix, length) == 0) {
221 s = string + length + 1;
7fd39587
ES
222 v = cvtnum(blocksize, sectorsize, s);
223 if (v == -1LL) {
224 fprintf(stderr,
225 _("%s: Error: could not parse size %s.\n"),
226 progname, s);
227 return 0;
228 }
14f8b681 229 *value = (uint64_t)v >> 9; /* syscalls use basic blocks */
39d09609
AM
230 if (v > 0 && *value == 0)
231 fprintf(stderr, _("%s: Warning: `%s' in quota blocks is 0 (unlimited).\n"), progname, s);
5aead01d
NS
232 return 1;
233 }
234 return 0;
235}
236
1774874a
NS
237/* extract number of inodes from an ascii string */
238static int
239extracti(
240 char *string,
241 const char *prefix,
242 int length,
14f8b681 243 uint64_t *value)
1774874a
NS
244{
245 char *sp, *s = string;
246
247 if (strncmp(string, prefix, length) == 0) {
248 s = string + length + 1;
249 *value = strtoll(s, &sp, 0);
250 return 1;
251 }
252 return 0;
253}
254
5aead01d
NS
255static int
256limit_f(
257 int argc,
258 char **argv)
259{
260 char *name;
14f8b681 261 uint64_t bsoft, bhard, isoft, ihard, rtbsoft, rtbhard;
5aead01d
NS
262 int c, type = 0, mask = 0, flags = 0;
263 uint bsize, ssize, endoptions;
264
265 init_cvtnum(&bsize, &ssize);
266 bsoft = bhard = isoft = ihard = rtbsoft = rtbhard = 0;
267 while ((c = getopt(argc, argv, "dgpu")) != EOF) {
268 switch (c) {
269 case 'd':
270 flags |= DEFAULTS_FLAG;
271 break;
272 case 'g':
c614d3bf 273 type |= XFS_GROUP_QUOTA;
5aead01d
NS
274 break;
275 case 'p':
c614d3bf 276 type |= XFS_PROJ_QUOTA;
5aead01d
NS
277 break;
278 case 'u':
c614d3bf 279 type |= XFS_USER_QUOTA;
5aead01d
NS
280 break;
281 default:
282 return command_usage(&limit_cmd);
283 }
284 }
285
286 /*
287 * In the usual case, we need at least 2 more arguments -
288 * one (or more) limits and a user name/id.
289 * For setting defaults (-d) we don't want a user name/id.
290 */
291 if (flags & DEFAULTS_FLAG) {
292 if (argc < optind + 1)
293 return command_usage(&limit_cmd);
294 endoptions = 1;
295 } else if (argc < optind + 2) {
296 return command_usage(&limit_cmd);
297 } else {
298 endoptions = 2;
299 }
300
301 /*
302 * Extract limit values from remaining optional arguments.
303 */
304 while (argc > optind + endoptions - 1) {
305 char *s = argv[optind++];
1774874a 306 if (extractb(s, "bsoft=", 5, bsize, ssize, &bsoft))
5aead01d 307 mask |= FS_DQ_BSOFT;
1774874a 308 else if (extractb(s, "bhard=", 5, bsize, ssize, &bhard))
5aead01d 309 mask |= FS_DQ_BHARD;
1774874a 310 else if (extracti(s, "isoft=", 5, &isoft))
5aead01d 311 mask |= FS_DQ_ISOFT;
1774874a 312 else if (extracti(s, "ihard=", 5, &ihard))
5aead01d 313 mask |= FS_DQ_IHARD;
1774874a 314 else if (extractb(s, "rtbsoft=", 7, bsize, ssize, &rtbsoft))
5aead01d 315 mask |= FS_DQ_RTBSOFT;
1774874a 316 else if (extractb(s, "rtbhard=", 7, bsize, ssize, &rtbhard))
5aead01d
NS
317 mask |= FS_DQ_RTBHARD;
318 else {
e3210fd8 319 exitcode = 1;
5aead01d
NS
320 fprintf(stderr, _("%s: unrecognised argument %s\n"),
321 progname, s);
322 return 0;
323 }
324 }
325 if (!mask) {
e3210fd8 326 exitcode = 1;
5aead01d
NS
327 fprintf(stderr, _("%s: cannot find any valid arguments\n"),
328 progname);
329 return 0;
330 }
331
332 name = (flags & DEFAULTS_FLAG) ? "0" : argv[optind++];
333
c614d3bf 334 if (!type) {
5aead01d 335 type = XFS_USER_QUOTA;
c614d3bf
ZL
336 } else if (type != XFS_GROUP_QUOTA &&
337 type != XFS_PROJ_QUOTA &&
338 type != XFS_USER_QUOTA) {
339 return command_usage(&limit_cmd);
340 }
5aead01d
NS
341
342 switch (type) {
343 case XFS_USER_QUOTA:
344 set_user_limits(name, type, mask,
345 &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard);
346 break;
347 case XFS_GROUP_QUOTA:
348 set_group_limits(name, type, mask,
349 &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard);
350 break;
351 case XFS_PROJ_QUOTA:
352 set_project_limits(name, type, mask,
353 &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard);
354 break;
355 }
356 return 0;
357}
358
359/*
360 * Iterate through input file, restoring the limits.
361 * File format is as follows:
362 * fs = <device>
363 * <numeric id> bsoft bhard isoft ihard [rtbsoft rtbhard]
364 */
365static void
366restore_file(
367 FILE *fp,
368 uint type)
369{
370 char buffer[512];
371 char devbuffer[512];
372 char *dev = NULL;
373 uint mask;
374 int cnt;
14f8b681
DW
375 uint32_t id;
376 uint64_t bsoft, bhard, isoft, ihard, rtbsoft, rtbhard;
5aead01d
NS
377
378 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
379 if (strncmp("fs = ", buffer, 5) == 0) {
380 dev = strncpy(devbuffer, buffer+5, sizeof(devbuffer));
381 dev[strlen(dev) - 1] = '\0';
382 continue;
383 }
384 rtbsoft = rtbhard = 0;
385 cnt = sscanf(buffer, "%u %llu %llu %llu %llu %llu %llu\n",
386 &id,
7a1525fd
NS
387 (unsigned long long *)&bsoft,
388 (unsigned long long *)&bhard,
389 (unsigned long long *)&isoft,
390 (unsigned long long *)&ihard,
391 (unsigned long long *)&rtbsoft,
392 (unsigned long long *)&rtbhard);
5aead01d
NS
393 if (cnt == 5 || cnt == 7) {
394 mask = FS_DQ_ISOFT|FS_DQ_IHARD|FS_DQ_BSOFT|FS_DQ_BHARD;
395 if (cnt == 7)
396 mask |= FS_DQ_RTBSOFT|FS_DQ_RTBHARD;
397 set_limits(id, type, mask, dev, &bsoft, &bhard,
398 &isoft, &ihard, &rtbsoft, &rtbhard);
399 }
400 }
401}
402
403static int
404restore_f(
405 int argc,
406 char **argv)
407{
408 FILE *fp = stdin;
409 char *fname = NULL;
410 int c, type = 0;
411
412 while ((c = getopt(argc, argv, "f:gpu")) != EOF) {
413 switch (c) {
414 case 'f':
415 fname = optarg;
416 break;
417 case 'g':
c614d3bf 418 type |= XFS_GROUP_QUOTA;
5aead01d
NS
419 break;
420 case 'p':
c614d3bf 421 type |= XFS_PROJ_QUOTA;
5aead01d
NS
422 break;
423 case 'u':
c614d3bf 424 type |= XFS_USER_QUOTA;
5aead01d
NS
425 break;
426 default:
427 return command_usage(&restore_cmd);
428 }
429 }
430
431 if (argc < optind)
432 return command_usage(&restore_cmd);
433
c614d3bf 434 if (!type) {
5aead01d 435 type = XFS_USER_QUOTA;
c614d3bf
ZL
436 } else if (type != XFS_GROUP_QUOTA &&
437 type != XFS_PROJ_QUOTA &&
438 type != XFS_USER_QUOTA) {
439 return command_usage(&restore_cmd);
440 }
5aead01d
NS
441
442 if (fname) {
443 if ((fp = fopen(fname, "r")) == NULL) {
e3210fd8 444 exitcode = 1;
5aead01d
NS
445 fprintf(stderr, _("%s: fopen on %s failed: %s\n"),
446 progname, fname, strerror(errno));
447 return 0;
448 }
449 }
450
451 restore_file(fp, type);
452
453 if (fname)
454 fclose(fp);
455 return 0;
456}
457
458static void
459set_timer(
5aead01d
NS
460 uint type,
461 uint mask,
462 char *dev,
463 uint value)
464{
465 fs_disk_quota_t d;
466
467 memset(&d, 0, sizeof(d));
468 d.d_version = FS_DQUOT_VERSION;
5aead01d
NS
469 d.d_flags = type;
470 d.d_fieldmask = mask;
471 d.d_itimer = value;
472 d.d_btimer = value;
473 d.d_rtbtimer = value;
474
e3210fd8
AM
475 if (xfsquotactl(XFS_SETQLIM, dev, type, 0, (void *)&d) < 0) {
476 exitcode = 1;
5aead01d
NS
477 fprintf(stderr, _("%s: cannot set timer: %s\n"),
478 progname, strerror(errno));
e3210fd8 479 }
5aead01d
NS
480}
481
5aead01d
NS
482static int
483timer_f(
484 int argc,
485 char **argv)
486{
5aead01d 487 uint value;
1774874a 488 int c, type = 0, mask = 0;
5aead01d 489
1774874a 490 while ((c = getopt(argc, argv, "bgipru")) != EOF) {
5aead01d 491 switch (c) {
5aead01d
NS
492 case 'b':
493 mask |= FS_DQ_BTIMER;
494 break;
495 case 'i':
496 mask |= FS_DQ_ITIMER;
497 break;
498 case 'r':
499 mask |= FS_DQ_RTBTIMER;
500 break;
501 case 'g':
c614d3bf 502 type |= XFS_GROUP_QUOTA;
5aead01d
NS
503 break;
504 case 'p':
c614d3bf 505 type |= XFS_PROJ_QUOTA;
5aead01d
NS
506 break;
507 case 'u':
c614d3bf 508 type |= XFS_USER_QUOTA;
5aead01d
NS
509 break;
510 default:
511 return command_usage(&timer_cmd);
512 }
513 }
514
1774874a 515 if (argc != optind + 1)
5aead01d 516 return command_usage(&timer_cmd);
5aead01d
NS
517
518 value = cvttime(argv[optind++]);
5aead01d
NS
519
520 if (!mask)
521 mask = FS_DQ_TIMER_MASK;
522
c614d3bf 523 if (!type) {
5aead01d 524 type = XFS_USER_QUOTA;
c614d3bf
ZL
525 } else if (type != XFS_GROUP_QUOTA &&
526 type != XFS_PROJ_QUOTA &&
527 type != XFS_USER_QUOTA) {
528 return command_usage(&timer_cmd);
529 }
5aead01d 530
1774874a 531 set_timer(type, mask, fs_path->fs_name, value);
5aead01d
NS
532 return 0;
533}
534
535static void
536set_warnings(
14f8b681 537 uint32_t id,
5aead01d
NS
538 uint type,
539 uint mask,
540 char *dev,
541 uint value)
542{
543 fs_disk_quota_t d;
544
545 memset(&d, 0, sizeof(d));
546 d.d_version = FS_DQUOT_VERSION;
547 d.d_id = id;
548 d.d_flags = type;
549 d.d_fieldmask = mask;
550 d.d_iwarns = value;
551 d.d_bwarns = value;
552 d.d_rtbwarns = value;
553
e3210fd8
AM
554 if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
555 exitcode = 1;
5aead01d
NS
556 fprintf(stderr, _("%s: cannot set warnings: %s\n"),
557 progname, strerror(errno));
e3210fd8 558 }
5aead01d
NS
559}
560
561static void
562set_user_warnings(
563 char *name,
564 uint type,
565 uint mask,
566 uint value)
567{
568 uid_t uid = uid_from_string(name);
569
e3210fd8
AM
570 if (uid == -1) {
571 exitcode = 1;
5aead01d
NS
572 fprintf(stderr, _("%s: invalid user name: %s\n"),
573 progname, name);
e3210fd8 574 } else
5aead01d
NS
575 set_warnings(uid, type, mask, fs_path->fs_name, value);
576}
577
578static void
579set_group_warnings(
580 char *name,
581 uint type,
582 uint mask,
583 uint value)
584{
585 gid_t gid = gid_from_string(name);
586
e3210fd8
AM
587 if (gid == -1) {
588 exitcode = 1;
5aead01d
NS
589 fprintf(stderr, _("%s: invalid group name: %s\n"),
590 progname, name);
e3210fd8 591 } else
5aead01d
NS
592 set_warnings(gid, type, mask, fs_path->fs_name, value);
593}
594
595static void
596set_project_warnings(
597 char *name,
598 uint type,
599 uint mask,
600 uint value)
601{
602 prid_t prid = prid_from_string(name);
603
e3210fd8
AM
604 if (prid == -1) {
605 exitcode = 1;
5aead01d
NS
606 fprintf(stderr, _("%s: invalid project name: %s\n"),
607 progname, name);
e3210fd8 608 } else
5aead01d
NS
609 set_warnings(prid, type, mask, fs_path->fs_name, value);
610}
611
612static int
613warn_f(
614 int argc,
615 char **argv)
616{
617 char *name;
618 uint value;
619 int c, flags = 0, type = 0, mask = 0;
620
621 while ((c = getopt(argc, argv, "bdgipru")) != EOF) {
622 switch (c) {
623 case 'd':
624 flags |= DEFAULTS_FLAG;
625 break;
626 case 'b':
627 mask |= FS_DQ_BWARNS;
628 break;
629 case 'i':
630 mask |= FS_DQ_IWARNS;
631 break;
632 case 'r':
633 mask |= FS_DQ_RTBWARNS;
634 break;
635 case 'g':
c614d3bf 636 type |= XFS_GROUP_QUOTA;
5aead01d
NS
637 break;
638 case 'p':
c614d3bf 639 type |= XFS_PROJ_QUOTA;
5aead01d
NS
640 break;
641 case 'u':
c614d3bf 642 type |= XFS_USER_QUOTA;
5aead01d
NS
643 break;
644 default:
645 return command_usage(&warn_cmd);
646 }
647 }
648
649 /*
650 * In the usual case, we need at least 2 more arguments -
651 * one (or more) value and a user name/id.
652 * For setting defaults (-d) we don't want a user name/id.
653 */
654 if (flags & DEFAULTS_FLAG) {
655 if (argc != optind + 1)
656 return command_usage(&warn_cmd);
657 } else if (argc != optind + 2) {
658 return command_usage(&warn_cmd);
659 }
660
661 value = atoi(argv[optind++]);
662 name = (flags & DEFAULTS_FLAG) ? "0" : argv[optind++];
663
664 if (!mask)
665 mask = FS_DQ_WARNS_MASK;
666
c614d3bf 667 if (!type) {
5aead01d 668 type = XFS_USER_QUOTA;
c614d3bf
ZL
669 } else if (type != XFS_GROUP_QUOTA &&
670 type != XFS_PROJ_QUOTA &&
671 type != XFS_USER_QUOTA) {
672 return command_usage(&warn_cmd);
673 }
5aead01d
NS
674
675 switch (type) {
676 case XFS_USER_QUOTA:
677 set_user_warnings(name, type, mask, value);
678 break;
679 case XFS_GROUP_QUOTA:
680 set_group_warnings(name, type, mask, value);
681 break;
682 case XFS_PROJ_QUOTA:
683 set_project_warnings(name, type, mask, value);
684 break;
685 }
686 return 0;
687}
688
689void
690edit_init(void)
691{
ad765595 692 limit_cmd.name = "limit";
5aead01d
NS
693 limit_cmd.cfunc = limit_f;
694 limit_cmd.argmin = 2;
695 limit_cmd.argmax = -1;
696 limit_cmd.args = \
c614d3bf 697 _("[-g|-p|-u] bsoft|bhard|isoft|ihard|rtbsoft|rtbhard=N -d|id|name");
5aead01d
NS
698 limit_cmd.oneline = _("modify quota limits");
699 limit_cmd.help = limit_help;
7e59be67 700 limit_cmd.flags = CMD_FLAG_FOREIGN_OK;
5aead01d 701
ad765595 702 restore_cmd.name = "restore";
5aead01d
NS
703 restore_cmd.cfunc = restore_f;
704 restore_cmd.argmin = 0;
705 restore_cmd.argmax = -1;
c614d3bf 706 restore_cmd.args = _("[-g|-p|-u] [-f file]");
5aead01d 707 restore_cmd.oneline = _("restore quota limits from a backup file");
7e59be67 708 restore_cmd.flags = CMD_FLAG_FOREIGN_OK;
5aead01d 709
ad765595 710 timer_cmd.name = "timer";
5aead01d
NS
711 timer_cmd.cfunc = timer_f;
712 timer_cmd.argmin = 2;
713 timer_cmd.argmax = -1;
c614d3bf 714 timer_cmd.args = _("[-bir] [-g|-p|-u] value");
75f70580 715 timer_cmd.oneline = _("set quota enforcement timeouts");
5aead01d 716 timer_cmd.help = timer_help;
7e59be67 717 timer_cmd.flags = CMD_FLAG_FOREIGN_OK;
5aead01d 718
ad765595 719 warn_cmd.name = "warn";
5aead01d
NS
720 warn_cmd.cfunc = warn_f;
721 warn_cmd.argmin = 2;
722 warn_cmd.argmax = -1;
c614d3bf 723 warn_cmd.args = _("[-bir] [-g|-p|-u] value -d|id|name");
5aead01d
NS
724 warn_cmd.oneline = _("get/set enforcement warning counter");
725 warn_cmd.help = warn_help;
726
727 if (expert) {
728 add_command(&limit_cmd);
729 add_command(&restore_cmd);
730 add_command(&timer_cmd);
731 add_command(&warn_cmd);
732 }
733}