diff options
author | Ron Yorston <rmy@pobox.com> | 2021-06-07 11:34:06 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2021-06-07 11:34:06 +0100 |
commit | abe872e2a0342357a5608342cb2892e94027b3e7 (patch) | |
tree | 297cdccf332fbb5e4eb31b1eac643180059f9b5f /shell | |
parent | 1f33f42d7bcb019b268d938df643a7a785dc19ab (diff) | |
parent | 4d983dcddeee94892d3072e84c7c9a01d4696055 (diff) | |
download | busybox-w32-abe872e2a0342357a5608342cb2892e94027b3e7.tar.gz busybox-w32-abe872e2a0342357a5608342cb2892e94027b3e7.tar.bz2 busybox-w32-abe872e2a0342357a5608342cb2892e94027b3e7.zip |
Merge branch 'busybox' into merge
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 191 | ||||
-rw-r--r-- | shell/ash_remove_unnecessary_code_in_backquote_expansion.patch | 135 | ||||
-rw-r--r-- | shell/ash_test/ash-psubst/bash_procsub.right | 9 | ||||
-rwxr-xr-x | shell/ash_test/ash-psubst/bash_procsub.tests | 33 | ||||
-rw-r--r-- | shell/hush.c | 13 | ||||
-rw-r--r-- | shell/shell_common.c | 4 |
6 files changed, 356 insertions, 29 deletions
diff --git a/shell/ash.c b/shell/ash.c index 3d6f25802..14712ef54 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -262,6 +262,14 @@ | |||
262 | #define BASH_READ_D ENABLE_ASH_BASH_COMPAT | 262 | #define BASH_READ_D ENABLE_ASH_BASH_COMPAT |
263 | #define IF_BASH_READ_D IF_ASH_BASH_COMPAT | 263 | #define IF_BASH_READ_D IF_ASH_BASH_COMPAT |
264 | #define BASH_WAIT_N ENABLE_ASH_BASH_COMPAT | 264 | #define BASH_WAIT_N ENABLE_ASH_BASH_COMPAT |
265 | /* <(...) and >(...) */ | ||
266 | #if HAVE_DEV_FD | ||
267 | # define BASH_PROCESS_SUBST ENABLE_ASH_BASH_COMPAT | ||
268 | # define IF_BASH_PROCESS_SUBST IF_ASH_BASH_COMPAT | ||
269 | #else | ||
270 | # define BASH_PROCESS_SUBST 0 | ||
271 | # define IF_BASH_PROCESS_SUBST(...) | ||
272 | #endif | ||
265 | 273 | ||
266 | #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 | 274 | #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 |
267 | /* Bionic at least up to version 24 has no glob() */ | 275 | /* Bionic at least up to version 24 has no glob() */ |
@@ -973,6 +981,12 @@ out2str(const char *p) | |||
973 | #define CTLENDARI ((unsigned char)'\207') | 981 | #define CTLENDARI ((unsigned char)'\207') |
974 | #define CTLQUOTEMARK ((unsigned char)'\210') | 982 | #define CTLQUOTEMARK ((unsigned char)'\210') |
975 | #define CTL_LAST CTLQUOTEMARK | 983 | #define CTL_LAST CTLQUOTEMARK |
984 | #if BASH_PROCESS_SUBST | ||
985 | # define CTLTOPROC ((unsigned char)'\211') | ||
986 | # define CTLFROMPROC ((unsigned char)'\212') | ||
987 | # undef CTL_LAST | ||
988 | # define CTL_LAST CTLFROMPROC | ||
989 | #endif | ||
976 | 990 | ||
977 | /* variable substitution byte (follows CTLVAR) */ | 991 | /* variable substitution byte (follows CTLVAR) */ |
978 | #define VSTYPE 0x0f /* type of variable substitution */ | 992 | #define VSTYPE 0x0f /* type of variable substitution */ |
@@ -1244,6 +1258,10 @@ trace_puts_quoted(char *s) | |||
1244 | case CTLESC: c = 'e'; goto backslash; | 1258 | case CTLESC: c = 'e'; goto backslash; |
1245 | case CTLVAR: c = 'v'; goto backslash; | 1259 | case CTLVAR: c = 'v'; goto backslash; |
1246 | case CTLBACKQ: c = 'q'; goto backslash; | 1260 | case CTLBACKQ: c = 'q'; goto backslash; |
1261 | #if BASH_PROCESS_SUBST | ||
1262 | case CTLTOPROC: c = 'p'; goto backslash; | ||
1263 | case CTLFROMPROC: c = 'P'; goto backslash; | ||
1264 | #endif | ||
1247 | backslash: | 1265 | backslash: |
1248 | putc('\\', tracefile); | 1266 | putc('\\', tracefile); |
1249 | putc(c, tracefile); | 1267 | putc(c, tracefile); |
@@ -1405,8 +1423,17 @@ sharg(union node *arg, FILE *fp) | |||
1405 | case CTLENDVAR: | 1423 | case CTLENDVAR: |
1406 | putc('}', fp); | 1424 | putc('}', fp); |
1407 | break; | 1425 | break; |
1426 | #if BASH_PROCESS_SUBST | ||
1427 | case CTLTOPROC: | ||
1428 | putc('>', fp); | ||
1429 | goto backq; | ||
1430 | case CTLFROMPROC: | ||
1431 | putc('<', fp); | ||
1432 | goto backq; | ||
1433 | #endif | ||
1408 | case CTLBACKQ: | 1434 | case CTLBACKQ: |
1409 | putc('$', fp); | 1435 | putc('$', fp); |
1436 | IF_BASH_PROCESS_SUBST(backq:) | ||
1410 | putc('(', fp); | 1437 | putc('(', fp); |
1411 | shtree(bqlist->n, -1, NULL, fp); | 1438 | shtree(bqlist->n, -1, NULL, fp); |
1412 | putc(')', fp); | 1439 | putc(')', fp); |
@@ -3663,8 +3690,13 @@ static const uint8_t syntax_index_table[] ALIGN1 = { | |||
3663 | /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL, | 3690 | /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL, |
3664 | /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL, | 3691 | /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL, |
3665 | /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL, | 3692 | /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL, |
3693 | #if BASH_PROCESS_SUBST | ||
3694 | /* 137 CTLTOPROC */ CCTL_CCTL_CCTL_CCTL, | ||
3695 | /* 138 CTLFROMPROC */ CCTL_CCTL_CCTL_CCTL, | ||
3696 | #else | ||
3666 | /* 137 */ CWORD_CWORD_CWORD_CWORD, | 3697 | /* 137 */ CWORD_CWORD_CWORD_CWORD, |
3667 | /* 138 */ CWORD_CWORD_CWORD_CWORD, | 3698 | /* 138 */ CWORD_CWORD_CWORD_CWORD, |
3699 | #endif | ||
3668 | /* 139 */ CWORD_CWORD_CWORD_CWORD, | 3700 | /* 139 */ CWORD_CWORD_CWORD_CWORD, |
3669 | /* 140 */ CWORD_CWORD_CWORD_CWORD, | 3701 | /* 140 */ CWORD_CWORD_CWORD_CWORD, |
3670 | /* 141 */ CWORD_CWORD_CWORD_CWORD, | 3702 | /* 141 */ CWORD_CWORD_CWORD_CWORD, |
@@ -5377,9 +5409,24 @@ cmdputs(const char *s) | |||
5377 | quoted >>= 1; | 5409 | quoted >>= 1; |
5378 | subtype = 0; | 5410 | subtype = 0; |
5379 | goto dostr; | 5411 | goto dostr; |
5412 | #if BASH_PROCESS_SUBST | ||
5413 | case CTLBACKQ: | ||
5414 | c = '$'; | ||
5415 | str = "(...)"; | ||
5416 | break; | ||
5417 | case CTLTOPROC: | ||
5418 | c = '>'; | ||
5419 | str = "(...)"; | ||
5420 | break; | ||
5421 | case CTLFROMPROC: | ||
5422 | c = '<'; | ||
5423 | str = "(...)"; | ||
5424 | break; | ||
5425 | #else | ||
5380 | case CTLBACKQ: | 5426 | case CTLBACKQ: |
5381 | str = "$(...)"; | 5427 | str = "$(...)"; |
5382 | goto dostr; | 5428 | goto dostr; |
5429 | #endif | ||
5383 | #if ENABLE_FEATURE_SH_MATH | 5430 | #if ENABLE_FEATURE_SH_MATH |
5384 | case CTLARI: | 5431 | case CTLARI: |
5385 | str = "$(("; | 5432 | str = "$(("; |
@@ -6446,6 +6493,21 @@ redirectsafe(union node *redir, int flags) | |||
6446 | return err; | 6493 | return err; |
6447 | } | 6494 | } |
6448 | 6495 | ||
6496 | #if BASH_PROCESS_SUBST | ||
6497 | static void | ||
6498 | pushfd(int fd) | ||
6499 | { | ||
6500 | struct redirtab *sv; | ||
6501 | |||
6502 | sv = ckzalloc(sizeof(*sv) + sizeof(sv->two_fd[0])); | ||
6503 | sv->pair_count = 1; | ||
6504 | sv->two_fd[0].orig_fd = fd; | ||
6505 | sv->two_fd[0].moved_to = CLOSED; | ||
6506 | sv->next = redirlist; | ||
6507 | redirlist = sv; | ||
6508 | } | ||
6509 | #endif | ||
6510 | |||
6449 | static struct redirtab* | 6511 | static struct redirtab* |
6450 | pushredir(union node *redir) | 6512 | pushredir(union node *redir) |
6451 | { | 6513 | { |
@@ -7084,10 +7146,20 @@ evaltreenr(union node *n, int flags) | |||
7084 | } | 7146 | } |
7085 | 7147 | ||
7086 | static void FAST_FUNC | 7148 | static void FAST_FUNC |
7087 | evalbackcmd(union node *n, struct backcmd *result) | 7149 | evalbackcmd(union node *n, struct backcmd *result |
7150 | IF_BASH_PROCESS_SUBST(, int ctl)) | ||
7088 | { | 7151 | { |
7089 | int pip[2]; | 7152 | int pip[2]; |
7090 | struct job *jp; | 7153 | struct job *jp; |
7154 | #if BASH_PROCESS_SUBST | ||
7155 | /* determine end of pipe used by parent (ip) and child (ic) */ | ||
7156 | const int ip = (ctl == CTLTOPROC); | ||
7157 | const int ic = !(ctl == CTLTOPROC); | ||
7158 | #else | ||
7159 | const int ctl = CTLBACKQ; | ||
7160 | const int ip = 0; | ||
7161 | const int ic = 1; | ||
7162 | #endif | ||
7091 | IF_PLATFORM_MINGW32(struct forkshell fs); | 7163 | IF_PLATFORM_MINGW32(struct forkshell fs); |
7092 | 7164 | ||
7093 | result->fd = -1; | 7165 | result->fd = -1; |
@@ -7100,23 +7172,26 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
7100 | 7172 | ||
7101 | if (pipe(pip) < 0) | 7173 | if (pipe(pip) < 0) |
7102 | ash_msg_and_raise_perror("can't create pipe"); | 7174 | ash_msg_and_raise_perror("can't create pipe"); |
7103 | jp = makejob(/*n,*/ 1); | 7175 | /* process substitution uses NULL job/node, like openhere() */ |
7176 | jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL; | ||
7104 | #if ENABLE_PLATFORM_MINGW32 | 7177 | #if ENABLE_PLATFORM_MINGW32 |
7105 | memset(&fs, 0, sizeof(fs)); | 7178 | memset(&fs, 0, sizeof(fs)); |
7106 | fs.fpid = FS_EVALBACKCMD; | 7179 | fs.fpid = FS_EVALBACKCMD; |
7107 | fs.n = n; | 7180 | fs.n = n; |
7108 | fs.fd[0] = pip[0]; | 7181 | fs.fd[0] = pip[0]; |
7109 | fs.fd[1] = pip[1]; | 7182 | fs.fd[1] = pip[1]; |
7110 | spawn_forkshell(&fs, jp, n, FORK_NOJOB); | 7183 | fs.fd[2] = ctl; |
7184 | spawn_forkshell(&fs, jp, (ctl == CTLBACKQ) ? n : NULL, FORK_NOJOB); | ||
7111 | #else | 7185 | #else |
7112 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 7186 | if (forkshell(jp, (ctl == CTLBACKQ) ? n : NULL, FORK_NOJOB) == 0) { |
7113 | /* child */ | 7187 | /* child */ |
7114 | FORCE_INT_ON; | 7188 | FORCE_INT_ON; |
7115 | close(pip[0]); | 7189 | close(pip[ip]); |
7116 | if (pip[1] != 1) { | 7190 | /* ic is index of child end of pipe *and* fd to connect it to */ |
7117 | /*close(1);*/ | 7191 | if (pip[ic] != ic) { |
7118 | dup2_or_raise(pip[1], 1); | 7192 | /*close(ic);*/ |
7119 | close(pip[1]); | 7193 | dup2_or_raise(pip[ic], ic); |
7194 | close(pip[ic]); | ||
7120 | } | 7195 | } |
7121 | /* TODO: eflag clearing makes the following not abort: | 7196 | /* TODO: eflag clearing makes the following not abort: |
7122 | * ash -c 'set -e; z=$(false;echo foo); echo $z' | 7197 | * ash -c 'set -e; z=$(false;echo foo); echo $z' |
@@ -7133,8 +7208,18 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
7133 | } | 7208 | } |
7134 | #endif | 7209 | #endif |
7135 | /* parent */ | 7210 | /* parent */ |
7136 | close(pip[1]); | 7211 | #if BASH_PROCESS_SUBST |
7137 | result->fd = pip[0]; | 7212 | if (ctl != CTLBACKQ) { |
7213 | int fd = fcntl(pip[ip], F_DUPFD, 64); | ||
7214 | if (fd > 0) { | ||
7215 | close(pip[ip]); | ||
7216 | pip[ip] = fd; | ||
7217 | } | ||
7218 | pushfd(pip[ip]); | ||
7219 | } | ||
7220 | #endif | ||
7221 | close(pip[ic]); | ||
7222 | result->fd = pip[ip]; | ||
7138 | result->jp = jp; | 7223 | result->jp = jp; |
7139 | 7224 | ||
7140 | out: | 7225 | out: |
@@ -7146,8 +7231,11 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
7146 | * Expand stuff in backwards quotes. | 7231 | * Expand stuff in backwards quotes. |
7147 | */ | 7232 | */ |
7148 | static void | 7233 | static void |
7149 | expbackq(union node *cmd, int flag) | 7234 | expbackq(union node *cmd, int flag IF_BASH_PROCESS_SUBST(, int ctl)) |
7150 | { | 7235 | { |
7236 | #if !BASH_PROCESS_SUBST | ||
7237 | const int ctl = CTLBACKQ; | ||
7238 | #endif | ||
7151 | struct backcmd in; | 7239 | struct backcmd in; |
7152 | int i; | 7240 | int i; |
7153 | char buf[128]; | 7241 | char buf[128]; |
@@ -7162,9 +7250,15 @@ expbackq(union node *cmd, int flag) | |||
7162 | INT_OFF; | 7250 | INT_OFF; |
7163 | startloc = expdest - (char *)stackblock(); | 7251 | startloc = expdest - (char *)stackblock(); |
7164 | pushstackmark(&smark, startloc); | 7252 | pushstackmark(&smark, startloc); |
7165 | evalbackcmd(cmd, &in); | 7253 | evalbackcmd(cmd, &in IF_BASH_PROCESS_SUBST(, ctl)); |
7166 | popstackmark(&smark); | 7254 | popstackmark(&smark); |
7167 | 7255 | ||
7256 | if (ctl != CTLBACKQ) { | ||
7257 | sprintf(buf, DEV_FD_PREFIX"%d", in.fd); | ||
7258 | strtodest(buf, BASESYNTAX); | ||
7259 | goto done; | ||
7260 | } | ||
7261 | |||
7168 | p = in.buf; | 7262 | p = in.buf; |
7169 | i = in.nleft; | 7263 | i = in.nleft; |
7170 | if (i == 0) | 7264 | if (i == 0) |
@@ -7186,6 +7280,7 @@ expbackq(union node *cmd, int flag) | |||
7186 | close(in.fd); | 7280 | close(in.fd); |
7187 | back_exitstatus = waitforjob(in.jp); | 7281 | back_exitstatus = waitforjob(in.jp); |
7188 | } | 7282 | } |
7283 | done: | ||
7189 | INT_ON; | 7284 | INT_ON; |
7190 | 7285 | ||
7191 | /* Eat all trailing newlines */ | 7286 | /* Eat all trailing newlines */ |
@@ -7274,6 +7369,10 @@ argstr(char *p, int flag) | |||
7274 | CTLESC, | 7369 | CTLESC, |
7275 | CTLVAR, | 7370 | CTLVAR, |
7276 | CTLBACKQ, | 7371 | CTLBACKQ, |
7372 | #if BASH_PROCESS_SUBST | ||
7373 | CTLTOPROC, | ||
7374 | CTLFROMPROC, | ||
7375 | #endif | ||
7277 | #if ENABLE_FEATURE_SH_MATH | 7376 | #if ENABLE_FEATURE_SH_MATH |
7278 | CTLARI, | 7377 | CTLARI, |
7279 | CTLENDARI, | 7378 | CTLENDARI, |
@@ -7373,8 +7472,12 @@ argstr(char *p, int flag) | |||
7373 | p = evalvar(p, flag | inquotes); | 7472 | p = evalvar(p, flag | inquotes); |
7374 | TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); | 7473 | TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); |
7375 | goto start; | 7474 | goto start; |
7475 | #if BASH_PROCESS_SUBST | ||
7476 | case CTLTOPROC: | ||
7477 | case CTLFROMPROC: | ||
7478 | #endif | ||
7376 | case CTLBACKQ: | 7479 | case CTLBACKQ: |
7377 | expbackq(argbackq->n, flag | inquotes); | 7480 | expbackq(argbackq->n, flag | inquotes IF_BASH_PROCESS_SUBST(, c)); |
7378 | goto start; | 7481 | goto start; |
7379 | #if ENABLE_FEATURE_SH_MATH | 7482 | #if ENABLE_FEATURE_SH_MATH |
7380 | case CTLARI: | 7483 | case CTLARI: |
@@ -12995,8 +13098,9 @@ realeofmark(const char *eofmark) | |||
12995 | #define CHECKEND() {goto checkend; checkend_return:;} | 13098 | #define CHECKEND() {goto checkend; checkend_return:;} |
12996 | #define PARSEREDIR() {goto parseredir; parseredir_return:;} | 13099 | #define PARSEREDIR() {goto parseredir; parseredir_return:;} |
12997 | #define PARSESUB() {goto parsesub; parsesub_return:;} | 13100 | #define PARSESUB() {goto parsesub; parsesub_return:;} |
12998 | #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} | 13101 | #define PARSEBACKQOLD() {style = OLD; goto parsebackq; parsebackq_oldreturn:;} |
12999 | #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} | 13102 | #define PARSEBACKQNEW() {style = NEW; goto parsebackq; parsebackq_newreturn:;} |
13103 | #define PARSEPROCSUB() {style = PSUB; goto parsebackq; parsebackq_psreturn:;} | ||
13000 | #define PARSEARITH() {goto parsearith; parsearith_return:;} | 13104 | #define PARSEARITH() {goto parsearith; parsearith_return:;} |
13001 | static int | 13105 | static int |
13002 | readtoken1(int c, int syntax, char *eofmark, int striptabs) | 13106 | readtoken1(int c, int syntax, char *eofmark, int striptabs) |
@@ -13007,7 +13111,9 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
13007 | size_t len; | 13111 | size_t len; |
13008 | struct nodelist *bqlist; | 13112 | struct nodelist *bqlist; |
13009 | smallint quotef; | 13113 | smallint quotef; |
13010 | smallint oldstyle; | 13114 | smallint style; |
13115 | enum { OLD, NEW, PSUB }; | ||
13116 | #define oldstyle (style == OLD) | ||
13011 | smallint pssyntax; /* we are expanding a prompt string */ | 13117 | smallint pssyntax; /* we are expanding a prompt string */ |
13012 | IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;) | 13118 | IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;) |
13013 | /* syntax stack */ | 13119 | /* syntax stack */ |
@@ -13189,6 +13295,15 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
13189 | pungetc(); | 13295 | pungetc(); |
13190 | } | 13296 | } |
13191 | #endif | 13297 | #endif |
13298 | #if BASH_PROCESS_SUBST | ||
13299 | if (c == '<' || c == '>') { | ||
13300 | if (pgetc() == '(') { | ||
13301 | PARSEPROCSUB(); | ||
13302 | break; | ||
13303 | } | ||
13304 | pungetc(); | ||
13305 | } | ||
13306 | #endif | ||
13192 | goto endword; /* exit outer loop */ | 13307 | goto endword; /* exit outer loop */ |
13193 | } | 13308 | } |
13194 | IF_ASH_ALIAS(if (c != PEOA)) | 13309 | IF_ASH_ALIAS(if (c != PEOA)) |
@@ -13673,9 +13788,18 @@ parsebackq: { | |||
13673 | memcpy(out, str, savelen); | 13788 | memcpy(out, str, savelen); |
13674 | STADJUST(savelen, out); | 13789 | STADJUST(savelen, out); |
13675 | } | 13790 | } |
13676 | USTPUTC(CTLBACKQ, out); | 13791 | #if BASH_PROCESS_SUBST |
13792 | if (style == PSUB) | ||
13793 | USTPUTC(c == '<' ? CTLFROMPROC : CTLTOPROC, out); | ||
13794 | else | ||
13795 | #endif | ||
13796 | USTPUTC(CTLBACKQ, out); | ||
13677 | if (oldstyle) | 13797 | if (oldstyle) |
13678 | goto parsebackq_oldreturn; | 13798 | goto parsebackq_oldreturn; |
13799 | #if BASH_PROCESS_SUBST | ||
13800 | else if (style == PSUB) | ||
13801 | goto parsebackq_psreturn; | ||
13802 | #endif | ||
13679 | goto parsebackq_newreturn; | 13803 | goto parsebackq_newreturn; |
13680 | } | 13804 | } |
13681 | 13805 | ||
@@ -14130,6 +14254,9 @@ cmdloop(int top) | |||
14130 | if (doing_jobctl) | 14254 | if (doing_jobctl) |
14131 | showjobs(SHOW_CHANGED|SHOW_STDERR); | 14255 | showjobs(SHOW_CHANGED|SHOW_STDERR); |
14132 | #endif | 14256 | #endif |
14257 | #if BASH_PROCESS_SUBST | ||
14258 | unwindredir(NULL); | ||
14259 | #endif | ||
14133 | inter = 0; | 14260 | inter = 0; |
14134 | if (iflag && top) { | 14261 | if (iflag && top) { |
14135 | inter++; | 14262 | inter++; |
@@ -14864,6 +14991,10 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14864 | } | 14991 | } |
14865 | } | 14992 | } |
14866 | 14993 | ||
14994 | if (!ENABLE_ASH_BASH_COMPAT && !argptr) { | ||
14995 | bb_simple_error_msg("read: need variable name"); | ||
14996 | return 1; | ||
14997 | } | ||
14867 | params.argv = argptr; | 14998 | params.argv = argptr; |
14868 | params.setvar = setvar0; | 14999 | params.setvar = setvar0; |
14869 | params.ifs = bltinlookup("IFS"); /* can be NULL */ | 15000 | params.ifs = bltinlookup("IFS"); /* can be NULL */ |
@@ -15578,15 +15709,27 @@ forkshell_openhere(struct forkshell *fs) | |||
15578 | static void | 15709 | static void |
15579 | forkshell_evalbackcmd(struct forkshell *fs) | 15710 | forkshell_evalbackcmd(struct forkshell *fs) |
15580 | { | 15711 | { |
15712 | #if BASH_PROCESS_SUBST | ||
15713 | /* determine end of pipe used by parent (ip) and child (ic) */ | ||
15714 | const int ctl = fs->fd[2]; | ||
15715 | const int ip = (ctl == CTLTOPROC); | ||
15716 | const int ic = !(ctl == CTLTOPROC); | ||
15717 | #else | ||
15718 | const int ip = 0; | ||
15719 | const int ic = 1; | ||
15720 | #endif | ||
15581 | union node *n = fs->n; | 15721 | union node *n = fs->n; |
15582 | int pip[2] = {fs->fd[0], fs->fd[1]}; | 15722 | int pip[2]; |
15723 | |||
15724 | pip[ip] = fs->fd[ip]; | ||
15725 | pip[ic] = fs->fd[ic]; | ||
15583 | 15726 | ||
15584 | FORCE_INT_ON; | 15727 | FORCE_INT_ON; |
15585 | close(pip[0]); | 15728 | close(pip[ip]); |
15586 | if (pip[1] != 1) { | 15729 | if (pip[ic] != ic) { |
15587 | /*close(1);*/ | 15730 | /*close(ic);*/ |
15588 | dup2_or_raise(pip[1], 1); | 15731 | dup2_or_raise(pip[ic], ic); |
15589 | close(pip[1]); | 15732 | close(pip[ic]); |
15590 | } | 15733 | } |
15591 | eflag = 0; | 15734 | eflag = 0; |
15592 | ifsfree(); | 15735 | ifsfree(); |
diff --git a/shell/ash_remove_unnecessary_code_in_backquote_expansion.patch b/shell/ash_remove_unnecessary_code_in_backquote_expansion.patch new file mode 100644 index 000000000..06067dde0 --- /dev/null +++ b/shell/ash_remove_unnecessary_code_in_backquote_expansion.patch | |||
@@ -0,0 +1,135 @@ | |||
1 | From: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx> | ||
2 | Date: Thu, 19 Apr 2018 18:16:12 +0800 | ||
3 | |||
4 | > ash originally had support for omitting the fork when expanding a | ||
5 | > builtin in backquotes. dash has gradually been removing this support, | ||
6 | > most recently in commit 66b614e29038e31745c4a5d296f64f8d64f5c377 | ||
7 | > ("[EVAL] Remove unused EV_BACKCMD flag"). | ||
8 | > | ||
9 | > Some traces still remain, however. Remove: | ||
10 | > | ||
11 | > - the buf and nleft elements of the backcmd structure; | ||
12 | > - a misleading comment regarding handling of builtins. | ||
13 | > | ||
14 | > Signed-off-by: Ron Yorston <rmy@xxxxxxxxxxxx> | ||
15 | |||
16 | Unfortunately we may need this at some point in the future due | ||
17 | to changes in POSIX. So let's keep it around for now until we | ||
18 | get things such as `jobs -p` to work. | ||
19 | |||
20 | ************************************* | ||
21 | |||
22 | From: Ron Yorston <rmy@xxxxxxxxxxxx> | ||
23 | Date: Thu, 19 Apr 2018 17:18:47 +0100 | ||
24 | |||
25 | >Unfortunately we may need this at some point in the future due | ||
26 | >to changes in POSIX. So let's keep it around for now until we | ||
27 | >get things such as `jobs -p` to work. | ||
28 | |||
29 | As you wish. | ||
30 | |||
31 | Something even more trivial I noticed later: the TRACE at the end of | ||
32 | expbackq incorrectly refers to the function as evalbackq. | ||
33 | |||
34 | ************************************* | ||
35 | |||
36 | Date: Tue, 10 Apr 2018 13:23:35 +0100 | ||
37 | From: Ron Yorston <rmy@pobox.com> | ||
38 | To: busybox@busybox.net | ||
39 | Subject: [PATCH] ash: remove unnecessary code in backquote expansion | ||
40 | |||
41 | Some traces remain of ash's ancient support for omitting the fork when | ||
42 | expanding a builtin command in backquotes. | ||
43 | |||
44 | Remove: | ||
45 | |||
46 | - the buf and nleft elements of the backcmd structure; | ||
47 | - a misleading comment regarding handling of builtins. | ||
48 | |||
49 | I've submitted a similar patch to dash. | ||
50 | |||
51 | Signed-off-by: Ron Yorston <rmy@pobox.com> | ||
52 | --- | ||
53 | shell/ash.c | 37 +++++++++---------------------------- | ||
54 | 1 file changed, 9 insertions(+), 28 deletions(-) | ||
55 | |||
56 | diff --git a/shell/ash.c b/shell/ash.c | ||
57 | index 45c747dbc..6f1458722 100644 | ||
58 | --- a/shell/ash.c | ||
59 | +++ b/shell/ash.c | ||
60 | @@ -6356,15 +6356,12 @@ exptilde(char *startp, char *p, int flags) | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | - * Execute a command inside back quotes. If it's a builtin command, we | ||
65 | - * want to save its output in a block obtained from malloc. Otherwise | ||
66 | - * we fork off a subprocess and get the output of the command via a pipe. | ||
67 | - * Should be called with interrupts off. | ||
68 | + * Execute a command inside back quotes. We fork off a subprocess and | ||
69 | + * get the output of the command via a pipe. Should be called with | ||
70 | + * interrupts off. | ||
71 | */ | ||
72 | struct backcmd { /* result of evalbackcmd */ | ||
73 | int fd; /* file descriptor to read from */ | ||
74 | - int nleft; /* number of chars in buffer */ | ||
75 | - char *buf; /* buffer */ | ||
76 | struct job *jp; /* job structure for command */ | ||
77 | }; | ||
78 | |||
79 | @@ -6394,8 +6391,6 @@ evalbackcmd(union node *n, struct backcmd *result) | ||
80 | struct job *jp; | ||
81 | |||
82 | result->fd = -1; | ||
83 | - result->buf = NULL; | ||
84 | - result->nleft = 0; | ||
85 | result->jp = NULL; | ||
86 | if (n == NULL) { | ||
87 | goto out; | ||
88 | @@ -6432,8 +6427,7 @@ evalbackcmd(union node *n, struct backcmd *result) | ||
89 | result->jp = jp; | ||
90 | |||
91 | out: | ||
92 | - TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", | ||
93 | - result->fd, result->buf, result->nleft, result->jp)); | ||
94 | + TRACE(("evalbackcmd done: fd=%d jp=0x%x\n", result->fd, result->jp)); | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | @@ -6445,7 +6439,6 @@ expbackq(union node *cmd, int flag) | ||
99 | struct backcmd in; | ||
100 | int i; | ||
101 | char buf[128]; | ||
102 | - char *p; | ||
103 | char *dest; | ||
104 | int startloc; | ||
105 | int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX; | ||
106 | @@ -6457,24 +6450,12 @@ expbackq(union node *cmd, int flag) | ||
107 | evalbackcmd(cmd, &in); | ||
108 | popstackmark(&smark); | ||
109 | |||
110 | - p = in.buf; | ||
111 | - i = in.nleft; | ||
112 | - if (i == 0) | ||
113 | - goto read; | ||
114 | - for (;;) { | ||
115 | - memtodest(p, i, syntax, flag & QUOTES_ESC); | ||
116 | - read: | ||
117 | - if (in.fd < 0) | ||
118 | - break; | ||
119 | - i = nonblock_immune_read(in.fd, buf, sizeof(buf)); | ||
120 | - TRACE(("expbackq: read returns %d\n", i)); | ||
121 | - if (i <= 0) | ||
122 | - break; | ||
123 | - p = buf; | ||
124 | - } | ||
125 | - | ||
126 | - free(in.buf); | ||
127 | if (in.fd >= 0) { | ||
128 | + while ((i = nonblock_immune_read(in.fd, buf, sizeof(buf))) > 0) { | ||
129 | + TRACE(("expbackq: read returns %d\n", i)); | ||
130 | + memtodest(buf, i, syntax, flag & QUOTES_ESC); | ||
131 | + } | ||
132 | + | ||
133 | close(in.fd); | ||
134 | back_exitstatus = waitforjob(in.jp); | ||
135 | } | ||
diff --git a/shell/ash_test/ash-psubst/bash_procsub.right b/shell/ash_test/ash-psubst/bash_procsub.right new file mode 100644 index 000000000..aa16a96be --- /dev/null +++ b/shell/ash_test/ash-psubst/bash_procsub.right | |||
@@ -0,0 +1,9 @@ | |||
1 | hello 1 | ||
2 | hello 2 | ||
3 | hello 3 | ||
4 | <(echo "hello 0") | ||
5 | hello 4 | ||
6 | HI THERE | ||
7 | hello error | ||
8 | hello error | ||
9 | hello stderr | ||
diff --git a/shell/ash_test/ash-psubst/bash_procsub.tests b/shell/ash_test/ash-psubst/bash_procsub.tests new file mode 100755 index 000000000..63b836782 --- /dev/null +++ b/shell/ash_test/ash-psubst/bash_procsub.tests | |||
@@ -0,0 +1,33 @@ | |||
1 | # simplest case | ||
2 | cat <(echo "hello 1") | ||
3 | |||
4 | # can have more than one | ||
5 | cat <(echo "hello 2") <(echo "hello 3") | ||
6 | |||
7 | # doesn't work in quotes | ||
8 | echo "<(echo \"hello 0\")" | ||
9 | |||
10 | # process substitution can be nested inside command substitution | ||
11 | echo $(cat <(echo "hello 4")) | ||
12 | |||
13 | # example from http://wiki.bash-hackers.org/syntax/expansion/proc_subst | ||
14 | # process substitutions can be passed to a function as parameters or | ||
15 | # variables | ||
16 | f() { | ||
17 | cat "$1" >"$x" | ||
18 | } | ||
19 | x=>(tr '[:lower:]' '[:upper:]') f <(echo 'hi there') | ||
20 | |||
21 | # process substitution can be combined with redirection on exec | ||
22 | rm -f err | ||
23 | # save stderr | ||
24 | exec 4>&2 | ||
25 | # copy stderr to a file | ||
26 | exec 2> >(tee err) | ||
27 | echo "hello error" >&2 | ||
28 | sync | ||
29 | # restore stderr | ||
30 | exec 2>&4 | ||
31 | cat err | ||
32 | rm -f err | ||
33 | echo "hello stderr" >&2 | ||
diff --git a/shell/hush.c b/shell/hush.c index 144ad3edd..77921e11c 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -4251,7 +4251,7 @@ static int done_word(struct parse_context *ctx) | |||
4251 | || endofname(command->argv[0])[0] != '\0' | 4251 | || endofname(command->argv[0])[0] != '\0' |
4252 | ) { | 4252 | ) { |
4253 | /* bash says just "not a valid identifier" */ | 4253 | /* bash says just "not a valid identifier" */ |
4254 | syntax_error("not a valid identifier in for"); | 4254 | syntax_error("bad variable name in for"); |
4255 | return 1; | 4255 | return 1; |
4256 | } | 4256 | } |
4257 | /* Force FOR to have just one word (variable name) */ | 4257 | /* Force FOR to have just one word (variable name) */ |
@@ -10799,10 +10799,17 @@ static int FAST_FUNC builtin_read(char **argv) | |||
10799 | */ | 10799 | */ |
10800 | params.read_flags = getopt32(argv, | 10800 | params.read_flags = getopt32(argv, |
10801 | # if BASH_READ_D | 10801 | # if BASH_READ_D |
10802 | "!srn:p:t:u:d:", ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u, ¶ms.opt_d | 10802 | IF_NOT_HUSH_BASH_COMPAT("^") |
10803 | "!srn:p:t:u:d:" IF_NOT_HUSH_BASH_COMPAT("\0" "-1"/*min 1 arg*/), | ||
10804 | ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u, ¶ms.opt_d | ||
10803 | # else | 10805 | # else |
10804 | "!srn:p:t:u:", ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u | 10806 | IF_NOT_HUSH_BASH_COMPAT("^") |
10807 | "!srn:p:t:u:" IF_NOT_HUSH_BASH_COMPAT("\0" "-1"/*min 1 arg*/), | ||
10808 | ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u | ||
10805 | # endif | 10809 | # endif |
10810 | //TODO: print "read: need variable name" | ||
10811 | //for the case of !BASH "read" with no args (now it fails silently) | ||
10812 | //(or maybe extend getopt32() to emit a message if "-1" fails) | ||
10806 | ); | 10813 | ); |
10807 | if ((uint32_t)params.read_flags == (uint32_t)-1) | 10814 | if ((uint32_t)params.read_flags == (uint32_t)-1) |
10808 | return EXIT_FAILURE; | 10815 | return EXIT_FAILURE; |
diff --git a/shell/shell_common.c b/shell/shell_common.c index 1897fee3b..fff356c04 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c | |||
@@ -65,7 +65,7 @@ shell_builtin_read(struct builtin_read_params *params) | |||
65 | while (*pp) { | 65 | while (*pp) { |
66 | if (endofname(*pp)[0] != '\0') { | 66 | if (endofname(*pp)[0] != '\0') { |
67 | /* Mimic bash message */ | 67 | /* Mimic bash message */ |
68 | bb_error_msg("read: '%s': not a valid identifier", *pp); | 68 | bb_error_msg("read: '%s': bad variable name", *pp); |
69 | return (const char *)(uintptr_t)1; | 69 | return (const char *)(uintptr_t)1; |
70 | } | 70 | } |
71 | pp++; | 71 | pp++; |
@@ -296,7 +296,7 @@ shell_builtin_read(struct builtin_read_params *params) | |||
296 | * without variable names (bash compat). | 296 | * without variable names (bash compat). |
297 | * Thus, "read" and "read REPLY" are not the same. | 297 | * Thus, "read" and "read REPLY" are not the same. |
298 | */ | 298 | */ |
299 | if (!params->opt_d && argv[0]) { | 299 | if (argv[0]) { |
300 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ | 300 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ |
301 | const char *is_ifs = strchr(ifs, c); | 301 | const char *is_ifs = strchr(ifs, c); |
302 | if (startword && is_ifs) { | 302 | if (startword && is_ifs) { |