]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - quota/edit.c
xfs: fix maxicount division by zero error
[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];
7f0d0b55 371 char dev[512];
5aead01d
NS
372 uint mask;
373 int cnt;
14f8b681
DW
374 uint32_t id;
375 uint64_t bsoft, bhard, isoft, ihard, rtbsoft, rtbhard;
5aead01d
NS
376
377 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
378 if (strncmp("fs = ", buffer, 5) == 0) {
7f0d0b55
DW
379 /*
380 * Copy the device name to dev, strip off the trailing
381 * newline, and move on to the next line.
382 */
383 strncpy(dev, buffer + 5, sizeof(dev) - 1);
5aead01d
NS
384 dev[strlen(dev) - 1] = '\0';
385 continue;
386 }
387 rtbsoft = rtbhard = 0;
388 cnt = sscanf(buffer, "%u %llu %llu %llu %llu %llu %llu\n",
389 &id,
7a1525fd
NS
390 (unsigned long long *)&bsoft,
391 (unsigned long long *)&bhard,
392 (unsigned long long *)&isoft,
393 (unsigned long long *)&ihard,
394 (unsigned long long *)&rtbsoft,
395 (unsigned long long *)&rtbhard);
5aead01d
NS
396 if (cnt == 5 || cnt == 7) {
397 mask = FS_DQ_ISOFT|FS_DQ_IHARD|FS_DQ_BSOFT|FS_DQ_BHARD;
398 if (cnt == 7)
399 mask |= FS_DQ_RTBSOFT|FS_DQ_RTBHARD;
400 set_limits(id, type, mask, dev, &bsoft, &bhard,
401 &isoft, &ihard, &rtbsoft, &rtbhard);
402 }
403 }
404}
405
406static int
407restore_f(
408 int argc,
409 char **argv)
410{
411 FILE *fp = stdin;
412 char *fname = NULL;
413 int c, type = 0;
414
415 while ((c = getopt(argc, argv, "f:gpu")) != EOF) {
416 switch (c) {
417 case 'f':
418 fname = optarg;
419 break;
420 case 'g':
c614d3bf 421 type |= XFS_GROUP_QUOTA;
5aead01d
NS
422 break;
423 case 'p':
c614d3bf 424 type |= XFS_PROJ_QUOTA;
5aead01d
NS
425 break;
426 case 'u':
c614d3bf 427 type |= XFS_USER_QUOTA;
5aead01d
NS
428 break;
429 default:
430 return command_usage(&restore_cmd);
431 }
432 }
433
434 if (argc < optind)
435 return command_usage(&restore_cmd);
436
c614d3bf 437 if (!type) {
5aead01d 438 type = XFS_USER_QUOTA;
c614d3bf
ZL
439 } else if (type != XFS_GROUP_QUOTA &&
440 type != XFS_PROJ_QUOTA &&
441 type != XFS_USER_QUOTA) {
442 return command_usage(&restore_cmd);
443 }
5aead01d
NS
444
445 if (fname) {
446 if ((fp = fopen(fname, "r")) == NULL) {
e3210fd8 447 exitcode = 1;
5aead01d
NS
448 fprintf(stderr, _("%s: fopen on %s failed: %s\n"),
449 progname, fname, strerror(errno));
450 return 0;
451 }
452 }
453
454 restore_file(fp, type);
455
456 if (fname)
457 fclose(fp);
458 return 0;
459}
460
461static void
462set_timer(
5aead01d
NS
463 uint type,
464 uint mask,
465 char *dev,
466 uint value)
467{
468 fs_disk_quota_t d;
469
470 memset(&d, 0, sizeof(d));
471 d.d_version = FS_DQUOT_VERSION;
5aead01d
NS
472 d.d_flags = type;
473 d.d_fieldmask = mask;
474 d.d_itimer = value;
475 d.d_btimer = value;
476 d.d_rtbtimer = value;
477
e3210fd8
AM
478 if (xfsquotactl(XFS_SETQLIM, dev, type, 0, (void *)&d) < 0) {
479 exitcode = 1;
5aead01d
NS
480 fprintf(stderr, _("%s: cannot set timer: %s\n"),
481 progname, strerror(errno));
e3210fd8 482 }
5aead01d
NS
483}
484
5aead01d
NS
485static int
486timer_f(
487 int argc,
488 char **argv)
489{
5aead01d 490 uint value;
1774874a 491 int c, type = 0, mask = 0;
5aead01d 492
1774874a 493 while ((c = getopt(argc, argv, "bgipru")) != EOF) {
5aead01d 494 switch (c) {
5aead01d
NS
495 case 'b':
496 mask |= FS_DQ_BTIMER;
497 break;
498 case 'i':
499 mask |= FS_DQ_ITIMER;
500 break;
501 case 'r':
502 mask |= FS_DQ_RTBTIMER;
503 break;
504 case 'g':
c614d3bf 505 type |= XFS_GROUP_QUOTA;
5aead01d
NS
506 break;
507 case 'p':
c614d3bf 508 type |= XFS_PROJ_QUOTA;
5aead01d
NS
509 break;
510 case 'u':
c614d3bf 511 type |= XFS_USER_QUOTA;
5aead01d
NS
512 break;
513 default:
514 return command_usage(&timer_cmd);
515 }
516 }
517
1774874a 518 if (argc != optind + 1)
5aead01d 519 return command_usage(&timer_cmd);
5aead01d
NS
520
521 value = cvttime(argv[optind++]);
5aead01d
NS
522
523 if (!mask)
524 mask = FS_DQ_TIMER_MASK;
525
c614d3bf 526 if (!type) {
5aead01d 527 type = XFS_USER_QUOTA;
c614d3bf
ZL
528 } else if (type != XFS_GROUP_QUOTA &&
529 type != XFS_PROJ_QUOTA &&
530 type != XFS_USER_QUOTA) {
531 return command_usage(&timer_cmd);
532 }
5aead01d 533
1774874a 534 set_timer(type, mask, fs_path->fs_name, value);
5aead01d
NS
535 return 0;
536}
537
538static void
539set_warnings(
14f8b681 540 uint32_t id,
5aead01d
NS
541 uint type,
542 uint mask,
543 char *dev,
544 uint value)
545{
546 fs_disk_quota_t d;
547
548 memset(&d, 0, sizeof(d));
549 d.d_version = FS_DQUOT_VERSION;
550 d.d_id = id;
551 d.d_flags = type;
552 d.d_fieldmask = mask;
553 d.d_iwarns = value;
554 d.d_bwarns = value;
555 d.d_rtbwarns = value;
556
e3210fd8
AM
557 if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
558 exitcode = 1;
5aead01d
NS
559 fprintf(stderr, _("%s: cannot set warnings: %s\n"),
560 progname, strerror(errno));
e3210fd8 561 }
5aead01d
NS
562}
563
564static void
565set_user_warnings(
566 char *name,
567 uint type,
568 uint mask,
569 uint value)
570{
571 uid_t uid = uid_from_string(name);
572
e3210fd8
AM
573 if (uid == -1) {
574 exitcode = 1;
5aead01d
NS
575 fprintf(stderr, _("%s: invalid user name: %s\n"),
576 progname, name);
e3210fd8 577 } else
5aead01d
NS
578 set_warnings(uid, type, mask, fs_path->fs_name, value);
579}
580
581static void
582set_group_warnings(
583 char *name,
584 uint type,
585 uint mask,
586 uint value)
587{
588 gid_t gid = gid_from_string(name);
589
e3210fd8
AM
590 if (gid == -1) {
591 exitcode = 1;
5aead01d
NS
592 fprintf(stderr, _("%s: invalid group name: %s\n"),
593 progname, name);
e3210fd8 594 } else
5aead01d
NS
595 set_warnings(gid, type, mask, fs_path->fs_name, value);
596}
597
598static void
599set_project_warnings(
600 char *name,
601 uint type,
602 uint mask,
603 uint value)
604{
605 prid_t prid = prid_from_string(name);
606
e3210fd8
AM
607 if (prid == -1) {
608 exitcode = 1;
5aead01d
NS
609 fprintf(stderr, _("%s: invalid project name: %s\n"),
610 progname, name);
e3210fd8 611 } else
5aead01d
NS
612 set_warnings(prid, type, mask, fs_path->fs_name, value);
613}
614
615static int
616warn_f(
617 int argc,
618 char **argv)
619{
620 char *name;
621 uint value;
622 int c, flags = 0, type = 0, mask = 0;
623
624 while ((c = getopt(argc, argv, "bdgipru")) != EOF) {
625 switch (c) {
626 case 'd':
627 flags |= DEFAULTS_FLAG;
628 break;
629 case 'b':
630 mask |= FS_DQ_BWARNS;
631 break;
632 case 'i':
633 mask |= FS_DQ_IWARNS;
634 break;
635 case 'r':
636 mask |= FS_DQ_RTBWARNS;
637 break;
638 case 'g':
c614d3bf 639 type |= XFS_GROUP_QUOTA;
5aead01d
NS
640 break;
641 case 'p':
c614d3bf 642 type |= XFS_PROJ_QUOTA;
5aead01d
NS
643 break;
644 case 'u':
c614d3bf 645 type |= XFS_USER_QUOTA;
5aead01d
NS
646 break;
647 default:
648 return command_usage(&warn_cmd);
649 }
650 }
651
652 /*
653 * In the usual case, we need at least 2 more arguments -
654 * one (or more) value and a user name/id.
655 * For setting defaults (-d) we don't want a user name/id.
656 */
657 if (flags & DEFAULTS_FLAG) {
658 if (argc != optind + 1)
659 return command_usage(&warn_cmd);
660 } else if (argc != optind + 2) {
661 return command_usage(&warn_cmd);
662 }
663
664 value = atoi(argv[optind++]);
665 name = (flags & DEFAULTS_FLAG) ? "0" : argv[optind++];
666
667 if (!mask)
668 mask = FS_DQ_WARNS_MASK;
669
c614d3bf 670 if (!type) {
5aead01d 671 type = XFS_USER_QUOTA;
c614d3bf
ZL
672 } else if (type != XFS_GROUP_QUOTA &&
673 type != XFS_PROJ_QUOTA &&
674 type != XFS_USER_QUOTA) {
675 return command_usage(&warn_cmd);
676 }
5aead01d
NS
677
678 switch (type) {
679 case XFS_USER_QUOTA:
680 set_user_warnings(name, type, mask, value);
681 break;
682 case XFS_GROUP_QUOTA:
683 set_group_warnings(name, type, mask, value);
684 break;
685 case XFS_PROJ_QUOTA:
686 set_project_warnings(name, type, mask, value);
687 break;
688 }
689 return 0;
690}
691
692void
693edit_init(void)
694{
ad765595 695 limit_cmd.name = "limit";
5aead01d
NS
696 limit_cmd.cfunc = limit_f;
697 limit_cmd.argmin = 2;
698 limit_cmd.argmax = -1;
699 limit_cmd.args = \
c614d3bf 700 _("[-g|-p|-u] bsoft|bhard|isoft|ihard|rtbsoft|rtbhard=N -d|id|name");
5aead01d
NS
701 limit_cmd.oneline = _("modify quota limits");
702 limit_cmd.help = limit_help;
7e59be67 703 limit_cmd.flags = CMD_FLAG_FOREIGN_OK;
5aead01d 704
ad765595 705 restore_cmd.name = "restore";
5aead01d
NS
706 restore_cmd.cfunc = restore_f;
707 restore_cmd.argmin = 0;
708 restore_cmd.argmax = -1;
c614d3bf 709 restore_cmd.args = _("[-g|-p|-u] [-f file]");
5aead01d 710 restore_cmd.oneline = _("restore quota limits from a backup file");
7e59be67 711 restore_cmd.flags = CMD_FLAG_FOREIGN_OK;
5aead01d 712
ad765595 713 timer_cmd.name = "timer";
5aead01d
NS
714 timer_cmd.cfunc = timer_f;
715 timer_cmd.argmin = 2;
716 timer_cmd.argmax = -1;
c614d3bf 717 timer_cmd.args = _("[-bir] [-g|-p|-u] value");
75f70580 718 timer_cmd.oneline = _("set quota enforcement timeouts");
5aead01d 719 timer_cmd.help = timer_help;
7e59be67 720 timer_cmd.flags = CMD_FLAG_FOREIGN_OK;
5aead01d 721
ad765595 722 warn_cmd.name = "warn";
5aead01d
NS
723 warn_cmd.cfunc = warn_f;
724 warn_cmd.argmin = 2;
725 warn_cmd.argmax = -1;
c614d3bf 726 warn_cmd.args = _("[-bir] [-g|-p|-u] value -d|id|name");
5aead01d
NS
727 warn_cmd.oneline = _("get/set enforcement warning counter");
728 warn_cmd.help = warn_help;
729
730 if (expert) {
731 add_command(&limit_cmd);
732 add_command(&restore_cmd);
733 add_command(&timer_cmd);
734 add_command(&warn_cmd);
735 }
736}