aboutsummaryrefslogtreecommitdiff
path: root/shell/shell_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/shell_common.c')
-rw-r--r--shell/shell_common.c343
1 files changed, 214 insertions, 129 deletions
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 70ecf2095..d1df5888c 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -26,19 +26,6 @@ const char defifsvar[] ALIGN1 = "IFS= \t\n\r";
26#endif 26#endif
27const char defoptindvar[] ALIGN1 = "OPTIND=1"; 27const char defoptindvar[] ALIGN1 = "OPTIND=1";
28 28
29
30int FAST_FUNC is_well_formed_var_name(const char *s, char terminator)
31{
32 if (!s || !(isalpha(*s) || *s == '_'))
33 return 0;
34
35 do
36 s++;
37 while (isalnum(*s) || *s == '_');
38
39 return *s == terminator;
40}
41
42/* read builtin */ 29/* read builtin */
43 30
44/* Needs to be interruptible: shell must handle traps and shell-special signals 31/* Needs to be interruptible: shell must handle traps and shell-special signals
@@ -76,7 +63,7 @@ shell_builtin_read(struct builtin_read_params *params)
76 argv = params->argv; 63 argv = params->argv;
77 pp = argv; 64 pp = argv;
78 while (*pp) { 65 while (*pp) {
79 if (!is_well_formed_var_name(*pp, '\0')) { 66 if (endofname(*pp)[0] != '\0') {
80 /* Mimic bash message */ 67 /* Mimic bash message */
81 bb_error_msg("read: '%s': not a valid identifier", *pp); 68 bb_error_msg("read: '%s': not a valid identifier", *pp);
82 return (const char *)(uintptr_t)1; 69 return (const char *)(uintptr_t)1;
@@ -384,99 +371,138 @@ shell_builtin_read(struct builtin_read_params *params)
384struct limits { 371struct limits {
385 uint8_t cmd; /* RLIMIT_xxx fit into it */ 372 uint8_t cmd; /* RLIMIT_xxx fit into it */
386 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ 373 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
387 char option;
388 const char *name; 374 const char *name;
389}; 375};
390 376
391static const struct limits limits_tbl[] = { 377static const struct limits limits_tbl[] = {
392#ifdef RLIMIT_FSIZE 378 { RLIMIT_CORE, 9, "core file size (blocks)" }, // -c
393 { RLIMIT_FSIZE, 9, 'f', "file size (blocks)" }, 379 { RLIMIT_DATA, 10, "data seg size (kb)" }, // -d
380 { RLIMIT_NICE, 0, "scheduling priority" }, // -e
381 { RLIMIT_FSIZE, 9, "file size (blocks)" }, // -f
382#define LIMIT_F_IDX 3
383#ifdef RLIMIT_SIGPENDING
384 { RLIMIT_SIGPENDING, 0, "pending signals" }, // -i
394#endif 385#endif
395#ifdef RLIMIT_CPU 386#ifdef RLIMIT_MEMLOCK
396 { RLIMIT_CPU, 0, 't', "cpu time (seconds)" }, 387 { RLIMIT_MEMLOCK, 10, "max locked memory (kb)" }, // -l
397#endif 388#endif
398#ifdef RLIMIT_DATA 389#ifdef RLIMIT_RSS
399 { RLIMIT_DATA, 10, 'd', "data seg size (kb)" }, 390 { RLIMIT_RSS, 10, "max memory size (kb)" }, // -m
400#endif 391#endif
401#ifdef RLIMIT_STACK 392#ifdef RLIMIT_NOFILE
402 { RLIMIT_STACK, 10, 's', "stack size (kb)" }, 393 { RLIMIT_NOFILE, 0, "open files" }, // -n
403#endif 394#endif
404#ifdef RLIMIT_CORE 395#ifdef RLIMIT_MSGQUEUE
405 { RLIMIT_CORE, 9, 'c', "core file size (blocks)" }, 396 { RLIMIT_MSGQUEUE, 0, "POSIX message queues (bytes)" }, // -q
406#endif 397#endif
407#ifdef RLIMIT_RSS 398#ifdef RLIMIT_RTPRIO
408 { RLIMIT_RSS, 10, 'm', "resident set size (kb)" }, 399 { RLIMIT_RTPRIO, 0, "real-time priority" }, // -r
409#endif 400#endif
410#ifdef RLIMIT_MEMLOCK 401#ifdef RLIMIT_STACK
411 { RLIMIT_MEMLOCK, 10, 'l', "locked memory (kb)" }, 402 { RLIMIT_STACK, 10, "stack size (kb)" }, // -s
412#endif 403#endif
413#ifdef RLIMIT_NPROC 404#ifdef RLIMIT_CPU
414 { RLIMIT_NPROC, 0, 'p', "processes" }, 405 { RLIMIT_CPU, 0, "cpu time (seconds)" }, // -t
415#endif 406#endif
416#ifdef RLIMIT_NOFILE 407#ifdef RLIMIT_NPROC
417 { RLIMIT_NOFILE, 0, 'n', "file descriptors" }, 408 { RLIMIT_NPROC, 0, "max user processes" }, // -u
418#endif 409#endif
419#ifdef RLIMIT_AS 410#ifdef RLIMIT_AS
420 { RLIMIT_AS, 10, 'v', "address space (kb)" }, 411 { RLIMIT_AS, 10, "virtual memory (kb)" }, // -v
421#endif 412#endif
422#ifdef RLIMIT_LOCKS 413#ifdef RLIMIT_LOCKS
423 { RLIMIT_LOCKS, 0, 'w', "locks" }, 414 { RLIMIT_LOCKS, 0, "file locks" }, // -x
415#endif
416};
417// bash also shows:
418//pipe size (512 bytes, -p) 8
419
420static const char limit_chars[] ALIGN1 =
421 "c"
422 "d"
423 "e"
424 "f"
425#ifdef RLIMIT_SIGPENDING
426 "i"
427#endif
428#ifdef RLIMIT_MEMLOCK
429 "l"
430#endif
431#ifdef RLIMIT_RSS
432 "m"
433#endif
434#ifdef RLIMIT_NOFILE
435 "n"
424#endif 436#endif
425#ifdef RLIMIT_NICE 437#ifdef RLIMIT_MSGQUEUE
426 { RLIMIT_NICE, 0, 'e', "scheduling priority" }, 438 "q"
427#endif 439#endif
428#ifdef RLIMIT_RTPRIO 440#ifdef RLIMIT_RTPRIO
429 { RLIMIT_RTPRIO, 0, 'r', "real-time priority" }, 441 "r"
430#endif 442#endif
431}; 443#ifdef RLIMIT_STACK
432 444 "s"
433enum {
434 OPT_hard = (1 << 0),
435 OPT_soft = (1 << 1),
436};
437
438/* "-": treat args as parameters of option with ASCII code 1 */
439static const char ulimit_opt_string[] ALIGN1 = "-HSa"
440#ifdef RLIMIT_FSIZE
441 "f::"
442#endif 445#endif
443#ifdef RLIMIT_CPU 446#ifdef RLIMIT_CPU
444 "t::" 447 "t"
445#endif 448#endif
446#ifdef RLIMIT_DATA 449#ifdef RLIMIT_NPROC
447 "d::" 450 "u"
448#endif 451#endif
449#ifdef RLIMIT_STACK 452#ifdef RLIMIT_AS
450 "s::" 453 "v"
451#endif 454#endif
452#ifdef RLIMIT_CORE 455#ifdef RLIMIT_LOCKS
453 "c::" 456 "x"
454#endif 457#endif
455#ifdef RLIMIT_RSS 458;
456 "m::" 459
460/* "-": treat args as parameters of option with ASCII code 1 */
461static const char ulimit_opt_string[] ALIGN1 = "-HSa"
462 "c::"
463 "d::"
464 "e::"
465 "f::"
466#ifdef RLIMIT_SIGPENDING
467 "i::"
457#endif 468#endif
458#ifdef RLIMIT_MEMLOCK 469#ifdef RLIMIT_MEMLOCK
459 "l::" 470 "l::"
460#endif 471#endif
461#ifdef RLIMIT_NPROC 472#ifdef RLIMIT_RSS
462 "p::" 473 "m::"
463#endif 474#endif
464#ifdef RLIMIT_NOFILE 475#ifdef RLIMIT_NOFILE
465 "n::" 476 "n::"
466#endif 477#endif
478#ifdef RLIMIT_MSGQUEUE
479 "q::"
480#endif
481#ifdef RLIMIT_RTPRIO
482 "r::"
483#endif
484#ifdef RLIMIT_STACK
485 "s::"
486#endif
487#ifdef RLIMIT_CPU
488 "t::"
489#endif
490#ifdef RLIMIT_NPROC
491 "u::"
492#endif
467#ifdef RLIMIT_AS 493#ifdef RLIMIT_AS
468 "v::" 494 "v::"
469#endif 495#endif
470#ifdef RLIMIT_LOCKS 496#ifdef RLIMIT_LOCKS
471 "w::" 497 "x::"
472#endif
473#ifdef RLIMIT_NICE
474 "e::"
475#endif
476#ifdef RLIMIT_RTPRIO
477 "r::"
478#endif 498#endif
479 ; 499;
500
501enum {
502 OPT_hard = (1 << 0),
503 OPT_soft = (1 << 1),
504 OPT_all = (1 << 2),
505};
480 506
481static void printlim(unsigned opts, const struct rlimit *limit, 507static void printlim(unsigned opts, const struct rlimit *limit,
482 const struct limits *l) 508 const struct limits *l)
@@ -484,7 +510,7 @@ static void printlim(unsigned opts, const struct rlimit *limit,
484 rlim_t val; 510 rlim_t val;
485 511
486 val = limit->rlim_max; 512 val = limit->rlim_max;
487 if (!(opts & OPT_hard)) 513 if (opts & OPT_soft)
488 val = limit->rlim_cur; 514 val = limit->rlim_cur;
489 515
490 if (val == RLIM_INFINITY) 516 if (val == RLIM_INFINITY)
@@ -498,8 +524,11 @@ static void printlim(unsigned opts, const struct rlimit *limit,
498int FAST_FUNC 524int FAST_FUNC
499shell_builtin_ulimit(char **argv) 525shell_builtin_ulimit(char **argv)
500{ 526{
527 struct rlimit limit;
528 unsigned opt_cnt;
501 unsigned opts; 529 unsigned opts;
502 unsigned argc; 530 unsigned argc;
531 unsigned i;
503 532
504 /* We can't use getopt32: need to handle commands like 533 /* We can't use getopt32: need to handle commands like
505 * ulimit 123 -c2 -l 456 534 * ulimit 123 -c2 -l 456
@@ -510,12 +539,48 @@ shell_builtin_ulimit(char **argv)
510 */ 539 */
511 GETOPT_RESET(); 540 GETOPT_RESET();
512 541
542// bash 4.4.23:
543//
544// -H and/or -S change meaning even of options *before* them: ulimit -f 2000 -H
545// sets hard limit, ulimit -a -H prints hard limits.
546//
547// -a is equivalent for requesting all limits to be shown.
548//
549// If -a is specified, attempts to set limits are ignored:
550// ulimit -m 1000; ulimit -m 2000 -a
551// shows 1000, not 2000. HOWEVER, *implicit* -f form "ulimit 2000 -a"
552// DOES set -f limit [we don't implement this quirk], "ulimit -a 2000" does not.
553// Options are still parsed: ulimit -az complains about unknown -z opt.
554//
555// -a is not cumulative: "ulimit -a -a" = "ulimit -a -f -m" = "ulimit -a"
556//
557// -HSa can be combined in one argument and with one other option (example: -Sm),
558// but other options can't: limit value is an optional argument,
559// thus "-mf" means "-m f", f is the parameter of -m.
560//
561// Limit can be set and then printed: ulimit -m 2000 -m
562// If set more than once, they are set and printed in order:
563// try ulimit -m -m 1000 -m -m 2000 -m -m 3000 -m
564//
565// Limits are shown in the order of options given:
566// ulimit -m -f is not the same as ulimit -f -m.
567//
568// If both -S and -H are given, show soft limit.
569//
570// Short printout (limit value only) is printed only if just one option
571// is given: ulimit -m. ulimit -f -m prints verbose lines.
572// ulimit -f -f prints same verbose line twice.
573// ulimit -m 10000 -f prints verbose line for -f.
574
513 argc = string_array_len(argv); 575 argc = string_array_len(argv);
514 576
577 /* First pass over options: detect -H/-S/-a status,
578 * and "bare ulimit" and "only one option" cases
579 * by counting other opts.
580 */
581 opt_cnt = 0;
515 opts = 0; 582 opts = 0;
516 while (1) { 583 while (1) {
517 struct rlimit limit;
518 const struct limits *l;
519 int opt_char = getopt(argc, argv, ulimit_opt_string); 584 int opt_char = getopt(argc, argv, ulimit_opt_string);
520 585
521 if (opt_char == -1) 586 if (opt_char == -1)
@@ -528,74 +593,94 @@ shell_builtin_ulimit(char **argv)
528 opts |= OPT_soft; 593 opts |= OPT_soft;
529 continue; 594 continue;
530 } 595 }
531
532 if (opt_char == 'a') { 596 if (opt_char == 'a') {
533 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) { 597 opts |= OPT_all;
534 getrlimit(l->cmd, &limit);
535 printf("-%c: %-30s ", l->option, l->name);
536 printlim(opts, &limit, l);
537 }
538 continue; 598 continue;
539 } 599 }
600 if (opt_char == '?') {
601 /* bad option. getopt already complained. */
602 return EXIT_FAILURE;
603 }
604 opt_cnt++;
605 } /* while (there are options) */
606
607 if (!(opts & (OPT_hard | OPT_soft)))
608 opts |= (OPT_hard | OPT_soft);
609 if (opts & OPT_all) {
610 for (i = 0; i < ARRAY_SIZE(limits_tbl); i++) {
611 getrlimit(limits_tbl[i].cmd, &limit);
612 printf("%-32s(-%c) ", limits_tbl[i].name, limit_chars[i]);
613 printlim(opts, &limit, &limits_tbl[i]);
614 }
615 return EXIT_SUCCESS;
616 }
540 617
541 if (opt_char == 1) 618 /* Second pass: set or print limits, in order */
619 GETOPT_RESET();
620 while (1) {
621 char *val_str;
622 int opt_char = getopt(argc, argv, ulimit_opt_string);
623
624 if (opt_char == -1)
625 break;
626 if (opt_char == 'H')
627 continue;
628 if (opt_char == 'S')
629 continue;
630 //if (opt_char == 'a') - impossible
631
632 if (opt_char == 1) /* if "ulimit NNN", -f is assumed */
542 opt_char = 'f'; 633 opt_char = 'f';
543 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) { 634 i = strchrnul(limit_chars, opt_char) - limit_chars;
544 if (opt_char == l->option) { 635 //if (i >= ARRAY_SIZE(limits_tbl)) - bad option, impossible
545 char *val_str; 636
546 637 val_str = optarg;
547 getrlimit(l->cmd, &limit); 638 if (!val_str && argv[optind] && argv[optind][0] != '-')
548 639 val_str = argv[optind++]; /* ++ skips NN in "-c NN" case */
549 val_str = optarg; 640
550 if (!val_str && argv[optind] && argv[optind][0] != '-') 641 getrlimit(limits_tbl[i].cmd, &limit);
551 val_str = argv[optind++]; /* ++ skips NN in "-c NN" case */ 642 if (!val_str) {
552 if (val_str) { 643 if (opt_cnt > 1)
553 rlim_t val; 644 printf("%-32s(-%c) ", limits_tbl[i].name, limit_chars[i]);
554 645 printlim(opts, &limit, &limits_tbl[i]);
555 if (strcmp(val_str, "unlimited") == 0) 646 } else {
556 val = RLIM_INFINITY; 647 rlim_t val = RLIM_INFINITY;
557 else { 648 if (strcmp(val_str, "unlimited") != 0) {
558 if (sizeof(val) == sizeof(int)) 649 if (sizeof(val) == sizeof(int))
559 val = bb_strtou(val_str, NULL, 10); 650 val = bb_strtou(val_str, NULL, 10);
560 else if (sizeof(val) == sizeof(long)) 651 else if (sizeof(val) == sizeof(long))
561 val = bb_strtoul(val_str, NULL, 10); 652 val = bb_strtoul(val_str, NULL, 10);
562 else 653 else
563 val = bb_strtoull(val_str, NULL, 10); 654 val = bb_strtoull(val_str, NULL, 10);
564 if (errno) { 655 if (errno) {
565 bb_error_msg("invalid number '%s'", val_str); 656 bb_error_msg("invalid number '%s'", val_str);
566 return EXIT_FAILURE; 657 return EXIT_FAILURE;
567 }
568 val <<= l->factor_shift;
569 }
570//bb_error_msg("opt %c val_str:'%s' val:%lld", opt_char, val_str, (long long)val);
571 /* from man bash: "If neither -H nor -S
572 * is specified, both the soft and hard
573 * limits are set. */
574 if (!opts)
575 opts = OPT_hard + OPT_soft;
576 if (opts & OPT_hard)
577 limit.rlim_max = val;
578 if (opts & OPT_soft)
579 limit.rlim_cur = val;
580//bb_error_msg("setrlimit(%d, %lld, %lld)", l->cmd, (long long)limit.rlim_cur, (long long)limit.rlim_max);
581 if (setrlimit(l->cmd, &limit) < 0) {
582 bb_perror_msg("error setting limit");
583 return EXIT_FAILURE;
584 }
585 } else {
586 printlim(opts, &limit, l);
587 } 658 }
588 break; 659 val <<= limits_tbl[i].factor_shift;
660 }
661//bb_error_msg("opt %c val_str:'%s' val:%lld", opt_char, val_str, (long long)val);
662 /* from man bash: "If neither -H nor -S
663 * is specified, both the soft and hard
664 * limits are set. */
665 if (opts & OPT_hard)
666 limit.rlim_max = val;
667 if (opts & OPT_soft)
668 limit.rlim_cur = val;
669//bb_error_msg("setrlimit(%d, %lld, %lld)", limits_tbl[i].cmd, (long long)limit.rlim_cur, (long long)limit.rlim_max);
670 if (setrlimit(limits_tbl[i].cmd, &limit) < 0) {
671 bb_perror_msg("error setting limit");
672 return EXIT_FAILURE;
589 } 673 }
590 } /* for (every possible opt) */
591
592 if (l == &limits_tbl[ARRAY_SIZE(limits_tbl)]) {
593 /* bad option. getopt already complained. */
594 break;
595 } 674 }
596 } /* while (there are options) */ 675 } /* while (there are options) */
597 676
598 return 0; 677 if (opt_cnt == 0) {
678 /* "bare ulimit": treat it as if it was -f */
679 getrlimit(limits_tbl[LIMIT_F_IDX].cmd, &limit);
680 printlim(opts, &limit, &limits_tbl[LIMIT_F_IDX]);
681 }
682
683 return EXIT_SUCCESS;
599} 684}
600#else 685#else
601int FAST_FUNC shell_builtin_ulimit(char **argv UNUSED_PARAM) 686int FAST_FUNC shell_builtin_ulimit(char **argv UNUSED_PARAM)