aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
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/ash.c
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/ash.c')
-rw-r--r--shell/ash.c191
1 files changed, 167 insertions, 24 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();