aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-06-07 11:34:06 +0100
committerRon Yorston <rmy@pobox.com>2021-06-07 11:34:06 +0100
commitabe872e2a0342357a5608342cb2892e94027b3e7 (patch)
tree297cdccf332fbb5e4eb31b1eac643180059f9b5f /shell
parent1f33f42d7bcb019b268d938df643a7a785dc19ab (diff)
parent4d983dcddeee94892d3072e84c7c9a01d4696055 (diff)
downloadbusybox-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.c191
-rw-r--r--shell/ash_remove_unnecessary_code_in_backquote_expansion.patch135
-rw-r--r--shell/ash_test/ash-psubst/bash_procsub.right9
-rwxr-xr-xshell/ash_test/ash-psubst/bash_procsub.tests33
-rw-r--r--shell/hush.c13
-rw-r--r--shell/shell_common.c4
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
6497static void
6498pushfd(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
6449static struct redirtab* 6511static struct redirtab*
6450pushredir(union node *redir) 6512pushredir(union node *redir)
6451{ 6513{
@@ -7084,10 +7146,20 @@ evaltreenr(union node *n, int flags)
7084} 7146}
7085 7147
7086static void FAST_FUNC 7148static void FAST_FUNC
7087evalbackcmd(union node *n, struct backcmd *result) 7149evalbackcmd(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 */
7148static void 7233static void
7149expbackq(union node *cmd, int flag) 7234expbackq(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:;}
13001static int 13105static int
13002readtoken1(int c, int syntax, char *eofmark, int striptabs) 13106readtoken1(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)
15578static void 15709static void
15579forkshell_evalbackcmd(struct forkshell *fs) 15710forkshell_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 @@
1From: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx>
2Date: 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
16Unfortunately we may need this at some point in the future due
17to changes in POSIX. So let's keep it around for now until we
18get things such as `jobs -p` to work.
19
20*************************************
21
22From: Ron Yorston <rmy@xxxxxxxxxxxx>
23Date: 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
29As you wish.
30
31Something even more trivial I noticed later: the TRACE at the end of
32expbackq incorrectly refers to the function as evalbackq.
33
34*************************************
35
36Date: Tue, 10 Apr 2018 13:23:35 +0100
37From: Ron Yorston <rmy@pobox.com>
38To: busybox@busybox.net
39Subject: [PATCH] ash: remove unnecessary code in backquote expansion
40
41Some traces remain of ash's ancient support for omitting the fork when
42expanding a builtin command in backquotes.
43
44Remove:
45
46- the buf and nleft elements of the backcmd structure;
47- a misleading comment regarding handling of builtins.
48
49I've submitted a similar patch to dash.
50
51Signed-off-by: Ron Yorston <rmy@pobox.com>
52---
53 shell/ash.c | 37 +++++++++----------------------------
54 1 file changed, 9 insertions(+), 28 deletions(-)
55
56diff --git a/shell/ash.c b/shell/ash.c
57index 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 @@
1hello 1
2hello 2
3hello 3
4<(echo "hello 0")
5hello 4
6HI THERE
7hello error
8hello error
9hello 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
2cat <(echo "hello 1")
3
4# can have more than one
5cat <(echo "hello 2") <(echo "hello 3")
6
7# doesn't work in quotes
8echo "<(echo \"hello 0\")"
9
10# process substitution can be nested inside command substitution
11echo $(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
16f() {
17 cat "$1" >"$x"
18}
19x=>(tr '[:lower:]' '[:upper:]') f <(echo 'hi there')
20
21# process substitution can be combined with redirection on exec
22rm -f err
23# save stderr
24exec 4>&2
25# copy stderr to a file
26exec 2> >(tee err)
27echo "hello error" >&2
28sync
29# restore stderr
30exec 2>&4
31cat err
32rm -f err
33echo "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:", &params.opt_n, &params.opt_p, &params.opt_t, &params.opt_u, &params.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 &params.opt_n, &params.opt_p, &params.opt_t, &params.opt_u, &params.opt_d
10803# else 10805# else
10804 "!srn:p:t:u:", &params.opt_n, &params.opt_p, &params.opt_t, &params.opt_u 10806 IF_NOT_HUSH_BASH_COMPAT("^")
10807 "!srn:p:t:u:" IF_NOT_HUSH_BASH_COMPAT("\0" "-1"/*min 1 arg*/),
10808 &params.opt_n, &params.opt_p, &params.opt_t, &params.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) {