diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 465 |
1 files changed, 294 insertions, 171 deletions
diff --git a/shell/ash.c b/shell/ash.c index e21c4433d..0325a325c 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -50,8 +50,6 @@ | |||
50 | //config: bool "Optimize for size instead of speed" | 50 | //config: bool "Optimize for size instead of speed" |
51 | //config: default y | 51 | //config: default y |
52 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 52 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
53 | //config: help | ||
54 | //config: Compile ash for reduced size at the price of speed. | ||
55 | //config: | 53 | //config: |
56 | //config:config ASH_INTERNAL_GLOB | 54 | //config:config ASH_INTERNAL_GLOB |
57 | //config: bool "Use internal glob() implementation" | 55 | //config: bool "Use internal glob() implementation" |
@@ -61,6 +59,23 @@ | |||
61 | //config: Do not use glob() function from libc, use internal implementation. | 59 | //config: Do not use glob() function from libc, use internal implementation. |
62 | //config: Use this if you are getting "glob.h: No such file or directory" | 60 | //config: Use this if you are getting "glob.h: No such file or directory" |
63 | //config: or similar build errors. | 61 | //config: or similar build errors. |
62 | //config: Note that as of now (2017-01), uclibc and musl glob() both have bugs | ||
63 | //config: which would break ash if you select N here. | ||
64 | //config: | ||
65 | //config:config ASH_BASH_COMPAT | ||
66 | //config: bool "bash-compatible extensions" | ||
67 | //config: default y | ||
68 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | ||
69 | //config: | ||
70 | //config:config ASH_JOB_CONTROL | ||
71 | //config: bool "Job control" | ||
72 | //config: default y | ||
73 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | ||
74 | //config: | ||
75 | //config:config ASH_ALIAS | ||
76 | //config: bool "Alias support" | ||
77 | //config: default y | ||
78 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | ||
64 | //config: | 79 | //config: |
65 | //config:config ASH_RANDOM_SUPPORT | 80 | //config:config ASH_RANDOM_SUPPORT |
66 | //config: bool "Pseudorandom generator and $RANDOM variable" | 81 | //config: bool "Pseudorandom generator and $RANDOM variable" |
@@ -78,88 +93,60 @@ | |||
78 | //config: default y | 93 | //config: default y |
79 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 94 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
80 | //config: help | 95 | //config: help |
81 | //config: "PS#" may contain volatile content, such as backquote commands. | 96 | //config: $PS# may contain volatile content, such as backquote commands. |
82 | //config: This option recreates the prompt string from the environment | 97 | //config: This option recreates the prompt string from the environment |
83 | //config: variable each time it is displayed. | 98 | //config: variable each time it is displayed. |
84 | //config: | 99 | //config: |
85 | //config:config ASH_BASH_COMPAT | ||
86 | //config: bool "bash-compatible extensions" | ||
87 | //config: default y | ||
88 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | ||
89 | //config: help | ||
90 | //config: Enable bash-compatible extensions. | ||
91 | //config: | ||
92 | //config:config ASH_IDLE_TIMEOUT | 100 | //config:config ASH_IDLE_TIMEOUT |
93 | //config: bool "Idle timeout variable" | 101 | //config: bool "Idle timeout variable $TMOUT" |
94 | //config: default n | ||
95 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | ||
96 | //config: help | ||
97 | //config: Enables bash-like auto-logout after $TMOUT seconds of idle time. | ||
98 | //config: | ||
99 | //config:config ASH_JOB_CONTROL | ||
100 | //config: bool "Job control" | ||
101 | //config: default y | ||
102 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | ||
103 | //config: help | ||
104 | //config: Enable job control in the ash shell. | ||
105 | //config: | ||
106 | //config:config ASH_ALIAS | ||
107 | //config: bool "Alias support" | ||
108 | //config: default y | 102 | //config: default y |
109 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 103 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
110 | //config: help | 104 | //config: help |
111 | //config: Enable alias support in the ash shell. | 105 | //config: Enable bash-like auto-logout after $TMOUT seconds of idle time. |
112 | //config: | 106 | //config: |
113 | //config:config ASH_GETOPTS | 107 | //config:config ASH_MAIL |
114 | //config: bool "Builtin getopt to parse positional parameters" | 108 | //config: bool "Check for new mail in interactive shell" |
115 | //config: default y | 109 | //config: default y |
116 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 110 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
117 | //config: help | 111 | //config: help |
118 | //config: Enable support for getopts builtin in ash. | 112 | //config: Enable "check for new mail" function: |
113 | //config: if set, $MAIL file and $MAILPATH list of files | ||
114 | //config: are checked for mtime changes, and "you have mail" | ||
115 | //config: message is printed if change is detected. | ||
119 | //config: | 116 | //config: |
120 | //config:config ASH_BUILTIN_ECHO | 117 | //config:config ASH_ECHO |
121 | //config: bool "Builtin version of 'echo'" | 118 | //config: bool "echo builtin" |
122 | //config: default y | 119 | //config: default y |
123 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 120 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
124 | //config: help | ||
125 | //config: Enable support for echo builtin in ash. | ||
126 | //config: | 121 | //config: |
127 | //config:config ASH_BUILTIN_PRINTF | 122 | //config:config ASH_PRINTF |
128 | //config: bool "Builtin version of 'printf'" | 123 | //config: bool "printf builtin" |
129 | //config: default y | 124 | //config: default y |
130 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 125 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
131 | //config: help | ||
132 | //config: Enable support for printf builtin in ash. | ||
133 | //config: | 126 | //config: |
134 | //config:config ASH_BUILTIN_TEST | 127 | //config:config ASH_TEST |
135 | //config: bool "Builtin version of 'test'" | 128 | //config: bool "test builtin" |
136 | //config: default y | 129 | //config: default y |
137 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 130 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
138 | //config: help | ||
139 | //config: Enable support for test builtin in ash. | ||
140 | //config: | 131 | //config: |
141 | //config:config ASH_HELP | 132 | //config:config ASH_HELP |
142 | //config: bool "help builtin" | 133 | //config: bool "help builtin" |
143 | //config: default y | 134 | //config: default y |
144 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 135 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
145 | //config: help | ||
146 | //config: Enable help builtin in ash. | ||
147 | //config: | 136 | //config: |
148 | //config:config ASH_CMDCMD | 137 | //config:config ASH_GETOPTS |
149 | //config: bool "'command' command to override shell builtins" | 138 | //config: bool "getopts builtin" |
150 | //config: default y | 139 | //config: default y |
151 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 140 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
152 | //config: help | ||
153 | //config: Enable support for the ash 'command' builtin, which allows | ||
154 | //config: you to run the specified command with the specified arguments, | ||
155 | //config: even when there is an ash builtin command with the same name. | ||
156 | //config: | 141 | //config: |
157 | //config:config ASH_MAIL | 142 | //config:config ASH_CMDCMD |
158 | //config: bool "Check for new mail on interactive shells" | 143 | //config: bool "command builtin" |
159 | //config: default y | 144 | //config: default y |
160 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 145 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
161 | //config: help | 146 | //config: help |
162 | //config: Enable "check for new mail" function in the ash shell. | 147 | //config: Enable support for the 'command' builtin, which allows |
148 | //config: you to run the specified command or builtin, | ||
149 | //config: even when there is a function with the same name. | ||
163 | //config: | 150 | //config: |
164 | //config: | 151 | //config: |
165 | //config:config ASH_NOCONSOLE | 152 | //config:config ASH_NOCONSOLE |
@@ -176,7 +163,8 @@ | |||
176 | //config:endif # ash options | 163 | //config:endif # ash options |
177 | 164 | ||
178 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) | 165 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) |
179 | //applet:IF_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) | 166 | // APPLET_ODDNAME:name main location suid_type help |
167 | //applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) | ||
180 | //applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) | 168 | //applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) |
181 | 169 | ||
182 | //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o | 170 | //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o |
@@ -185,15 +173,10 @@ | |||
185 | //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o | 173 | //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o |
186 | 174 | ||
187 | /* | 175 | /* |
188 | * The following should be set to reflect the type of system you have: | 176 | * DEBUG=1 to compile in debugging ('set -o debug' turns on) |
189 | * JOBS -> 1 if you have Berkeley job control, 0 otherwise. | 177 | * DEBUG=2 to compile in and turn on debugging. |
190 | * define SYSV if you are running under System V. | 178 | * When debugging is on ("set -o debug" was executed, or DEBUG=2), |
191 | * define DEBUG=1 to compile in debugging ('set -o debug' to turn on) | 179 | * debugging info is written to ./trace, quit signal generates core dump. |
192 | * define DEBUG=2 to compile in and turn on debugging. | ||
193 | * | ||
194 | * When debugging is on (DEBUG is 1 and "set -o debug" was executed), | ||
195 | * debugging info will be written to ./trace and a quit signal | ||
196 | * will generate a core dump. | ||
197 | */ | 180 | */ |
198 | #define DEBUG 0 | 181 | #define DEBUG 0 |
199 | /* Tweak debug output verbosity here */ | 182 | /* Tweak debug output verbosity here */ |
@@ -210,9 +193,30 @@ | |||
210 | #include <fnmatch.h> | 193 | #include <fnmatch.h> |
211 | #include <sys/times.h> | 194 | #include <sys/times.h> |
212 | #include <sys/utsname.h> /* for setting $HOSTNAME */ | 195 | #include <sys/utsname.h> /* for setting $HOSTNAME */ |
213 | |||
214 | #include "busybox.h" /* for applet_names */ | 196 | #include "busybox.h" /* for applet_names */ |
215 | 197 | ||
198 | /* So far, all bash compat is controlled by one config option */ | ||
199 | /* Separate defines document which part of code implements what */ | ||
200 | /* function keyword */ | ||
201 | #define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT | ||
202 | #define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT | ||
203 | /* &>file */ | ||
204 | #define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT | ||
205 | #define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT | ||
206 | /* $'...' */ | ||
207 | #define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT | ||
208 | #define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT | ||
209 | #define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT | ||
210 | #define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT | ||
211 | #define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT | ||
212 | #define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT | ||
213 | /* [[ EXPR ]] */ | ||
214 | #define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST) | ||
215 | #define BASH_SOURCE ENABLE_ASH_BASH_COMPAT | ||
216 | #define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT | ||
217 | #define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT | ||
218 | #define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT | ||
219 | |||
216 | #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 | 220 | #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 |
217 | /* Bionic at least up to version 24 has no glob() */ | 221 | /* Bionic at least up to version 24 has no glob() */ |
218 | # undef ENABLE_ASH_INTERNAL_GLOB | 222 | # undef ENABLE_ASH_INTERNAL_GLOB |
@@ -338,7 +342,7 @@ static const char *const optletters_optnames[] = { | |||
338 | "b" "notify", | 342 | "b" "notify", |
339 | "u" "nounset", | 343 | "u" "nounset", |
340 | "\0" "vi" | 344 | "\0" "vi" |
341 | #if ENABLE_ASH_BASH_COMPAT | 345 | #if BASH_PIPEFAIL |
342 | ,"\0" "pipefail" | 346 | ,"\0" "pipefail" |
343 | #endif | 347 | #endif |
344 | #if DEBUG | 348 | #if DEBUG |
@@ -421,14 +425,14 @@ struct globals_misc { | |||
421 | #define bflag optlist[11] | 425 | #define bflag optlist[11] |
422 | #define uflag optlist[12] | 426 | #define uflag optlist[12] |
423 | #define viflag optlist[13] | 427 | #define viflag optlist[13] |
424 | #if ENABLE_ASH_BASH_COMPAT | 428 | #if BASH_PIPEFAIL |
425 | # define pipefail optlist[14] | 429 | # define pipefail optlist[14] |
426 | #else | 430 | #else |
427 | # define pipefail 0 | 431 | # define pipefail 0 |
428 | #endif | 432 | #endif |
429 | #if DEBUG | 433 | #if DEBUG |
430 | # define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] | 434 | # define nolog optlist[14 + BASH_PIPEFAIL] |
431 | # define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] | 435 | # define debug optlist[15 + BASH_PIPEFAIL] |
432 | #endif | 436 | #endif |
433 | #if ENABLE_PLATFORM_MINGW32 | 437 | #if ENABLE_PLATFORM_MINGW32 |
434 | # define winxp optlist[14 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG] | 438 | # define winxp optlist[14 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG] |
@@ -755,8 +759,10 @@ out2str(const char *p) | |||
755 | #define VSTRIMLEFT 0x8 /* ${var#pattern} */ | 759 | #define VSTRIMLEFT 0x8 /* ${var#pattern} */ |
756 | #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */ | 760 | #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */ |
757 | #define VSLENGTH 0xa /* ${#var} */ | 761 | #define VSLENGTH 0xa /* ${#var} */ |
758 | #if ENABLE_ASH_BASH_COMPAT | 762 | #if BASH_SUBSTR |
759 | #define VSSUBSTR 0xc /* ${var:position:length} */ | 763 | #define VSSUBSTR 0xc /* ${var:position:length} */ |
764 | #endif | ||
765 | #if BASH_PATTERN_SUBST | ||
760 | #define VSREPLACE 0xd /* ${var/pattern/replacement} */ | 766 | #define VSREPLACE 0xd /* ${var/pattern/replacement} */ |
761 | #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */ | 767 | #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */ |
762 | #endif | 768 | #endif |
@@ -783,7 +789,7 @@ static const char dolatstr[] ALIGN1 = { | |||
783 | #define NDEFUN 14 | 789 | #define NDEFUN 14 |
784 | #define NARG 15 | 790 | #define NARG 15 |
785 | #define NTO 16 | 791 | #define NTO 16 |
786 | #if ENABLE_ASH_BASH_COMPAT | 792 | #if BASH_REDIR_OUTPUT |
787 | #define NTO2 17 | 793 | #define NTO2 17 |
788 | #endif | 794 | #endif |
789 | #define NCLOBBER 18 | 795 | #define NCLOBBER 18 |
@@ -1193,7 +1199,7 @@ shcmd(union node *cmd, FILE *fp) | |||
1193 | case NTO: s = ">>"+1; dftfd = 1; break; | 1199 | case NTO: s = ">>"+1; dftfd = 1; break; |
1194 | case NCLOBBER: s = ">|"; dftfd = 1; break; | 1200 | case NCLOBBER: s = ">|"; dftfd = 1; break; |
1195 | case NAPPEND: s = ">>"; dftfd = 1; break; | 1201 | case NAPPEND: s = ">>"; dftfd = 1; break; |
1196 | #if ENABLE_ASH_BASH_COMPAT | 1202 | #if BASH_REDIR_OUTPUT |
1197 | case NTO2: | 1203 | case NTO2: |
1198 | #endif | 1204 | #endif |
1199 | case NTOFD: s = ">&"; dftfd = 1; break; | 1205 | case NTOFD: s = ">&"; dftfd = 1; break; |
@@ -3599,12 +3605,13 @@ struct job { | |||
3599 | #if JOBS | 3605 | #if JOBS |
3600 | int stopstatus; /* status of a stopped job */ | 3606 | int stopstatus; /* status of a stopped job */ |
3601 | #endif | 3607 | #endif |
3602 | uint32_t | 3608 | unsigned nprocs; /* number of processes */ |
3603 | nprocs: 16, /* number of processes */ | 3609 | |
3604 | state: 8, | ||
3605 | #define JOBRUNNING 0 /* at least one proc running */ | 3610 | #define JOBRUNNING 0 /* at least one proc running */ |
3606 | #define JOBSTOPPED 1 /* all procs are stopped */ | 3611 | #define JOBSTOPPED 1 /* all procs are stopped */ |
3607 | #define JOBDONE 2 /* all procs are completed */ | 3612 | #define JOBDONE 2 /* all procs are completed */ |
3613 | unsigned | ||
3614 | state: 8, | ||
3608 | #if JOBS | 3615 | #if JOBS |
3609 | sigint: 1, /* job was killed by SIGINT */ | 3616 | sigint: 1, /* job was killed by SIGINT */ |
3610 | jobctl: 1, /* job running under job control */ | 3617 | jobctl: 1, /* job running under job control */ |
@@ -3791,6 +3798,72 @@ static struct job *curjob; //lots | |||
3791 | /* number of presumed living untracked jobs */ | 3798 | /* number of presumed living untracked jobs */ |
3792 | static int jobless; //4 | 3799 | static int jobless; //4 |
3793 | 3800 | ||
3801 | #if 0 | ||
3802 | /* Bash has a feature: it restores termios after a successful wait for | ||
3803 | * a foreground job which had at least one stopped or sigkilled member. | ||
3804 | * The probable rationale is that SIGSTOP and SIGKILL can preclude task from | ||
3805 | * properly restoring tty state. Should we do this too? | ||
3806 | * A reproducer: ^Z an interactive python: | ||
3807 | * | ||
3808 | * # python | ||
3809 | * Python 2.7.12 (...) | ||
3810 | * >>> ^Z | ||
3811 | * { python leaves tty in -icanon -echo state. We do survive that... } | ||
3812 | * [1]+ Stopped python | ||
3813 | * { ...however, next program (python #2) does not survive it well: } | ||
3814 | * # python | ||
3815 | * Python 2.7.12 (...) | ||
3816 | * >>> Traceback (most recent call last): | ||
3817 | * { above, I typed "qwerty<CR>", but -echo state is still in effect } | ||
3818 | * File "<stdin>", line 1, in <module> | ||
3819 | * NameError: name 'qwerty' is not defined | ||
3820 | * | ||
3821 | * The implementation below is modeled on bash code and seems to work. | ||
3822 | * However, I'm not sure we should do this. For one: what if I'd fg | ||
3823 | * the stopped python instead? It'll be confused by "restored" tty state. | ||
3824 | */ | ||
3825 | static struct termios shell_tty_info; | ||
3826 | static void | ||
3827 | get_tty_state(void) | ||
3828 | { | ||
3829 | if (rootshell && ttyfd >= 0) | ||
3830 | tcgetattr(ttyfd, &shell_tty_info); | ||
3831 | } | ||
3832 | static void | ||
3833 | set_tty_state(void) | ||
3834 | { | ||
3835 | /* if (rootshell) - caller ensures this */ | ||
3836 | if (ttyfd >= 0) | ||
3837 | tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info); | ||
3838 | } | ||
3839 | static int | ||
3840 | job_signal_status(struct job *jp) | ||
3841 | { | ||
3842 | int status; | ||
3843 | unsigned i; | ||
3844 | struct procstat *ps = jp->ps; | ||
3845 | for (i = 0; i < jp->nprocs; i++) { | ||
3846 | status = ps[i].ps_status; | ||
3847 | if (WIFSIGNALED(status) || WIFSTOPPED(status)) | ||
3848 | return status; | ||
3849 | } | ||
3850 | return 0; | ||
3851 | } | ||
3852 | static void | ||
3853 | restore_tty_if_stopped_or_signaled(struct job *jp) | ||
3854 | { | ||
3855 | //TODO: check what happens if we come from waitforjob() in expbackq() | ||
3856 | if (rootshell) { | ||
3857 | int s = job_signal_status(jp); | ||
3858 | if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */ | ||
3859 | set_tty_state(); | ||
3860 | } | ||
3861 | } | ||
3862 | #else | ||
3863 | # define get_tty_state() ((void)0) | ||
3864 | # define restore_tty_if_stopped_or_signaled(jp) ((void)0) | ||
3865 | #endif | ||
3866 | |||
3794 | static void | 3867 | static void |
3795 | set_curjob(struct job *jp, unsigned mode) | 3868 | set_curjob(struct job *jp, unsigned mode) |
3796 | { | 3869 | { |
@@ -4122,8 +4195,10 @@ restartjob(struct job *jp, int mode) | |||
4122 | goto out; | 4195 | goto out; |
4123 | jp->state = JOBRUNNING; | 4196 | jp->state = JOBRUNNING; |
4124 | pgid = jp->ps[0].ps_pid; | 4197 | pgid = jp->ps[0].ps_pid; |
4125 | if (mode == FORK_FG) | 4198 | if (mode == FORK_FG) { |
4199 | get_tty_state(); | ||
4126 | xtcsetpgrp(ttyfd, pgid); | 4200 | xtcsetpgrp(ttyfd, pgid); |
4201 | } | ||
4127 | killpg(pgid, SIGCONT); | 4202 | killpg(pgid, SIGCONT); |
4128 | ps = jp->ps; | 4203 | ps = jp->ps; |
4129 | i = jp->nprocs; | 4204 | i = jp->nprocs; |
@@ -4754,7 +4829,7 @@ makejob(/*union node *node,*/ int nprocs) | |||
4754 | memset(jp, 0, sizeof(*jp)); | 4829 | memset(jp, 0, sizeof(*jp)); |
4755 | #if JOBS | 4830 | #if JOBS |
4756 | /* jp->jobctl is a bitfield. | 4831 | /* jp->jobctl is a bitfield. |
4757 | * "jp->jobctl |= jobctl" likely to give awful code */ | 4832 | * "jp->jobctl |= doing_jobctl" likely to give awful code */ |
4758 | if (doing_jobctl) | 4833 | if (doing_jobctl) |
4759 | jp->jobctl = 1; | 4834 | jp->jobctl = 1; |
4760 | #endif | 4835 | #endif |
@@ -4783,7 +4858,8 @@ cmdputs(const char *s) | |||
4783 | static const char vstype[VSTYPE + 1][3] = { | 4858 | static const char vstype[VSTYPE + 1][3] = { |
4784 | "", "}", "-", "+", "?", "=", | 4859 | "", "}", "-", "+", "?", "=", |
4785 | "%", "%%", "#", "##" | 4860 | "%", "%%", "#", "##" |
4786 | IF_ASH_BASH_COMPAT(, ":", "/", "//") | 4861 | IF_BASH_SUBSTR(, ":") |
4862 | IF_BASH_PATTERN_SUBST(, "/", "//") | ||
4787 | }; | 4863 | }; |
4788 | 4864 | ||
4789 | const char *p, *str; | 4865 | const char *p, *str; |
@@ -5010,7 +5086,7 @@ cmdtxt(union node *n) | |||
5010 | case NAPPEND: | 5086 | case NAPPEND: |
5011 | p = ">>"; | 5087 | p = ">>"; |
5012 | goto redir; | 5088 | goto redir; |
5013 | #if ENABLE_ASH_BASH_COMPAT | 5089 | #if BASH_REDIR_OUTPUT |
5014 | case NTO2: | 5090 | case NTO2: |
5015 | #endif | 5091 | #endif |
5016 | case NTOFD: | 5092 | case NTOFD: |
@@ -5362,6 +5438,8 @@ waitforjob(struct job *jp) | |||
5362 | #if JOBS | 5438 | #if JOBS |
5363 | if (jp->jobctl) { | 5439 | if (jp->jobctl) { |
5364 | xtcsetpgrp(ttyfd, rootpid); | 5440 | xtcsetpgrp(ttyfd, rootpid); |
5441 | restore_tty_if_stopped_or_signaled(jp); | ||
5442 | |||
5365 | /* | 5443 | /* |
5366 | * This is truly gross. | 5444 | * This is truly gross. |
5367 | * If we're doing job control, then we did a TIOCSPGRP which | 5445 | * If we're doing job control, then we did a TIOCSPGRP which |
@@ -5587,7 +5665,7 @@ openredirect(union node *redir) | |||
5587 | goto ecreate; | 5665 | goto ecreate; |
5588 | break; | 5666 | break; |
5589 | case NTO: | 5667 | case NTO: |
5590 | #if ENABLE_ASH_BASH_COMPAT | 5668 | #if BASH_REDIR_OUTPUT |
5591 | case NTO2: | 5669 | case NTO2: |
5592 | #endif | 5670 | #endif |
5593 | /* Take care of noclobber mode. */ | 5671 | /* Take care of noclobber mode. */ |
@@ -5751,7 +5829,7 @@ redirect(union node *redir, int flags) | |||
5751 | union node *tmp = redir; | 5829 | union node *tmp = redir; |
5752 | do { | 5830 | do { |
5753 | sv_pos++; | 5831 | sv_pos++; |
5754 | #if ENABLE_ASH_BASH_COMPAT | 5832 | #if BASH_REDIR_OUTPUT |
5755 | if (tmp->nfile.type == NTO2) | 5833 | if (tmp->nfile.type == NTO2) |
5756 | sv_pos++; | 5834 | sv_pos++; |
5757 | #endif | 5835 | #endif |
@@ -5793,7 +5871,7 @@ redirect(union node *redir, int flags) | |||
5793 | continue; | 5871 | continue; |
5794 | } | 5872 | } |
5795 | } | 5873 | } |
5796 | #if ENABLE_ASH_BASH_COMPAT | 5874 | #if BASH_REDIR_OUTPUT |
5797 | redirect_more: | 5875 | redirect_more: |
5798 | #endif | 5876 | #endif |
5799 | if (need_to_remember(sv, fd)) { | 5877 | if (need_to_remember(sv, fd)) { |
@@ -5846,12 +5924,12 @@ redirect(union node *redir, int flags) | |||
5846 | } | 5924 | } |
5847 | } else if (fd != newfd) { /* move newfd to fd */ | 5925 | } else if (fd != newfd) { /* move newfd to fd */ |
5848 | dup2_or_raise(newfd, fd); | 5926 | dup2_or_raise(newfd, fd); |
5849 | #if ENABLE_ASH_BASH_COMPAT | 5927 | #if BASH_REDIR_OUTPUT |
5850 | if (!(redir->nfile.type == NTO2 && fd == 2)) | 5928 | if (!(redir->nfile.type == NTO2 && fd == 2)) |
5851 | #endif | 5929 | #endif |
5852 | close(newfd); | 5930 | close(newfd); |
5853 | } | 5931 | } |
5854 | #if ENABLE_ASH_BASH_COMPAT | 5932 | #if BASH_REDIR_OUTPUT |
5855 | if (redir->nfile.type == NTO2 && fd == 1) { | 5933 | if (redir->nfile.type == NTO2 && fd == 1) { |
5856 | /* We already redirected it to fd 1, now copy it to 2 */ | 5934 | /* We already redirected it to fd 1, now copy it to 2 */ |
5857 | newfd = 1; | 5935 | newfd = 1; |
@@ -6168,15 +6246,15 @@ static char * | |||
6168 | rmescapes(char *str, int flag) | 6246 | rmescapes(char *str, int flag) |
6169 | { | 6247 | { |
6170 | static const char qchars[] ALIGN1 = { | 6248 | static const char qchars[] ALIGN1 = { |
6171 | IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' }; | 6249 | IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' }; |
6172 | 6250 | ||
6173 | char *p, *q, *r; | 6251 | char *p, *q, *r; |
6174 | unsigned inquotes; | 6252 | unsigned inquotes; |
6175 | unsigned protect_against_glob; | 6253 | unsigned protect_against_glob; |
6176 | unsigned globbing; | 6254 | unsigned globbing; |
6177 | IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;) | 6255 | IF_BASH_PATTERN_SUBST(unsigned slash = flag & RMESCAPE_SLASH;) |
6178 | 6256 | ||
6179 | p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash)); | 6257 | p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash)); |
6180 | if (!p) | 6258 | if (!p) |
6181 | return str; | 6259 | return str; |
6182 | 6260 | ||
@@ -6228,7 +6306,7 @@ rmescapes(char *str, int flag) | |||
6228 | protect_against_glob = 0; | 6306 | protect_against_glob = 0; |
6229 | goto copy; | 6307 | goto copy; |
6230 | } | 6308 | } |
6231 | #if ENABLE_ASH_BASH_COMPAT | 6309 | #if BASH_PATTERN_SUBST |
6232 | else if (*p == '/' && slash) { | 6310 | else if (*p == '/' && slash) { |
6233 | /* stop handling globbing and mark location of slash */ | 6311 | /* stop handling globbing and mark location of slash */ |
6234 | globbing = slash = 0; | 6312 | globbing = slash = 0; |
@@ -6887,10 +6965,10 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6887 | char *loc; | 6965 | char *loc; |
6888 | char *rmesc, *rmescend; | 6966 | char *rmesc, *rmescend; |
6889 | char *str; | 6967 | char *str; |
6890 | IF_ASH_BASH_COMPAT(char *repl = NULL;) | 6968 | IF_BASH_SUBSTR(int pos, len, orig_len;) |
6891 | IF_ASH_BASH_COMPAT(int pos, len, orig_len;) | ||
6892 | int amount, resetloc; | 6969 | int amount, resetloc; |
6893 | IF_ASH_BASH_COMPAT(int workloc;) | 6970 | IF_BASH_PATTERN_SUBST(int workloc;) |
6971 | IF_BASH_PATTERN_SUBST(char *repl = NULL;) | ||
6894 | int zero; | 6972 | int zero; |
6895 | char *(*scan)(char*, char*, char*, char*, int, int); | 6973 | char *(*scan)(char*, char*, char*, char*, int, int); |
6896 | 6974 | ||
@@ -6915,7 +6993,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6915 | varunset(p, varname, startp, varflags); | 6993 | varunset(p, varname, startp, varflags); |
6916 | /* NOTREACHED */ | 6994 | /* NOTREACHED */ |
6917 | 6995 | ||
6918 | #if ENABLE_ASH_BASH_COMPAT | 6996 | #if BASH_SUBSTR |
6919 | case VSSUBSTR: | 6997 | case VSSUBSTR: |
6920 | //TODO: support more general format ${v:EXPR:EXPR}, | 6998 | //TODO: support more general format ${v:EXPR:EXPR}, |
6921 | // where EXPR follows $(()) rules | 6999 | // where EXPR follows $(()) rules |
@@ -6984,17 +7062,19 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6984 | amount = loc - expdest; | 7062 | amount = loc - expdest; |
6985 | STADJUST(amount, expdest); | 7063 | STADJUST(amount, expdest); |
6986 | return loc; | 7064 | return loc; |
6987 | #endif | 7065 | #endif /* BASH_SUBSTR */ |
6988 | } | 7066 | } |
6989 | 7067 | ||
6990 | resetloc = expdest - (char *)stackblock(); | 7068 | resetloc = expdest - (char *)stackblock(); |
6991 | 7069 | ||
7070 | #if BASH_PATTERN_SUBST | ||
6992 | /* We'll comeback here if we grow the stack while handling | 7071 | /* We'll comeback here if we grow the stack while handling |
6993 | * a VSREPLACE or VSREPLACEALL, since our pointers into the | 7072 | * a VSREPLACE or VSREPLACEALL, since our pointers into the |
6994 | * stack will need rebasing, and we'll need to remove our work | 7073 | * stack will need rebasing, and we'll need to remove our work |
6995 | * areas each time | 7074 | * areas each time |
6996 | */ | 7075 | */ |
6997 | IF_ASH_BASH_COMPAT(restart:) | 7076 | restart: |
7077 | #endif | ||
6998 | 7078 | ||
6999 | amount = expdest - ((char *)stackblock() + resetloc); | 7079 | amount = expdest - ((char *)stackblock() + resetloc); |
7000 | STADJUST(-amount, expdest); | 7080 | STADJUST(-amount, expdest); |
@@ -7019,11 +7099,11 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7019 | * RMESCAPE_SLASH causes preglob to work differently on the pattern | 7099 | * RMESCAPE_SLASH causes preglob to work differently on the pattern |
7020 | * and string. It's only used on the first call. | 7100 | * and string. It's only used on the first call. |
7021 | */ | 7101 | */ |
7022 | preglob(str, IF_ASH_BASH_COMPAT( | 7102 | preglob(str, IF_BASH_PATTERN_SUBST( |
7023 | (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ? | 7103 | (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ? |
7024 | RMESCAPE_SLASH :) 0); | 7104 | RMESCAPE_SLASH : ) 0); |
7025 | 7105 | ||
7026 | #if ENABLE_ASH_BASH_COMPAT | 7106 | #if BASH_PATTERN_SUBST |
7027 | workloc = expdest - (char *)stackblock(); | 7107 | workloc = expdest - (char *)stackblock(); |
7028 | if (subtype == VSREPLACE || subtype == VSREPLACEALL) { | 7108 | if (subtype == VSREPLACE || subtype == VSREPLACEALL) { |
7029 | char *idx, *end; | 7109 | char *idx, *end; |
@@ -7124,7 +7204,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7124 | STADJUST(-amount, expdest); | 7204 | STADJUST(-amount, expdest); |
7125 | return startp; | 7205 | return startp; |
7126 | } | 7206 | } |
7127 | #endif /* ENABLE_ASH_BASH_COMPAT */ | 7207 | #endif /* BASH_PATTERN_SUBST */ |
7128 | 7208 | ||
7129 | subtype -= VSTRIMRIGHT; | 7209 | subtype -= VSTRIMRIGHT; |
7130 | #if DEBUG | 7210 | #if DEBUG |
@@ -7392,8 +7472,10 @@ evalvar(char *p, int flag, struct strlist *var_str_list) | |||
7392 | case VSTRIMLEFTMAX: | 7472 | case VSTRIMLEFTMAX: |
7393 | case VSTRIMRIGHT: | 7473 | case VSTRIMRIGHT: |
7394 | case VSTRIMRIGHTMAX: | 7474 | case VSTRIMRIGHTMAX: |
7395 | #if ENABLE_ASH_BASH_COMPAT | 7475 | #if BASH_SUBSTR |
7396 | case VSSUBSTR: | 7476 | case VSSUBSTR: |
7477 | #endif | ||
7478 | #if BASH_PATTERN_SUBST | ||
7397 | case VSREPLACE: | 7479 | case VSREPLACE: |
7398 | case VSREPLACEALL: | 7480 | case VSREPLACEALL: |
7399 | #endif | 7481 | #endif |
@@ -7458,6 +7540,57 @@ addfname(const char *name) | |||
7458 | exparg.lastp = &sp->next; | 7540 | exparg.lastp = &sp->next; |
7459 | } | 7541 | } |
7460 | 7542 | ||
7543 | /* Avoid glob() (and thus, stat() et al) for words like "echo" */ | ||
7544 | static int | ||
7545 | hasmeta(const char *p) | ||
7546 | { | ||
7547 | static const char chars[] ALIGN1 = { | ||
7548 | '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0 | ||
7549 | }; | ||
7550 | |||
7551 | for (;;) { | ||
7552 | p = strpbrk(p, chars); | ||
7553 | if (!p) | ||
7554 | break; | ||
7555 | switch ((unsigned char) *p) { | ||
7556 | case CTLQUOTEMARK: | ||
7557 | for (;;) { | ||
7558 | p++; | ||
7559 | if (*p == CTLQUOTEMARK) | ||
7560 | break; | ||
7561 | if (*p == CTLESC) | ||
7562 | p++; | ||
7563 | if (*p == '\0') /* huh? */ | ||
7564 | return 0; | ||
7565 | } | ||
7566 | break; | ||
7567 | case '\\': | ||
7568 | case CTLESC: | ||
7569 | p++; | ||
7570 | if (*p == '\0') | ||
7571 | return 0; | ||
7572 | break; | ||
7573 | case '[': | ||
7574 | if (!strchr(p + 1, ']')) { | ||
7575 | /* It's not a properly closed [] pattern, | ||
7576 | * but other metas may follow. Continue checking. | ||
7577 | * my[file* _is_ globbed by bash | ||
7578 | * and matches filenames like "my[file1". | ||
7579 | */ | ||
7580 | break; | ||
7581 | } | ||
7582 | /* fallthrough */ | ||
7583 | default: | ||
7584 | /* case '*': */ | ||
7585 | /* case '?': */ | ||
7586 | return 1; | ||
7587 | } | ||
7588 | p++; | ||
7589 | } | ||
7590 | |||
7591 | return 0; | ||
7592 | } | ||
7593 | |||
7461 | /* If we want to use glob() from libc... */ | 7594 | /* If we want to use glob() from libc... */ |
7462 | #if !ENABLE_ASH_INTERNAL_GLOB | 7595 | #if !ENABLE_ASH_INTERNAL_GLOB |
7463 | 7596 | ||
@@ -7484,20 +7617,9 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
7484 | if (fflag) | 7617 | if (fflag) |
7485 | goto nometa; | 7618 | goto nometa; |
7486 | 7619 | ||
7487 | /* Avoid glob() (and thus, stat() et al) for words like "echo" */ | 7620 | if (!hasmeta(str->text)) |
7488 | p = str->text; | 7621 | goto nometa; |
7489 | while (*p) { | ||
7490 | if (*p == '*') | ||
7491 | goto need_glob; | ||
7492 | if (*p == '?') | ||
7493 | goto need_glob; | ||
7494 | if (*p == '[') | ||
7495 | goto need_glob; | ||
7496 | p++; | ||
7497 | } | ||
7498 | goto nometa; | ||
7499 | 7622 | ||
7500 | need_glob: | ||
7501 | INT_OFF; | 7623 | INT_OFF; |
7502 | p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); | 7624 | p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); |
7503 | // GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match | 7625 | // GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match |
@@ -7734,9 +7856,6 @@ expsort(struct strlist *str) | |||
7734 | static void | 7856 | static void |
7735 | expandmeta(struct strlist *str /*, int flag*/) | 7857 | expandmeta(struct strlist *str /*, int flag*/) |
7736 | { | 7858 | { |
7737 | static const char metachars[] ALIGN1 = { | ||
7738 | '*', '?', '[', 0 | ||
7739 | }; | ||
7740 | /* TODO - EXP_REDIR */ | 7859 | /* TODO - EXP_REDIR */ |
7741 | 7860 | ||
7742 | while (str) { | 7861 | while (str) { |
@@ -7747,7 +7866,7 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
7747 | 7866 | ||
7748 | if (fflag) | 7867 | if (fflag) |
7749 | goto nometa; | 7868 | goto nometa; |
7750 | if (!strpbrk(str->text, metachars)) | 7869 | if (!hasmeta(str->text)) |
7751 | goto nometa; | 7870 | goto nometa; |
7752 | savelastp = exparg.lastp; | 7871 | savelastp = exparg.lastp; |
7753 | 7872 | ||
@@ -8322,7 +8441,7 @@ enum { | |||
8322 | TESAC, | 8441 | TESAC, |
8323 | TFI, | 8442 | TFI, |
8324 | TFOR, | 8443 | TFOR, |
8325 | #if ENABLE_ASH_BASH_COMPAT | 8444 | #if BASH_FUNCTION |
8326 | TFUNCTION, | 8445 | TFUNCTION, |
8327 | #endif | 8446 | #endif |
8328 | TIF, | 8447 | TIF, |
@@ -8360,7 +8479,7 @@ enum { | |||
8360 | /* 19 */ | (1u << TESAC) | 8479 | /* 19 */ | (1u << TESAC) |
8361 | /* 20 */ | (1u << TFI) | 8480 | /* 20 */ | (1u << TFI) |
8362 | /* 21 */ | (0u << TFOR) | 8481 | /* 21 */ | (0u << TFOR) |
8363 | #if ENABLE_ASH_BASH_COMPAT | 8482 | #if BASH_FUNCTION |
8364 | /* 22 */ | (0u << TFUNCTION) | 8483 | /* 22 */ | (0u << TFUNCTION) |
8365 | #endif | 8484 | #endif |
8366 | /* 23 */ | (0u << TIF) | 8485 | /* 23 */ | (0u << TIF) |
@@ -8398,7 +8517,7 @@ static const char *const tokname_array[] = { | |||
8398 | "esac", | 8517 | "esac", |
8399 | "fi", | 8518 | "fi", |
8400 | "for", | 8519 | "for", |
8401 | #if ENABLE_ASH_BASH_COMPAT | 8520 | #if BASH_FUNCTION |
8402 | "function", | 8521 | "function", |
8403 | #endif | 8522 | #endif |
8404 | "if", | 8523 | "if", |
@@ -8646,7 +8765,7 @@ static const uint8_t nodesize[N_NUMBER] ALIGN1 = { | |||
8646 | [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)), | 8765 | [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)), |
8647 | [NARG ] = SHELL_ALIGN(sizeof(struct narg)), | 8766 | [NARG ] = SHELL_ALIGN(sizeof(struct narg)), |
8648 | [NTO ] = SHELL_ALIGN(sizeof(struct nfile)), | 8767 | [NTO ] = SHELL_ALIGN(sizeof(struct nfile)), |
8649 | #if ENABLE_ASH_BASH_COMPAT | 8768 | #if BASH_REDIR_OUTPUT |
8650 | [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)), | 8769 | [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)), |
8651 | #endif | 8770 | #endif |
8652 | [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)), | 8771 | [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)), |
@@ -8737,7 +8856,7 @@ calcsize(union node *n) | |||
8737 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | 8856 | IF_PLATFORM_MINGW32(nodeptrsize += 3); |
8738 | break; | 8857 | break; |
8739 | case NTO: | 8858 | case NTO: |
8740 | #if ENABLE_ASH_BASH_COMPAT | 8859 | #if BASH_REDIR_OUTPUT |
8741 | case NTO2: | 8860 | case NTO2: |
8742 | #endif | 8861 | #endif |
8743 | case NCLOBBER: | 8862 | case NCLOBBER: |
@@ -8881,7 +9000,7 @@ copynode(union node *n) | |||
8881 | SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next); | 9000 | SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next); |
8882 | break; | 9001 | break; |
8883 | case NTO: | 9002 | case NTO: |
8884 | #if ENABLE_ASH_BASH_COMPAT | 9003 | #if BASH_REDIR_OUTPUT |
8885 | case NTO2: | 9004 | case NTO2: |
8886 | #endif | 9005 | #endif |
8887 | case NCLOBBER: | 9006 | case NCLOBBER: |
@@ -9277,13 +9396,15 @@ evalsubshell(union node *n, int flags) | |||
9277 | { | 9396 | { |
9278 | IF_PLATFORM_MINGW32(struct forkshell fs;) | 9397 | IF_PLATFORM_MINGW32(struct forkshell fs;) |
9279 | struct job *jp; | 9398 | struct job *jp; |
9280 | int backgnd = (n->type == NBACKGND); | 9399 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ |
9281 | int status; | 9400 | int status; |
9282 | 9401 | ||
9283 | expredir(n->nredir.redirect); | 9402 | expredir(n->nredir.redirect); |
9284 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) | 9403 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) |
9285 | goto nofork; | 9404 | goto nofork; |
9286 | INT_OFF; | 9405 | INT_OFF; |
9406 | if (backgnd == FORK_FG) | ||
9407 | get_tty_state(); | ||
9287 | jp = makejob(/*n,*/ 1); | 9408 | jp = makejob(/*n,*/ 1); |
9288 | #if ENABLE_PLATFORM_MINGW32 | 9409 | #if ENABLE_PLATFORM_MINGW32 |
9289 | memset(&fs, 0, sizeof(fs)); | 9410 | memset(&fs, 0, sizeof(fs)); |
@@ -9308,7 +9429,7 @@ evalsubshell(union node *n, int flags) | |||
9308 | } | 9429 | } |
9309 | /* parent */ | 9430 | /* parent */ |
9310 | status = 0; | 9431 | status = 0; |
9311 | if (!backgnd) | 9432 | if (backgnd == FORK_FG) |
9312 | status = waitforjob(jp); | 9433 | status = waitforjob(jp); |
9313 | INT_ON; | 9434 | INT_ON; |
9314 | return status; | 9435 | return status; |
@@ -9332,14 +9453,14 @@ expredir(union node *n) | |||
9332 | case NFROMTO: | 9453 | case NFROMTO: |
9333 | case NFROM: | 9454 | case NFROM: |
9334 | case NTO: | 9455 | case NTO: |
9335 | #if ENABLE_ASH_BASH_COMPAT | 9456 | #if BASH_REDIR_OUTPUT |
9336 | case NTO2: | 9457 | case NTO2: |
9337 | #endif | 9458 | #endif |
9338 | case NCLOBBER: | 9459 | case NCLOBBER: |
9339 | case NAPPEND: | 9460 | case NAPPEND: |
9340 | expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); | 9461 | expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); |
9341 | TRACE(("expredir expanded to '%s'\n", fn.list->text)); | 9462 | TRACE(("expredir expanded to '%s'\n", fn.list->text)); |
9342 | #if ENABLE_ASH_BASH_COMPAT | 9463 | #if BASH_REDIR_OUTPUT |
9343 | store_expfname: | 9464 | store_expfname: |
9344 | #endif | 9465 | #endif |
9345 | #if 0 | 9466 | #if 0 |
@@ -9361,7 +9482,7 @@ expredir(union node *n) | |||
9361 | expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); | 9482 | expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); |
9362 | if (fn.list == NULL) | 9483 | if (fn.list == NULL) |
9363 | ash_msg_and_raise_error("redir error"); | 9484 | ash_msg_and_raise_error("redir error"); |
9364 | #if ENABLE_ASH_BASH_COMPAT | 9485 | #if BASH_REDIR_OUTPUT |
9365 | //FIXME: we used expandarg with different args! | 9486 | //FIXME: we used expandarg with different args! |
9366 | if (!isdigit_str9(fn.list->text)) { | 9487 | if (!isdigit_str9(fn.list->text)) { |
9367 | /* >&file, not >&fd */ | 9488 | /* >&file, not >&fd */ |
@@ -9401,6 +9522,8 @@ evalpipe(union node *n, int flags) | |||
9401 | pipelen++; | 9522 | pipelen++; |
9402 | flags |= EV_EXIT; | 9523 | flags |= EV_EXIT; |
9403 | INT_OFF; | 9524 | INT_OFF; |
9525 | if (n->npipe.pipe_backgnd == 0) | ||
9526 | get_tty_state(); | ||
9404 | jp = makejob(/*n,*/ pipelen); | 9527 | jp = makejob(/*n,*/ pipelen); |
9405 | prevfd = -1; | 9528 | prevfd = -1; |
9406 | for (lp = n->npipe.cmdlist; lp; lp = lp->next) { | 9529 | for (lp = n->npipe.cmdlist; lp; lp = lp->next) { |
@@ -9764,13 +9887,13 @@ static int ulimitcmd(int, char **) FAST_FUNC; | |||
9764 | #define BUILTIN_SPEC_REG_ASSG "7" | 9887 | #define BUILTIN_SPEC_REG_ASSG "7" |
9765 | 9888 | ||
9766 | /* Stubs for calling non-FAST_FUNC's */ | 9889 | /* Stubs for calling non-FAST_FUNC's */ |
9767 | #if ENABLE_ASH_BUILTIN_ECHO | 9890 | #if ENABLE_ASH_ECHO |
9768 | static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); } | 9891 | static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); } |
9769 | #endif | 9892 | #endif |
9770 | #if ENABLE_ASH_BUILTIN_PRINTF | 9893 | #if ENABLE_ASH_PRINTF |
9771 | static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); } | 9894 | static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); } |
9772 | #endif | 9895 | #endif |
9773 | #if ENABLE_ASH_BUILTIN_TEST | 9896 | #if ENABLE_ASH_TEST || BASH_TEST2 |
9774 | static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); } | 9897 | static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); } |
9775 | #endif | 9898 | #endif |
9776 | 9899 | ||
@@ -9778,11 +9901,11 @@ static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, a | |||
9778 | static const struct builtincmd builtintab[] = { | 9901 | static const struct builtincmd builtintab[] = { |
9779 | { BUILTIN_SPEC_REG "." , dotcmd }, | 9902 | { BUILTIN_SPEC_REG "." , dotcmd }, |
9780 | { BUILTIN_SPEC_REG ":" , truecmd }, | 9903 | { BUILTIN_SPEC_REG ":" , truecmd }, |
9781 | #if ENABLE_ASH_BUILTIN_TEST | 9904 | #if ENABLE_ASH_TEST |
9782 | { BUILTIN_REGULAR "[" , testcmd }, | 9905 | { BUILTIN_REGULAR "[" , testcmd }, |
9783 | # if ENABLE_ASH_BASH_COMPAT | 9906 | #endif |
9907 | #if BASH_TEST2 | ||
9784 | { BUILTIN_REGULAR "[[" , testcmd }, | 9908 | { BUILTIN_REGULAR "[[" , testcmd }, |
9785 | # endif | ||
9786 | #endif | 9909 | #endif |
9787 | #if ENABLE_ASH_ALIAS | 9910 | #if ENABLE_ASH_ALIAS |
9788 | { BUILTIN_REG_ASSG "alias" , aliascmd }, | 9911 | { BUILTIN_REG_ASSG "alias" , aliascmd }, |
@@ -9797,7 +9920,7 @@ static const struct builtincmd builtintab[] = { | |||
9797 | { BUILTIN_REGULAR "command" , commandcmd }, | 9920 | { BUILTIN_REGULAR "command" , commandcmd }, |
9798 | #endif | 9921 | #endif |
9799 | { BUILTIN_SPEC_REG "continue", breakcmd }, | 9922 | { BUILTIN_SPEC_REG "continue", breakcmd }, |
9800 | #if ENABLE_ASH_BUILTIN_ECHO | 9923 | #if ENABLE_ASH_ECHO |
9801 | { BUILTIN_REGULAR "echo" , echocmd }, | 9924 | { BUILTIN_REGULAR "echo" , echocmd }, |
9802 | #endif | 9925 | #endif |
9803 | { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/ | 9926 | { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/ |
@@ -9826,7 +9949,7 @@ static const struct builtincmd builtintab[] = { | |||
9826 | { BUILTIN_NOSPEC "let" , letcmd }, | 9949 | { BUILTIN_NOSPEC "let" , letcmd }, |
9827 | #endif | 9950 | #endif |
9828 | { BUILTIN_ASSIGN "local" , localcmd }, | 9951 | { BUILTIN_ASSIGN "local" , localcmd }, |
9829 | #if ENABLE_ASH_BUILTIN_PRINTF | 9952 | #if ENABLE_ASH_PRINTF |
9830 | { BUILTIN_REGULAR "printf" , printfcmd }, | 9953 | { BUILTIN_REGULAR "printf" , printfcmd }, |
9831 | #endif | 9954 | #endif |
9832 | { BUILTIN_NOSPEC "pwd" , pwdcmd }, | 9955 | { BUILTIN_NOSPEC "pwd" , pwdcmd }, |
@@ -9835,10 +9958,10 @@ static const struct builtincmd builtintab[] = { | |||
9835 | { BUILTIN_SPEC_REG "return" , returncmd }, | 9958 | { BUILTIN_SPEC_REG "return" , returncmd }, |
9836 | { BUILTIN_SPEC_REG "set" , setcmd }, | 9959 | { BUILTIN_SPEC_REG "set" , setcmd }, |
9837 | { BUILTIN_SPEC_REG "shift" , shiftcmd }, | 9960 | { BUILTIN_SPEC_REG "shift" , shiftcmd }, |
9838 | #if ENABLE_ASH_BASH_COMPAT | 9961 | #if BASH_SOURCE |
9839 | { BUILTIN_SPEC_REG "source" , dotcmd }, | 9962 | { BUILTIN_SPEC_REG "source" , dotcmd }, |
9840 | #endif | 9963 | #endif |
9841 | #if ENABLE_ASH_BUILTIN_TEST | 9964 | #if ENABLE_ASH_TEST |
9842 | { BUILTIN_REGULAR "test" , testcmd }, | 9965 | { BUILTIN_REGULAR "test" , testcmd }, |
9843 | #endif | 9966 | #endif |
9844 | { BUILTIN_SPEC_REG "times" , timescmd }, | 9967 | { BUILTIN_SPEC_REG "times" , timescmd }, |
@@ -9857,15 +9980,15 @@ static const struct builtincmd builtintab[] = { | |||
9857 | /* Should match the above table! */ | 9980 | /* Should match the above table! */ |
9858 | #define COMMANDCMD (builtintab + \ | 9981 | #define COMMANDCMD (builtintab + \ |
9859 | /* . : */ 2 + \ | 9982 | /* . : */ 2 + \ |
9860 | /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \ | 9983 | /* [ */ 1 * ENABLE_ASH_TEST + \ |
9861 | /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \ | 9984 | /* [[ */ 1 * BASH_TEST2 + \ |
9862 | /* alias */ 1 * ENABLE_ASH_ALIAS + \ | 9985 | /* alias */ 1 * ENABLE_ASH_ALIAS + \ |
9863 | /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \ | 9986 | /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \ |
9864 | /* break cd cddir */ 3) | 9987 | /* break cd cddir */ 3) |
9865 | #define EVALCMD (COMMANDCMD + \ | 9988 | #define EVALCMD (COMMANDCMD + \ |
9866 | /* command */ 1 * ENABLE_ASH_CMDCMD + \ | 9989 | /* command */ 1 * ENABLE_ASH_CMDCMD + \ |
9867 | /* continue */ 1 + \ | 9990 | /* continue */ 1 + \ |
9868 | /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \ | 9991 | /* echo */ 1 * ENABLE_ASH_ECHO + \ |
9869 | 0) | 9992 | 0) |
9870 | #define EXECCMD (EVALCMD + \ | 9993 | #define EXECCMD (EVALCMD + \ |
9871 | /* eval */ 1) | 9994 | /* eval */ 1) |
@@ -10117,6 +10240,7 @@ evalcommand(union node *cmd, int flags) | |||
10117 | if (!(flags & EV_EXIT) || may_have_traps) { | 10240 | if (!(flags & EV_EXIT) || may_have_traps) { |
10118 | /* No, forking off a child is necessary */ | 10241 | /* No, forking off a child is necessary */ |
10119 | INT_OFF; | 10242 | INT_OFF; |
10243 | get_tty_state(); | ||
10120 | jp = makejob(/*cmd,*/ 1); | 10244 | jp = makejob(/*cmd,*/ 1); |
10121 | if (forkshell(jp, cmd, FORK_FG) != 0) { | 10245 | if (forkshell(jp, cmd, FORK_FG) != 0) { |
10122 | /* parent */ | 10246 | /* parent */ |
@@ -11505,10 +11629,10 @@ simplecmd(void) | |||
11505 | union node *vars, **vpp; | 11629 | union node *vars, **vpp; |
11506 | union node **rpp, *redir; | 11630 | union node **rpp, *redir; |
11507 | int savecheckkwd; | 11631 | int savecheckkwd; |
11508 | #if ENABLE_ASH_BASH_COMPAT | 11632 | #if BASH_TEST2 |
11509 | smallint double_brackets_flag = 0; | 11633 | smallint double_brackets_flag = 0; |
11510 | smallint function_flag = 0; | ||
11511 | #endif | 11634 | #endif |
11635 | IF_BASH_FUNCTION(smallint function_flag = 0;) | ||
11512 | 11636 | ||
11513 | args = NULL; | 11637 | args = NULL; |
11514 | app = &args; | 11638 | app = &args; |
@@ -11523,12 +11647,14 @@ simplecmd(void) | |||
11523 | checkkwd = savecheckkwd; | 11647 | checkkwd = savecheckkwd; |
11524 | t = readtoken(); | 11648 | t = readtoken(); |
11525 | switch (t) { | 11649 | switch (t) { |
11526 | #if ENABLE_ASH_BASH_COMPAT | 11650 | #if BASH_FUNCTION |
11527 | case TFUNCTION: | 11651 | case TFUNCTION: |
11528 | if (peektoken() != TWORD) | 11652 | if (peektoken() != TWORD) |
11529 | raise_error_unexpected_syntax(TWORD); | 11653 | raise_error_unexpected_syntax(TWORD); |
11530 | function_flag = 1; | 11654 | function_flag = 1; |
11531 | break; | 11655 | break; |
11656 | #endif | ||
11657 | #if BASH_TEST2 | ||
11532 | case TAND: /* "&&" */ | 11658 | case TAND: /* "&&" */ |
11533 | case TOR: /* "||" */ | 11659 | case TOR: /* "||" */ |
11534 | if (!double_brackets_flag) { | 11660 | if (!double_brackets_flag) { |
@@ -11542,7 +11668,7 @@ simplecmd(void) | |||
11542 | n->type = NARG; | 11668 | n->type = NARG; |
11543 | /*n->narg.next = NULL; - stzalloc did it */ | 11669 | /*n->narg.next = NULL; - stzalloc did it */ |
11544 | n->narg.text = wordtext; | 11670 | n->narg.text = wordtext; |
11545 | #if ENABLE_ASH_BASH_COMPAT | 11671 | #if BASH_TEST2 |
11546 | if (strcmp("[[", wordtext) == 0) | 11672 | if (strcmp("[[", wordtext) == 0) |
11547 | double_brackets_flag = 1; | 11673 | double_brackets_flag = 1; |
11548 | else if (strcmp("]]", wordtext) == 0) | 11674 | else if (strcmp("]]", wordtext) == 0) |
@@ -11557,7 +11683,7 @@ simplecmd(void) | |||
11557 | app = &n->narg.next; | 11683 | app = &n->narg.next; |
11558 | savecheckkwd = 0; | 11684 | savecheckkwd = 0; |
11559 | } | 11685 | } |
11560 | #if ENABLE_ASH_BASH_COMPAT | 11686 | #if BASH_FUNCTION |
11561 | if (function_flag) { | 11687 | if (function_flag) { |
11562 | checkkwd = CHKNL | CHKKWD; | 11688 | checkkwd = CHKNL | CHKKWD; |
11563 | switch (peektoken()) { | 11689 | switch (peektoken()) { |
@@ -11587,7 +11713,7 @@ simplecmd(void) | |||
11587 | parsefname(); /* read name of redirection file */ | 11713 | parsefname(); /* read name of redirection file */ |
11588 | break; | 11714 | break; |
11589 | case TLP: | 11715 | case TLP: |
11590 | IF_ASH_BASH_COMPAT(do_func:) | 11716 | IF_BASH_FUNCTION(do_func:) |
11591 | if (args && app == &args->narg.next | 11717 | if (args && app == &args->narg.next |
11592 | && !vars && !redir | 11718 | && !vars && !redir |
11593 | ) { | 11719 | ) { |
@@ -11595,7 +11721,7 @@ simplecmd(void) | |||
11595 | const char *name; | 11721 | const char *name; |
11596 | 11722 | ||
11597 | /* We have a function */ | 11723 | /* We have a function */ |
11598 | if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP) | 11724 | if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP) |
11599 | raise_error_unexpected_syntax(TRP); | 11725 | raise_error_unexpected_syntax(TRP); |
11600 | name = n->narg.text; | 11726 | name = n->narg.text; |
11601 | if (!goodname(name) | 11727 | if (!goodname(name) |
@@ -11608,7 +11734,7 @@ simplecmd(void) | |||
11608 | n->narg.next = parse_command(); | 11734 | n->narg.next = parse_command(); |
11609 | return n; | 11735 | return n; |
11610 | } | 11736 | } |
11611 | IF_ASH_BASH_COMPAT(function_flag = 0;) | 11737 | IF_BASH_FUNCTION(function_flag = 0;) |
11612 | /* fall through */ | 11738 | /* fall through */ |
11613 | default: | 11739 | default: |
11614 | tokpushback = 1; | 11740 | tokpushback = 1; |
@@ -11789,7 +11915,7 @@ parse_command(void) | |||
11789 | n1 = list(0); | 11915 | n1 = list(0); |
11790 | t = TEND; | 11916 | t = TEND; |
11791 | break; | 11917 | break; |
11792 | IF_ASH_BASH_COMPAT(case TFUNCTION:) | 11918 | IF_BASH_FUNCTION(case TFUNCTION:) |
11793 | case TWORD: | 11919 | case TWORD: |
11794 | case TREDIR: | 11920 | case TREDIR: |
11795 | tokpushback = 1; | 11921 | tokpushback = 1; |
@@ -11822,7 +11948,7 @@ parse_command(void) | |||
11822 | return n1; | 11948 | return n1; |
11823 | } | 11949 | } |
11824 | 11950 | ||
11825 | #if ENABLE_ASH_BASH_COMPAT | 11951 | #if BASH_DOLLAR_SQUOTE |
11826 | static int | 11952 | static int |
11827 | decode_dollar_squote(void) | 11953 | decode_dollar_squote(void) |
11828 | { | 11954 | { |
@@ -11907,7 +12033,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
11907 | IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */ | 12033 | IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */ |
11908 | int dqvarnest; /* levels of variables expansion within double quotes */ | 12034 | int dqvarnest; /* levels of variables expansion within double quotes */ |
11909 | 12035 | ||
11910 | IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;) | 12036 | IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;) |
11911 | 12037 | ||
11912 | startlinno = g_parsefile->linno; | 12038 | startlinno = g_parsefile->linno; |
11913 | bqlist = NULL; | 12039 | bqlist = NULL; |
@@ -11942,7 +12068,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
11942 | USTPUTC(c, out); | 12068 | USTPUTC(c, out); |
11943 | break; | 12069 | break; |
11944 | case CCTL: | 12070 | case CCTL: |
11945 | #if ENABLE_ASH_BASH_COMPAT | 12071 | #if BASH_DOLLAR_SQUOTE |
11946 | if (c == '\\' && bash_dollar_squote) { | 12072 | if (c == '\\' && bash_dollar_squote) { |
11947 | c = decode_dollar_squote(); | 12073 | c = decode_dollar_squote(); |
11948 | if (c == '\0') { | 12074 | if (c == '\0') { |
@@ -12003,7 +12129,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
12003 | dblquote = 1; | 12129 | dblquote = 1; |
12004 | goto quotemark; | 12130 | goto quotemark; |
12005 | case CENDQUOTE: | 12131 | case CENDQUOTE: |
12006 | IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) | 12132 | IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;) |
12007 | if (eofmark != NULL && varnest == 0) { | 12133 | if (eofmark != NULL && varnest == 0) { |
12008 | USTPUTC(c, out); | 12134 | USTPUTC(c, out); |
12009 | } else { | 12135 | } else { |
@@ -12062,7 +12188,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
12062 | break; | 12188 | break; |
12063 | default: | 12189 | default: |
12064 | if (varnest == 0) { | 12190 | if (varnest == 0) { |
12065 | #if ENABLE_ASH_BASH_COMPAT | 12191 | #if BASH_REDIR_OUTPUT |
12066 | if (c == '&') { | 12192 | if (c == '&') { |
12067 | //Can't call pgetc_eatbnl() here, this requires three-deep pungetc() | 12193 | //Can't call pgetc_eatbnl() here, this requires three-deep pungetc() |
12068 | if (pgetc() == '>') | 12194 | if (pgetc() == '>') |
@@ -12094,7 +12220,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
12094 | len = out - (char *)stackblock(); | 12220 | len = out - (char *)stackblock(); |
12095 | out = stackblock(); | 12221 | out = stackblock(); |
12096 | if (eofmark == NULL) { | 12222 | if (eofmark == NULL) { |
12097 | if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>')) | 12223 | if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>')) |
12098 | && quotef == 0 | 12224 | && quotef == 0 |
12099 | ) { | 12225 | ) { |
12100 | if (isdigit_str9(out)) { | 12226 | if (isdigit_str9(out)) { |
@@ -12182,7 +12308,7 @@ parseredir: { | |||
12182 | pungetc(); | 12308 | pungetc(); |
12183 | } | 12309 | } |
12184 | } | 12310 | } |
12185 | #if ENABLE_ASH_BASH_COMPAT | 12311 | #if BASH_REDIR_OUTPUT |
12186 | else if (c == 0x100 + '>') { /* this flags &> redirection */ | 12312 | else if (c == 0x100 + '>') { /* this flags &> redirection */ |
12187 | np->nfile.fd = 1; | 12313 | np->nfile.fd = 1; |
12188 | pgetc(); /* this is '>', no need to check */ | 12314 | pgetc(); /* this is '>', no need to check */ |
@@ -12248,7 +12374,7 @@ parsesub: { | |||
12248 | if (c > 255 /* PEOA or PEOF */ | 12374 | if (c > 255 /* PEOA or PEOF */ |
12249 | || (c != '(' && c != '{' && !is_name(c) && !is_special(c)) | 12375 | || (c != '(' && c != '{' && !is_name(c) && !is_special(c)) |
12250 | ) { | 12376 | ) { |
12251 | #if ENABLE_ASH_BASH_COMPAT | 12377 | #if BASH_DOLLAR_SQUOTE |
12252 | if (syntax != DQSYNTAX && c == '\'') | 12378 | if (syntax != DQSYNTAX && c == '\'') |
12253 | bash_dollar_squote = 1; | 12379 | bash_dollar_squote = 1; |
12254 | else | 12380 | else |
@@ -12324,7 +12450,7 @@ parsesub: { | |||
12324 | switch (c) { | 12450 | switch (c) { |
12325 | case ':': | 12451 | case ':': |
12326 | c = pgetc_eatbnl(); | 12452 | c = pgetc_eatbnl(); |
12327 | #if ENABLE_ASH_BASH_COMPAT | 12453 | #if BASH_SUBSTR |
12328 | /* This check is only needed to not misinterpret | 12454 | /* This check is only needed to not misinterpret |
12329 | * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD} | 12455 | * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD} |
12330 | * constructs. | 12456 | * constructs. |
@@ -12354,7 +12480,7 @@ parsesub: { | |||
12354 | subtype++; | 12480 | subtype++; |
12355 | break; | 12481 | break; |
12356 | } | 12482 | } |
12357 | #if ENABLE_ASH_BASH_COMPAT | 12483 | #if BASH_PATTERN_SUBST |
12358 | case '/': | 12484 | case '/': |
12359 | /* ${v/[/]pattern/repl} */ | 12485 | /* ${v/[/]pattern/repl} */ |
12360 | //TODO: encode pattern and repl separately. | 12486 | //TODO: encode pattern and repl separately. |
@@ -12609,7 +12735,7 @@ xxreadtoken(void) | |||
12609 | p += xxreadtoken_doubles + 1; | 12735 | p += xxreadtoken_doubles + 1; |
12610 | } else { | 12736 | } else { |
12611 | pungetc(); | 12737 | pungetc(); |
12612 | #if ENABLE_ASH_BASH_COMPAT | 12738 | #if BASH_REDIR_OUTPUT |
12613 | if (c == '&' && cc == '>') /* &> */ | 12739 | if (c == '&' && cc == '>') /* &> */ |
12614 | break; /* return readtoken1(...) */ | 12740 | break; /* return readtoken1(...) */ |
12615 | #endif | 12741 | #endif |
@@ -12999,16 +13125,7 @@ find_dot_file(char *name) | |||
12999 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) | 13125 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) |
13000 | return name; | 13126 | return name; |
13001 | 13127 | ||
13002 | /* IIRC standards do not say whether . is to be searched. | ||
13003 | * And it is even smaller this way, making it unconditional for now: | ||
13004 | */ | ||
13005 | if (1) { /* ENABLE_ASH_BASH_COMPAT */ | ||
13006 | fullname = name; | ||
13007 | goto try_cur_dir; | ||
13008 | } | ||
13009 | |||
13010 | while ((fullname = path_advance(&path, name)) != NULL) { | 13128 | while ((fullname = path_advance(&path, name)) != NULL) { |
13011 | try_cur_dir: | ||
13012 | if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { | 13129 | if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { |
13013 | /* | 13130 | /* |
13014 | * Don't bother freeing here, since it will | 13131 | * Don't bother freeing here, since it will |
@@ -13032,6 +13149,7 @@ dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM) | |||
13032 | int status = 0; | 13149 | int status = 0; |
13033 | char *fullname; | 13150 | char *fullname; |
13034 | char **argv; | 13151 | char **argv; |
13152 | char *args_need_save; | ||
13035 | struct strlist *sp; | 13153 | struct strlist *sp; |
13036 | volatile struct shparam saveparam; | 13154 | volatile struct shparam saveparam; |
13037 | 13155 | ||
@@ -13051,7 +13169,8 @@ dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM) | |||
13051 | */ | 13169 | */ |
13052 | fullname = find_dot_file(argv[0]); | 13170 | fullname = find_dot_file(argv[0]); |
13053 | argv++; | 13171 | argv++; |
13054 | if (argv[0]) { /* . FILE ARGS, ARGS exist */ | 13172 | args_need_save = argv[0]; |
13173 | if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */ | ||
13055 | int argc; | 13174 | int argc; |
13056 | saveparam = shellparam; | 13175 | saveparam = shellparam; |
13057 | shellparam.malloced = 0; | 13176 | shellparam.malloced = 0; |
@@ -13070,7 +13189,7 @@ dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM) | |||
13070 | status = cmdloop(0); | 13189 | status = cmdloop(0); |
13071 | popfile(); | 13190 | popfile(); |
13072 | 13191 | ||
13073 | if (argv[0]) { | 13192 | if (args_need_save) { |
13074 | freeparam(&shellparam); | 13193 | freeparam(&shellparam); |
13075 | shellparam = saveparam; | 13194 | shellparam = saveparam; |
13076 | }; | 13195 | }; |
@@ -13902,9 +14021,11 @@ init(void) | |||
13902 | setvareq((char*)defoptindvar, VTEXTFIXED); | 14021 | setvareq((char*)defoptindvar, VTEXTFIXED); |
13903 | 14022 | ||
13904 | setvar0("PPID", utoa(getppid())); | 14023 | setvar0("PPID", utoa(getppid())); |
13905 | #if ENABLE_ASH_BASH_COMPAT | 14024 | #if BASH_SHLVL_VAR |
13906 | p = lookupvar("SHLVL"); | 14025 | p = lookupvar("SHLVL"); |
13907 | setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT); | 14026 | setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT); |
14027 | #endif | ||
14028 | #if BASH_HOSTNAME_VAR | ||
13908 | if (!lookupvar("HOSTNAME")) { | 14029 | if (!lookupvar("HOSTNAME")) { |
13909 | struct utsname uts; | 14030 | struct utsname uts; |
13910 | uname(&uts); | 14031 | uname(&uts); |
@@ -13967,7 +14088,7 @@ procargs(char **argv) | |||
13967 | #if DEBUG == 2 | 14088 | #if DEBUG == 2 |
13968 | debug = 1; | 14089 | debug = 1; |
13969 | #endif | 14090 | #endif |
13970 | /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ | 14091 | /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */ |
13971 | if (xminusc) { | 14092 | if (xminusc) { |
13972 | minusc = *xargv++; | 14093 | minusc = *xargv++; |
13973 | if (*xargv) | 14094 | if (*xargv) |
@@ -14174,9 +14295,11 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14174 | if (!hp) { | 14295 | if (!hp) { |
14175 | hp = lookupvar("HOME"); | 14296 | hp = lookupvar("HOME"); |
14176 | if (hp) { | 14297 | if (hp) { |
14298 | INT_OFF; | ||
14177 | hp = concat_path_file(hp, ".ash_history"); | 14299 | hp = concat_path_file(hp, ".ash_history"); |
14178 | setvar0("HISTFILE", hp); | 14300 | setvar0("HISTFILE", hp); |
14179 | free((char*)hp); | 14301 | free((char*)hp); |
14302 | INT_ON; | ||
14180 | hp = lookupvar("HISTFILE"); | 14303 | hp = lookupvar("HISTFILE"); |
14181 | } | 14304 | } |
14182 | } | 14305 | } |