aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-10-13 08:53:43 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-10-13 08:53:43 +0000
commit22d10a029283b93c31890366a1f8dcfc59e6298c (patch)
tree0bc9778756164d7f89158f1ce993e4e1979e33d4
parent1e19afd38adae3c44197254255ed43d88ae9726c (diff)
downloadbusybox-w32-22d10a029283b93c31890366a1f8dcfc59e6298c.tar.gz
busybox-w32-22d10a029283b93c31890366a1f8dcfc59e6298c.tar.bz2
busybox-w32-22d10a029283b93c31890366a1f8dcfc59e6298c.zip
hush: fix trashing of environment by local env vars:
a=a; a=b cmd; - a was unset! +57 bytes function old new delta add_string_to_strings - 110 +110 putenv_all - 27 +27 run_list 2086 2111 +25 free_strings - 7 +7 free_pipe 210 208 -2 add_malloced_string_to_strings 110 - -110 ------------------------------------------------------------------------------ (add/remove: 3/1 grow/shrink: 1/1 up/down: 169/-112) Total: 57 bytes
-rw-r--r--shell/hush.c164
-rw-r--r--util-linux/Config.in2
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
617static char **add_malloced_strings_to_strings(char **strings, char **add) 617static 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
646static char **add_malloced_string_to_strings(char **strings, char *add) 646static 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
654static void putenv_all(char **strings)
655{
656 if (!strings)
657 return;
658 while (*strings)
659 putenv(*strings++);
660}
661
662static 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
656static void free_strings_and_unsetenv(char **strings, int unset) 679static 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 */
1789static 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}
1765static int run_pipe(struct pipe *pi) 1799static 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