]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - quota/edit.c
xfs_quota: fix unsigned int id comparisons
[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
67a73d61
ES
104static uint32_t
105id_from_string(
106 char *name,
107 int type)
108{
109 uint32_t id = -1;
110 const char *type_name = "unknown type";
111
112 switch (type) {
113 case XFS_USER_QUOTA:
114 type_name = "user";
115 id = uid_from_string(name);
116 break;
117 case XFS_GROUP_QUOTA:
118 type_name = "group";
119 id = gid_from_string(name);
120 break;
121 case XFS_PROJ_QUOTA:
122 type_name = "project";
123 id = prid_from_string(name);
124 break;
125 default:
126 ASSERT(0);
127 break;
128 }
129
130 if (id == -1) {
131 fprintf(stderr, _("%s: invalid %s name: %s\n"),
132 type_name, progname, name);
133 exitcode = 1;
134 }
135 return id;
136}
137
5aead01d
NS
138static void
139set_limits(
14f8b681 140 uint32_t id,
5aead01d
NS
141 uint type,
142 uint mask,
143 char *dev,
14f8b681
DW
144 uint64_t *bsoft,
145 uint64_t *bhard,
146 uint64_t *isoft,
147 uint64_t *ihard,
148 uint64_t *rtbsoft,
149 uint64_t *rtbhard)
5aead01d
NS
150{
151 fs_disk_quota_t d;
152
153 memset(&d, 0, sizeof(d));
154 d.d_version = FS_DQUOT_VERSION;
155 d.d_id = id;
156 d.d_flags = type;
157 d.d_fieldmask = mask;
158 d.d_blk_hardlimit = *bhard;
159 d.d_blk_softlimit = *bsoft;
160 d.d_ino_hardlimit = *ihard;
161 d.d_ino_softlimit = *isoft;
162 d.d_rtb_hardlimit = *rtbhard;
163 d.d_rtb_softlimit = *rtbsoft;
164
e3210fd8
AM
165 if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
166 exitcode = 1;
5aead01d
NS
167 fprintf(stderr, _("%s: cannot set limits: %s\n"),
168 progname, strerror(errno));
e3210fd8 169 }
5aead01d
NS
170}
171
1774874a 172/* extract number of blocks from an ascii string */
5aead01d 173static int
1774874a 174extractb(
5aead01d
NS
175 char *string,
176 const char *prefix,
177 int length,
178 uint blocksize,
179 uint sectorsize,
14f8b681 180 uint64_t *value)
5aead01d 181{
7fd39587 182 long long v;
5aead01d
NS
183 char *s = string;
184
185 if (strncmp(string, prefix, length) == 0) {
186 s = string + length + 1;
7fd39587
ES
187 v = cvtnum(blocksize, sectorsize, s);
188 if (v == -1LL) {
189 fprintf(stderr,
190 _("%s: Error: could not parse size %s.\n"),
191 progname, s);
192 return 0;
193 }
14f8b681 194 *value = (uint64_t)v >> 9; /* syscalls use basic blocks */
39d09609
AM
195 if (v > 0 && *value == 0)
196 fprintf(stderr, _("%s: Warning: `%s' in quota blocks is 0 (unlimited).\n"), progname, s);
5aead01d
NS
197 return 1;
198 }
199 return 0;
200}
201
1774874a
NS
202/* extract number of inodes from an ascii string */
203static int
204extracti(
205 char *string,
206 const char *prefix,
207 int length,
14f8b681 208 uint64_t *value)
1774874a
NS
209{
210 char *sp, *s = string;
211
212 if (strncmp(string, prefix, length) == 0) {
213 s = string + length + 1;
214 *value = strtoll(s, &sp, 0);
215 return 1;
216 }
217 return 0;
218}
219
5aead01d
NS
220static int
221limit_f(
222 int argc,
223 char **argv)
224{
225 char *name;
67a73d61 226 uint32_t id;
14f8b681 227 uint64_t bsoft, bhard, isoft, ihard, rtbsoft, rtbhard;
5aead01d
NS
228 int c, type = 0, mask = 0, flags = 0;
229 uint bsize, ssize, endoptions;
230
231 init_cvtnum(&bsize, &ssize);
232 bsoft = bhard = isoft = ihard = rtbsoft = rtbhard = 0;
233 while ((c = getopt(argc, argv, "dgpu")) != EOF) {
234 switch (c) {
235 case 'd':
236 flags |= DEFAULTS_FLAG;
237 break;
238 case 'g':
c614d3bf 239 type |= XFS_GROUP_QUOTA;
5aead01d
NS
240 break;
241 case 'p':
c614d3bf 242 type |= XFS_PROJ_QUOTA;
5aead01d
NS
243 break;
244 case 'u':
c614d3bf 245 type |= XFS_USER_QUOTA;
5aead01d
NS
246 break;
247 default:
248 return command_usage(&limit_cmd);
249 }
250 }
251
252 /*
253 * In the usual case, we need at least 2 more arguments -
254 * one (or more) limits and a user name/id.
255 * For setting defaults (-d) we don't want a user name/id.
256 */
257 if (flags & DEFAULTS_FLAG) {
258 if (argc < optind + 1)
259 return command_usage(&limit_cmd);
260 endoptions = 1;
261 } else if (argc < optind + 2) {
262 return command_usage(&limit_cmd);
263 } else {
264 endoptions = 2;
265 }
266
267 /*
268 * Extract limit values from remaining optional arguments.
269 */
270 while (argc > optind + endoptions - 1) {
271 char *s = argv[optind++];
1774874a 272 if (extractb(s, "bsoft=", 5, bsize, ssize, &bsoft))
5aead01d 273 mask |= FS_DQ_BSOFT;
1774874a 274 else if (extractb(s, "bhard=", 5, bsize, ssize, &bhard))
5aead01d 275 mask |= FS_DQ_BHARD;
1774874a 276 else if (extracti(s, "isoft=", 5, &isoft))
5aead01d 277 mask |= FS_DQ_ISOFT;
1774874a 278 else if (extracti(s, "ihard=", 5, &ihard))
5aead01d 279 mask |= FS_DQ_IHARD;
1774874a 280 else if (extractb(s, "rtbsoft=", 7, bsize, ssize, &rtbsoft))
5aead01d 281 mask |= FS_DQ_RTBSOFT;
1774874a 282 else if (extractb(s, "rtbhard=", 7, bsize, ssize, &rtbhard))
5aead01d
NS
283 mask |= FS_DQ_RTBHARD;
284 else {
e3210fd8 285 exitcode = 1;
5aead01d
NS
286 fprintf(stderr, _("%s: unrecognised argument %s\n"),
287 progname, s);
288 return 0;
289 }
290 }
291 if (!mask) {
e3210fd8 292 exitcode = 1;
5aead01d
NS
293 fprintf(stderr, _("%s: cannot find any valid arguments\n"),
294 progname);
295 return 0;
296 }
297
298 name = (flags & DEFAULTS_FLAG) ? "0" : argv[optind++];
299
c614d3bf 300 if (!type) {
5aead01d 301 type = XFS_USER_QUOTA;
c614d3bf
ZL
302 } else if (type != XFS_GROUP_QUOTA &&
303 type != XFS_PROJ_QUOTA &&
304 type != XFS_USER_QUOTA) {
305 return command_usage(&limit_cmd);
306 }
5aead01d 307
67a73d61
ES
308
309 id = id_from_string(name, type);
eaa5b0b7
DW
310 if (id == -1)
311 return 0;
312
313 set_limits(id, type, mask, fs_path->fs_name,
314 &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard);
5aead01d
NS
315 return 0;
316}
317
318/*
319 * Iterate through input file, restoring the limits.
320 * File format is as follows:
321 * fs = <device>
322 * <numeric id> bsoft bhard isoft ihard [rtbsoft rtbhard]
323 */
324static void
325restore_file(
326 FILE *fp,
327 uint type)
328{
329 char buffer[512];
7f0d0b55 330 char dev[512];
5aead01d
NS
331 uint mask;
332 int cnt;
14f8b681
DW
333 uint32_t id;
334 uint64_t bsoft, bhard, isoft, ihard, rtbsoft, rtbhard;
5aead01d
NS
335
336 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
337 if (strncmp("fs = ", buffer, 5) == 0) {
7f0d0b55
DW
338 /*
339 * Copy the device name to dev, strip off the trailing
340 * newline, and move on to the next line.
341 */
342 strncpy(dev, buffer + 5, sizeof(dev) - 1);
5aead01d
NS
343 dev[strlen(dev) - 1] = '\0';
344 continue;
345 }
346 rtbsoft = rtbhard = 0;
347 cnt = sscanf(buffer, "%u %llu %llu %llu %llu %llu %llu\n",
348 &id,
7a1525fd
NS
349 (unsigned long long *)&bsoft,
350 (unsigned long long *)&bhard,
351 (unsigned long long *)&isoft,
352 (unsigned long long *)&ihard,
353 (unsigned long long *)&rtbsoft,
354 (unsigned long long *)&rtbhard);
5aead01d
NS
355 if (cnt == 5 || cnt == 7) {
356 mask = FS_DQ_ISOFT|FS_DQ_IHARD|FS_DQ_BSOFT|FS_DQ_BHARD;
357 if (cnt == 7)
358 mask |= FS_DQ_RTBSOFT|FS_DQ_RTBHARD;
359 set_limits(id, type, mask, dev, &bsoft, &bhard,
360 &isoft, &ihard, &rtbsoft, &rtbhard);
361 }
362 }
363}
364
365static int
366restore_f(
367 int argc,
368 char **argv)
369{
370 FILE *fp = stdin;
371 char *fname = NULL;
372 int c, type = 0;
373
374 while ((c = getopt(argc, argv, "f:gpu")) != EOF) {
375 switch (c) {
376 case 'f':
377 fname = optarg;
378 break;
379 case 'g':
c614d3bf 380 type |= XFS_GROUP_QUOTA;
5aead01d
NS
381 break;
382 case 'p':
c614d3bf 383 type |= XFS_PROJ_QUOTA;
5aead01d
NS
384 break;
385 case 'u':
c614d3bf 386 type |= XFS_USER_QUOTA;
5aead01d
NS
387 break;
388 default:
389 return command_usage(&restore_cmd);
390 }
391 }
392
393 if (argc < optind)
394 return command_usage(&restore_cmd);
395
c614d3bf 396 if (!type) {
5aead01d 397 type = XFS_USER_QUOTA;
c614d3bf
ZL
398 } else if (type != XFS_GROUP_QUOTA &&
399 type != XFS_PROJ_QUOTA &&
400 type != XFS_USER_QUOTA) {
401 return command_usage(&restore_cmd);
402 }
5aead01d
NS
403
404 if (fname) {
405 if ((fp = fopen(fname, "r")) == NULL) {
e3210fd8 406 exitcode = 1;
5aead01d
NS
407 fprintf(stderr, _("%s: fopen on %s failed: %s\n"),
408 progname, fname, strerror(errno));
409 return 0;
410 }
411 }
412
413 restore_file(fp, type);
414
415 if (fname)
416 fclose(fp);
417 return 0;
418}
419
420static void
421set_timer(
36dc471c 422 uint32_t id,
5aead01d
NS
423 uint type,
424 uint mask,
425 char *dev,
426 uint value)
427{
428 fs_disk_quota_t d;
429
430 memset(&d, 0, sizeof(d));
36dc471c
ES
431
432 /*
433 * If id is specified we are extending grace time by value
434 * Otherwise we are setting the default grace time
435 */
436 if (id) {
437 time_t now;
438
439 /* Get quota to find out whether user is past soft limits */
440 if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0) {
441 exitcode = 1;
442 fprintf(stderr, _("%s: cannot get quota: %s\n"),
443 progname, strerror(errno));
444 return;
445 }
446
447 time(&now);
448
449 /* Only set grace time if user is already past soft limit */
450 if (d.d_blk_softlimit && d.d_bcount > d.d_blk_softlimit)
451 d.d_btimer = now + value;
452 if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
453 d.d_itimer = now + value;
454 if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
455 d.d_rtbtimer = now + value;
456 } else {
457 d.d_btimer = value;
458 d.d_itimer = value;
459 d.d_rtbtimer = value;
460 }
461
5aead01d 462 d.d_version = FS_DQUOT_VERSION;
5aead01d
NS
463 d.d_flags = type;
464 d.d_fieldmask = mask;
36dc471c 465 d.d_id = id;
5aead01d 466
36dc471c 467 if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
e3210fd8 468 exitcode = 1;
5aead01d
NS
469 fprintf(stderr, _("%s: cannot set timer: %s\n"),
470 progname, strerror(errno));
e3210fd8 471 }
5aead01d
NS
472}
473
5aead01d
NS
474static int
475timer_f(
476 int argc,
477 char **argv)
478{
5aead01d 479 uint value;
36dc471c
ES
480 char *name = NULL;
481 uint32_t id = 0;
482 int c, flags = 0, type = 0, mask = 0;
5aead01d 483
36dc471c 484 while ((c = getopt(argc, argv, "bdgipru")) != EOF) {
5aead01d 485 switch (c) {
36dc471c
ES
486 case 'd':
487 flags |= DEFAULTS_FLAG;
488 break;
5aead01d
NS
489 case 'b':
490 mask |= FS_DQ_BTIMER;
491 break;
492 case 'i':
493 mask |= FS_DQ_ITIMER;
494 break;
495 case 'r':
496 mask |= FS_DQ_RTBTIMER;
497 break;
498 case 'g':
c614d3bf 499 type |= XFS_GROUP_QUOTA;
5aead01d
NS
500 break;
501 case 'p':
c614d3bf 502 type |= XFS_PROJ_QUOTA;
5aead01d
NS
503 break;
504 case 'u':
c614d3bf 505 type |= XFS_USER_QUOTA;
5aead01d
NS
506 break;
507 default:
508 return command_usage(&timer_cmd);
509 }
510 }
511
36dc471c
ES
512 /*
513 * Older versions of the command did not accept -d|id|name,
514 * so in that case we assume we're setting default timer,
515 * and the last arg is the timer value.
516 *
517 * Otherwise, if the defaults flag is set, we expect 1 more arg for
518 * timer value ; if not, 2 more args: 1 for value, one for id/name.
519 */
520 if (!(flags & DEFAULTS_FLAG) && (argc == optind + 1)) {
521 value = cvttime(argv[optind++]);
522 } else if (flags & DEFAULTS_FLAG) {
523 if (argc != optind + 1)
524 return command_usage(&timer_cmd);
525 value = cvttime(argv[optind++]);
526 } else if (argc == optind + 2) {
527 value = cvttime(argv[optind++]);
528 name = (flags & DEFAULTS_FLAG) ? "0" : argv[optind++];
529 } else
5aead01d 530 return command_usage(&timer_cmd);
5aead01d 531
5aead01d 532
36dc471c 533 /* if none of -bir specified, set them all */
5aead01d
NS
534 if (!mask)
535 mask = FS_DQ_TIMER_MASK;
536
c614d3bf 537 if (!type) {
5aead01d 538 type = XFS_USER_QUOTA;
c614d3bf 539 } else if (type != XFS_GROUP_QUOTA &&
36dc471c
ES
540 type != XFS_PROJ_QUOTA &&
541 type != XFS_USER_QUOTA) {
c614d3bf
ZL
542 return command_usage(&timer_cmd);
543 }
5aead01d 544
36dc471c
ES
545 if (name)
546 id = id_from_string(name, type);
547
eaa5b0b7
DW
548 if (id == -1)
549 return 0;
36dc471c 550
eaa5b0b7 551 set_timer(id, type, mask, fs_path->fs_name, value);
5aead01d
NS
552 return 0;
553}
554
555static void
556set_warnings(
14f8b681 557 uint32_t id,
5aead01d
NS
558 uint type,
559 uint mask,
560 char *dev,
561 uint value)
562{
563 fs_disk_quota_t d;
564
565 memset(&d, 0, sizeof(d));
566 d.d_version = FS_DQUOT_VERSION;
567 d.d_id = id;
568 d.d_flags = type;
569 d.d_fieldmask = mask;
570 d.d_iwarns = value;
571 d.d_bwarns = value;
572 d.d_rtbwarns = value;
573
e3210fd8
AM
574 if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
575 exitcode = 1;
5aead01d
NS
576 fprintf(stderr, _("%s: cannot set warnings: %s\n"),
577 progname, strerror(errno));
e3210fd8 578 }
5aead01d
NS
579}
580
5aead01d
NS
581static int
582warn_f(
583 int argc,
584 char **argv)
585{
586 char *name;
67a73d61 587 uint32_t id;
5aead01d
NS
588 uint value;
589 int c, flags = 0, type = 0, mask = 0;
590
591 while ((c = getopt(argc, argv, "bdgipru")) != EOF) {
592 switch (c) {
593 case 'd':
594 flags |= DEFAULTS_FLAG;
595 break;
596 case 'b':
597 mask |= FS_DQ_BWARNS;
598 break;
599 case 'i':
600 mask |= FS_DQ_IWARNS;
601 break;
602 case 'r':
603 mask |= FS_DQ_RTBWARNS;
604 break;
605 case 'g':
c614d3bf 606 type |= XFS_GROUP_QUOTA;
5aead01d
NS
607 break;
608 case 'p':
c614d3bf 609 type |= XFS_PROJ_QUOTA;
5aead01d
NS
610 break;
611 case 'u':
c614d3bf 612 type |= XFS_USER_QUOTA;
5aead01d
NS
613 break;
614 default:
615 return command_usage(&warn_cmd);
616 }
617 }
618
619 /*
620 * In the usual case, we need at least 2 more arguments -
621 * one (or more) value and a user name/id.
622 * For setting defaults (-d) we don't want a user name/id.
623 */
624 if (flags & DEFAULTS_FLAG) {
625 if (argc != optind + 1)
626 return command_usage(&warn_cmd);
627 } else if (argc != optind + 2) {
628 return command_usage(&warn_cmd);
629 }
630
631 value = atoi(argv[optind++]);
632 name = (flags & DEFAULTS_FLAG) ? "0" : argv[optind++];
633
634 if (!mask)
635 mask = FS_DQ_WARNS_MASK;
636
c614d3bf 637 if (!type) {
5aead01d 638 type = XFS_USER_QUOTA;
c614d3bf
ZL
639 } else if (type != XFS_GROUP_QUOTA &&
640 type != XFS_PROJ_QUOTA &&
641 type != XFS_USER_QUOTA) {
642 return command_usage(&warn_cmd);
643 }
5aead01d 644
67a73d61 645 id = id_from_string(name, type);
eaa5b0b7
DW
646 if (id == -1)
647 return 0;
67a73d61 648
eaa5b0b7 649 set_warnings(id, type, mask, fs_path->fs_name, value);
5aead01d
NS
650 return 0;
651}
652
653void
654edit_init(void)
655{
ad765595 656 limit_cmd.name = "limit";
5aead01d
NS
657 limit_cmd.cfunc = limit_f;
658 limit_cmd.argmin = 2;
659 limit_cmd.argmax = -1;
660 limit_cmd.args = \
c614d3bf 661 _("[-g|-p|-u] bsoft|bhard|isoft|ihard|rtbsoft|rtbhard=N -d|id|name");
5aead01d
NS
662 limit_cmd.oneline = _("modify quota limits");
663 limit_cmd.help = limit_help;
7e59be67 664 limit_cmd.flags = CMD_FLAG_FOREIGN_OK;
5aead01d 665
ad765595 666 restore_cmd.name = "restore";
5aead01d
NS
667 restore_cmd.cfunc = restore_f;
668 restore_cmd.argmin = 0;
669 restore_cmd.argmax = -1;
c614d3bf 670 restore_cmd.args = _("[-g|-p|-u] [-f file]");
5aead01d 671 restore_cmd.oneline = _("restore quota limits from a backup file");
7e59be67 672 restore_cmd.flags = CMD_FLAG_FOREIGN_OK;
5aead01d 673
ad765595 674 timer_cmd.name = "timer";
5aead01d 675 timer_cmd.cfunc = timer_f;
36dc471c 676 timer_cmd.argmin = 1;
5aead01d 677 timer_cmd.argmax = -1;
36dc471c 678 timer_cmd.args = _("[-bir] [-g|-p|-u] value [-d|id|name]");
75f70580 679 timer_cmd.oneline = _("set quota enforcement timeouts");
5aead01d 680 timer_cmd.help = timer_help;
7e59be67 681 timer_cmd.flags = CMD_FLAG_FOREIGN_OK;
5aead01d 682
ad765595 683 warn_cmd.name = "warn";
5aead01d
NS
684 warn_cmd.cfunc = warn_f;
685 warn_cmd.argmin = 2;
686 warn_cmd.argmax = -1;
c614d3bf 687 warn_cmd.args = _("[-bir] [-g|-p|-u] value -d|id|name");
5aead01d
NS
688 warn_cmd.oneline = _("get/set enforcement warning counter");
689 warn_cmd.help = warn_help;
690
691 if (expert) {
692 add_command(&limit_cmd);
693 add_command(&restore_cmd);
694 add_command(&timer_cmd);
695 add_command(&warn_cmd);
696 }
697}