aboutsummaryrefslogtreecommitdiff
path: root/shell/shell_common.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2019-04-27 21:01:35 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2019-04-27 21:01:35 +0200
commita4d76ea1373a7cf06d3d0a3c8905646638e97a13 (patch)
tree3db6c879b4fa44cbc4d87b7a4062ee386c511266 /shell/shell_common.c
parent100fa20c68564311cef8f625bcb1b423e96c97d6 (diff)
downloadbusybox-w32-a4d76ea1373a7cf06d3d0a3c8905646638e97a13.tar.gz
busybox-w32-a4d76ea1373a7cf06d3d0a3c8905646638e97a13.tar.bz2
busybox-w32-a4d76ea1373a7cf06d3d0a3c8905646638e97a13.zip
ash,hush: fix ulimit to be more bash-compat, closes 11791
function old new delta shell_builtin_ulimit 486 651 +165 limit_chars - 14 +14 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/0 up/down: 179/0) Total: 179 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to '')
-rw-r--r--shell/shell_common.c265
1 files changed, 181 insertions, 84 deletions
diff --git a/shell/shell_common.c b/shell/shell_common.c
index f2bf5ab65..686c18f54 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -335,62 +335,93 @@ shell_builtin_read(struct builtin_read_params *params)
335struct limits { 335struct limits {
336 uint8_t cmd; /* RLIMIT_xxx fit into it */ 336 uint8_t cmd; /* RLIMIT_xxx fit into it */
337 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ 337 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
338 char option;
339 const char *name; 338 const char *name;
340}; 339};
341 340
342static const struct limits limits_tbl[] = { 341static const struct limits limits_tbl[] = {
343#ifdef RLIMIT_FSIZE 342/* No RLIMIT_FSIZE define guard since -f is the default limit and this must exist */
344 { RLIMIT_FSIZE, 9, 'f', "file size (blocks)" }, 343 { RLIMIT_FSIZE, 9, "file size (blocks)" }, // -f
345#endif
346#ifdef RLIMIT_CPU 344#ifdef RLIMIT_CPU
347 { RLIMIT_CPU, 0, 't', "cpu time (seconds)" }, 345 { RLIMIT_CPU, 0, "cpu time (seconds)" }, // -t
348#endif 346#endif
349#ifdef RLIMIT_DATA 347#ifdef RLIMIT_DATA
350 { RLIMIT_DATA, 10, 'd', "data seg size (kb)" }, 348 { RLIMIT_DATA, 10, "data seg size (kb)" }, // -d
351#endif 349#endif
352#ifdef RLIMIT_STACK 350#ifdef RLIMIT_STACK
353 { RLIMIT_STACK, 10, 's', "stack size (kb)" }, 351 { RLIMIT_STACK, 10, "stack size (kb)" }, // -s
354#endif 352#endif
355#ifdef RLIMIT_CORE 353#ifdef RLIMIT_CORE
356 { RLIMIT_CORE, 9, 'c', "core file size (blocks)" }, 354 { RLIMIT_CORE, 9, "core file size (blocks)" }, // -c
357#endif 355#endif
358#ifdef RLIMIT_RSS 356#ifdef RLIMIT_RSS
359 { RLIMIT_RSS, 10, 'm', "resident set size (kb)" }, 357 { RLIMIT_RSS, 10, "resident set size (kb)" }, // -m
360#endif 358#endif
361#ifdef RLIMIT_MEMLOCK 359#ifdef RLIMIT_MEMLOCK
362 { RLIMIT_MEMLOCK, 10, 'l', "locked memory (kb)" }, 360 { RLIMIT_MEMLOCK, 10, "locked memory (kb)" }, // -l
363#endif 361#endif
364#ifdef RLIMIT_NPROC 362#ifdef RLIMIT_NPROC
365 { RLIMIT_NPROC, 0, 'p', "processes" }, 363 { RLIMIT_NPROC, 0, "processes" }, // -p
366#endif 364#endif
367#ifdef RLIMIT_NOFILE 365#ifdef RLIMIT_NOFILE
368 { RLIMIT_NOFILE, 0, 'n', "file descriptors" }, 366 { RLIMIT_NOFILE, 0, "file descriptors" }, // -n
369#endif 367#endif
370#ifdef RLIMIT_AS 368#ifdef RLIMIT_AS
371 { RLIMIT_AS, 10, 'v', "address space (kb)" }, 369 { RLIMIT_AS, 10, "address space (kb)" }, // -v
372#endif 370#endif
373#ifdef RLIMIT_LOCKS 371#ifdef RLIMIT_LOCKS
374 { RLIMIT_LOCKS, 0, 'w', "locks" }, 372 { RLIMIT_LOCKS, 0, "locks" }, // -w
375#endif 373#endif
376#ifdef RLIMIT_NICE 374#ifdef RLIMIT_NICE
377 { RLIMIT_NICE, 0, 'e', "scheduling priority" }, 375 { RLIMIT_NICE, 0, "scheduling priority" }, // -e
378#endif 376#endif
379#ifdef RLIMIT_RTPRIO 377#ifdef RLIMIT_RTPRIO
380 { RLIMIT_RTPRIO, 0, 'r', "real-time priority" }, 378 { RLIMIT_RTPRIO, 0, "real-time priority" }, // -r
381#endif 379#endif
382}; 380};
383 381
384enum { 382static const char limit_chars[] ALIGN1 =
385 OPT_hard = (1 << 0), 383 "f"
386 OPT_soft = (1 << 1), 384#ifdef RLIMIT_CPU
387}; 385 "t"
386#endif
387#ifdef RLIMIT_DATA
388 "d"
389#endif
390#ifdef RLIMIT_STACK
391 "s"
392#endif
393#ifdef RLIMIT_CORE
394 "c"
395#endif
396#ifdef RLIMIT_RSS
397 "m"
398#endif
399#ifdef RLIMIT_MEMLOCK
400 "l"
401#endif
402#ifdef RLIMIT_NPROC
403 "p"
404#endif
405#ifdef RLIMIT_NOFILE
406 "n"
407#endif
408#ifdef RLIMIT_AS
409 "v"
410#endif
411#ifdef RLIMIT_LOCKS
412 "w"
413#endif
414#ifdef RLIMIT_NICE
415 "e"
416#endif
417#ifdef RLIMIT_RTPRIO
418 "r"
419#endif
420;
388 421
389/* "-": treat args as parameters of option with ASCII code 1 */ 422/* "-": treat args as parameters of option with ASCII code 1 */
390static const char ulimit_opt_string[] ALIGN1 = "-HSa" 423static const char ulimit_opt_string[] ALIGN1 = "-HSa"
391#ifdef RLIMIT_FSIZE
392 "f::" 424 "f::"
393#endif
394#ifdef RLIMIT_CPU 425#ifdef RLIMIT_CPU
395 "t::" 426 "t::"
396#endif 427#endif
@@ -429,13 +460,19 @@ static const char ulimit_opt_string[] ALIGN1 = "-HSa"
429#endif 460#endif
430 ; 461 ;
431 462
463enum {
464 OPT_hard = (1 << 0),
465 OPT_soft = (1 << 1),
466 OPT_all = (1 << 2),
467};
468
432static void printlim(unsigned opts, const struct rlimit *limit, 469static void printlim(unsigned opts, const struct rlimit *limit,
433 const struct limits *l) 470 const struct limits *l)
434{ 471{
435 rlim_t val; 472 rlim_t val;
436 473
437 val = limit->rlim_max; 474 val = limit->rlim_max;
438 if (!(opts & OPT_hard)) 475 if (opts & OPT_soft)
439 val = limit->rlim_cur; 476 val = limit->rlim_cur;
440 477
441 if (val == RLIM_INFINITY) 478 if (val == RLIM_INFINITY)
@@ -449,8 +486,11 @@ static void printlim(unsigned opts, const struct rlimit *limit,
449int FAST_FUNC 486int FAST_FUNC
450shell_builtin_ulimit(char **argv) 487shell_builtin_ulimit(char **argv)
451{ 488{
489 struct rlimit limit;
490 unsigned opt_cnt;
452 unsigned opts; 491 unsigned opts;
453 unsigned argc; 492 unsigned argc;
493 unsigned i;
454 494
455 /* We can't use getopt32: need to handle commands like 495 /* We can't use getopt32: need to handle commands like
456 * ulimit 123 -c2 -l 456 496 * ulimit 123 -c2 -l 456
@@ -461,12 +501,48 @@ shell_builtin_ulimit(char **argv)
461 */ 501 */
462 GETOPT_RESET(); 502 GETOPT_RESET();
463 503
504// bash 4.4.23:
505//
506// -H and/or -S change meaning even of options *before* them: ulimit -f 2000 -H
507// sets hard limit, ulimit -a -H prints hard limits.
508//
509// -a is equivalent for requesting all limits to be shown.
510//
511// If -a is specified, attempts to set limits are ignored:
512// ulimit -m 1000; ulimit -m 2000 -a
513// shows 1000, not 2000. HOWEVER, *implicit* -f form "ulimit 2000 -a"
514// DOES set -f limit [we don't implement this quirk], "ulimit -a 2000" does not.
515// Options are still parsed: ulimit -az complains about unknown -z opt.
516//
517// -a is not cumulative: "ulimit -a -a" = "ulimit -a -f -m" = "ulimit -a"
518//
519// -HSa can be combined in one argument and with one other option (example: -Sm),
520// but other options can't: limit value is an optional argument,
521// thus "-mf" means "-m f", f is the parameter of -m.
522//
523// Limit can be set and then printed: ulimit -m 2000 -m
524// If set more than once, they are set and printed in order:
525// try ulimit -m -m 1000 -m -m 2000 -m -m 3000 -m
526//
527// Limits are shown in the order of options given:
528// ulimit -m -f is not the same as ulimit -f -m.
529//
530// If both -S and -H are given, show soft limit.
531//
532// Short printout (limit value only) is printed only if just one option
533// is given: ulimit -m. ulimit -f -m prints verbose lines.
534// ulimit -f -f prints same verbose line twice.
535// ulimit -m 10000 -f prints verbose line for -f.
536
464 argc = string_array_len(argv); 537 argc = string_array_len(argv);
465 538
539 /* First pass over options: detect -H/-S/-a status,
540 * and "bare ulimit" and "only one option" cases
541 * by counting other opts.
542 */
543 opt_cnt = 0;
466 opts = 0; 544 opts = 0;
467 while (1) { 545 while (1) {
468 struct rlimit limit;
469 const struct limits *l;
470 int opt_char = getopt(argc, argv, ulimit_opt_string); 546 int opt_char = getopt(argc, argv, ulimit_opt_string);
471 547
472 if (opt_char == -1) 548 if (opt_char == -1)
@@ -479,72 +555,93 @@ shell_builtin_ulimit(char **argv)
479 opts |= OPT_soft; 555 opts |= OPT_soft;
480 continue; 556 continue;
481 } 557 }
482
483 if (opt_char == 'a') { 558 if (opt_char == 'a') {
484 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) { 559 opts |= OPT_all;
485 getrlimit(l->cmd, &limit);
486 printf("-%c: %-30s ", l->option, l->name);
487 printlim(opts, &limit, l);
488 }
489 continue; 560 continue;
490 } 561 }
562 if (opt_char == '?') {
563 /* bad option. getopt already complained. */
564 return EXIT_FAILURE;
565 }
566 opt_cnt++;
567 } /* while (there are options) */
491 568
492 if (opt_char == 1) 569 if (!(opts & (OPT_hard | OPT_soft)))
493 opt_char = 'f'; 570 opts |= (OPT_hard | OPT_soft);
494 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) { 571 if (opts & OPT_all) {
495 if (opt_char == l->option) { 572 for (i = 0; i < ARRAY_SIZE(limits_tbl); i++) {
496 char *val_str; 573 getrlimit(limits_tbl[i].cmd, &limit);
497 574 printf("-%c: %-30s ", limit_chars[i], limits_tbl[i].name);
498 getrlimit(l->cmd, &limit); 575 printlim(opts, &limit, &limits_tbl[i]);
499 576 }
500 val_str = optarg; 577 return EXIT_SUCCESS;
501 if (!val_str && argv[optind] && argv[optind][0] != '-') 578 }
502 val_str = argv[optind++]; /* ++ skips NN in "-c NN" case */
503 if (val_str) {
504 rlim_t val;
505
506 if (strcmp(val_str, "unlimited") == 0)
507 val = RLIM_INFINITY;
508 else {
509 if (sizeof(val) == sizeof(int))
510 val = bb_strtou(val_str, NULL, 10);
511 else if (sizeof(val) == sizeof(long))
512 val = bb_strtoul(val_str, NULL, 10);
513 else
514 val = bb_strtoull(val_str, NULL, 10);
515 if (errno) {
516 bb_error_msg("invalid number '%s'", val_str);
517 return EXIT_FAILURE;
518 }
519 val <<= l->factor_shift;
520 }
521//bb_error_msg("opt %c val_str:'%s' val:%lld", opt_char, val_str, (long long)val);
522 /* from man bash: "If neither -H nor -S
523 * is specified, both the soft and hard
524 * limits are set. */
525 if (!opts)
526 opts = OPT_hard + OPT_soft;
527 if (opts & OPT_hard)
528 limit.rlim_max = val;
529 if (opts & OPT_soft)
530 limit.rlim_cur = val;
531//bb_error_msg("setrlimit(%d, %lld, %lld)", l->cmd, (long long)limit.rlim_cur, (long long)limit.rlim_max);
532 if (setrlimit(l->cmd, &limit) < 0) {
533 bb_perror_msg("error setting limit");
534 return EXIT_FAILURE;
535 }
536 } else {
537 printlim(opts, &limit, l);
538 }
539 break;
540 }
541 } /* for (every possible opt) */
542 579
543 if (l == &limits_tbl[ARRAY_SIZE(limits_tbl)]) { 580 /* Second pass: set or print limits, in order */
544 /* bad option. getopt already complained. */ 581 GETOPT_RESET();
582 while (1) {
583 char *val_str;
584 int opt_char = getopt(argc, argv, ulimit_opt_string);
585
586 if (opt_char == -1)
545 break; 587 break;
588 if (opt_char == 'H')
589 continue;
590 if (opt_char == 'S')
591 continue;
592 //if (opt_char == 'a') - impossible
593
594 i = 0; /* if "ulimit NNN", -f is assumed */
595 if (opt_char != 1) {
596 i = strchrnul(limit_chars, opt_char) - limit_chars;
597 //if (i >= ARRAY_SIZE(limits_tbl)) - bad option, impossible
598 }
599
600 val_str = optarg;
601 if (!val_str && argv[optind] && argv[optind][0] != '-')
602 val_str = argv[optind++]; /* ++ skips NN in "-c NN" case */
603
604 getrlimit(limits_tbl[i].cmd, &limit);
605 if (!val_str) {
606 if (opt_cnt > 1)
607 printf("-%c: %-30s ", limit_chars[i], limits_tbl[i].name);
608 printlim(opts, &limit, &limits_tbl[i]);
609 } else {
610 rlim_t val = RLIM_INFINITY;
611 if (strcmp(val_str, "unlimited") != 0) {
612 if (sizeof(val) == sizeof(int))
613 val = bb_strtou(val_str, NULL, 10);
614 else if (sizeof(val) == sizeof(long))
615 val = bb_strtoul(val_str, NULL, 10);
616 else
617 val = bb_strtoull(val_str, NULL, 10);
618 if (errno) {
619 bb_error_msg("invalid number '%s'", val_str);
620 return EXIT_FAILURE;
621 }
622 val <<= limits_tbl[i].factor_shift;
623 }
624//bb_error_msg("opt %c val_str:'%s' val:%lld", opt_char, val_str, (long long)val);
625 /* from man bash: "If neither -H nor -S
626 * is specified, both the soft and hard
627 * limits are set. */
628 if (opts & OPT_hard)
629 limit.rlim_max = val;
630 if (opts & OPT_soft)
631 limit.rlim_cur = val;
632//bb_error_msg("setrlimit(%d, %lld, %lld)", limits_tbl[i].cmd, (long long)limit.rlim_cur, (long long)limit.rlim_max);
633 if (setrlimit(limits_tbl[i].cmd, &limit) < 0) {
634 bb_perror_msg("error setting limit");
635 return EXIT_FAILURE;
636 }
546 } 637 }
547 } /* while (there are options) */ 638 } /* while (there are options) */
548 639
549 return 0; 640 if (opt_cnt == 0) {
641 /* "bare ulimit": treat it as if it was -f */
642 getrlimit(limits_tbl[0].cmd, &limit);
643 printlim(opts, &limit, &limits_tbl[0]);
644 }
645
646 return EXIT_SUCCESS;
550} 647}