diff options
-rw-r--r-- | shell/hush.c | 164 | ||||
-rw-r--r-- | util-linux/Config.in | 2 |
2 files changed, 105 insertions, 61 deletions
diff --git a/shell/hush.c b/shell/hush.c index 7cf2f3322..b62350404 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -614,7 +614,7 @@ static char *unbackslash(char *src) | |||
614 | return dst; | 614 | return dst; |
615 | } | 615 | } |
616 | 616 | ||
617 | static char **add_malloced_strings_to_strings(char **strings, char **add) | 617 | static char **add_strings_to_strings(char **strings, char **add) |
618 | { | 618 | { |
619 | int i; | 619 | int i; |
620 | unsigned count1; | 620 | unsigned count1; |
@@ -643,14 +643,37 @@ static char **add_malloced_strings_to_strings(char **strings, char **add) | |||
643 | return v; | 643 | return v; |
644 | } | 644 | } |
645 | 645 | ||
646 | static char **add_malloced_string_to_strings(char **strings, char *add) | 646 | static char **add_string_to_strings(char **strings, char *add) |
647 | { | 647 | { |
648 | char *v[2]; | 648 | char *v[2]; |
649 | |||
650 | v[0] = add; | 649 | v[0] = add; |
651 | v[1] = NULL; | 650 | v[1] = NULL; |
651 | return add_strings_to_strings(strings, v); | ||
652 | } | ||
653 | |||
654 | static void putenv_all(char **strings) | ||
655 | { | ||
656 | if (!strings) | ||
657 | return; | ||
658 | while (*strings) | ||
659 | putenv(*strings++); | ||
660 | } | ||
661 | |||
662 | static char **putenv_all_and_save_old(char **strings) | ||
663 | { | ||
664 | char **old = NULL; | ||
665 | char **s = strings; | ||
652 | 666 | ||
653 | return add_malloced_strings_to_strings(strings, v); | 667 | if (!strings) |
668 | return old; | ||
669 | while (*strings) { | ||
670 | char *v = getenv(*strings++); | ||
671 | if (!v) | ||
672 | continue; | ||
673 | old = add_string_to_strings(old, v); | ||
674 | } | ||
675 | putenv_all(s); | ||
676 | return old; | ||
654 | } | 677 | } |
655 | 678 | ||
656 | static void free_strings_and_unsetenv(char **strings, int unset) | 679 | static void free_strings_and_unsetenv(char **strings, int unset) |
@@ -1432,7 +1455,7 @@ static void pseudo_exec_argv(char ***ptr_ptrs2free, char **argv, int assignment_ | |||
1432 | p = expand_string_to_string(*argv); | 1455 | p = expand_string_to_string(*argv); |
1433 | putenv(p); | 1456 | putenv(p); |
1434 | #if !BB_MMU | 1457 | #if !BB_MMU |
1435 | *ptr_ptrs2free = add_malloced_string_to_strings(*ptr_ptrs2free, p); | 1458 | *ptr_ptrs2free = add_string_to_strings(*ptr_ptrs2free, p); |
1436 | #endif | 1459 | #endif |
1437 | argv++; | 1460 | argv++; |
1438 | } | 1461 | } |
@@ -1442,8 +1465,8 @@ static void pseudo_exec_argv(char ***ptr_ptrs2free, char **argv, int assignment_ | |||
1442 | argv = expand_strvec_to_strvec(argv); | 1465 | argv = expand_strvec_to_strvec(argv); |
1443 | #if !BB_MMU | 1466 | #if !BB_MMU |
1444 | /* Inserting magic guard pointer to not unsetenv junk later */ | 1467 | /* Inserting magic guard pointer to not unsetenv junk later */ |
1445 | *ptr_ptrs2free = add_malloced_string_to_strings(*ptr_ptrs2free, (char*)hush_version_str); | 1468 | *ptr_ptrs2free = add_string_to_strings(*ptr_ptrs2free, (char*)hush_version_str); |
1446 | *ptr_ptrs2free = add_malloced_string_to_strings(*ptr_ptrs2free, (char*)argv); | 1469 | *ptr_ptrs2free = add_string_to_strings(*ptr_ptrs2free, (char*)argv); |
1447 | #endif | 1470 | #endif |
1448 | } | 1471 | } |
1449 | 1472 | ||
@@ -1762,14 +1785,24 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe) | |||
1762 | * Returns -1 only if started some children. IOW: we have to | 1785 | * Returns -1 only if started some children. IOW: we have to |
1763 | * mask out retvals of builtins etc with 0xff! | 1786 | * mask out retvals of builtins etc with 0xff! |
1764 | */ | 1787 | */ |
1788 | /* A little helper first */ | ||
1789 | static char **expand_assignments(char **argv, int count) | ||
1790 | { | ||
1791 | int i; | ||
1792 | char **p = NULL; | ||
1793 | /* Expand assignments into one string each */ | ||
1794 | for (i = 0; i < count; i++) { | ||
1795 | p = add_string_to_strings(p, expand_string_to_string(argv[i])); | ||
1796 | } | ||
1797 | return p; | ||
1798 | } | ||
1765 | static int run_pipe(struct pipe *pi) | 1799 | static int run_pipe(struct pipe *pi) |
1766 | { | 1800 | { |
1767 | int i; | 1801 | int i; |
1768 | int nextin; | 1802 | int nextin; |
1769 | int pipefds[2]; /* pipefds[0] is for reading */ | 1803 | int pipefds[2]; /* pipefds[0] is for reading */ |
1770 | struct command *command; | 1804 | struct command *command; |
1771 | char **ptrs2free = NULL; | 1805 | char **argv_expanded; |
1772 | char **argv_expanded = NULL; | ||
1773 | char **argv; | 1806 | char **argv; |
1774 | const struct built_in_command *x; | 1807 | const struct built_in_command *x; |
1775 | char *p; | 1808 | char *p; |
@@ -1791,6 +1824,7 @@ static int run_pipe(struct pipe *pi) | |||
1791 | * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. | 1824 | * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. |
1792 | */ | 1825 | */ |
1793 | command = &(pi->cmds[0]); | 1826 | command = &(pi->cmds[0]); |
1827 | |||
1794 | if (single_and_fg && command->group && command->subshell == 0) { | 1828 | if (single_and_fg && command->group && command->subshell == 0) { |
1795 | debug_printf("non-subshell grouping\n"); | 1829 | debug_printf("non-subshell grouping\n"); |
1796 | setup_redirects(command, squirrel); | 1830 | setup_redirects(command, squirrel); |
@@ -1803,8 +1837,12 @@ static int run_pipe(struct pipe *pi) | |||
1803 | } | 1837 | } |
1804 | 1838 | ||
1805 | argv = command->argv; | 1839 | argv = command->argv; |
1840 | argv_expanded = NULL; | ||
1806 | 1841 | ||
1807 | if (single_and_fg && argv != NULL) { | 1842 | if (single_and_fg && argv != NULL) { |
1843 | char **new_env = NULL; | ||
1844 | char **old_env = NULL; | ||
1845 | |||
1808 | i = command->assignment_cnt; | 1846 | i = command->assignment_cnt; |
1809 | if (i != 0 && argv[i] == NULL) { | 1847 | if (i != 0 && argv[i] == NULL) { |
1810 | /* assignments, but no command: set local environment */ | 1848 | /* assignments, but no command: set local environment */ |
@@ -1816,52 +1854,49 @@ static int run_pipe(struct pipe *pi) | |||
1816 | return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ | 1854 | return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ |
1817 | } | 1855 | } |
1818 | 1856 | ||
1819 | /* Expand assignments into one string each */ | ||
1820 | for (i = 0; i < command->assignment_cnt; i++) { | ||
1821 | p = expand_string_to_string(argv[i]); | ||
1822 | putenv(p); | ||
1823 | ptrs2free = add_malloced_string_to_strings(ptrs2free, p); | ||
1824 | } | ||
1825 | |||
1826 | /* Expand the rest into (possibly) many strings each */ | 1857 | /* Expand the rest into (possibly) many strings each */ |
1827 | argv_expanded = expand_strvec_to_strvec(argv + i); | 1858 | argv_expanded = expand_strvec_to_strvec(argv + i); |
1828 | 1859 | ||
1829 | for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { | 1860 | for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { |
1830 | if (strcmp(argv_expanded[0], x->cmd) == 0) { | 1861 | if (strcmp(argv_expanded[0], x->cmd) != 0) |
1831 | if (x->function == builtin_exec && argv_expanded[1] == NULL) { | 1862 | continue; |
1832 | debug_printf("exec with redirects only\n"); | 1863 | if (x->function == builtin_exec && argv_expanded[1] == NULL) { |
1833 | setup_redirects(command, NULL); | 1864 | debug_printf("exec with redirects only\n"); |
1834 | rcode = EXIT_SUCCESS; | 1865 | setup_redirects(command, NULL); |
1835 | goto clean_up_and_ret1; | 1866 | rcode = EXIT_SUCCESS; |
1836 | } | 1867 | goto clean_up_and_ret1; |
1837 | debug_printf("builtin inline %s\n", argv_expanded[0]); | 1868 | } |
1838 | /* XXX setup_redirects acts on file descriptors, not FILEs. | 1869 | debug_printf("builtin inline %s\n", argv_expanded[0]); |
1839 | * This is perfect for work that comes after exec(). | 1870 | /* XXX setup_redirects acts on file descriptors, not FILEs. |
1840 | * Is it really safe for inline use? Experimentally, | 1871 | * This is perfect for work that comes after exec(). |
1841 | * things seem to work with glibc. */ | 1872 | * Is it really safe for inline use? Experimentally, |
1842 | setup_redirects(command, squirrel); | 1873 | * things seem to work with glibc. */ |
1843 | debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv_expanded[1]); | 1874 | setup_redirects(command, squirrel); |
1844 | rcode = x->function(argv_expanded) & 0xff; | 1875 | new_env = expand_assignments(argv, command->assignment_cnt); |
1876 | old_env = putenv_all_and_save_old(new_env); | ||
1877 | debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv_expanded[1]); | ||
1878 | rcode = x->function(argv_expanded) & 0xff; | ||
1845 | USE_FEATURE_SH_STANDALONE(clean_up_and_ret:) | 1879 | USE_FEATURE_SH_STANDALONE(clean_up_and_ret:) |
1846 | restore_redirects(squirrel); | 1880 | restore_redirects(squirrel); |
1881 | free_strings_and_unsetenv(new_env, 1); | ||
1882 | putenv_all(old_env); | ||
1883 | free_strings(old_env); | ||
1847 | clean_up_and_ret1: | 1884 | clean_up_and_ret1: |
1848 | free_strings_and_unsetenv(ptrs2free, 1); | 1885 | free(argv_expanded); |
1849 | free(argv_expanded); | 1886 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) |
1850 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) | 1887 | debug_printf_exec("run_pipe return %d\n", rcode); |
1851 | debug_printf_exec("run_pipe return %d\n", rcode); | 1888 | return rcode; |
1852 | return rcode; | ||
1853 | } | ||
1854 | } | 1889 | } |
1855 | #if ENABLE_FEATURE_SH_STANDALONE | 1890 | #if ENABLE_FEATURE_SH_STANDALONE |
1856 | { | 1891 | i = find_applet_by_name(argv_expanded[0]); |
1857 | int a = find_applet_by_name(argv_expanded[0]); | 1892 | if (i >= 0 && APPLET_IS_NOFORK(i)) { |
1858 | if (a >= 0 && APPLET_IS_NOFORK(a)) { | 1893 | setup_redirects(command, squirrel); |
1859 | setup_redirects(command, squirrel); | 1894 | save_nofork_data(&G.nofork_save); |
1860 | save_nofork_data(&G.nofork_save); | 1895 | new_env = expand_assignments(argv, command->assignment_cnt); |
1861 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); | 1896 | old_env = putenv_all_and_save_old(new_env); |
1862 | rcode = run_nofork_applet_prime(&G.nofork_save, a, argv_expanded); | 1897 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); |
1863 | goto clean_up_and_ret; | 1898 | rcode = run_nofork_applet_prime(&G.nofork_save, i, argv_expanded); |
1864 | } | 1899 | goto clean_up_and_ret; |
1865 | } | 1900 | } |
1866 | #endif | 1901 | #endif |
1867 | } | 1902 | } |
@@ -1883,7 +1918,7 @@ static int run_pipe(struct pipe *pi) | |||
1883 | /* Avoid confusion WHAT is volatile. Pointer is volatile, | 1918 | /* Avoid confusion WHAT is volatile. Pointer is volatile, |
1884 | * not the stuff it points to. */ | 1919 | * not the stuff it points to. */ |
1885 | typedef char **ppchar_t; | 1920 | typedef char **ppchar_t; |
1886 | volatile ppchar_t shared_across_vfork; | 1921 | volatile ppchar_t shared_across_vfork = NULL; |
1887 | #endif | 1922 | #endif |
1888 | 1923 | ||
1889 | command = &(pi->cmds[i]); | 1924 | command = &(pi->cmds[i]); |
@@ -1898,9 +1933,6 @@ static int run_pipe(struct pipe *pi) | |||
1898 | if ((i + 1) < pi->num_cmds) | 1933 | if ((i + 1) < pi->num_cmds) |
1899 | xpipe(pipefds); | 1934 | xpipe(pipefds); |
1900 | 1935 | ||
1901 | #if !BB_MMU | ||
1902 | shared_across_vfork = ptrs2free; | ||
1903 | #endif | ||
1904 | command->pid = BB_MMU ? fork() : vfork(); | 1936 | command->pid = BB_MMU ? fork() : vfork(); |
1905 | if (!command->pid) { /* child */ | 1937 | if (!command->pid) { /* child */ |
1906 | if (ENABLE_HUSH_JOB) | 1938 | if (ENABLE_HUSH_JOB) |
@@ -1941,12 +1973,11 @@ for single_and_fg, it's already set yes? */ | |||
1941 | } | 1973 | } |
1942 | /* parent */ | 1974 | /* parent */ |
1943 | #if !BB_MMU | 1975 | #if !BB_MMU |
1944 | ptrs2free = shared_across_vfork; | 1976 | //BUG: does not restore OLD env var contents |
1977 | free_strings_and_unsetenv((char **)shared_across_vfork, 1); | ||
1945 | #endif | 1978 | #endif |
1946 | free(argv_expanded); | 1979 | free(argv_expanded); |
1947 | argv_expanded = NULL; | 1980 | argv_expanded = NULL; |
1948 | free_strings_and_unsetenv(ptrs2free, 1); | ||
1949 | ptrs2free = NULL; | ||
1950 | if (command->pid < 0) { /* [v]fork failed */ | 1981 | if (command->pid < 0) { /* [v]fork failed */ |
1951 | /* Clearly indicate, was it fork or vfork */ | 1982 | /* Clearly indicate, was it fork or vfork */ |
1952 | bb_perror_msg(BB_MMU ? "fork" : "vfork"); | 1983 | bb_perror_msg(BB_MMU ? "fork" : "vfork"); |
@@ -3145,7 +3176,7 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3145 | o_addchr(word, SPECIAL_VAR_SYMBOL); | 3176 | o_addchr(word, SPECIAL_VAR_SYMBOL); |
3146 | } | 3177 | } |
3147 | } | 3178 | } |
3148 | command->argv = add_malloced_string_to_strings(command->argv, xstrdup(word->data)); | 3179 | command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); |
3149 | debug_print_strings("word appended to argv", command->argv); | 3180 | debug_print_strings("word appended to argv", command->argv); |
3150 | } | 3181 | } |
3151 | 3182 | ||
@@ -3436,6 +3467,11 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
3436 | endch = ")"; | 3467 | endch = ")"; |
3437 | command->subshell = 1; | 3468 | command->subshell = 1; |
3438 | } | 3469 | } |
3470 | #if 0 /* TODO function support */ | ||
3471 | if (ch == 'F') { /* function definition */ | ||
3472 | command->subshell = 2; | ||
3473 | } | ||
3474 | #endif | ||
3439 | rcode = parse_stream(dest, &sub, input, endch); | 3475 | rcode = parse_stream(dest, &sub, input, endch); |
3440 | if (rcode == 0) { | 3476 | if (rcode == 0) { |
3441 | done_word(dest, &sub); /* finish off the final word in the subcontext */ | 3477 | done_word(dest, &sub); /* finish off the final word in the subcontext */ |
@@ -3929,10 +3965,10 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, | |||
3929 | case '(': | 3965 | case '(': |
3930 | #if ENABLE_HUSH_CASE | 3966 | #if ENABLE_HUSH_CASE |
3931 | /* "case... in [(]word)..." - skip '(' */ | 3967 | /* "case... in [(]word)..." - skip '(' */ |
3932 | if (dest->length == 0 /* not word(... */ | 3968 | if (ctx->ctx_res_w == RES_MATCH |
3933 | && dest->nonnull == 0 /* not ""(... */ | ||
3934 | && ctx->ctx_res_w == RES_MATCH | ||
3935 | && ctx->command->argv == NULL /* not (word|(... */ | 3969 | && ctx->command->argv == NULL /* not (word|(... */ |
3970 | && dest->length == 0 /* not word(... */ | ||
3971 | && dest->nonnull == 0 /* not ""(... */ | ||
3936 | ) { | 3972 | ) { |
3937 | continue; | 3973 | continue; |
3938 | } | 3974 | } |
@@ -3942,10 +3978,18 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, | |||
3942 | && dest->nonnull == 0 /* not a"b"c() */ | 3978 | && dest->nonnull == 0 /* not a"b"c() */ |
3943 | && ctx->command->argv == NULL /* it's the first word */ | 3979 | && ctx->command->argv == NULL /* it's the first word */ |
3944 | && i_peek(input) == ')' | 3980 | && i_peek(input) == ')' |
3981 | && !match_reserved_word(dest) | ||
3945 | ) { | 3982 | ) { |
3946 | bb_error_msg("seems like a function definition"); | 3983 | bb_error_msg("seems like a function definition"); |
3947 | if (match_reserved_word(dest)) | 3984 | i_getch(input); |
3948 | bb_error_msg("but '%s' is a reserved word!", dest->data); | 3985 | do { |
3986 | ch = i_getch(input); | ||
3987 | } while (ch == ' ' || ch == '\n'); | ||
3988 | if (ch != '{') { | ||
3989 | syntax("was expecting {"); | ||
3990 | debug_printf_parse("parse_stream return 1\n"); | ||
3991 | return 1; | ||
3992 | } | ||
3949 | } | 3993 | } |
3950 | #endif | 3994 | #endif |
3951 | case '{': | 3995 | case '{': |
diff --git a/util-linux/Config.in b/util-linux/Config.in index ba0916a50..8cecc60f2 100644 --- a/util-linux/Config.in +++ b/util-linux/Config.in | |||
@@ -165,7 +165,7 @@ config FINDFS | |||
165 | default n | 165 | default n |
166 | select VOLUMEID | 166 | select VOLUMEID |
167 | help | 167 | help |
168 | Prints the name of a filesystem with given laver or UUID. | 168 | Prints the name of a filesystem with given label or UUID. |
169 | WARNING: | 169 | WARNING: |
170 | With all submodules selected, it will add ~8k to busybox. | 170 | With all submodules selected, it will add ~8k to busybox. |
171 | 171 | ||