diff options
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 104 | ||||
-rw-r--r-- | shell/hush.c | 147 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/return1.right | 1 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/return1.tests | 4 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/source1.right | 5 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/source1.tests | 10 |
6 files changed, 172 insertions, 99 deletions
diff --git a/shell/ash.c b/shell/ash.c index fd9141661..d12a483a3 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -56,6 +56,9 @@ | |||
56 | #include <fnmatch.h> | 56 | #include <fnmatch.h> |
57 | #include <sys/times.h> | 57 | #include <sys/times.h> |
58 | 58 | ||
59 | #include "busybox.h" /* for applet_names */ | ||
60 | #include "unicode.h" | ||
61 | |||
59 | #include "shell_common.h" | 62 | #include "shell_common.h" |
60 | #if ENABLE_SH_MATH_SUPPORT | 63 | #if ENABLE_SH_MATH_SUPPORT |
61 | # include "math.h" | 64 | # include "math.h" |
@@ -86,13 +89,6 @@ | |||
86 | # error "Do not even bother, ash will not run on NOMMU machine" | 89 | # error "Do not even bother, ash will not run on NOMMU machine" |
87 | #endif | 90 | #endif |
88 | 91 | ||
89 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) | ||
90 | //applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh)) | ||
91 | //applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash)) | ||
92 | |||
93 | //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o | ||
94 | //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o | ||
95 | |||
96 | //config:config ASH | 92 | //config:config ASH |
97 | //config: bool "ash" | 93 | //config: bool "ash" |
98 | //config: default y | 94 | //config: default y |
@@ -204,12 +200,12 @@ | |||
204 | //config: variable each time it is displayed. | 200 | //config: variable each time it is displayed. |
205 | //config: | 201 | //config: |
206 | 202 | ||
207 | //usage:#define ash_trivial_usage NOUSAGE_STR | 203 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) |
208 | //usage:#define ash_full_usage "" | 204 | //applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh)) |
209 | //usage:#define sh_trivial_usage NOUSAGE_STR | 205 | //applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash)) |
210 | //usage:#define sh_full_usage "" | 206 | |
211 | //usage:#define bash_trivial_usage NOUSAGE_STR | 207 | //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o |
212 | //usage:#define bash_full_usage "" | 208 | //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o |
213 | 209 | ||
214 | #if ENABLE_PLATFORM_MINGW32 | 210 | #if ENABLE_PLATFORM_MINGW32 |
215 | struct forkshell; | 211 | struct forkshell; |
@@ -3705,12 +3701,12 @@ set_curjob(struct job *jp, unsigned mode) | |||
3705 | 3701 | ||
3706 | /* first remove from list */ | 3702 | /* first remove from list */ |
3707 | jpp = curp = &curjob; | 3703 | jpp = curp = &curjob; |
3708 | do { | 3704 | while (1) { |
3709 | jp1 = *jpp; | 3705 | jp1 = *jpp; |
3710 | if (jp1 == jp) | 3706 | if (jp1 == jp) |
3711 | break; | 3707 | break; |
3712 | jpp = &jp1->prev_job; | 3708 | jpp = &jp1->prev_job; |
3713 | } while (1); | 3709 | } |
3714 | *jpp = jp1->prev_job; | 3710 | *jpp = jp1->prev_job; |
3715 | 3711 | ||
3716 | /* Then re-insert in correct position */ | 3712 | /* Then re-insert in correct position */ |
@@ -3726,14 +3722,14 @@ set_curjob(struct job *jp, unsigned mode) | |||
3726 | case CUR_RUNNING: | 3722 | case CUR_RUNNING: |
3727 | /* newly created job or backgrounded job, | 3723 | /* newly created job or backgrounded job, |
3728 | put after all stopped jobs. */ | 3724 | put after all stopped jobs. */ |
3729 | do { | 3725 | while (1) { |
3730 | jp1 = *jpp; | 3726 | jp1 = *jpp; |
3731 | #if JOBS | 3727 | #if JOBS |
3732 | if (!jp1 || jp1->state != JOBSTOPPED) | 3728 | if (!jp1 || jp1->state != JOBSTOPPED) |
3733 | #endif | 3729 | #endif |
3734 | break; | 3730 | break; |
3735 | jpp = &jp1->prev_job; | 3731 | jpp = &jp1->prev_job; |
3736 | } while (1); | 3732 | } |
3737 | /* FALLTHROUGH */ | 3733 | /* FALLTHROUGH */ |
3738 | #if JOBS | 3734 | #if JOBS |
3739 | case CUR_STOPPED: | 3735 | case CUR_STOPPED: |
@@ -3906,7 +3902,7 @@ setjobctl(int on) | |||
3906 | goto out; | 3902 | goto out; |
3907 | /* fd is a tty at this point */ | 3903 | /* fd is a tty at this point */ |
3908 | close_on_exec_on(fd); | 3904 | close_on_exec_on(fd); |
3909 | do { /* while we are in the background */ | 3905 | while (1) { /* while we are in the background */ |
3910 | pgrp = tcgetpgrp(fd); | 3906 | pgrp = tcgetpgrp(fd); |
3911 | if (pgrp < 0) { | 3907 | if (pgrp < 0) { |
3912 | out: | 3908 | out: |
@@ -3917,7 +3913,7 @@ setjobctl(int on) | |||
3917 | if (pgrp == getpgrp()) | 3913 | if (pgrp == getpgrp()) |
3918 | break; | 3914 | break; |
3919 | killpg(0, SIGTTIN); | 3915 | killpg(0, SIGTTIN); |
3920 | } while (1); | 3916 | } |
3921 | initialpgrp = pgrp; | 3917 | initialpgrp = pgrp; |
3922 | 3918 | ||
3923 | setsignal(SIGTSTP); | 3919 | setsignal(SIGTSTP); |
@@ -6328,7 +6324,7 @@ expari(int quotes) | |||
6328 | p = expdest - 1; | 6324 | p = expdest - 1; |
6329 | *p = '\0'; | 6325 | *p = '\0'; |
6330 | p--; | 6326 | p--; |
6331 | do { | 6327 | while (1) { |
6332 | int esc; | 6328 | int esc; |
6333 | 6329 | ||
6334 | while ((unsigned char)*p != CTLARI) { | 6330 | while ((unsigned char)*p != CTLARI) { |
@@ -6346,7 +6342,7 @@ expari(int quotes) | |||
6346 | } | 6342 | } |
6347 | 6343 | ||
6348 | p -= esc + 1; | 6344 | p -= esc + 1; |
6349 | } while (1); | 6345 | } |
6350 | 6346 | ||
6351 | begoff = p - start; | 6347 | begoff = p - start; |
6352 | 6348 | ||
@@ -7754,8 +7750,6 @@ static int builtinloc = -1; /* index in path of %builtin, or -1 */ | |||
7754 | static void | 7750 | static void |
7755 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp) | 7751 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp) |
7756 | { | 7752 | { |
7757 | int repeated = 0; | ||
7758 | |||
7759 | #if ENABLE_FEATURE_SH_STANDALONE | 7753 | #if ENABLE_FEATURE_SH_STANDALONE |
7760 | if (applet_no >= 0) { | 7754 | if (applet_no >= 0) { |
7761 | if (APPLET_IS_NOEXEC(applet_no)) { | 7755 | if (APPLET_IS_NOEXEC(applet_no)) { |
@@ -7779,25 +7773,36 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** | |||
7779 | #else | 7773 | #else |
7780 | execve(cmd, argv, envp); | 7774 | execve(cmd, argv, envp); |
7781 | #endif | 7775 | #endif |
7782 | if (repeated) { | 7776 | if (cmd == (char*) bb_busybox_exec_path) { |
7777 | /* We already visited ENOEXEC branch below, don't do it again */ | ||
7778 | //TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up? | ||
7783 | free(argv); | 7779 | free(argv); |
7784 | return; | 7780 | return; |
7785 | } | 7781 | } |
7786 | if (errno == ENOEXEC) { | 7782 | if (errno == ENOEXEC) { |
7783 | /* Run "cmd" as a shell script: | ||
7784 | * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html | ||
7785 | * "If the execve() function fails with ENOEXEC, the shell | ||
7786 | * shall execute a command equivalent to having a shell invoked | ||
7787 | * with the command name as its first operand, | ||
7788 | * with any remaining arguments passed to the new shell" | ||
7789 | * | ||
7790 | * That is, do not use $SHELL, user's shell, or /bin/sh; | ||
7791 | * just call ourselves. | ||
7792 | */ | ||
7787 | char **ap; | 7793 | char **ap; |
7788 | char **new; | 7794 | char **new; |
7789 | 7795 | ||
7790 | for (ap = argv; *ap; ap++) | 7796 | for (ap = argv; *ap; ap++) |
7791 | continue; | 7797 | continue; |
7792 | ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0])); | 7798 | new = ckmalloc((ap - argv + 2) * sizeof(new[0])); |
7793 | ap[1] = cmd; | 7799 | new[0] = (char*) "ash"; |
7794 | ap[0] = cmd = (char *)DEFAULT_SHELL; | 7800 | new[1] = cmd; |
7795 | ap += 2; | 7801 | ap = new + 2; |
7796 | argv++; | 7802 | while ((*ap++ = *++argv) != NULL) |
7797 | while ((*ap++ = *argv++) != NULL) | ||
7798 | continue; | 7803 | continue; |
7804 | cmd = (char*) bb_busybox_exec_path; | ||
7799 | argv = new; | 7805 | argv = new; |
7800 | repeated++; | ||
7801 | goto repeat; | 7806 | goto repeat; |
7802 | } | 7807 | } |
7803 | } | 7808 | } |
@@ -10126,6 +10131,11 @@ preadfd(void) | |||
10126 | # if ENABLE_FEATURE_TAB_COMPLETION | 10131 | # if ENABLE_FEATURE_TAB_COMPLETION |
10127 | line_input_state->path_lookup = pathval(); | 10132 | line_input_state->path_lookup = pathval(); |
10128 | # endif | 10133 | # endif |
10134 | /* Unicode support should be activated even if LANG is set | ||
10135 | * _during_ shell execution, not only if it was set when | ||
10136 | * shell was started. Therefore, re-check LANG every time: | ||
10137 | */ | ||
10138 | reinit_unicode(lookupvar("LANG")); | ||
10129 | nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); | 10139 | nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); |
10130 | if (nr == 0) { | 10140 | if (nr == 0) { |
10131 | /* Ctrl+C pressed */ | 10141 | /* Ctrl+C pressed */ |
@@ -10673,7 +10683,7 @@ options(int cmdline) | |||
10673 | else if (*argptr == NULL) | 10683 | else if (*argptr == NULL) |
10674 | setparam(argptr); | 10684 | setparam(argptr); |
10675 | } | 10685 | } |
10676 | break; /* "-" or "--" terminates options */ | 10686 | break; /* "-" or "--" terminates options */ |
10677 | } | 10687 | } |
10678 | } | 10688 | } |
10679 | /* first char was + or - */ | 10689 | /* first char was + or - */ |
@@ -10775,10 +10785,10 @@ setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
10775 | 10785 | ||
10776 | if (!argv[1]) | 10786 | if (!argv[1]) |
10777 | return showvars(nullstr, 0, VUNSET); | 10787 | return showvars(nullstr, 0, VUNSET); |
10788 | |||
10778 | INT_OFF; | 10789 | INT_OFF; |
10779 | retval = 1; | 10790 | retval = options(/*cmdline:*/ 0); |
10780 | if (!options(0)) { /* if no parse error... */ | 10791 | if (retval == 0) { /* if no parse error... */ |
10781 | retval = 0; | ||
10782 | optschanged(); | 10792 | optschanged(); |
10783 | if (*argptr != NULL) { | 10793 | if (*argptr != NULL) { |
10784 | setparam(argptr); | 10794 | setparam(argptr); |
@@ -13525,14 +13535,32 @@ init(void) | |||
13525 | setvar("PPID", utoa(getppid()), 0); | 13535 | setvar("PPID", utoa(getppid()), 0); |
13526 | 13536 | ||
13527 | p = lookupvar("PWD"); | 13537 | p = lookupvar("PWD"); |
13528 | if (p) | 13538 | if (p) { |
13529 | if (*p != '/' || stat(p, &st1) || stat(".", &st2) | 13539 | if (*p != '/' || stat(p, &st1) || stat(".", &st2) |
13530 | || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) | 13540 | || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino |
13541 | ) { | ||
13531 | p = '\0'; | 13542 | p = '\0'; |
13543 | } | ||
13544 | } | ||
13532 | setpwd(p, 0); | 13545 | setpwd(p, 0); |
13533 | } | 13546 | } |
13534 | } | 13547 | } |
13535 | 13548 | ||
13549 | |||
13550 | //usage:#define ash_trivial_usage | ||
13551 | //usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" | ||
13552 | //usage:#define ash_full_usage "\n\n" | ||
13553 | //usage: "Unix shell interpreter" | ||
13554 | |||
13555 | //usage:#if ENABLE_FEATURE_SH_IS_ASH | ||
13556 | //usage:# define sh_trivial_usage ash_trivial_usage | ||
13557 | //usage:# define sh_full_usage ash_full_usage | ||
13558 | //usage:#endif | ||
13559 | //usage:#if ENABLE_FEATURE_BASH_IS_ASH | ||
13560 | //usage:# define bash_trivial_usage ash_trivial_usage | ||
13561 | //usage:# define bash_full_usage ash_full_usage | ||
13562 | //usage:#endif | ||
13563 | |||
13536 | /* | 13564 | /* |
13537 | * Process the shell command line arguments. | 13565 | * Process the shell command line arguments. |
13538 | */ | 13566 | */ |
@@ -13550,7 +13578,7 @@ procargs(char **argv) | |||
13550 | for (i = 0; i < NOPTS; i++) | 13578 | for (i = 0; i < NOPTS; i++) |
13551 | optlist[i] = 2; | 13579 | optlist[i] = 2; |
13552 | argptr = xargv; | 13580 | argptr = xargv; |
13553 | if (options(1)) { | 13581 | if (options(/*cmdline:*/ 1)) { |
13554 | /* it already printed err message */ | 13582 | /* it already printed err message */ |
13555 | raise_exception(EXERROR); | 13583 | raise_exception(EXERROR); |
13556 | } | 13584 | } |
diff --git a/shell/hush.c b/shell/hush.c index 4d9e5f8c7..e4c3a7d77 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -81,7 +81,6 @@ | |||
81 | * $ "export" i=`echo 'aaa bbb'`; echo "$i" | 81 | * $ "export" i=`echo 'aaa bbb'`; echo "$i" |
82 | * aaa | 82 | * aaa |
83 | */ | 83 | */ |
84 | #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ | ||
85 | #if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ | 84 | #if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ |
86 | || defined(__APPLE__) \ | 85 | || defined(__APPLE__) \ |
87 | ) | 86 | ) |
@@ -93,6 +92,8 @@ | |||
93 | # include <fnmatch.h> | 92 | # include <fnmatch.h> |
94 | #endif | 93 | #endif |
95 | 94 | ||
95 | #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ | ||
96 | #include "unicode.h" | ||
96 | #include "shell_common.h" | 97 | #include "shell_common.h" |
97 | #include "math.h" | 98 | #include "math.h" |
98 | #include "match.h" | 99 | #include "match.h" |
@@ -105,14 +106,6 @@ | |||
105 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ | 106 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ |
106 | #endif | 107 | #endif |
107 | 108 | ||
108 | //applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP)) | ||
109 | //applet:IF_MSH(APPLET(msh, BB_DIR_BIN, BB_SUID_DROP)) | ||
110 | //applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, sh)) | ||
111 | //applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, bash)) | ||
112 | |||
113 | //kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o | ||
114 | //kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o | ||
115 | |||
116 | //config:config HUSH | 109 | //config:config HUSH |
117 | //config: bool "hush" | 110 | //config: bool "hush" |
118 | //config: default y | 111 | //config: default y |
@@ -249,20 +242,35 @@ | |||
249 | //config: msh is deprecated and will be removed, please migrate to hush. | 242 | //config: msh is deprecated and will be removed, please migrate to hush. |
250 | //config: | 243 | //config: |
251 | 244 | ||
245 | //applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP)) | ||
246 | //applet:IF_MSH(APPLET(msh, BB_DIR_BIN, BB_SUID_DROP)) | ||
247 | //applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, sh)) | ||
248 | //applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, bash)) | ||
249 | |||
250 | //kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o | ||
251 | //kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o | ||
252 | |||
252 | /* -i (interactive) and -s (read stdin) are also accepted, | 253 | /* -i (interactive) and -s (read stdin) are also accepted, |
253 | * but currently do nothing, therefore aren't shown in help. | 254 | * but currently do nothing, therefore aren't shown in help. |
254 | * NOMMU-specific options are not meant to be used by users, | 255 | * NOMMU-specific options are not meant to be used by users, |
255 | * therefore we don't show them either. | 256 | * therefore we don't show them either. |
256 | */ | 257 | */ |
257 | //usage:#define hush_trivial_usage | 258 | //usage:#define hush_trivial_usage |
258 | //usage: "[-nx] [-c SCRIPT]" | 259 | //usage: "[-nx] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" |
259 | //usage:#define hush_full_usage "" | 260 | //usage:#define hush_full_usage "\n\n" |
261 | //usage: "Unix shell interpreter" | ||
262 | |||
260 | //usage:#define msh_trivial_usage hush_trivial_usage | 263 | //usage:#define msh_trivial_usage hush_trivial_usage |
261 | //usage:#define msh_full_usage "" | 264 | //usage:#define msh_full_usage hush_full_usage |
262 | //usage:#define sh_trivial_usage NOUSAGE_STR | 265 | |
263 | //usage:#define sh_full_usage "" | 266 | //usage:#if ENABLE_FEATURE_SH_IS_HUSH |
264 | //usage:#define bash_trivial_usage NOUSAGE_STR | 267 | //usage:# define sh_trivial_usage hush_trivial_usage |
265 | //usage:#define bash_full_usage "" | 268 | //usage:# define sh_full_usage hush_full_usage |
269 | //usage:#endif | ||
270 | //usage:#if ENABLE_FEATURE_BASH_IS_HUSH | ||
271 | //usage:# define bash_trivial_usage hush_trivial_usage | ||
272 | //usage:# define bash_full_usage hush_full_usage | ||
273 | //usage:#endif | ||
266 | 274 | ||
267 | 275 | ||
268 | /* Build knobs */ | 276 | /* Build knobs */ |
@@ -1087,17 +1095,10 @@ static void syntax_error_unterm_str(unsigned lineno, const char *s) | |||
1087 | die_if_script(lineno, "syntax error: unterminated %s", s); | 1095 | die_if_script(lineno, "syntax error: unterminated %s", s); |
1088 | } | 1096 | } |
1089 | 1097 | ||
1090 | /* It so happens that all such cases are totally fatal | ||
1091 | * even if shell is interactive: EOF while looking for closing | ||
1092 | * delimiter. There is nowhere to read stuff from after that, | ||
1093 | * it's EOF! The only choice is to terminate. | ||
1094 | */ | ||
1095 | static void syntax_error_unterm_ch(unsigned lineno, char ch) NORETURN; | ||
1096 | static void syntax_error_unterm_ch(unsigned lineno, char ch) | 1098 | static void syntax_error_unterm_ch(unsigned lineno, char ch) |
1097 | { | 1099 | { |
1098 | char msg[2] = { ch, '\0' }; | 1100 | char msg[2] = { ch, '\0' }; |
1099 | syntax_error_unterm_str(lineno, msg); | 1101 | syntax_error_unterm_str(lineno, msg); |
1100 | xfunc_die(); | ||
1101 | } | 1102 | } |
1102 | 1103 | ||
1103 | static void syntax_error_unexpected_ch(unsigned lineno, int ch) | 1104 | static void syntax_error_unexpected_ch(unsigned lineno, int ch) |
@@ -1899,6 +1900,12 @@ static void get_user_input(struct in_str *i) | |||
1899 | /* Enable command line editing only while a command line | 1900 | /* Enable command line editing only while a command line |
1900 | * is actually being read */ | 1901 | * is actually being read */ |
1901 | do { | 1902 | do { |
1903 | /* Unicode support should be activated even if LANG is set | ||
1904 | * _during_ shell execution, not only if it was set when | ||
1905 | * shell was started. Therefore, re-check LANG every time: | ||
1906 | */ | ||
1907 | reinit_unicode(get_local_var_value("LANG")); | ||
1908 | |||
1902 | G.flag_SIGINT = 0; | 1909 | G.flag_SIGINT = 0; |
1903 | /* buglet: SIGINT will not make new prompt to appear _at once_, | 1910 | /* buglet: SIGINT will not make new prompt to appear _at once_, |
1904 | * only after <Enter>. (^C will work) */ | 1911 | * only after <Enter>. (^C will work) */ |
@@ -3525,39 +3532,40 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
3525 | 3532 | ||
3526 | #if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS | 3533 | #if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS |
3527 | /* Subroutines for copying $(...) and `...` things */ | 3534 | /* Subroutines for copying $(...) and `...` things */ |
3528 | static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); | 3535 | static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); |
3529 | /* '...' */ | 3536 | /* '...' */ |
3530 | static void add_till_single_quote(o_string *dest, struct in_str *input) | 3537 | static int add_till_single_quote(o_string *dest, struct in_str *input) |
3531 | { | 3538 | { |
3532 | while (1) { | 3539 | while (1) { |
3533 | int ch = i_getch(input); | 3540 | int ch = i_getch(input); |
3534 | if (ch == EOF) { | 3541 | if (ch == EOF) { |
3535 | syntax_error_unterm_ch('\''); | 3542 | syntax_error_unterm_ch('\''); |
3536 | /*xfunc_die(); - redundant */ | 3543 | return 0; |
3537 | } | 3544 | } |
3538 | if (ch == '\'') | 3545 | if (ch == '\'') |
3539 | return; | 3546 | return 1; |
3540 | o_addchr(dest, ch); | 3547 | o_addchr(dest, ch); |
3541 | } | 3548 | } |
3542 | } | 3549 | } |
3543 | /* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ | 3550 | /* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ |
3544 | static void add_till_double_quote(o_string *dest, struct in_str *input) | 3551 | static int add_till_double_quote(o_string *dest, struct in_str *input) |
3545 | { | 3552 | { |
3546 | while (1) { | 3553 | while (1) { |
3547 | int ch = i_getch(input); | 3554 | int ch = i_getch(input); |
3548 | if (ch == EOF) { | 3555 | if (ch == EOF) { |
3549 | syntax_error_unterm_ch('"'); | 3556 | syntax_error_unterm_ch('"'); |
3550 | /*xfunc_die(); - redundant */ | 3557 | return 0; |
3551 | } | 3558 | } |
3552 | if (ch == '"') | 3559 | if (ch == '"') |
3553 | return; | 3560 | return 1; |
3554 | if (ch == '\\') { /* \x. Copy both chars. */ | 3561 | if (ch == '\\') { /* \x. Copy both chars. */ |
3555 | o_addchr(dest, ch); | 3562 | o_addchr(dest, ch); |
3556 | ch = i_getch(input); | 3563 | ch = i_getch(input); |
3557 | } | 3564 | } |
3558 | o_addchr(dest, ch); | 3565 | o_addchr(dest, ch); |
3559 | if (ch == '`') { | 3566 | if (ch == '`') { |
3560 | add_till_backquote(dest, input, /*in_dquote:*/ 1); | 3567 | if (!add_till_backquote(dest, input, /*in_dquote:*/ 1)) |
3568 | return 0; | ||
3561 | o_addchr(dest, ch); | 3569 | o_addchr(dest, ch); |
3562 | continue; | 3570 | continue; |
3563 | } | 3571 | } |
@@ -3578,12 +3586,12 @@ static void add_till_double_quote(o_string *dest, struct in_str *input) | |||
3578 | * Example Output | 3586 | * Example Output |
3579 | * echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST | 3587 | * echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST |
3580 | */ | 3588 | */ |
3581 | static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquote) | 3589 | static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote) |
3582 | { | 3590 | { |
3583 | while (1) { | 3591 | while (1) { |
3584 | int ch = i_getch(input); | 3592 | int ch = i_getch(input); |
3585 | if (ch == '`') | 3593 | if (ch == '`') |
3586 | return; | 3594 | return 1; |
3587 | if (ch == '\\') { | 3595 | if (ch == '\\') { |
3588 | /* \x. Copy both unless it is \`, \$, \\ and maybe \" */ | 3596 | /* \x. Copy both unless it is \`, \$, \\ and maybe \" */ |
3589 | ch = i_getch(input); | 3597 | ch = i_getch(input); |
@@ -3597,7 +3605,7 @@ static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquo | |||
3597 | } | 3605 | } |
3598 | if (ch == EOF) { | 3606 | if (ch == EOF) { |
3599 | syntax_error_unterm_ch('`'); | 3607 | syntax_error_unterm_ch('`'); |
3600 | /*xfunc_die(); - redundant */ | 3608 | return 0; |
3601 | } | 3609 | } |
3602 | o_addchr(dest, ch); | 3610 | o_addchr(dest, ch); |
3603 | } | 3611 | } |
@@ -3633,7 +3641,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign | |||
3633 | ch = i_getch(input); | 3641 | ch = i_getch(input); |
3634 | if (ch == EOF) { | 3642 | if (ch == EOF) { |
3635 | syntax_error_unterm_ch(end_ch); | 3643 | syntax_error_unterm_ch(end_ch); |
3636 | /*xfunc_die(); - redundant */ | 3644 | return 0; |
3637 | } | 3645 | } |
3638 | if (ch == end_ch IF_HUSH_BASH_COMPAT( || ch == end_char2)) { | 3646 | if (ch == end_ch IF_HUSH_BASH_COMPAT( || ch == end_char2)) { |
3639 | if (!dbl) | 3647 | if (!dbl) |
@@ -3647,22 +3655,26 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign | |||
3647 | o_addchr(dest, ch); | 3655 | o_addchr(dest, ch); |
3648 | if (ch == '(' || ch == '{') { | 3656 | if (ch == '(' || ch == '{') { |
3649 | ch = (ch == '(' ? ')' : '}'); | 3657 | ch = (ch == '(' ? ')' : '}'); |
3650 | add_till_closing_bracket(dest, input, ch); | 3658 | if (!add_till_closing_bracket(dest, input, ch)) |
3659 | return 0; | ||
3651 | o_addchr(dest, ch); | 3660 | o_addchr(dest, ch); |
3652 | continue; | 3661 | continue; |
3653 | } | 3662 | } |
3654 | if (ch == '\'') { | 3663 | if (ch == '\'') { |
3655 | add_till_single_quote(dest, input); | 3664 | if (!add_till_single_quote(dest, input)) |
3665 | return 0; | ||
3656 | o_addchr(dest, ch); | 3666 | o_addchr(dest, ch); |
3657 | continue; | 3667 | continue; |
3658 | } | 3668 | } |
3659 | if (ch == '"') { | 3669 | if (ch == '"') { |
3660 | add_till_double_quote(dest, input); | 3670 | if (!add_till_double_quote(dest, input)) |
3671 | return 0; | ||
3661 | o_addchr(dest, ch); | 3672 | o_addchr(dest, ch); |
3662 | continue; | 3673 | continue; |
3663 | } | 3674 | } |
3664 | if (ch == '`') { | 3675 | if (ch == '`') { |
3665 | add_till_backquote(dest, input, /*in_dquote:*/ 0); | 3676 | if (!add_till_backquote(dest, input, /*in_dquote:*/ 0)) |
3677 | return 0; | ||
3666 | o_addchr(dest, ch); | 3678 | o_addchr(dest, ch); |
3667 | continue; | 3679 | continue; |
3668 | } | 3680 | } |
@@ -3671,7 +3683,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign | |||
3671 | ch = i_getch(input); | 3683 | ch = i_getch(input); |
3672 | if (ch == EOF) { | 3684 | if (ch == EOF) { |
3673 | syntax_error_unterm_ch(')'); | 3685 | syntax_error_unterm_ch(')'); |
3674 | /*xfunc_die(); - redundant */ | 3686 | return 0; |
3675 | } | 3687 | } |
3676 | o_addchr(dest, ch); | 3688 | o_addchr(dest, ch); |
3677 | continue; | 3689 | continue; |
@@ -3742,8 +3754,8 @@ static int parse_dollar(o_string *as_string, | |||
3742 | ) { | 3754 | ) { |
3743 | bad_dollar_syntax: | 3755 | bad_dollar_syntax: |
3744 | syntax_error_unterm_str("${name}"); | 3756 | syntax_error_unterm_str("${name}"); |
3745 | debug_printf_parse("parse_dollar return 1: unterminated ${name}\n"); | 3757 | debug_printf_parse("parse_dollar return 0: unterminated ${name}\n"); |
3746 | return 1; | 3758 | return 0; |
3747 | } | 3759 | } |
3748 | nommu_addchr(as_string, ch); | 3760 | nommu_addchr(as_string, ch); |
3749 | ch |= quote_mask; | 3761 | ch |= quote_mask; |
@@ -3799,6 +3811,8 @@ static int parse_dollar(o_string *as_string, | |||
3799 | pos = dest->length; | 3811 | pos = dest->length; |
3800 | #if ENABLE_HUSH_DOLLAR_OPS | 3812 | #if ENABLE_HUSH_DOLLAR_OPS |
3801 | last_ch = add_till_closing_bracket(dest, input, end_ch); | 3813 | last_ch = add_till_closing_bracket(dest, input, end_ch); |
3814 | if (last_ch == 0) /* error? */ | ||
3815 | return 0; | ||
3802 | #else | 3816 | #else |
3803 | #error Simple code to only allow ${var} is not implemented | 3817 | #error Simple code to only allow ${var} is not implemented |
3804 | #endif | 3818 | #endif |
@@ -3843,7 +3857,8 @@ static int parse_dollar(o_string *as_string, | |||
3843 | o_addchr(dest, /*quote_mask |*/ '+'); | 3857 | o_addchr(dest, /*quote_mask |*/ '+'); |
3844 | if (!BB_MMU) | 3858 | if (!BB_MMU) |
3845 | pos = dest->length; | 3859 | pos = dest->length; |
3846 | add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG); | 3860 | if (!add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG)) |
3861 | return 0; /* error */ | ||
3847 | if (as_string) { | 3862 | if (as_string) { |
3848 | o_addstr(as_string, dest->data + pos); | 3863 | o_addstr(as_string, dest->data + pos); |
3849 | o_addchr(as_string, ')'); | 3864 | o_addchr(as_string, ')'); |
@@ -3858,7 +3873,8 @@ static int parse_dollar(o_string *as_string, | |||
3858 | o_addchr(dest, quote_mask | '`'); | 3873 | o_addchr(dest, quote_mask | '`'); |
3859 | if (!BB_MMU) | 3874 | if (!BB_MMU) |
3860 | pos = dest->length; | 3875 | pos = dest->length; |
3861 | add_till_closing_bracket(dest, input, ')'); | 3876 | if (!add_till_closing_bracket(dest, input, ')')) |
3877 | return 0; /* error */ | ||
3862 | if (as_string) { | 3878 | if (as_string) { |
3863 | o_addstr(as_string, dest->data + pos); | 3879 | o_addstr(as_string, dest->data + pos); |
3864 | o_addchr(as_string, ')'); | 3880 | o_addchr(as_string, ')'); |
@@ -3885,8 +3901,8 @@ static int parse_dollar(o_string *as_string, | |||
3885 | default: | 3901 | default: |
3886 | o_addQchr(dest, '$'); | 3902 | o_addQchr(dest, '$'); |
3887 | } | 3903 | } |
3888 | debug_printf_parse("parse_dollar return 0\n"); | 3904 | debug_printf_parse("parse_dollar return 1 (ok)\n"); |
3889 | return 0; | 3905 | return 1; |
3890 | #undef as_string | 3906 | #undef as_string |
3891 | } | 3907 | } |
3892 | 3908 | ||
@@ -3927,13 +3943,13 @@ static int encode_string(o_string *as_string, | |||
3927 | if (ch != EOF) | 3943 | if (ch != EOF) |
3928 | nommu_addchr(as_string, ch); | 3944 | nommu_addchr(as_string, ch); |
3929 | if (ch == dquote_end) { /* may be only '"' or EOF */ | 3945 | if (ch == dquote_end) { /* may be only '"' or EOF */ |
3930 | debug_printf_parse("encode_string return 0\n"); | 3946 | debug_printf_parse("encode_string return 1 (ok)\n"); |
3931 | return 0; | 3947 | return 1; |
3932 | } | 3948 | } |
3933 | /* note: can't move it above ch == dquote_end check! */ | 3949 | /* note: can't move it above ch == dquote_end check! */ |
3934 | if (ch == EOF) { | 3950 | if (ch == EOF) { |
3935 | syntax_error_unterm_ch('"'); | 3951 | syntax_error_unterm_ch('"'); |
3936 | /*xfunc_die(); - redundant */ | 3952 | return 0; /* error */ |
3937 | } | 3953 | } |
3938 | next = '\0'; | 3954 | next = '\0'; |
3939 | if (ch != '\n') { | 3955 | if (ch != '\n') { |
@@ -3964,10 +3980,10 @@ static int encode_string(o_string *as_string, | |||
3964 | goto again; | 3980 | goto again; |
3965 | } | 3981 | } |
3966 | if (ch == '$') { | 3982 | if (ch == '$') { |
3967 | if (parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80) != 0) { | 3983 | if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) { |
3968 | debug_printf_parse("encode_string return 1: " | 3984 | debug_printf_parse("encode_string return 0: " |
3969 | "parse_dollar returned non-0\n"); | 3985 | "parse_dollar returned 0 (error)\n"); |
3970 | return 1; | 3986 | return 0; |
3971 | } | 3987 | } |
3972 | goto again; | 3988 | goto again; |
3973 | } | 3989 | } |
@@ -3976,7 +3992,8 @@ static int encode_string(o_string *as_string, | |||
3976 | //unsigned pos = dest->length; | 3992 | //unsigned pos = dest->length; |
3977 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 3993 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
3978 | o_addchr(dest, 0x80 | '`'); | 3994 | o_addchr(dest, 0x80 | '`'); |
3979 | add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"'); | 3995 | if (!add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"')) |
3996 | return 0; /* error */ | ||
3980 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 3997 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
3981 | //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); | 3998 | //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); |
3982 | goto again; | 3999 | goto again; |
@@ -4047,8 +4064,8 @@ static struct pipe *parse_stream(char **pstring, | |||
4047 | /* end_trigger == '}' case errors out earlier, | 4064 | /* end_trigger == '}' case errors out earlier, |
4048 | * checking only ')' */ | 4065 | * checking only ')' */ |
4049 | if (end_trigger == ')') { | 4066 | if (end_trigger == ')') { |
4050 | syntax_error_unterm_ch('('); /* exits */ | 4067 | syntax_error_unterm_ch('('); |
4051 | /* goto parse_error; */ | 4068 | goto parse_error; |
4052 | } | 4069 | } |
4053 | 4070 | ||
4054 | if (done_word(&dest, &ctx)) { | 4071 | if (done_word(&dest, &ctx)) { |
@@ -4339,9 +4356,9 @@ static struct pipe *parse_stream(char **pstring, | |||
4339 | dest.has_quoted_part = 1; | 4356 | dest.has_quoted_part = 1; |
4340 | break; | 4357 | break; |
4341 | case '$': | 4358 | case '$': |
4342 | if (parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0) != 0) { | 4359 | if (!parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0)) { |
4343 | debug_printf_parse("parse_stream parse error: " | 4360 | debug_printf_parse("parse_stream parse error: " |
4344 | "parse_dollar returned non-0\n"); | 4361 | "parse_dollar returned 0 (error)\n"); |
4345 | goto parse_error; | 4362 | goto parse_error; |
4346 | } | 4363 | } |
4347 | break; | 4364 | break; |
@@ -4351,7 +4368,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4351 | ch = i_getch(input); | 4368 | ch = i_getch(input); |
4352 | if (ch == EOF) { | 4369 | if (ch == EOF) { |
4353 | syntax_error_unterm_ch('\''); | 4370 | syntax_error_unterm_ch('\''); |
4354 | /*xfunc_die(); - redundant */ | 4371 | goto parse_error; |
4355 | } | 4372 | } |
4356 | nommu_addchr(&ctx.as_string, ch); | 4373 | nommu_addchr(&ctx.as_string, ch); |
4357 | if (ch == '\'') | 4374 | if (ch == '\'') |
@@ -4363,7 +4380,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4363 | dest.has_quoted_part = 1; | 4380 | dest.has_quoted_part = 1; |
4364 | if (dest.o_assignment == NOT_ASSIGNMENT) | 4381 | if (dest.o_assignment == NOT_ASSIGNMENT) |
4365 | dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; | 4382 | dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; |
4366 | if (encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) | 4383 | if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) |
4367 | goto parse_error; | 4384 | goto parse_error; |
4368 | dest.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; | 4385 | dest.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; |
4369 | break; | 4386 | break; |
@@ -4374,7 +4391,8 @@ static struct pipe *parse_stream(char **pstring, | |||
4374 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); | 4391 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); |
4375 | o_addchr(&dest, '`'); | 4392 | o_addchr(&dest, '`'); |
4376 | pos = dest.length; | 4393 | pos = dest.length; |
4377 | add_till_backquote(&dest, input, /*in_dquote:*/ 0); | 4394 | if (!add_till_backquote(&dest, input, /*in_dquote:*/ 0)) |
4395 | goto parse_error; | ||
4378 | # if !BB_MMU | 4396 | # if !BB_MMU |
4379 | o_addstr(&ctx.as_string, dest.data + pos); | 4397 | o_addstr(&ctx.as_string, dest.data + pos); |
4380 | o_addchr(&ctx.as_string, '`'); | 4398 | o_addchr(&ctx.as_string, '`'); |
@@ -4650,6 +4668,7 @@ static char *encode_then_expand_string(const char *str, int process_bkslash, int | |||
4650 | */ | 4668 | */ |
4651 | setup_string_in_str(&input, str); | 4669 | setup_string_in_str(&input, str); |
4652 | encode_string(NULL, &dest, &input, EOF, process_bkslash); | 4670 | encode_string(NULL, &dest, &input, EOF, process_bkslash); |
4671 | //TODO: error check (encode_string returns 0 on error)? | ||
4653 | //bb_error_msg("'%s' -> '%s'", str, dest.data); | 4672 | //bb_error_msg("'%s' -> '%s'", str, dest.data); |
4654 | exp_str = expand_string_to_string(dest.data, /*unbackslash:*/ do_unbackslash); | 4673 | exp_str = expand_string_to_string(dest.data, /*unbackslash:*/ do_unbackslash); |
4655 | //bb_error_msg("'%s' -> '%s'", dest.data, exp_str); | 4674 | //bb_error_msg("'%s' -> '%s'", dest.data, exp_str); |
@@ -5540,6 +5559,10 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger) | |||
5540 | debug_printf_exec("parse_and_run_stream: run_and_free_list\n"); | 5559 | debug_printf_exec("parse_and_run_stream: run_and_free_list\n"); |
5541 | run_and_free_list(pipe_list); | 5560 | run_and_free_list(pipe_list); |
5542 | empty = 0; | 5561 | empty = 0; |
5562 | #if ENABLE_HUSH_FUNCTIONS | ||
5563 | if (G.flag_return_in_progress == 1) | ||
5564 | break; | ||
5565 | #endif | ||
5543 | } | 5566 | } |
5544 | } | 5567 | } |
5545 | 5568 | ||
@@ -8607,6 +8630,8 @@ static int FAST_FUNC builtin_source(char **argv) | |||
8607 | #endif | 8630 | #endif |
8608 | save_and_replace_G_args(&sv, argv); | 8631 | save_and_replace_G_args(&sv, argv); |
8609 | 8632 | ||
8633 | //TODO: syntax errors in sourced file should never abort the "calling" script. | ||
8634 | //Try: bash -c '. ./bad_file; echo YES' | ||
8610 | parse_and_run_file(input); | 8635 | parse_and_run_file(input); |
8611 | fclose(input); | 8636 | fclose(input); |
8612 | 8637 | ||
diff --git a/shell/hush_test/hush-misc/return1.right b/shell/hush_test/hush-misc/return1.right new file mode 100644 index 000000000..7b24a35ff --- /dev/null +++ b/shell/hush_test/hush-misc/return1.right | |||
@@ -0,0 +1 @@ | |||
Ok:0 | |||
diff --git a/shell/hush_test/hush-misc/return1.tests b/shell/hush_test/hush-misc/return1.tests new file mode 100755 index 000000000..eeb92ef3f --- /dev/null +++ b/shell/hush_test/hush-misc/return1.tests | |||
@@ -0,0 +1,4 @@ | |||
1 | echo "true && return; echo Should not be printed" >return_sourced | ||
2 | . ./return_sourced | ||
3 | rm return_sourced | ||
4 | echo Ok:$? | ||
diff --git a/shell/hush_test/hush-misc/source1.right b/shell/hush_test/hush-misc/source1.right new file mode 100644 index 000000000..d4256034b --- /dev/null +++ b/shell/hush_test/hush-misc/source1.right | |||
@@ -0,0 +1,5 @@ | |||
1 | hush: syntax error: unterminated ${name} | ||
2 | line2 | ||
3 | Ok1:0 | ||
4 | hush: syntax error: unterminated ' | ||
5 | Ok2:1 | ||
diff --git a/shell/hush_test/hush-misc/source1.tests b/shell/hush_test/hush-misc/source1.tests new file mode 100755 index 000000000..c13888359 --- /dev/null +++ b/shell/hush_test/hush-misc/source1.tests | |||
@@ -0,0 +1,10 @@ | |||
1 | echo 'echo ${^} | ||
2 | echo line2' >sourced1 | ||
3 | . ./sourced1 | ||
4 | echo Ok1:$? | ||
5 | |||
6 | echo "echo '" >sourced1 | ||
7 | . ./sourced1 | ||
8 | echo Ok2:$? | ||
9 | |||
10 | rm sourced1 | ||