aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c1245
1 files changed, 742 insertions, 503 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 750ca7b6d..02e76c0ae 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -57,8 +57,18 @@
57#include <sys/utsname.h> /* for setting $HOSTNAME */ 57#include <sys/utsname.h> /* for setting $HOSTNAME */
58 58
59#include "busybox.h" /* for applet_names */ 59#include "busybox.h" /* for applet_names */
60#include "unicode.h"
61 60
61#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
62/* Bionic at least up to version 24 has no glob() */
63# undef ENABLE_ASH_INTERNAL_GLOB
64# define ENABLE_ASH_INTERNAL_GLOB 1
65#endif
66
67#if !ENABLE_ASH_INTERNAL_GLOB
68# include <glob.h>
69#endif
70
71#include "unicode.h"
62#include "shell_common.h" 72#include "shell_common.h"
63#if ENABLE_SH_MATH_SUPPORT 73#if ENABLE_SH_MATH_SUPPORT
64# include "math.h" 74# include "math.h"
@@ -104,6 +114,42 @@
104//config: shell (by Herbert Xu), which was created by porting the 'ash' shell 114//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
105//config: (written by Kenneth Almquist) from NetBSD. 115//config: (written by Kenneth Almquist) from NetBSD.
106//config: 116//config:
117//config:config ASH_OPTIMIZE_FOR_SIZE
118//config: bool "Optimize for size instead of speed"
119//config: default y
120//config: depends on ASH
121//config: help
122//config: Compile ash for reduced size at the price of speed.
123//config:
124//config:config ASH_INTERNAL_GLOB
125//config: bool "Use internal glob() implementation"
126//config: default n
127//config: depends on ASH
128//config: help
129//config: Do not use glob() function from libc, use internal implementation.
130//config: Use this if you are getting "glob.h: No such file or directory"
131//config: or similar build errors.
132//config:
133//config:config ASH_RANDOM_SUPPORT
134//config: bool "Pseudorandom generator and $RANDOM variable"
135//config: default y
136//config: depends on ASH
137//config: help
138//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
139//config: Each read of "$RANDOM" will generate a new pseudorandom value.
140//config: You can reset the generator by using a specified start value.
141//config: After "unset RANDOM" the generator will switch off and this
142//config: variable will no longer have special treatment.
143//config:
144//config:config ASH_EXPAND_PRMT
145//config: bool "Expand prompt string"
146//config: default y
147//config: depends on ASH
148//config: help
149//config: "PS#" may contain volatile content, such as backquote commands.
150//config: This option recreates the prompt string from the environment
151//config: variable each time it is displayed.
152//config:
107//config:config ASH_BASH_COMPAT 153//config:config ASH_BASH_COMPAT
108//config: bool "bash-compatible extensions" 154//config: bool "bash-compatible extensions"
109//config: default y 155//config: default y
@@ -183,33 +229,6 @@
183//config: help 229//config: help
184//config: Enable "check for new mail" function in the ash shell. 230//config: Enable "check for new mail" function in the ash shell.
185//config: 231//config:
186//config:config ASH_OPTIMIZE_FOR_SIZE
187//config: bool "Optimize for size instead of speed"
188//config: default y
189//config: depends on ASH
190//config: help
191//config: Compile ash for reduced size at the price of speed.
192//config:
193//config:config ASH_RANDOM_SUPPORT
194//config: bool "Pseudorandom generator and $RANDOM variable"
195//config: default y
196//config: depends on ASH
197//config: help
198//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
199//config: Each read of "$RANDOM" will generate a new pseudorandom value.
200//config: You can reset the generator by using a specified start value.
201//config: After "unset RANDOM" the generator will switch off and this
202//config: variable will no longer have special treatment.
203//config:
204//config:config ASH_EXPAND_PRMT
205//config: bool "Expand prompt string"
206//config: default y
207//config: depends on ASH
208//config: help
209//config: "PS#" may contain volatile content, such as backquote commands.
210//config: This option recreates the prompt string from the environment
211//config: variable each time it is displayed.
212//config:
213 232
214//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) 233//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
215//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh)) 234//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh))
@@ -324,8 +343,10 @@ struct jmploc {
324}; 343};
325 344
326struct globals_misc { 345struct globals_misc {
327 /* pid of main shell */ 346 uint8_t exitstatus; /* exit status of last command */
328 int rootpid; 347 uint8_t back_exitstatus;/* exit status of backquoted command */
348 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
349 int rootpid; /* pid of main shell */
329 /* shell level: 0 for the main shell, 1 for its children, and so on */ 350 /* shell level: 0 for the main shell, 1 for its children, and so on */
330 int shlvl; 351 int shlvl;
331#define rootshell (!shlvl) 352#define rootshell (!shlvl)
@@ -393,7 +414,7 @@ struct globals_misc {
393#define S_DFL 1 /* default signal handling (SIG_DFL) */ 414#define S_DFL 1 /* default signal handling (SIG_DFL) */
394#define S_CATCH 2 /* signal is caught */ 415#define S_CATCH 2 /* signal is caught */
395#define S_IGN 3 /* signal is ignored (SIG_IGN) */ 416#define S_IGN 3 /* signal is ignored (SIG_IGN) */
396#define S_HARD_IGN 4 /* signal is ignored permenantly */ 417#define S_HARD_IGN 4 /* signal is ignored permanently */
397 418
398 /* indicates specified signal received */ 419 /* indicates specified signal received */
399 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ 420 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
@@ -406,10 +427,12 @@ struct globals_misc {
406 random_t random_gen; 427 random_t random_gen;
407#endif 428#endif
408 pid_t backgndpid; /* pid of last background process */ 429 pid_t backgndpid; /* pid of last background process */
409 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
410}; 430};
411extern struct globals_misc *const ash_ptr_to_globals_misc; 431extern struct globals_misc *const ash_ptr_to_globals_misc;
412#define G_misc (*ash_ptr_to_globals_misc) 432#define G_misc (*ash_ptr_to_globals_misc)
433#define exitstatus (G_misc.exitstatus )
434#define back_exitstatus (G_misc.back_exitstatus )
435#define job_warning (G_misc.job_warning)
413#define rootpid (G_misc.rootpid ) 436#define rootpid (G_misc.rootpid )
414#define shlvl (G_misc.shlvl ) 437#define shlvl (G_misc.shlvl )
415#define minusc (G_misc.minusc ) 438#define minusc (G_misc.minusc )
@@ -431,7 +454,6 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
431#define trap_ptr (G_misc.trap_ptr ) 454#define trap_ptr (G_misc.trap_ptr )
432#define random_gen (G_misc.random_gen ) 455#define random_gen (G_misc.random_gen )
433#define backgndpid (G_misc.backgndpid ) 456#define backgndpid (G_misc.backgndpid )
434#define job_warning (G_misc.job_warning)
435#define INIT_G_misc() do { \ 457#define INIT_G_misc() do { \
436 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \ 458 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
437 barrier(); \ 459 barrier(); \
@@ -460,12 +482,11 @@ static void trace_vprintf(const char *fmt, va_list va);
460 482
461 483
462/* ============ Utility functions */ 484/* ============ Utility functions */
463#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
464
465#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) 485#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
466#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) 486#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
467 487
468static int isdigit_str9(const char *str) 488static int
489isdigit_str9(const char *str)
469{ 490{
470 int maxlen = 9 + 1; /* max 9 digits: 999999999 */ 491 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
471 while (--maxlen && isdigit(*str)) 492 while (--maxlen && isdigit(*str))
@@ -473,7 +494,8 @@ static int isdigit_str9(const char *str)
473 return (*str == '\0'); 494 return (*str == '\0');
474} 495}
475 496
476static const char *var_end(const char *var) 497static const char *
498var_end(const char *var)
477{ 499{
478 while (*var) 500 while (*var)
479 if (*var++ == '=') 501 if (*var++ == '=')
@@ -494,7 +516,7 @@ static void exitshell(void) NORETURN;
494 */ 516 */
495#define INT_OFF do { \ 517#define INT_OFF do { \
496 suppress_int++; \ 518 suppress_int++; \
497 xbarrier(); \ 519 barrier(); \
498} while (0) 520} while (0)
499 521
500/* 522/*
@@ -522,7 +544,7 @@ raise_exception(int e)
522#endif 544#endif
523 545
524/* 546/*
525 * Called from trap.c when a SIGINT is received. (If the user specifies 547 * Called when a SIGINT is received. (If the user specifies
526 * that SIGINT is to be trapped or ignored using the trap builtin, then 548 * that SIGINT is to be trapped or ignored using the trap builtin, then
527 * this routine is not called.) Suppressint is nonzero when interrupts 549 * this routine is not called.) Suppressint is nonzero when interrupts
528 * are held using the INT_OFF macro. (The test for iflag is just 550 * are held using the INT_OFF macro. (The test for iflag is just
@@ -549,6 +571,8 @@ raise_interrupt(void)
549 } 571 }
550 ex_type = EXINT; 572 ex_type = EXINT;
551 } 573 }
574 /* bash: ^C even on empty command line sets $? */
575 exitstatus = SIGINT + 128;
552 raise_exception(ex_type); 576 raise_exception(ex_type);
553 /* NOTREACHED */ 577 /* NOTREACHED */
554} 578}
@@ -562,7 +586,7 @@ raise_interrupt(void)
562static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void 586static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
563int_on(void) 587int_on(void)
564{ 588{
565 xbarrier(); 589 barrier();
566 if (--suppress_int == 0 && pending_int) { 590 if (--suppress_int == 0 && pending_int) {
567 raise_interrupt(); 591 raise_interrupt();
568 } 592 }
@@ -571,7 +595,7 @@ int_on(void)
571static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void 595static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
572force_int_on(void) 596force_int_on(void)
573{ 597{
574 xbarrier(); 598 barrier();
575 suppress_int = 0; 599 suppress_int = 0;
576 if (pending_int) 600 if (pending_int)
577 raise_interrupt(); 601 raise_interrupt();
@@ -581,7 +605,7 @@ force_int_on(void)
581#define SAVE_INT(v) ((v) = suppress_int) 605#define SAVE_INT(v) ((v) = suppress_int)
582 606
583#define RESTORE_INT(v) do { \ 607#define RESTORE_INT(v) do { \
584 xbarrier(); \ 608 barrier(); \
585 suppress_int = (v); \ 609 suppress_int = (v); \
586 if (suppress_int == 0 && pending_int) \ 610 if (suppress_int == 0 && pending_int) \
587 raise_interrupt(); \ 611 raise_interrupt(); \
@@ -1237,6 +1261,12 @@ struct strpush {
1237 struct alias *ap; /* if push was associated with an alias */ 1261 struct alias *ap; /* if push was associated with an alias */
1238#endif 1262#endif
1239 char *string; /* remember the string since it may change */ 1263 char *string; /* remember the string since it may change */
1264
1265 /* Remember last two characters for pungetc. */
1266 int lastc[2];
1267
1268 /* Number of outstanding calls to pungetc. */
1269 int unget;
1240}; 1270};
1241 1271
1242struct parsefile { 1272struct parsefile {
@@ -1249,6 +1279,12 @@ struct parsefile {
1249 char *buf; /* input buffer */ 1279 char *buf; /* input buffer */
1250 struct strpush *strpush; /* for pushing strings at this level */ 1280 struct strpush *strpush; /* for pushing strings at this level */
1251 struct strpush basestrpush; /* so pushing one is fast */ 1281 struct strpush basestrpush; /* so pushing one is fast */
1282
1283 /* Remember last two characters for pungetc. */
1284 int lastc[2];
1285
1286 /* Number of outstanding calls to pungetc. */
1287 int unget;
1252}; 1288};
1253 1289
1254static struct parsefile basepf; /* top level input file */ 1290static struct parsefile basepf; /* top level input file */
@@ -1256,7 +1292,6 @@ static struct parsefile *g_parsefile = &basepf; /* current input file */
1256static int startlinno; /* line # where last token started */ 1292static int startlinno; /* line # where last token started */
1257static char *commandname; /* currently executing command */ 1293static char *commandname; /* currently executing command */
1258static struct strlist *cmdenviron; /* environment for builtin command */ 1294static struct strlist *cmdenviron; /* environment for builtin command */
1259static uint8_t exitstatus; /* exit status of last command */
1260 1295
1261 1296
1262/* ============ Message printing */ 1297/* ============ Message printing */
@@ -1428,13 +1463,11 @@ struct stackmark {
1428 struct stack_block *stackp; 1463 struct stack_block *stackp;
1429 char *stacknxt; 1464 char *stacknxt;
1430 size_t stacknleft; 1465 size_t stacknleft;
1431 struct stackmark *marknext;
1432}; 1466};
1433 1467
1434 1468
1435struct globals_memstack { 1469struct globals_memstack {
1436 struct stack_block *g_stackp; // = &stackbase; 1470 struct stack_block *g_stackp; // = &stackbase;
1437 struct stackmark *markp;
1438 char *g_stacknxt; // = stackbase.space; 1471 char *g_stacknxt; // = stackbase.space;
1439 char *sstrend; // = stackbase.space + MINSIZE; 1472 char *sstrend; // = stackbase.space + MINSIZE;
1440 size_t g_stacknleft; // = MINSIZE; 1473 size_t g_stacknleft; // = MINSIZE;
@@ -1444,7 +1477,6 @@ struct globals_memstack {
1444extern struct globals_memstack *const ash_ptr_to_globals_memstack; 1477extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1445#define G_memstack (*ash_ptr_to_globals_memstack) 1478#define G_memstack (*ash_ptr_to_globals_memstack)
1446#define g_stackp (G_memstack.g_stackp ) 1479#define g_stackp (G_memstack.g_stackp )
1447#define markp (G_memstack.markp )
1448#define g_stacknxt (G_memstack.g_stacknxt ) 1480#define g_stacknxt (G_memstack.g_stacknxt )
1449#define sstrend (G_memstack.sstrend ) 1481#define sstrend (G_memstack.sstrend )
1450#define g_stacknleft (G_memstack.g_stacknleft) 1482#define g_stacknleft (G_memstack.g_stacknleft)
@@ -1528,20 +1560,33 @@ stunalloc(void *p)
1528 * Like strdup but works with the ash stack. 1560 * Like strdup but works with the ash stack.
1529 */ 1561 */
1530static char * 1562static char *
1531ststrdup(const char *p) 1563sstrdup(const char *p)
1532{ 1564{
1533 size_t len = strlen(p) + 1; 1565 size_t len = strlen(p) + 1;
1534 return memcpy(stalloc(len), p, len); 1566 return memcpy(stalloc(len), p, len);
1535} 1567}
1536 1568
1537static void 1569static void
1538setstackmark(struct stackmark *mark) 1570grabstackblock(size_t len)
1571{
1572 len = SHELL_ALIGN(len);
1573 g_stacknxt += len;
1574 g_stacknleft -= len;
1575}
1576
1577static void
1578pushstackmark(struct stackmark *mark, size_t len)
1539{ 1579{
1540 mark->stackp = g_stackp; 1580 mark->stackp = g_stackp;
1541 mark->stacknxt = g_stacknxt; 1581 mark->stacknxt = g_stacknxt;
1542 mark->stacknleft = g_stacknleft; 1582 mark->stacknleft = g_stacknleft;
1543 mark->marknext = markp; 1583 grabstackblock(len);
1544 markp = mark; 1584}
1585
1586static void
1587setstackmark(struct stackmark *mark)
1588{
1589 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
1545} 1590}
1546 1591
1547static void 1592static void
@@ -1553,7 +1598,6 @@ popstackmark(struct stackmark *mark)
1553 return; 1598 return;
1554 1599
1555 INT_OFF; 1600 INT_OFF;
1556 markp = mark->marknext;
1557 while (g_stackp != mark->stackp) { 1601 while (g_stackp != mark->stackp) {
1558 sp = g_stackp; 1602 sp = g_stackp;
1559 g_stackp = sp->prev; 1603 g_stackp = sp->prev;
@@ -1586,14 +1630,11 @@ growstackblock(void)
1586 newlen += 128; 1630 newlen += 128;
1587 1631
1588 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) { 1632 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1589 struct stack_block *oldstackp;
1590 struct stackmark *xmark;
1591 struct stack_block *sp; 1633 struct stack_block *sp;
1592 struct stack_block *prevstackp; 1634 struct stack_block *prevstackp;
1593 size_t grosslen; 1635 size_t grosslen;
1594 1636
1595 INT_OFF; 1637 INT_OFF;
1596 oldstackp = g_stackp;
1597 sp = g_stackp; 1638 sp = g_stackp;
1598 prevstackp = sp->prev; 1639 prevstackp = sp->prev;
1599 grosslen = newlen + sizeof(struct stack_block) - MINSIZE; 1640 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
@@ -1603,18 +1644,6 @@ growstackblock(void)
1603 g_stacknxt = sp->space; 1644 g_stacknxt = sp->space;
1604 g_stacknleft = newlen; 1645 g_stacknleft = newlen;
1605 sstrend = sp->space + newlen; 1646 sstrend = sp->space + newlen;
1606
1607 /*
1608 * Stack marks pointing to the start of the old block
1609 * must be relocated to point to the new block
1610 */
1611 xmark = markp;
1612 while (xmark != NULL && xmark->stackp == oldstackp) {
1613 xmark->stackp = g_stackp;
1614 xmark->stacknxt = g_stacknxt;
1615 xmark->stacknleft = g_stacknleft;
1616 xmark = xmark->marknext;
1617 }
1618 INT_ON; 1647 INT_ON;
1619 } else { 1648 } else {
1620 char *oldspace = g_stacknxt; 1649 char *oldspace = g_stacknxt;
@@ -1627,14 +1656,6 @@ growstackblock(void)
1627 } 1656 }
1628} 1657}
1629 1658
1630static void
1631grabstackblock(size_t len)
1632{
1633 len = SHELL_ALIGN(len);
1634 g_stacknxt += len;
1635 g_stacknleft -= len;
1636}
1637
1638/* 1659/*
1639 * The following routines are somewhat easier to use than the above. 1660 * The following routines are somewhat easier to use than the above.
1640 * The user declares a variable of type STACKSTR, which may be declared 1661 * The user declares a variable of type STACKSTR, which may be declared
@@ -1671,7 +1692,7 @@ static char *
1671makestrspace(size_t newlen, char *p) 1692makestrspace(size_t newlen, char *p)
1672{ 1693{
1673 size_t len = p - g_stacknxt; 1694 size_t len = p - g_stacknxt;
1674 size_t size = stackblocksize(); 1695 size_t size;
1675 1696
1676 for (;;) { 1697 for (;;) {
1677 size_t nleft; 1698 size_t nleft;
@@ -1990,7 +2011,7 @@ static const struct {
1990 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL }, 2011 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1991 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL }, 2012 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1992#if ENABLE_ASH_GETOPTS 2013#if ENABLE_ASH_GETOPTS
1993 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset }, 2014 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
1994#endif 2015#endif
1995#if ENABLE_ASH_RANDOM_SUPPORT 2016#if ENABLE_ASH_RANDOM_SUPPORT
1996 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random }, 2017 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
@@ -2193,7 +2214,8 @@ lookupvar(const char *name)
2193 return NULL; 2214 return NULL;
2194} 2215}
2195 2216
2196static void reinit_unicode_for_ash(void) 2217static void
2218reinit_unicode_for_ash(void)
2197{ 2219{
2198 /* Unicode support should be activated even if LANG is set 2220 /* Unicode support should be activated even if LANG is set
2199 * _during_ shell execution, not only if it was set when 2221 * _during_ shell execution, not only if it was set when
@@ -2560,8 +2582,7 @@ setprompt_if(smallint do_set, int whichprompt)
2560 prompt = nullstr; 2582 prompt = nullstr;
2561 } 2583 }
2562#if ENABLE_ASH_EXPAND_PRMT 2584#if ENABLE_ASH_EXPAND_PRMT
2563 setstackmark(&smark); 2585 pushstackmark(&smark, stackblocksize());
2564 stalloc(stackblocksize());
2565#endif 2586#endif
2566 putprompt(expandstr(prompt)); 2587 putprompt(expandstr(prompt));
2567#if ENABLE_ASH_EXPAND_PRMT 2588#if ENABLE_ASH_EXPAND_PRMT
@@ -2704,7 +2725,7 @@ updatepwd(const char *dir)
2704 char *cdcomppath; 2725 char *cdcomppath;
2705 const char *lim; 2726 const char *lim;
2706 2727
2707 cdcomppath = ststrdup(dir); 2728 cdcomppath = sstrdup(dir);
2708 STARTSTACKSTR(new); 2729 STARTSTACKSTR(new);
2709 if (*dir != '/') { 2730 if (*dir != '/') {
2710 if (curdir == nullstr) 2731 if (curdir == nullstr)
@@ -3000,18 +3021,27 @@ enum {
3000static int 3021static int
3001SIT(int c, int syntax) 3022SIT(int c, int syntax)
3002{ 3023{
3003 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~"; 3024 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
3025 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
3026 /*
3027 * This causes '/' to be prepended with CTLESC in dquoted string,
3028 * making "./file"* treated incorrectly because we feed
3029 * ".\/file*" string to glob(), confusing it (see expandmeta func).
3030 * The "homegrown" glob implementation is okay with that,
3031 * but glibc one isn't. With '/' always treated as CWORD,
3032 * both work fine.
3033 */
3004# if ENABLE_ASH_ALIAS 3034# if ENABLE_ASH_ALIAS
3005 static const uint8_t syntax_index_table[] ALIGN1 = { 3035 static const uint8_t syntax_index_table[] ALIGN1 = {
3006 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */ 3036 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
3007 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */ 3037 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
3008 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */ 3038 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
3009 11, 3 /* "}~" */ 3039 11, 3 /* "}~" */
3010 }; 3040 };
3011# else 3041# else
3012 static const uint8_t syntax_index_table[] ALIGN1 = { 3042 static const uint8_t syntax_index_table[] ALIGN1 = {
3013 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */ 3043 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
3014 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */ 3044 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
3015 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */ 3045 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
3016 10, 2 /* "}~" */ 3046 10, 2 /* "}~" */
3017 }; 3047 };
@@ -3093,7 +3123,8 @@ static const uint8_t syntax_index_table[] ALIGN1 = {
3093 /* 44 "," */ CWORD_CWORD_CWORD_CWORD, 3123 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
3094 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD, 3124 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
3095 /* 46 "." */ CWORD_CWORD_CWORD_CWORD, 3125 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
3096 /* 47 "/" */ CWORD_CCTL_CCTL_CWORD, 3126/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
3127 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
3097 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD, 3128 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
3098 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD, 3129 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
3099 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD, 3130 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
@@ -3335,7 +3366,8 @@ static struct alias **atab; // [ATABSIZE];
3335 3366
3336 3367
3337static struct alias ** 3368static struct alias **
3338__lookupalias(const char *name) { 3369__lookupalias(const char *name)
3370{
3339 unsigned int hashval; 3371 unsigned int hashval;
3340 struct alias **app; 3372 struct alias **app;
3341 const char *p; 3373 const char *p;
@@ -3517,8 +3549,6 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3517#endif /* ASH_ALIAS */ 3549#endif /* ASH_ALIAS */
3518 3550
3519 3551
3520/* ============ jobs.c */
3521
3522/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ 3552/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3523#define FORK_FG 0 3553#define FORK_FG 0
3524#define FORK_BG 1 3554#define FORK_BG 1
@@ -3842,7 +3872,7 @@ getjob(const char *name, int getctl)
3842 3872
3843 if (is_number(p)) { 3873 if (is_number(p)) {
3844 num = atoi(p); 3874 num = atoi(p);
3845 if (num <= njobs) { 3875 if (num > 0 && num <= njobs) {
3846 jp = jobtab + num - 1; 3876 jp = jobtab + num - 1;
3847 if (jp->used) 3877 if (jp->used)
3848 goto gotit; 3878 goto gotit;
@@ -5419,6 +5449,19 @@ openredirect(union node *redir)
5419 char *fname; 5449 char *fname;
5420 int f; 5450 int f;
5421 5451
5452 switch (redir->nfile.type) {
5453/* Can't happen, our single caller does this itself */
5454// case NTOFD:
5455// case NFROMFD:
5456// return -1;
5457 case NHERE:
5458 case NXHERE:
5459 return openhere(redir);
5460 }
5461
5462 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5463 * allocated space. Do it only when we know it is safe.
5464 */
5422 fname = redir->nfile.expfname; 5465 fname = redir->nfile.expfname;
5423#if ENABLE_PLATFORM_MINGW32 5466#if ENABLE_PLATFORM_MINGW32
5424 /* Support for /dev/null */ 5467 /* Support for /dev/null */
@@ -5445,7 +5488,12 @@ openredirect(union node *redir)
5445 break; 5488 break;
5446 } 5489 }
5447#endif 5490#endif
5491
5448 switch (redir->nfile.type) { 5492 switch (redir->nfile.type) {
5493 default:
5494#if DEBUG
5495 abort();
5496#endif
5449 case NFROM: 5497 case NFROM:
5450 f = open(fname, O_RDONLY); 5498 f = open(fname, O_RDONLY);
5451 if (f < 0) 5499 if (f < 0)
@@ -5481,20 +5529,6 @@ openredirect(union node *redir)
5481 lseek(f, 0, SEEK_END); 5529 lseek(f, 0, SEEK_END);
5482#endif 5530#endif
5483 break; 5531 break;
5484 default:
5485#if DEBUG
5486 abort();
5487#endif
5488 /* Fall through to eliminate warning. */
5489/* Our single caller does this itself */
5490// case NTOFD:
5491// case NFROMFD:
5492// f = -1;
5493// break;
5494 case NHERE:
5495 case NXHERE:
5496 f = openhere(redir);
5497 break;
5498 } 5532 }
5499 5533
5500 return f; 5534 return f;
@@ -5548,7 +5582,8 @@ struct redirtab {
5548}; 5582};
5549#define redirlist (G_var.redirlist) 5583#define redirlist (G_var.redirlist)
5550 5584
5551static int need_to_remember(struct redirtab *rp, int fd) 5585static int
5586need_to_remember(struct redirtab *rp, int fd)
5552{ 5587{
5553 int i; 5588 int i;
5554 5589
@@ -5565,7 +5600,8 @@ static int need_to_remember(struct redirtab *rp, int fd)
5565} 5600}
5566 5601
5567/* "hidden" fd is a fd used to read scripts, or a copy of such */ 5602/* "hidden" fd is a fd used to read scripts, or a copy of such */
5568static int is_hidden_fd(struct redirtab *rp, int fd) 5603static int
5604is_hidden_fd(struct redirtab *rp, int fd)
5569{ 5605{
5570 int i; 5606 int i;
5571 struct parsefile *pf; 5607 struct parsefile *pf;
@@ -5979,7 +6015,6 @@ rmescapes(char *str, int flag)
5979 while (*p) { 6015 while (*p) {
5980 if ((unsigned char)*p == CTLQUOTEMARK) { 6016 if ((unsigned char)*p == CTLQUOTEMARK) {
5981// Note: both inquotes and protect_against_glob only affect whether 6017// Note: both inquotes and protect_against_glob only affect whether
5982// CTLESC,<ch> gets converted to <ch> or to \<ch>
5983 inquotes = ~inquotes; 6018 inquotes = ~inquotes;
5984 p++; 6019 p++;
5985 protect_against_glob = globbing; 6020 protect_against_glob = globbing;
@@ -5987,6 +6022,10 @@ rmescapes(char *str, int flag)
5987 } 6022 }
5988 if ((unsigned char)*p == CTLESC) { 6023 if ((unsigned char)*p == CTLESC) {
5989 p++; 6024 p++;
6025#if DEBUG
6026 if (*p == '\0')
6027 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6028#endif
5990 if (protect_against_glob) { 6029 if (protect_against_glob) {
5991 *q++ = '\\'; 6030 *q++ = '\\';
5992 } 6031 }
@@ -6043,11 +6082,14 @@ memtodest(const char *p, size_t len, int syntax, int quotes)
6043 unsigned char c = *p++; 6082 unsigned char c = *p++;
6044 if (c) { 6083 if (c) {
6045 int n = SIT(c, syntax); 6084 int n = SIT(c, syntax);
6046 if ((quotes & QUOTES_ESC) && 6085 if ((quotes & QUOTES_ESC)
6047 ((n == CCTL) || 6086 && ((n == CCTL)
6048 (((quotes & EXP_FULL) || syntax != BASESYNTAX) && 6087 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
6049 n == CBACK))) 6088 && n == CBACK)
6089 )
6090 ) {
6050 USTPUTC(CTLESC, q); 6091 USTPUTC(CTLESC, q);
6092 }
6051 } else if (!(quotes & QUOTES_KEEPNUL)) 6093 } else if (!(quotes & QUOTES_KEEPNUL))
6052 continue; 6094 continue;
6053 USTPUTC(c, q); 6095 USTPUTC(c, q);
@@ -6188,9 +6230,8 @@ struct backcmd { /* result of evalbackcmd */
6188}; 6230};
6189 6231
6190/* These forward decls are needed to use "eval" code for backticks handling: */ 6232/* These forward decls are needed to use "eval" code for backticks handling: */
6191static uint8_t back_exitstatus; /* exit status of backquoted command */
6192#define EV_EXIT 01 /* exit after evaluating tree */ 6233#define EV_EXIT 01 /* exit after evaluating tree */
6193static void evaltree(union node *, int); 6234static int evaltree(union node *, int);
6194 6235
6195static void FAST_FUNC 6236static void FAST_FUNC
6196evalbackcmd(union node *n, struct backcmd *result) 6237evalbackcmd(union node *n, struct backcmd *result)
@@ -6262,10 +6303,8 @@ expbackq(union node *cmd, int flag)
6262 struct stackmark smark; 6303 struct stackmark smark;
6263 6304
6264 INT_OFF; 6305 INT_OFF;
6265 setstackmark(&smark); 6306 startloc = expdest - (char *)stackblock();
6266 dest = expdest; 6307 pushstackmark(&smark, startloc);
6267 startloc = dest - (char *)stackblock();
6268 grabstackstr(dest);
6269 evalbackcmd(cmd, &in); 6308 evalbackcmd(cmd, &in);
6270 popstackmark(&smark); 6309 popstackmark(&smark);
6271 6310
@@ -6681,6 +6720,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6681 6720
6682#if ENABLE_ASH_BASH_COMPAT 6721#if ENABLE_ASH_BASH_COMPAT
6683 case VSSUBSTR: 6722 case VSSUBSTR:
6723//TODO: support more general format ${v:EXPR:EXPR},
6724// where EXPR follows $(()) rules
6684 loc = str = stackblock() + strloc; 6725 loc = str = stackblock() + strloc;
6685 /* Read POS in ${var:POS:LEN} */ 6726 /* Read POS in ${var:POS:LEN} */
6686 pos = atoi(loc); /* number(loc) errors out on "1:4" */ 6727 pos = atoi(loc); /* number(loc) errors out on "1:4" */
@@ -6791,7 +6832,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6791 char *idx, *end; 6832 char *idx, *end;
6792 6833
6793 if (!repl) { 6834 if (!repl) {
6794 if ((repl=strchr(str, CTLESC))) 6835 repl = strchr(str, CTLESC);
6836 if (repl)
6795 *repl++ = '\0'; 6837 *repl++ = '\0';
6796 else 6838 else
6797 repl = nullstr; 6839 repl = nullstr;
@@ -6924,20 +6966,21 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6924 * ash -c 'echo ${#1#}' name:'1=#' 6966 * ash -c 'echo ${#1#}' name:'1=#'
6925 */ 6967 */
6926static NOINLINE ssize_t 6968static NOINLINE ssize_t
6927varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) 6969varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
6928{ 6970{
6929 const char *p; 6971 const char *p;
6930 int num; 6972 int num;
6931 int i; 6973 int i;
6932 ssize_t len = 0; 6974 ssize_t len = 0;
6933 int sep; 6975 int sep;
6934 int quoted = flags & EXP_QUOTED; 6976 int quoted = *quotedp;
6935 int subtype = varflags & VSTYPE; 6977 int subtype = varflags & VSTYPE;
6936 int discard = subtype == VSPLUS || subtype == VSLENGTH; 6978 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6937 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL; 6979 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
6938 int syntax = quoted ? DQSYNTAX : BASESYNTAX; 6980 int syntax;
6939 6981
6940 sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0; 6982 sep = (flags & EXP_FULL) << CHAR_BIT;
6983 syntax = quoted ? DQSYNTAX : BASESYNTAX;
6941 6984
6942 switch (*name) { 6985 switch (*name) {
6943 case '$': 6986 case '$':
@@ -6971,21 +7014,21 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6971 raise_error_syntax("bad substitution"); 7014 raise_error_syntax("bad substitution");
6972#endif 7015#endif
6973 break; 7016 break;
6974 case '@': { 7017 case '@':
7018 if (quoted && sep)
7019 goto param;
7020 /* fall through */
7021 case '*': {
6975 char **ap; 7022 char **ap;
6976 char sepc; 7023 char sepc;
6977 7024
6978 if (quoted && (flags & EXP_FULL)) { 7025 if (quoted)
6979 /* note: this is not meant as PEOF value */ 7026 sep = 0;
6980 sep = 1 << CHAR_BIT; 7027 sep |= ifsset() ? ifsval()[0] : ' ';
6981 goto param;
6982 }
6983 /* fall through */
6984 case '*':
6985 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
6986 param: 7028 param:
6987 ap = shellparam.p;
6988 sepc = sep; 7029 sepc = sep;
7030 *quotedp = !sepc;
7031 ap = shellparam.p;
6989 if (!ap) 7032 if (!ap)
6990 return -1; 7033 return -1;
6991 while ((p = *ap++) != NULL) { 7034 while ((p = *ap++) != NULL) {
@@ -6997,7 +7040,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6997 } 7040 }
6998 } 7041 }
6999 break; 7042 break;
7000 } /* case '@' and '*' */ 7043 } /* case '*' */
7001 case '0': 7044 case '0':
7002 case '1': 7045 case '1':
7003 case '2': 7046 case '2':
@@ -7069,7 +7112,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
7069 * input string. 7112 * input string.
7070 */ 7113 */
7071static char * 7114static char *
7072evalvar(char *p, int flags, struct strlist *var_str_list) 7115evalvar(char *p, int flag, struct strlist *var_str_list)
7073{ 7116{
7074 char varflags; 7117 char varflags;
7075 char subtype; 7118 char subtype;
@@ -7082,14 +7125,14 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
7082 7125
7083 varflags = (unsigned char) *p++; 7126 varflags = (unsigned char) *p++;
7084 subtype = varflags & VSTYPE; 7127 subtype = varflags & VSTYPE;
7085 quoted = flags & EXP_QUOTED; 7128 quoted = flag & EXP_QUOTED;
7086 var = p; 7129 var = p;
7087 easy = (!quoted || (*var == '@' && shellparam.nparam)); 7130 easy = (!quoted || (*var == '@' && shellparam.nparam));
7088 startloc = expdest - (char *)stackblock(); 7131 startloc = expdest - (char *)stackblock();
7089 p = strchr(p, '=') + 1; //TODO: use var_end(p)? 7132 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
7090 7133
7091 again: 7134 again:
7092 varlen = varvalue(var, varflags, flags, var_str_list); 7135 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
7093 if (varflags & VSNUL) 7136 if (varflags & VSNUL)
7094 varlen--; 7137 varlen--;
7095 7138
@@ -7103,36 +7146,27 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
7103 if (varlen < 0) { 7146 if (varlen < 0) {
7104 argstr( 7147 argstr(
7105 p, 7148 p,
7106 flags | EXP_TILDE | EXP_WORD, 7149 flag | EXP_TILDE | EXP_WORD,
7107 var_str_list 7150 var_str_list
7108 ); 7151 );
7109 goto end; 7152 goto end;
7110 } 7153 }
7111 if (easy) 7154 goto record;
7112 goto record;
7113 goto end;
7114 } 7155 }
7115 7156
7116 if (subtype == VSASSIGN || subtype == VSQUESTION) { 7157 if (subtype == VSASSIGN || subtype == VSQUESTION) {
7117 if (varlen < 0) { 7158 if (varlen >= 0)
7118 if (subevalvar(p, var, /* strloc: */ 0,
7119 subtype, startloc, varflags,
7120 /* quotes: */ flags & ~QUOTES_ESC,
7121 var_str_list)
7122 ) {
7123 varflags &= ~VSNUL;
7124 /*
7125 * Remove any recorded regions beyond
7126 * start of variable
7127 */
7128 removerecordregions(startloc);
7129 goto again;
7130 }
7131 goto end;
7132 }
7133 if (easy)
7134 goto record; 7159 goto record;
7135 goto end; 7160
7161 subevalvar(p, var, 0, subtype, startloc, varflags,
7162 flag & ~QUOTES_ESC, var_str_list);
7163 varflags &= ~VSNUL;
7164 /*
7165 * Remove any recorded regions beyond
7166 * start of variable
7167 */
7168 removerecordregions(startloc);
7169 goto again;
7136 } 7170 }
7137 7171
7138 if (varlen < 0 && uflag) 7172 if (varlen < 0 && uflag)
@@ -7144,8 +7178,10 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
7144 } 7178 }
7145 7179
7146 if (subtype == VSNORMAL) { 7180 if (subtype == VSNORMAL) {
7147 if (easy) 7181 record:
7148 goto record; 7182 if (!easy)
7183 goto end;
7184 recordregion(startloc, expdest - (char *)stackblock(), quoted);
7149 goto end; 7185 goto end;
7150 } 7186 }
7151 7187
@@ -7174,7 +7210,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
7174 STPUTC('\0', expdest); 7210 STPUTC('\0', expdest);
7175 patloc = expdest - (char *)stackblock(); 7211 patloc = expdest - (char *)stackblock();
7176 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, 7212 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
7177 startloc, varflags, flags, var_str_list)) { 7213 startloc, varflags, flag, var_str_list)) {
7178 int amount = expdest - ( 7214 int amount = expdest - (
7179 (char *)stackblock() + patloc - 1 7215 (char *)stackblock() + patloc - 1
7180 ); 7216 );
@@ -7182,8 +7218,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
7182 } 7218 }
7183 /* Remove any recorded regions beyond start of variable */ 7219 /* Remove any recorded regions beyond start of variable */
7184 removerecordregions(startloc); 7220 removerecordregions(startloc);
7185 record: 7221 goto record;
7186 recordregion(startloc, expdest - (char *)stackblock(), quoted);
7187 } 7222 }
7188 7223
7189 end: 7224 end:
@@ -7327,11 +7362,90 @@ addfname(const char *name)
7327 struct strlist *sp; 7362 struct strlist *sp;
7328 7363
7329 sp = stzalloc(sizeof(*sp)); 7364 sp = stzalloc(sizeof(*sp));
7330 sp->text = ststrdup(name); 7365 sp->text = sstrdup(name);
7331 *exparg.lastp = sp; 7366 *exparg.lastp = sp;
7332 exparg.lastp = &sp->next; 7367 exparg.lastp = &sp->next;
7333} 7368}
7334 7369
7370/* If we want to use glob() from libc... */
7371#if !ENABLE_ASH_INTERNAL_GLOB
7372
7373/* Add the result of glob() to the list */
7374static void
7375addglob(const glob_t *pglob)
7376{
7377 char **p = pglob->gl_pathv;
7378
7379 do {
7380 addfname(*p);
7381 } while (*++p);
7382}
7383static void
7384expandmeta(struct strlist *str /*, int flag*/)
7385{
7386 /* TODO - EXP_REDIR */
7387
7388 while (str) {
7389 char *p;
7390 glob_t pglob;
7391 int i;
7392
7393 if (fflag)
7394 goto nometa;
7395 INT_OFF;
7396 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7397// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7398// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7399//
7400// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7401// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7402// Which means you need to unescape the string, right? Not so fast:
7403// if there _is_ a file named "file\?" (with backslash), it is returned
7404// as "file\?" too (whichever pattern you used to find it, say, "file*").
7405// You DONT KNOW by looking at the result whether you need to unescape it.
7406//
7407// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7408// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7409// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7410// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7411// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7412// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7413 i = glob(p, 0, NULL, &pglob);
7414 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
7415 if (p != str->text)
7416 free(p);
7417 switch (i) {
7418 case 0:
7419#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
7420 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7421 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7422 goto nometa2;
7423#endif
7424 addglob(&pglob);
7425 globfree(&pglob);
7426 INT_ON;
7427 break;
7428 case GLOB_NOMATCH:
7429 //nometa2:
7430 globfree(&pglob);
7431 INT_ON;
7432 nometa:
7433 *exparg.lastp = str;
7434 rmescapes(str->text, 0);
7435 exparg.lastp = &str->next;
7436 break;
7437 default: /* GLOB_NOSPACE */
7438 globfree(&pglob);
7439 INT_ON;
7440 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7441 }
7442 str = str->next;
7443 }
7444}
7445
7446#else
7447/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
7448
7335/* 7449/*
7336 * Do metacharacter (i.e. *, ?, [...]) expansion. 7450 * Do metacharacter (i.e. *, ?, [...]) expansion.
7337 */ 7451 */
@@ -7535,7 +7649,8 @@ expandmeta(struct strlist *str /*, int flag*/)
7535 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); 7649 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7536 { 7650 {
7537 int i = strlen(str->text); 7651 int i = strlen(str->text);
7538 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ 7652//BUGGY estimation of how long expanded name can be
7653 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
7539 } 7654 }
7540 expmeta(expdir, expdir, p); 7655 expmeta(expdir, expdir, p);
7541 free(expdir); 7656 free(expdir);
@@ -7560,6 +7675,7 @@ expandmeta(struct strlist *str /*, int flag*/)
7560 str = str->next; 7675 str = str->next;
7561 } 7676 }
7562} 7677}
7678#endif /* ENABLE_ASH_INTERNAL_GLOB */
7563 7679
7564/* 7680/*
7565 * Perform variable substitution and command substitution on an argument, 7681 * Perform variable substitution and command substitution on an argument,
@@ -8126,49 +8242,86 @@ enum {
8126}; 8242};
8127typedef smallint token_id_t; 8243typedef smallint token_id_t;
8128 8244
8129/* first char is indicating which tokens mark the end of a list */ 8245/* Nth bit indicates if token marks the end of a list */
8246enum {
8247 tokendlist = 0
8248 /* 0 */ | (1u << TEOF)
8249 /* 1 */ | (0u << TNL)
8250 /* 2 */ | (0u << TREDIR)
8251 /* 3 */ | (0u << TWORD)
8252 /* 4 */ | (0u << TSEMI)
8253 /* 5 */ | (0u << TBACKGND)
8254 /* 6 */ | (0u << TAND)
8255 /* 7 */ | (0u << TOR)
8256 /* 8 */ | (0u << TPIPE)
8257 /* 9 */ | (0u << TLP)
8258 /* 10 */ | (1u << TRP)
8259 /* 11 */ | (1u << TENDCASE)
8260 /* 12 */ | (1u << TENDBQUOTE)
8261 /* 13 */ | (0u << TNOT)
8262 /* 14 */ | (0u << TCASE)
8263 /* 15 */ | (1u << TDO)
8264 /* 16 */ | (1u << TDONE)
8265 /* 17 */ | (1u << TELIF)
8266 /* 18 */ | (1u << TELSE)
8267 /* 19 */ | (1u << TESAC)
8268 /* 20 */ | (1u << TFI)
8269 /* 21 */ | (0u << TFOR)
8270#if ENABLE_ASH_BASH_COMPAT
8271 /* 22 */ | (0u << TFUNCTION)
8272#endif
8273 /* 23 */ | (0u << TIF)
8274 /* 24 */ | (0u << TIN)
8275 /* 25 */ | (1u << TTHEN)
8276 /* 26 */ | (0u << TUNTIL)
8277 /* 27 */ | (0u << TWHILE)
8278 /* 28 */ | (0u << TBEGIN)
8279 /* 29 */ | (1u << TEND)
8280 , /* thus far 29 bits used */
8281};
8282
8130static const char *const tokname_array[] = { 8283static const char *const tokname_array[] = {
8131 "\1end of file", 8284 "end of file",
8132 "\0newline", 8285 "newline",
8133 "\0redirection", 8286 "redirection",
8134 "\0word", 8287 "word",
8135 "\0;", 8288 ";",
8136 "\0&", 8289 "&",
8137 "\0&&", 8290 "&&",
8138 "\0||", 8291 "||",
8139 "\0|", 8292 "|",
8140 "\0(", 8293 "(",
8141 "\1)", 8294 ")",
8142 "\1;;", 8295 ";;",
8143 "\1`", 8296 "`",
8144#define KWDOFFSET 13 8297#define KWDOFFSET 13
8145 /* the following are keywords */ 8298 /* the following are keywords */
8146 "\0!", 8299 "!",
8147 "\0case", 8300 "case",
8148 "\1do", 8301 "do",
8149 "\1done", 8302 "done",
8150 "\1elif", 8303 "elif",
8151 "\1else", 8304 "else",
8152 "\1esac", 8305 "esac",
8153 "\1fi", 8306 "fi",
8154 "\0for", 8307 "for",
8155#if ENABLE_ASH_BASH_COMPAT 8308#if ENABLE_ASH_BASH_COMPAT
8156 "\0function", 8309 "function",
8157#endif 8310#endif
8158 "\0if", 8311 "if",
8159 "\0in", 8312 "in",
8160 "\1then", 8313 "then",
8161 "\0until", 8314 "until",
8162 "\0while", 8315 "while",
8163 "\0{", 8316 "{",
8164 "\1}", 8317 "}",
8165}; 8318};
8166 8319
8167/* Wrapper around strcmp for qsort/bsearch/... */ 8320/* Wrapper around strcmp for qsort/bsearch/... */
8168static int 8321static int
8169pstrcmp(const void *a, const void *b) 8322pstrcmp(const void *a, const void *b)
8170{ 8323{
8171 return strcmp((char*) a, (*(char**) b) + 1); 8324 return strcmp((char*)a, *(char**)b);
8172} 8325}
8173 8326
8174static const char *const * 8327static const char *const *
@@ -8297,9 +8450,45 @@ typecmd(int argc UNUSED_PARAM, char **argv)
8297} 8450}
8298 8451
8299#if ENABLE_ASH_CMDCMD 8452#if ENABLE_ASH_CMDCMD
8453/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8454static char **
8455parse_command_args(char **argv, const char **path)
8456{
8457 char *cp, c;
8458
8459 for (;;) {
8460 cp = *++argv;
8461 if (!cp)
8462 return NULL;
8463 if (*cp++ != '-')
8464 break;
8465 c = *cp++;
8466 if (!c)
8467 break;
8468 if (c == '-' && !*cp) {
8469 if (!*++argv)
8470 return NULL;
8471 break;
8472 }
8473 do {
8474 switch (c) {
8475 case 'p':
8476 *path = bb_default_path;
8477 break;
8478 default:
8479 /* run 'typecmd' for other options */
8480 return NULL;
8481 }
8482 c = *cp++;
8483 } while (c);
8484 }
8485 return argv;
8486}
8487
8300static int FAST_FUNC 8488static int FAST_FUNC
8301commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 8489commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8302{ 8490{
8491 char *cmd;
8303 int c; 8492 int c;
8304 enum { 8493 enum {
8305 VERIFY_BRIEF = 1, 8494 VERIFY_BRIEF = 1,
@@ -8307,29 +8496,32 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8307 } verify = 0; 8496 } verify = 0;
8308 const char *path = NULL; 8497 const char *path = NULL;
8309 8498
8499 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8500 * never reaches this function.
8501 */
8502
8310 while ((c = nextopt("pvV")) != '\0') 8503 while ((c = nextopt("pvV")) != '\0')
8311 if (c == 'V') 8504 if (c == 'V')
8312 verify |= VERIFY_VERBOSE; 8505 verify |= VERIFY_VERBOSE;
8313 else if (c == 'v') 8506 else if (c == 'v')
8314 verify |= VERIFY_BRIEF; 8507 /*verify |= VERIFY_BRIEF*/;
8315#if DEBUG 8508#if DEBUG
8316 else if (c != 'p') 8509 else if (c != 'p')
8317 abort(); 8510 abort();
8318#endif 8511#endif
8319 else 8512 else
8320 path = bb_default_path; 8513 path = bb_default_path;
8514
8321 /* Mimic bash: just "command -v" doesn't complain, it's a nop */ 8515 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8322 if (verify && (*argptr != NULL)) { 8516 cmd = *argptr;
8323 return describe_command(*argptr, path, verify - VERIFY_BRIEF); 8517 if (/*verify && */ cmd)
8324 } 8518 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
8325 8519
8326 return 0; 8520 return 0;
8327} 8521}
8328#endif 8522#endif
8329 8523
8330 8524
8331/* ============ eval.c */
8332
8333static int funcblocksize; /* size of structures in function */ 8525static int funcblocksize; /* size of structures in function */
8334static int funcstringsize; /* size of strings in node */ 8526static int funcstringsize; /* size of strings in node */
8335static void *funcblock; /* block to allocate function from */ 8527static void *funcblock; /* block to allocate function from */
@@ -8342,7 +8534,6 @@ static char **nodeptr;
8342/* flags in argument to evaltree */ 8534/* flags in argument to evaltree */
8343#define EV_EXIT 01 /* exit after evaluating tree */ 8535#define EV_EXIT 01 /* exit after evaluating tree */
8344#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 8536#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
8345#define EV_BACKCMD 04 /* command executing within back quotes */
8346 8537
8347static const uint8_t nodesize[N_NUMBER] ALIGN1 = { 8538static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8348 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), 8539 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
@@ -8674,15 +8865,13 @@ defun(char *name, union node *func)
8674#define SKIPBREAK (1 << 0) 8865#define SKIPBREAK (1 << 0)
8675#define SKIPCONT (1 << 1) 8866#define SKIPCONT (1 << 1)
8676#define SKIPFUNC (1 << 2) 8867#define SKIPFUNC (1 << 2)
8677#define SKIPFILE (1 << 3)
8678#define SKIPEVAL (1 << 4)
8679static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ 8868static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
8680static int skipcount; /* number of levels to skip */ 8869static int skipcount; /* number of levels to skip */
8681static int funcnest; /* depth of function calls */ 8870static int funcnest; /* depth of function calls */
8682static int loopnest; /* current loop nesting level */ 8871static int loopnest; /* current loop nesting level */
8683 8872
8684/* Forward decl way out to parsing code - dotrap needs it */ 8873/* Forward decl way out to parsing code - dotrap needs it */
8685static int evalstring(char *s, int mask); 8874static int evalstring(char *s, int flags);
8686 8875
8687/* Called to execute a trap. 8876/* Called to execute a trap.
8688 * Single callsite - at the end of evaltree(). 8877 * Single callsite - at the end of evaltree().
@@ -8691,69 +8880,71 @@ static int evalstring(char *s, int mask);
8691 * Perhaps we should avoid entering new trap handlers 8880 * Perhaps we should avoid entering new trap handlers
8692 * while we are executing a trap handler. [is it a TODO?] 8881 * while we are executing a trap handler. [is it a TODO?]
8693 */ 8882 */
8694static int 8883static void
8695dotrap(void) 8884dotrap(void)
8696{ 8885{
8697 uint8_t *g; 8886 uint8_t *g;
8698 int sig; 8887 int sig;
8699 uint8_t savestatus; 8888 uint8_t last_status;
8889
8890 if (!pending_sig)
8891 return;
8700 8892
8701 savestatus = exitstatus; 8893 last_status = exitstatus;
8702 pending_sig = 0; 8894 pending_sig = 0;
8703 xbarrier(); 8895 barrier();
8704 8896
8705 TRACE(("dotrap entered\n")); 8897 TRACE(("dotrap entered\n"));
8706 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) { 8898 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8707 int want_exexit; 8899 char *p;
8708 char *t;
8709 8900
8710 if (*g == 0) 8901 if (!*g)
8711 continue; 8902 continue;
8712 t = trap[sig]; 8903
8904 if (evalskip) {
8905 pending_sig = sig;
8906 break;
8907 }
8908
8909 p = trap[sig];
8713 /* non-trapped SIGINT is handled separately by raise_interrupt, 8910 /* non-trapped SIGINT is handled separately by raise_interrupt,
8714 * don't upset it by resetting gotsig[SIGINT-1] */ 8911 * don't upset it by resetting gotsig[SIGINT-1] */
8715 if (sig == SIGINT && !t) 8912 if (sig == SIGINT && !p)
8716 continue; 8913 continue;
8717 8914
8718 TRACE(("sig %d is active, will run handler '%s'\n", sig, t)); 8915 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
8719 *g = 0; 8916 *g = 0;
8720 if (!t) 8917 if (!p)
8721 continue; 8918 continue;
8722 want_exexit = evalstring(t, SKIPEVAL); 8919 evalstring(p, 0);
8723 exitstatus = savestatus;
8724 if (want_exexit) {
8725 TRACE(("dotrap returns %d\n", want_exexit));
8726 return want_exexit;
8727 }
8728 } 8920 }
8729 8921 exitstatus = last_status;
8730 TRACE(("dotrap returns 0\n")); 8922 TRACE(("dotrap returns\n"));
8731 return 0;
8732} 8923}
8733 8924
8734/* forward declarations - evaluation is fairly recursive business... */ 8925/* forward declarations - evaluation is fairly recursive business... */
8735static void evalloop(union node *, int); 8926static int evalloop(union node *, int);
8736static void evalfor(union node *, int); 8927static int evalfor(union node *, int);
8737static void evalcase(union node *, int); 8928static int evalcase(union node *, int);
8738static void evalsubshell(union node *, int); 8929static int evalsubshell(union node *, int);
8739static void expredir(union node *); 8930static void expredir(union node *);
8740static void evalpipe(union node *, int); 8931static int evalpipe(union node *, int);
8741static void evalcommand(union node *, int); 8932static int evalcommand(union node *, int);
8742static int evalbltin(const struct builtincmd *, int, char **); 8933static int evalbltin(const struct builtincmd *, int, char **, int);
8743static void prehash(union node *); 8934static void prehash(union node *);
8744 8935
8745/* 8936/*
8746 * Evaluate a parse tree. The value is left in the global variable 8937 * Evaluate a parse tree. The value is left in the global variable
8747 * exitstatus. 8938 * exitstatus.
8748 */ 8939 */
8749static void 8940static int
8750evaltree(union node *n, int flags) 8941evaltree(union node *n, int flags)
8751{ 8942{
8752 struct jmploc *volatile savehandler = exception_handler; 8943 struct jmploc *volatile savehandler = exception_handler;
8753 struct jmploc jmploc; 8944 struct jmploc jmploc;
8754 int checkexit = 0; 8945 int checkexit = 0;
8755 void (*evalfn)(union node *, int); 8946 int (*evalfn)(union node *, int);
8756 int status; 8947 int status = 0;
8757 int int_level; 8948 int int_level;
8758 8949
8759 SAVE_INT(int_level); 8950 SAVE_INT(int_level);
@@ -8764,6 +8955,8 @@ evaltree(union node *n, int flags)
8764 } 8955 }
8765 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags)); 8956 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
8766 8957
8958 dotrap();
8959
8767 exception_handler = &jmploc; 8960 exception_handler = &jmploc;
8768 { 8961 {
8769 int err = setjmp(jmploc.loc); 8962 int err = setjmp(jmploc.loc);
@@ -8790,15 +8983,13 @@ evaltree(union node *n, int flags)
8790 break; 8983 break;
8791#endif 8984#endif
8792 case NNOT: 8985 case NNOT:
8793 evaltree(n->nnot.com, EV_TESTED); 8986 status = !evaltree(n->nnot.com, EV_TESTED);
8794 status = !exitstatus;
8795 goto setstatus; 8987 goto setstatus;
8796 case NREDIR: 8988 case NREDIR:
8797 expredir(n->nredir.redirect); 8989 expredir(n->nredir.redirect);
8798 status = redirectsafe(n->nredir.redirect, REDIR_PUSH); 8990 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8799 if (!status) { 8991 if (!status) {
8800 evaltree(n->nredir.n, flags & EV_TESTED); 8992 status = evaltree(n->nredir.n, flags & EV_TESTED);
8801 status = exitstatus;
8802 } 8993 }
8803 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */); 8994 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
8804 goto setstatus; 8995 goto setstatus;
@@ -8816,6 +9007,8 @@ evaltree(union node *n, int flags)
8816 evalfn = evalloop; 9007 evalfn = evalloop;
8817 goto calleval; 9008 goto calleval;
8818 case NSUBSHELL: 9009 case NSUBSHELL:
9010 evalfn = evalsubshell;
9011 goto checkexit;
8819 case NBACKGND: 9012 case NBACKGND:
8820 evalfn = evalsubshell; 9013 evalfn = evalsubshell;
8821 goto calleval; 9014 goto calleval;
@@ -8836,27 +9029,24 @@ evaltree(union node *n, int flags)
8836#error NOR + 1 != NSEMI 9029#error NOR + 1 != NSEMI
8837#endif 9030#endif
8838 unsigned is_or = n->type - NAND; 9031 unsigned is_or = n->type - NAND;
8839 evaltree( 9032 status = evaltree(
8840 n->nbinary.ch1, 9033 n->nbinary.ch1,
8841 (flags | ((is_or >> 1) - 1)) & EV_TESTED 9034 (flags | ((is_or >> 1) - 1)) & EV_TESTED
8842 ); 9035 );
8843 if ((!exitstatus) == is_or) 9036 if ((!status) == is_or || evalskip)
8844 break; 9037 break;
8845 if (!evalskip) { 9038 n = n->nbinary.ch2;
8846 n = n->nbinary.ch2;
8847 evaln: 9039 evaln:
8848 evalfn = evaltree; 9040 evalfn = evaltree;
8849 calleval: 9041 calleval:
8850 evalfn(n, flags); 9042 status = evalfn(n, flags);
8851 break; 9043 goto setstatus;
8852 }
8853 break;
8854 } 9044 }
8855 case NIF: 9045 case NIF:
8856 evaltree(n->nif.test, EV_TESTED); 9046 status = evaltree(n->nif.test, EV_TESTED);
8857 if (evalskip) 9047 if (evalskip)
8858 break; 9048 break;
8859 if (exitstatus == 0) { 9049 if (!status) {
8860 n = n->nif.ifpart; 9050 n = n->nif.ifpart;
8861 goto evaln; 9051 goto evaln;
8862 } 9052 }
@@ -8864,11 +9054,14 @@ evaltree(union node *n, int flags)
8864 n = n->nif.elsepart; 9054 n = n->nif.elsepart;
8865 goto evaln; 9055 goto evaln;
8866 } 9056 }
8867 goto success; 9057 status = 0;
9058 goto setstatus;
8868 case NDEFUN: 9059 case NDEFUN:
8869 defun(n->narg.text, n->narg.next); 9060 defun(n->narg.text, n->narg.next);
8870 success: 9061 /* Not necessary. To test it:
8871 status = 0; 9062 * "false; f() { qwerty; }; echo $?" should print 0.
9063 */
9064 /* status = 0; */
8872 setstatus: 9065 setstatus:
8873 exitstatus = status; 9066 exitstatus = status;
8874 break; 9067 break;
@@ -8881,119 +9074,127 @@ evaltree(union node *n, int flags)
8881 /* Order of checks below is important: 9074 /* Order of checks below is important:
8882 * signal handlers trigger before exit caused by "set -e". 9075 * signal handlers trigger before exit caused by "set -e".
8883 */ 9076 */
8884 if (pending_sig && dotrap()) 9077 dotrap();
8885 goto exexit;
8886 if (checkexit & exitstatus)
8887 evalskip |= SKIPEVAL;
8888 9078
8889 if (flags & EV_EXIT) { 9079 if (checkexit & status)
8890 exexit: 9080 raise_exception(EXEXIT);
9081 if (flags & EV_EXIT)
8891 raise_exception(EXEXIT); 9082 raise_exception(EXEXIT);
8892 }
8893 9083
8894 RESTORE_INT(int_level); 9084 RESTORE_INT(int_level);
8895 TRACE(("leaving evaltree (no interrupts)\n")); 9085 TRACE(("leaving evaltree (no interrupts)\n"));
9086
9087 return exitstatus;
8896} 9088}
8897 9089
8898#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3) 9090#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8899static 9091static
8900#endif 9092#endif
8901void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__)); 9093int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8902 9094
8903static void 9095static int
9096skiploop(void)
9097{
9098 int skip = evalskip;
9099
9100 switch (skip) {
9101 case 0:
9102 break;
9103 case SKIPBREAK:
9104 case SKIPCONT:
9105 if (--skipcount <= 0) {
9106 evalskip = 0;
9107 break;
9108 }
9109 skip = SKIPBREAK;
9110 break;
9111 }
9112 return skip;
9113}
9114
9115static int
8904evalloop(union node *n, int flags) 9116evalloop(union node *n, int flags)
8905{ 9117{
9118 int skip;
8906 int status; 9119 int status;
8907 9120
8908 loopnest++; 9121 loopnest++;
8909 status = 0; 9122 status = 0;
8910 flags &= EV_TESTED; 9123 flags &= EV_TESTED;
8911 for (;;) { 9124 do {
8912 int i; 9125 int i;
8913 9126
8914 evaltree(n->nbinary.ch1, EV_TESTED); 9127 i = evaltree(n->nbinary.ch1, EV_TESTED);
8915 if (evalskip) { 9128 skip = skiploop();
8916 skipping: 9129 if (skip == SKIPFUNC)
8917 if (evalskip == SKIPCONT && --skipcount <= 0) { 9130 status = i;
8918 evalskip = 0; 9131 if (skip)
8919 continue; 9132 continue;
8920 }
8921 if (evalskip == SKIPBREAK && --skipcount <= 0)
8922 evalskip = 0;
8923 break;
8924 }
8925 i = exitstatus;
8926 if (n->type != NWHILE) 9133 if (n->type != NWHILE)
8927 i = !i; 9134 i = !i;
8928 if (i != 0) 9135 if (i != 0)
8929 break; 9136 break;
8930 evaltree(n->nbinary.ch2, flags); 9137 status = evaltree(n->nbinary.ch2, flags);
8931 status = exitstatus; 9138 skip = skiploop();
8932 if (evalskip) 9139 } while (!(skip & ~SKIPCONT));
8933 goto skipping;
8934 }
8935 loopnest--; 9140 loopnest--;
8936 exitstatus = status; 9141
9142 return status;
8937} 9143}
8938 9144
8939static void 9145static int
8940evalfor(union node *n, int flags) 9146evalfor(union node *n, int flags)
8941{ 9147{
8942 struct arglist arglist; 9148 struct arglist arglist;
8943 union node *argp; 9149 union node *argp;
8944 struct strlist *sp; 9150 struct strlist *sp;
8945 struct stackmark smark; 9151 struct stackmark smark;
9152 int status = 0;
8946 9153
8947 setstackmark(&smark); 9154 setstackmark(&smark);
8948 arglist.list = NULL; 9155 arglist.list = NULL;
8949 arglist.lastp = &arglist.list; 9156 arglist.lastp = &arglist.list;
8950 for (argp = n->nfor.args; argp; argp = argp->narg.next) { 9157 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8951 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 9158 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8952 /* XXX */
8953 if (evalskip)
8954 goto out;
8955 } 9159 }
8956 *arglist.lastp = NULL; 9160 *arglist.lastp = NULL;
8957 9161
8958 exitstatus = 0;
8959 loopnest++; 9162 loopnest++;
8960 flags &= EV_TESTED; 9163 flags &= EV_TESTED;
8961 for (sp = arglist.list; sp; sp = sp->next) { 9164 for (sp = arglist.list; sp; sp = sp->next) {
8962 setvar0(n->nfor.var, sp->text); 9165 setvar0(n->nfor.var, sp->text);
8963 evaltree(n->nfor.body, flags); 9166 status = evaltree(n->nfor.body, flags);
8964 if (evalskip) { 9167 if (skiploop() & ~SKIPCONT)
8965 if (evalskip == SKIPCONT && --skipcount <= 0) {
8966 evalskip = 0;
8967 continue;
8968 }
8969 if (evalskip == SKIPBREAK && --skipcount <= 0)
8970 evalskip = 0;
8971 break; 9168 break;
8972 }
8973 } 9169 }
8974 loopnest--; 9170 loopnest--;
8975 out:
8976 popstackmark(&smark); 9171 popstackmark(&smark);
9172
9173 return status;
8977} 9174}
8978 9175
8979static void 9176static int
8980evalcase(union node *n, int flags) 9177evalcase(union node *n, int flags)
8981{ 9178{
8982 union node *cp; 9179 union node *cp;
8983 union node *patp; 9180 union node *patp;
8984 struct arglist arglist; 9181 struct arglist arglist;
8985 struct stackmark smark; 9182 struct stackmark smark;
9183 int status = 0;
8986 9184
8987 setstackmark(&smark); 9185 setstackmark(&smark);
8988 arglist.list = NULL; 9186 arglist.list = NULL;
8989 arglist.lastp = &arglist.list; 9187 arglist.lastp = &arglist.list;
8990 expandarg(n->ncase.expr, &arglist, EXP_TILDE); 9188 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8991 exitstatus = 0;
8992 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) { 9189 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8993 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) { 9190 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8994 if (casematch(patp, arglist.list->text)) { 9191 if (casematch(patp, arglist.list->text)) {
8995 if (evalskip == 0) { 9192 /* Ensure body is non-empty as otherwise
8996 evaltree(cp->nclist.body, flags); 9193 * EV_EXIT may prevent us from setting the
9194 * exit status.
9195 */
9196 if (evalskip == 0 && cp->nclist.body) {
9197 status = evaltree(cp->nclist.body, flags);
8997 } 9198 }
8998 goto out; 9199 goto out;
8999 } 9200 }
@@ -9001,12 +9202,14 @@ evalcase(union node *n, int flags)
9001 } 9202 }
9002 out: 9203 out:
9003 popstackmark(&smark); 9204 popstackmark(&smark);
9205
9206 return status;
9004} 9207}
9005 9208
9006/* 9209/*
9007 * Kick off a subshell to evaluate a tree. 9210 * Kick off a subshell to evaluate a tree.
9008 */ 9211 */
9009static void 9212static int
9010evalsubshell(union node *n, int flags) 9213evalsubshell(union node *n, int flags)
9011{ 9214{
9012 IF_PLATFORM_MINGW32(struct forkshell fs;) 9215 IF_PLATFORM_MINGW32(struct forkshell fs;)
@@ -9043,8 +9246,8 @@ evalsubshell(union node *n, int flags)
9043 status = 0; 9246 status = 0;
9044 if (!backgnd) 9247 if (!backgnd)
9045 status = waitforjob(jp); 9248 status = waitforjob(jp);
9046 exitstatus = status;
9047 INT_ON; 9249 INT_ON;
9250 return status;
9048} 9251}
9049 9252
9050/* 9253/*
@@ -9117,7 +9320,7 @@ expredir(union node *n)
9117 * of the shell, which make the last process in a pipeline the parent 9320 * of the shell, which make the last process in a pipeline the parent
9118 * of all the rest.) 9321 * of all the rest.)
9119 */ 9322 */
9120static void 9323static int
9121evalpipe(union node *n, int flags) 9324evalpipe(union node *n, int flags)
9122{ 9325{
9123 IF_PLATFORM_MINGW32(struct forkshell fs;) 9326 IF_PLATFORM_MINGW32(struct forkshell fs;)
@@ -9126,6 +9329,7 @@ evalpipe(union node *n, int flags)
9126 int pipelen; 9329 int pipelen;
9127 int prevfd; 9330 int prevfd;
9128 int pip[2]; 9331 int pip[2];
9332 int status = 0;
9129 9333
9130 TRACE(("evalpipe(0x%lx) called\n", (long)n)); 9334 TRACE(("evalpipe(0x%lx) called\n", (long)n));
9131 pipelen = 0; 9335 pipelen = 0;
@@ -9180,10 +9384,12 @@ evalpipe(union node *n, int flags)
9180 close(pip[1]); 9384 close(pip[1]);
9181 } 9385 }
9182 if (n->npipe.pipe_backgnd == 0) { 9386 if (n->npipe.pipe_backgnd == 0) {
9183 exitstatus = waitforjob(jp); 9387 status = waitforjob(jp);
9184 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 9388 TRACE(("evalpipe: job done exit status %d\n", status));
9185 } 9389 }
9186 INT_ON; 9390 INT_ON;
9391
9392 return status;
9187} 9393}
9188 9394
9189/* 9395/*
@@ -9282,12 +9488,12 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
9282 9488
9283 saveparam = shellparam; 9489 saveparam = shellparam;
9284 savelocalvars = localvars; 9490 savelocalvars = localvars;
9491 savehandler = exception_handler;
9285 e = setjmp(jmploc.loc); 9492 e = setjmp(jmploc.loc);
9286 if (e) { 9493 if (e) {
9287 goto funcdone; 9494 goto funcdone;
9288 } 9495 }
9289 INT_OFF; 9496 INT_OFF;
9290 savehandler = exception_handler;
9291 exception_handler = &jmploc; 9497 exception_handler = &jmploc;
9292 localvars = NULL; 9498 localvars = NULL;
9293 shellparam.malloced = 0; 9499 shellparam.malloced = 0;
@@ -9315,42 +9521,6 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
9315 return e; 9521 return e;
9316} 9522}
9317 9523
9318#if ENABLE_ASH_CMDCMD
9319static char **
9320parse_command_args(char **argv, const char **path)
9321{
9322 char *cp, c;
9323
9324 for (;;) {
9325 cp = *++argv;
9326 if (!cp)
9327 return NULL;
9328 if (*cp++ != '-')
9329 break;
9330 c = *cp++;
9331 if (!c)
9332 break;
9333 if (c == '-' && !*cp) {
9334 if (!*++argv)
9335 return NULL;
9336 break;
9337 }
9338 do {
9339 switch (c) {
9340 case 'p':
9341 *path = bb_default_path;
9342 break;
9343 default:
9344 /* run 'typecmd' for other options */
9345 return NULL;
9346 }
9347 c = *cp++;
9348 } while (c);
9349 }
9350 return argv;
9351}
9352#endif
9353
9354/* 9524/*
9355 * Make a variable a local variable. When a variable is made local, it's 9525 * Make a variable a local variable. When a variable is made local, it's
9356 * value and flags are saved in a localvar structure. The saved values 9526 * value and flags are saved in a localvar structure. The saved values
@@ -9458,7 +9628,20 @@ execcmd(int argc UNUSED_PARAM, char **argv)
9458 iflag = 0; /* exit on error */ 9628 iflag = 0; /* exit on error */
9459 mflag = 0; 9629 mflag = 0;
9460 optschanged(); 9630 optschanged();
9631 /* We should set up signals for "exec CMD"
9632 * the same way as for "CMD" without "exec".
9633 * But optschanged->setinteractive->setsignal
9634 * still thought we are a root shell. Therefore, for example,
9635 * SIGQUIT is still set to IGN. Fix it:
9636 */
9637 shlvl++;
9638 setsignal(SIGQUIT);
9639 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9640 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9641 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9642
9461 shellexec(argv + 1, pathval(), 0); 9643 shellexec(argv + 1, pathval(), 0);
9644 /* NOTREACHED */
9462 } 9645 }
9463 return 0; 9646 return 0;
9464} 9647}
@@ -9473,14 +9656,14 @@ returncmd(int argc UNUSED_PARAM, char **argv)
9473 * If called outside a function, do what ksh does; 9656 * If called outside a function, do what ksh does;
9474 * skip the rest of the file. 9657 * skip the rest of the file.
9475 */ 9658 */
9476 evalskip = funcnest ? SKIPFUNC : SKIPFILE; 9659 evalskip = SKIPFUNC;
9477 return argv[1] ? number(argv[1]) : exitstatus; 9660 return argv[1] ? number(argv[1]) : exitstatus;
9478} 9661}
9479 9662
9480/* Forward declarations for builtintab[] */ 9663/* Forward declarations for builtintab[] */
9481static int breakcmd(int, char **) FAST_FUNC; 9664static int breakcmd(int, char **) FAST_FUNC;
9482static int dotcmd(int, char **) FAST_FUNC; 9665static int dotcmd(int, char **) FAST_FUNC;
9483static int evalcmd(int, char **) FAST_FUNC; 9666static int evalcmd(int, char **, int) FAST_FUNC;
9484static int exitcmd(int, char **) FAST_FUNC; 9667static int exitcmd(int, char **) FAST_FUNC;
9485static int exportcmd(int, char **) FAST_FUNC; 9668static int exportcmd(int, char **) FAST_FUNC;
9486#if ENABLE_ASH_GETOPTS 9669#if ENABLE_ASH_GETOPTS
@@ -9550,7 +9733,7 @@ static const struct builtincmd builtintab[] = {
9550#if ENABLE_ASH_BUILTIN_ECHO 9733#if ENABLE_ASH_BUILTIN_ECHO
9551 { BUILTIN_REGULAR "echo" , echocmd }, 9734 { BUILTIN_REGULAR "echo" , echocmd },
9552#endif 9735#endif
9553 { BUILTIN_SPEC_REG "eval" , evalcmd }, 9736 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
9554 { BUILTIN_SPEC_REG "exec" , execcmd }, 9737 { BUILTIN_SPEC_REG "exec" , execcmd },
9555 { BUILTIN_SPEC_REG "exit" , exitcmd }, 9738 { BUILTIN_SPEC_REG "exit" , exitcmd },
9556 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd }, 9739 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
@@ -9606,27 +9789,28 @@ static const struct builtincmd builtintab[] = {
9606 9789
9607/* Should match the above table! */ 9790/* Should match the above table! */
9608#define COMMANDCMD (builtintab + \ 9791#define COMMANDCMD (builtintab + \
9609 2 + \ 9792 /* . : */ 2 + \
9610 1 * ENABLE_ASH_BUILTIN_TEST + \ 9793 /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \
9611 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \ 9794 /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9612 1 * ENABLE_ASH_ALIAS + \ 9795 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9613 1 * ENABLE_ASH_JOB_CONTROL + \ 9796 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9614 3) 9797 /* break cd cddir */ 3)
9615#define EXECCMD (builtintab + \ 9798#define EVALCMD (COMMANDCMD + \
9616 2 + \ 9799 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9617 1 * ENABLE_ASH_BUILTIN_TEST + \ 9800 /* continue */ 1 + \
9618 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \ 9801 /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \
9619 1 * ENABLE_ASH_ALIAS + \ 9802 0)
9620 1 * ENABLE_ASH_JOB_CONTROL + \ 9803#define EXECCMD (EVALCMD + \
9621 3 + \ 9804 /* eval */ 1)
9622 1 * ENABLE_ASH_CMDCMD + \
9623 1 + \
9624 ENABLE_ASH_BUILTIN_ECHO + \
9625 1)
9626 9805
9627/* 9806/*
9628 * Search the table of builtin commands. 9807 * Search the table of builtin commands.
9629 */ 9808 */
9809static int
9810pstrcmp1(const void *a, const void *b)
9811{
9812 return strcmp((char*)a, *(char**)b + 1);
9813}
9630static struct builtincmd * 9814static struct builtincmd *
9631find_builtin(const char *name) 9815find_builtin(const char *name)
9632{ 9816{
@@ -9634,7 +9818,7 @@ find_builtin(const char *name)
9634 9818
9635 bp = bsearch( 9819 bp = bsearch(
9636 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]), 9820 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
9637 pstrcmp 9821 pstrcmp1
9638 ); 9822 );
9639 return bp; 9823 return bp;
9640} 9824}
@@ -9658,7 +9842,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9658 return back_exitstatus; 9842 return back_exitstatus;
9659} 9843}
9660 9844
9661static void 9845static int
9662evalcommand(union node *cmd, int flags) 9846evalcommand(union node *cmd, int flags)
9663{ 9847{
9664 static const struct builtincmd null_bltin = { 9848 static const struct builtincmd null_bltin = {
@@ -9794,6 +9978,9 @@ evalcommand(union node *cmd, int flags)
9794 nargv = parse_command_args(argv, &path); 9978 nargv = parse_command_args(argv, &path);
9795 if (!nargv) 9979 if (!nargv)
9796 break; 9980 break;
9981 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9982 * nargv => "PROG". path is updated if -p.
9983 */
9797 argc -= nargv - argv; 9984 argc -= nargv - argv;
9798 argv = nargv; 9985 argv = nargv;
9799 cmd_flag |= DO_NOFUNC; 9986 cmd_flag |= DO_NOFUNC;
@@ -9862,9 +10049,9 @@ evalcommand(union node *cmd, int flags)
9862 jp = makejob(/*cmd,*/ 1); 10049 jp = makejob(/*cmd,*/ 1);
9863 if (forkshell(jp, cmd, FORK_FG) != 0) { 10050 if (forkshell(jp, cmd, FORK_FG) != 0) {
9864 /* parent */ 10051 /* parent */
9865 exitstatus = waitforjob(jp); 10052 status = waitforjob(jp);
9866 INT_ON; 10053 INT_ON;
9867 TRACE(("forked child exited with %d\n", exitstatus)); 10054 TRACE(("forked child exited with %d\n", status));
9868 break; 10055 break;
9869 } 10056 }
9870 /* child */ 10057 /* child */
@@ -9894,7 +10081,7 @@ evalcommand(union node *cmd, int flags)
9894 * to reap the zombie and make kill detect that it's gone: */ 10081 * to reap the zombie and make kill detect that it's gone: */
9895 dowait(DOWAIT_NONBLOCK, NULL); 10082 dowait(DOWAIT_NONBLOCK, NULL);
9896 10083
9897 if (evalbltin(cmdentry.u.cmd, argc, argv)) { 10084 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
9898 int exit_status; 10085 int exit_status;
9899 int i = exception_type; 10086 int i = exception_type;
9900 if (i == EXEXIT || i == EXEXEC) 10087 if (i == EXEXIT || i == EXEXEC)
@@ -9911,7 +10098,7 @@ evalcommand(union node *cmd, int flags)
9911 } 10098 }
9912 FORCE_INT_ON; 10099 FORCE_INT_ON;
9913 } 10100 }
9914 break; 10101 goto readstatus;
9915 10102
9916 case CMDFUNCTION: 10103 case CMDFUNCTION:
9917 listsetvar(varlist.list, 0); 10104 listsetvar(varlist.list, 0);
@@ -9919,6 +10106,8 @@ evalcommand(union node *cmd, int flags)
9919 dowait(DOWAIT_NONBLOCK, NULL); 10106 dowait(DOWAIT_NONBLOCK, NULL);
9920 if (evalfun(cmdentry.u.func, argc, argv, flags)) 10107 if (evalfun(cmdentry.u.func, argc, argv, flags))
9921 goto raise; 10108 goto raise;
10109 readstatus:
10110 status = exitstatus;
9922 break; 10111 break;
9923 } /* switch */ 10112 } /* switch */
9924 10113
@@ -9932,29 +10121,36 @@ evalcommand(union node *cmd, int flags)
9932 setvar0("_", lastarg); 10121 setvar0("_", lastarg);
9933 } 10122 }
9934 popstackmark(&smark); 10123 popstackmark(&smark);
10124
10125 return status;
9935} 10126}
9936 10127
9937static int 10128static int
9938evalbltin(const struct builtincmd *cmd, int argc, char **argv) 10129evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
9939{ 10130{
9940 char *volatile savecmdname; 10131 char *volatile savecmdname;
9941 struct jmploc *volatile savehandler; 10132 struct jmploc *volatile savehandler;
9942 struct jmploc jmploc; 10133 struct jmploc jmploc;
10134 int status;
9943 int i; 10135 int i;
9944 10136
9945 savecmdname = commandname; 10137 savecmdname = commandname;
10138 savehandler = exception_handler;
9946 i = setjmp(jmploc.loc); 10139 i = setjmp(jmploc.loc);
9947 if (i) 10140 if (i)
9948 goto cmddone; 10141 goto cmddone;
9949 savehandler = exception_handler;
9950 exception_handler = &jmploc; 10142 exception_handler = &jmploc;
9951 commandname = argv[0]; 10143 commandname = argv[0];
9952 argptr = argv + 1; 10144 argptr = argv + 1;
9953 optptr = NULL; /* initialize nextopt */ 10145 optptr = NULL; /* initialize nextopt */
9954 exitstatus = (*cmd->builtin)(argc, argv); 10146 if (cmd == EVALCMD)
10147 status = evalcmd(argc, argv, flags);
10148 else
10149 status = (*cmd->builtin)(argc, argv);
9955 flush_stdout_stderr(); 10150 flush_stdout_stderr();
10151 status |= ferror(stdout);
10152 exitstatus = status;
9956 cmddone: 10153 cmddone:
9957 exitstatus |= ferror(stdout);
9958 clearerr(stdout); 10154 clearerr(stdout);
9959 commandname = savecmdname; 10155 commandname = savecmdname;
9960 exception_handler = savehandler; 10156 exception_handler = savehandler;
@@ -10058,6 +10254,8 @@ pushstring(char *s, struct alias *ap)
10058 g_parsefile->strpush = sp; 10254 g_parsefile->strpush = sp;
10059 sp->prev_string = g_parsefile->next_to_pgetc; 10255 sp->prev_string = g_parsefile->next_to_pgetc;
10060 sp->prev_left_in_line = g_parsefile->left_in_line; 10256 sp->prev_left_in_line = g_parsefile->left_in_line;
10257 sp->unget = g_parsefile->unget;
10258 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
10061#if ENABLE_ASH_ALIAS 10259#if ENABLE_ASH_ALIAS
10062 sp->ap = ap; 10260 sp->ap = ap;
10063 if (ap) { 10261 if (ap) {
@@ -10067,6 +10265,7 @@ pushstring(char *s, struct alias *ap)
10067#endif 10265#endif
10068 g_parsefile->next_to_pgetc = s; 10266 g_parsefile->next_to_pgetc = s;
10069 g_parsefile->left_in_line = len; 10267 g_parsefile->left_in_line = len;
10268 g_parsefile->unget = 0;
10070 INT_ON; 10269 INT_ON;
10071} 10270}
10072 10271
@@ -10094,17 +10293,14 @@ popstring(void)
10094#endif 10293#endif
10095 g_parsefile->next_to_pgetc = sp->prev_string; 10294 g_parsefile->next_to_pgetc = sp->prev_string;
10096 g_parsefile->left_in_line = sp->prev_left_in_line; 10295 g_parsefile->left_in_line = sp->prev_left_in_line;
10296 g_parsefile->unget = sp->unget;
10297 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
10097 g_parsefile->strpush = sp->prev; 10298 g_parsefile->strpush = sp->prev;
10098 if (sp != &(g_parsefile->basestrpush)) 10299 if (sp != &(g_parsefile->basestrpush))
10099 free(sp); 10300 free(sp);
10100 INT_ON; 10301 INT_ON;
10101} 10302}
10102 10303
10103//FIXME: BASH_COMPAT with "...&" does TWO pungetc():
10104//it peeks whether it is &>, and then pushes back both chars.
10105//This function needs to save last *next_to_pgetc to buf[0]
10106//to make two pungetc() reliable. Currently,
10107// pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
10108static int 10304static int
10109preadfd(void) 10305preadfd(void)
10110{ 10306{
@@ -10189,13 +10385,14 @@ preadfd(void)
10189 */ 10385 */
10190//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__) 10386//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10191#define pgetc_debug(...) ((void)0) 10387#define pgetc_debug(...) ((void)0)
10388static int pgetc(void);
10192static int 10389static int
10193preadbuffer(void) 10390preadbuffer(void)
10194{ 10391{
10195 char *q; 10392 char *q;
10196 int more; 10393 int more;
10197 10394
10198 while (g_parsefile->strpush) { 10395 if (g_parsefile->strpush) {
10199#if ENABLE_ASH_ALIAS 10396#if ENABLE_ASH_ALIAS
10200 if (g_parsefile->left_in_line == -1 10397 if (g_parsefile->left_in_line == -1
10201 && g_parsefile->strpush->ap 10398 && g_parsefile->strpush->ap
@@ -10207,13 +10404,7 @@ preadbuffer(void)
10207 } 10404 }
10208#endif 10405#endif
10209 popstring(); 10406 popstring();
10210 /* try "pgetc" now: */ 10407 return pgetc();
10211 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
10212 g_parsefile->left_in_line,
10213 g_parsefile->next_to_pgetc,
10214 g_parsefile->next_to_pgetc);
10215 if (--g_parsefile->left_in_line >= 0)
10216 return (unsigned char)(*g_parsefile->next_to_pgetc++);
10217 } 10408 }
10218 /* on both branches above g_parsefile->left_in_line < 0. 10409 /* on both branches above g_parsefile->left_in_line < 0.
10219 * "pgetc" needs refilling. 10410 * "pgetc" needs refilling.
@@ -10292,27 +10483,41 @@ preadbuffer(void)
10292 return (unsigned char)*g_parsefile->next_to_pgetc++; 10483 return (unsigned char)*g_parsefile->next_to_pgetc++;
10293} 10484}
10294 10485
10295#define pgetc_as_macro() \ 10486static void
10296 (--g_parsefile->left_in_line >= 0 \ 10487nlprompt(void)
10297 ? (unsigned char)*g_parsefile->next_to_pgetc++ \ 10488{
10298 : preadbuffer() \ 10489 g_parsefile->linno++;
10299 ) 10490 setprompt_if(doprompt, 2);
10491}
10492static void
10493nlnoprompt(void)
10494{
10495 g_parsefile->linno++;
10496 needprompt = doprompt;
10497}
10300 10498
10301static int 10499static int
10302pgetc(void) 10500pgetc(void)
10303{ 10501{
10304 pgetc_debug("pgetc_fast at %d:%p'%s'", 10502 int c;
10503
10504 pgetc_debug("pgetc at %d:%p'%s'",
10305 g_parsefile->left_in_line, 10505 g_parsefile->left_in_line,
10306 g_parsefile->next_to_pgetc, 10506 g_parsefile->next_to_pgetc,
10307 g_parsefile->next_to_pgetc); 10507 g_parsefile->next_to_pgetc);
10308 return pgetc_as_macro(); 10508 if (g_parsefile->unget)
10309} 10509 return g_parsefile->lastc[--g_parsefile->unget];
10310 10510
10311#if ENABLE_ASH_OPTIMIZE_FOR_SIZE 10511 if (--g_parsefile->left_in_line >= 0)
10312# define pgetc_fast() pgetc() 10512 c = (signed char)*g_parsefile->next_to_pgetc++;
10313#else 10513 else
10314# define pgetc_fast() pgetc_as_macro() 10514 c = preadbuffer();
10315#endif 10515
10516 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10517 g_parsefile->lastc[0] = c;
10518
10519 return c;
10520}
10316 10521
10317#if ENABLE_ASH_ALIAS 10522#if ENABLE_ASH_ALIAS
10318static int 10523static int
@@ -10320,11 +10525,11 @@ pgetc_without_PEOA(void)
10320{ 10525{
10321 int c; 10526 int c;
10322 do { 10527 do {
10323 pgetc_debug("pgetc_fast at %d:%p'%s'", 10528 pgetc_debug("pgetc at %d:%p'%s'",
10324 g_parsefile->left_in_line, 10529 g_parsefile->left_in_line,
10325 g_parsefile->next_to_pgetc, 10530 g_parsefile->next_to_pgetc,
10326 g_parsefile->next_to_pgetc); 10531 g_parsefile->next_to_pgetc);
10327 c = pgetc_fast(); 10532 c = pgetc();
10328 } while (c == PEOA); 10533 } while (c == PEOA);
10329 return c; 10534 return c;
10330} 10535}
@@ -10358,18 +10563,31 @@ pfgets(char *line, int len)
10358} 10563}
10359 10564
10360/* 10565/*
10361 * Undo the last call to pgetc. Only one character may be pushed back. 10566 * Undo a call to pgetc. Only two characters may be pushed back.
10362 * PEOF may be pushed back. 10567 * PEOF may be pushed back.
10363 */ 10568 */
10364static void 10569static void
10365pungetc(void) 10570pungetc(void)
10366{ 10571{
10367 g_parsefile->left_in_line++; 10572 g_parsefile->unget++;
10368 g_parsefile->next_to_pgetc--; 10573}
10369 pgetc_debug("pushed back to %d:%p'%s'", 10574
10370 g_parsefile->left_in_line, 10575/* This one eats backslash+newline */
10371 g_parsefile->next_to_pgetc, 10576static int
10372 g_parsefile->next_to_pgetc); 10577pgetc_eatbnl(void)
10578{
10579 int c;
10580
10581 while ((c = pgetc()) == '\\') {
10582 if (pgetc() != '\n') {
10583 pungetc();
10584 break;
10585 }
10586
10587 nlprompt();
10588 }
10589
10590 return c;
10373} 10591}
10374 10592
10375/* 10593/*
@@ -10386,6 +10604,7 @@ pushfile(void)
10386 pf->pf_fd = -1; 10604 pf->pf_fd = -1;
10387 /*pf->strpush = NULL; - ckzalloc did it */ 10605 /*pf->strpush = NULL; - ckzalloc did it */
10388 /*pf->basestrpush.prev = NULL;*/ 10606 /*pf->basestrpush.prev = NULL;*/
10607 /*pf->unget = 0;*/
10389 g_parsefile = pf; 10608 g_parsefile = pf;
10390} 10609}
10391 10610
@@ -10959,8 +11178,8 @@ static const char *
10959tokname(char *buf, int tok) 11178tokname(char *buf, int tok)
10960{ 11179{
10961 if (tok < TSEMI) 11180 if (tok < TSEMI)
10962 return tokname_array[tok] + 1; 11181 return tokname_array[tok];
10963 sprintf(buf, "\"%s\"", tokname_array[tok] + 1); 11182 sprintf(buf, "\"%s\"", tokname_array[tok]);
10964 return buf; 11183 return buf;
10965} 11184}
10966 11185
@@ -11017,7 +11236,7 @@ list(int nlflag)
11017 } 11236 }
11018 11237
11019 checkkwd = CHKNL | CHKKWD | CHKALIAS; 11238 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11020 if (nlflag == 2 && tokname_array[peektoken()][0]) 11239 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
11021 return n1; 11240 return n1;
11022 nlflag |= 2; 11241 nlflag |= 2;
11023 11242
@@ -11399,7 +11618,7 @@ parse_command(void)
11399 n1->nbinary.ch1 = list(0); 11618 n1->nbinary.ch1 = list(0);
11400 got = readtoken(); 11619 got = readtoken();
11401 if (got != TDO) { 11620 if (got != TDO) {
11402 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1, 11621 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
11403 got == TWORD ? wordtext : "")); 11622 got == TWORD ? wordtext : ""));
11404 raise_error_unexpected_syntax(TDO); 11623 raise_error_unexpected_syntax(TDO);
11405 } 11624 }
@@ -11545,7 +11764,8 @@ parse_command(void)
11545} 11764}
11546 11765
11547#if ENABLE_ASH_BASH_COMPAT 11766#if ENABLE_ASH_BASH_COMPAT
11548static int decode_dollar_squote(void) 11767static int
11768decode_dollar_squote(void)
11549{ 11769{
11550 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567"; 11770 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11551 int c, cnt; 11771 int c, cnt;
@@ -11613,7 +11833,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11613 /* NB: syntax parameter fits into smallint */ 11833 /* NB: syntax parameter fits into smallint */
11614 /* c parameter is an unsigned char or PEOF or PEOA */ 11834 /* c parameter is an unsigned char or PEOF or PEOA */
11615 char *out; 11835 char *out;
11616 int len; 11836 size_t len;
11617 char line[EOFMARKLEN + 1]; 11837 char line[EOFMARKLEN + 1];
11618 struct nodelist *bqlist; 11838 struct nodelist *bqlist;
11619 smallint quotef; 11839 smallint quotef;
@@ -11656,25 +11876,31 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11656 if (syntax == BASESYNTAX) 11876 if (syntax == BASESYNTAX)
11657 goto endword; /* exit outer loop */ 11877 goto endword; /* exit outer loop */
11658 USTPUTC(c, out); 11878 USTPUTC(c, out);
11659 g_parsefile->linno++; 11879 nlprompt();
11660 setprompt_if(doprompt, 2);
11661 c = pgetc(); 11880 c = pgetc();
11662 goto loop; /* continue outer loop */ 11881 goto loop; /* continue outer loop */
11663 case CWORD: 11882 case CWORD:
11664 USTPUTC(c, out); 11883 USTPUTC(c, out);
11665 break; 11884 break;
11666 case CCTL: 11885 case CCTL:
11667 if (eofmark == NULL || dblquote)
11668 USTPUTC(CTLESC, out);
11669#if ENABLE_ASH_BASH_COMPAT 11886#if ENABLE_ASH_BASH_COMPAT
11670 if (c == '\\' && bash_dollar_squote) { 11887 if (c == '\\' && bash_dollar_squote) {
11671 c = decode_dollar_squote(); 11888 c = decode_dollar_squote();
11889 if (c == '\0') {
11890 /* skip $'\000', $'\x00' (like bash) */
11891 break;
11892 }
11672 if (c & 0x100) { 11893 if (c & 0x100) {
11673 USTPUTC('\\', out); 11894 /* Unknown escape. Encode as '\z' */
11674 c = (unsigned char)c; 11895 c = (unsigned char)c;
11896 if (eofmark == NULL || dblquote)
11897 USTPUTC(CTLESC, out);
11898 USTPUTC('\\', out);
11675 } 11899 }
11676 } 11900 }
11677#endif 11901#endif
11902 if (eofmark == NULL || dblquote)
11903 USTPUTC(CTLESC, out);
11678 USTPUTC(c, out); 11904 USTPUTC(c, out);
11679 break; 11905 break;
11680 case CBACK: /* backslash */ 11906 case CBACK: /* backslash */
@@ -11684,7 +11910,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11684 USTPUTC('\\', out); 11910 USTPUTC('\\', out);
11685 pungetc(); 11911 pungetc();
11686 } else if (c == '\n') { 11912 } else if (c == '\n') {
11687 setprompt_if(doprompt, 2); 11913 nlprompt();
11688 } else { 11914 } else {
11689#if ENABLE_ASH_EXPAND_PRMT 11915#if ENABLE_ASH_EXPAND_PRMT
11690 if (c == '$' && pssyntax) { 11916 if (c == '$' && pssyntax) {
@@ -11752,7 +11978,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11752 if (parenlevel > 0) { 11978 if (parenlevel > 0) {
11753 parenlevel--; 11979 parenlevel--;
11754 } else { 11980 } else {
11755 if (pgetc() == ')') { 11981 if (pgetc_eatbnl() == ')') {
11756 c = CTLENDARI; 11982 c = CTLENDARI;
11757 if (--arinest == 0) { 11983 if (--arinest == 0) {
11758 syntax = prevsyntax; 11984 syntax = prevsyntax;
@@ -11779,6 +12005,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11779 if (varnest == 0) { 12005 if (varnest == 0) {
11780#if ENABLE_ASH_BASH_COMPAT 12006#if ENABLE_ASH_BASH_COMPAT
11781 if (c == '&') { 12007 if (c == '&') {
12008//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
11782 if (pgetc() == '>') 12009 if (pgetc() == '>')
11783 c = 0x100 + '>'; /* flag &> */ 12010 c = 0x100 + '>'; /* flag &> */
11784 pungetc(); 12011 pungetc();
@@ -11789,7 +12016,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11789 IF_ASH_ALIAS(if (c != PEOA)) 12016 IF_ASH_ALIAS(if (c != PEOA))
11790 USTPUTC(c, out); 12017 USTPUTC(c, out);
11791 } 12018 }
11792 c = pgetc_fast(); 12019 c = pgetc();
11793 } /* for (;;) */ 12020 } /* for (;;) */
11794 endword: 12021 endword:
11795 12022
@@ -11854,8 +12081,7 @@ checkend: {
11854 continue; 12081 continue;
11855 if (*p == '\n' && *q == '\0') { 12082 if (*p == '\n' && *q == '\0') {
11856 c = PEOF; 12083 c = PEOF;
11857 g_parsefile->linno++; 12084 nlnoprompt();
11858 needprompt = doprompt;
11859 } else { 12085 } else {
11860 pushstring(line, NULL); 12086 pushstring(line, NULL);
11861 } 12087 }
@@ -11954,7 +12180,7 @@ parsesub: {
11954 int typeloc; 12180 int typeloc;
11955 int flags; 12181 int flags;
11956 12182
11957 c = pgetc(); 12183 c = pgetc_eatbnl();
11958 if (c > 255 /* PEOA or PEOF */ 12184 if (c > 255 /* PEOA or PEOF */
11959 || (c != '(' && c != '{' && !is_name(c) && !is_special(c)) 12185 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
11960 ) { 12186 ) {
@@ -11967,7 +12193,7 @@ parsesub: {
11967 pungetc(); 12193 pungetc();
11968 } else if (c == '(') { 12194 } else if (c == '(') {
11969 /* $(command) or $((arith)) */ 12195 /* $(command) or $((arith)) */
11970 if (pgetc() == '(') { 12196 if (pgetc_eatbnl() == '(') {
11971#if ENABLE_SH_MATH_SUPPORT 12197#if ENABLE_SH_MATH_SUPPORT
11972 PARSEARITH(); 12198 PARSEARITH();
11973#else 12199#else
@@ -11984,9 +12210,9 @@ parsesub: {
11984 USTPUTC(VSNORMAL, out); 12210 USTPUTC(VSNORMAL, out);
11985 subtype = VSNORMAL; 12211 subtype = VSNORMAL;
11986 if (c == '{') { 12212 if (c == '{') {
11987 c = pgetc(); 12213 c = pgetc_eatbnl();
11988 if (c == '#') { 12214 if (c == '#') {
11989 c = pgetc(); 12215 c = pgetc_eatbnl();
11990 if (c == '}') 12216 if (c == '}')
11991 c = '#'; /* ${#} - same as $# */ 12217 c = '#'; /* ${#} - same as $# */
11992 else 12218 else
@@ -11999,18 +12225,18 @@ parsesub: {
11999 /* $[{[#]]NAME[}] */ 12225 /* $[{[#]]NAME[}] */
12000 do { 12226 do {
12001 STPUTC(c, out); 12227 STPUTC(c, out);
12002 c = pgetc(); 12228 c = pgetc_eatbnl();
12003 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c)); 12229 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
12004 } else if (isdigit(c)) { 12230 } else if (isdigit(c)) {
12005 /* $[{[#]]NUM[}] */ 12231 /* $[{[#]]NUM[}] */
12006 do { 12232 do {
12007 STPUTC(c, out); 12233 STPUTC(c, out);
12008 c = pgetc(); 12234 c = pgetc_eatbnl();
12009 } while (isdigit(c)); 12235 } while (isdigit(c));
12010 } else if (is_special(c)) { 12236 } else if (is_special(c)) {
12011 /* $[{[#]]<specialchar>[}] */ 12237 /* $[{[#]]<specialchar>[}] */
12012 USTPUTC(c, out); 12238 USTPUTC(c, out);
12013 c = pgetc(); 12239 c = pgetc_eatbnl();
12014 } else { 12240 } else {
12015 badsub: 12241 badsub:
12016 raise_error_syntax("bad substitution"); 12242 raise_error_syntax("bad substitution");
@@ -12023,15 +12249,18 @@ parsesub: {
12023 STPUTC('=', out); 12249 STPUTC('=', out);
12024 flags = 0; 12250 flags = 0;
12025 if (subtype == 0) { 12251 if (subtype == 0) {
12252 static const char types[] ALIGN1 = "}-+?=";
12026 /* ${VAR...} but not $VAR or ${#VAR} */ 12253 /* ${VAR...} but not $VAR or ${#VAR} */
12027 /* c == first char after VAR */ 12254 /* c == first char after VAR */
12028 switch (c) { 12255 switch (c) {
12029 case ':': 12256 case ':':
12030 c = pgetc(); 12257 c = pgetc_eatbnl();
12031#if ENABLE_ASH_BASH_COMPAT 12258#if ENABLE_ASH_BASH_COMPAT
12032 if (c == ':' || c == '$' || isdigit(c)) { 12259 /* This check is only needed to not misinterpret
12033//TODO: support more general format ${v:EXPR:EXPR}, 12260 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12034// where EXPR follows $(()) rules 12261 * constructs.
12262 */
12263 if (!strchr(types, c)) {
12035 subtype = VSSUBSTR; 12264 subtype = VSSUBSTR;
12036 pungetc(); 12265 pungetc();
12037 break; /* "goto do_pungetc" is bigger (!) */ 12266 break; /* "goto do_pungetc" is bigger (!) */
@@ -12040,7 +12269,6 @@ parsesub: {
12040 flags = VSNUL; 12269 flags = VSNUL;
12041 /*FALLTHROUGH*/ 12270 /*FALLTHROUGH*/
12042 default: { 12271 default: {
12043 static const char types[] ALIGN1 = "}-+?=";
12044 const char *p = strchr(types, c); 12272 const char *p = strchr(types, c);
12045 if (p == NULL) 12273 if (p == NULL)
12046 goto badsub; 12274 goto badsub;
@@ -12051,7 +12279,7 @@ parsesub: {
12051 case '#': { 12279 case '#': {
12052 int cc = c; 12280 int cc = c;
12053 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT); 12281 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
12054 c = pgetc(); 12282 c = pgetc_eatbnl();
12055 if (c != cc) 12283 if (c != cc)
12056 goto do_pungetc; 12284 goto do_pungetc;
12057 subtype++; 12285 subtype++;
@@ -12063,7 +12291,7 @@ parsesub: {
12063//TODO: encode pattern and repl separately. 12291//TODO: encode pattern and repl separately.
12064// Currently ${v/$var_with_slash/repl} is horribly broken 12292// Currently ${v/$var_with_slash/repl} is horribly broken
12065 subtype = VSREPLACE; 12293 subtype = VSREPLACE;
12066 c = pgetc(); 12294 c = pgetc_eatbnl();
12067 if (c != '/') 12295 if (c != '/')
12068 goto do_pungetc; 12296 goto do_pungetc;
12069 subtype++; /* VSREPLACEALL */ 12297 subtype++; /* VSREPLACEALL */
@@ -12101,9 +12329,18 @@ parsebackq: {
12101 str = NULL; 12329 str = NULL;
12102 savelen = out - (char *)stackblock(); 12330 savelen = out - (char *)stackblock();
12103 if (savelen > 0) { 12331 if (savelen > 0) {
12332 /*
12333 * FIXME: this can allocate very large block on stack and SEGV.
12334 * Example:
12335 * echo "..<100kbytes>..`true` $(true) `true` ..."
12336 * allocates 100kb for every command subst. With about
12337 * a hundred command substitutions stack overflows.
12338 * With larger prepended string, SEGV happens sooner.
12339 */
12104 str = alloca(savelen); 12340 str = alloca(savelen);
12105 memcpy(str, stackblock(), savelen); 12341 memcpy(str, stackblock(), savelen);
12106 } 12342 }
12343
12107 if (oldstyle) { 12344 if (oldstyle) {
12108 /* We must read until the closing backquote, giving special 12345 /* We must read until the closing backquote, giving special
12109 * treatment to some slashes, and then push the string and 12346 * treatment to some slashes, and then push the string and
@@ -12126,8 +12363,7 @@ parsebackq: {
12126 case '\\': 12363 case '\\':
12127 pc = pgetc(); 12364 pc = pgetc();
12128 if (pc == '\n') { 12365 if (pc == '\n') {
12129 g_parsefile->linno++; 12366 nlprompt();
12130 setprompt_if(doprompt, 2);
12131 /* 12367 /*
12132 * If eating a newline, avoid putting 12368 * If eating a newline, avoid putting
12133 * the newline into the new character 12369 * the newline into the new character
@@ -12152,8 +12388,7 @@ parsebackq: {
12152 raise_error_syntax("EOF in backquote substitution"); 12388 raise_error_syntax("EOF in backquote substitution");
12153 12389
12154 case '\n': 12390 case '\n':
12155 g_parsefile->linno++; 12391 nlnoprompt();
12156 needprompt = doprompt;
12157 break; 12392 break;
12158 12393
12159 default: 12394 default:
@@ -12272,7 +12507,7 @@ xxreadtoken(void)
12272 setprompt_if(needprompt, 2); 12507 setprompt_if(needprompt, 2);
12273 startlinno = g_parsefile->linno; 12508 startlinno = g_parsefile->linno;
12274 for (;;) { /* until token or start of word found */ 12509 for (;;) { /* until token or start of word found */
12275 c = pgetc_fast(); 12510 c = pgetc();
12276 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA)) 12511 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
12277 continue; 12512 continue;
12278 12513
@@ -12285,16 +12520,14 @@ xxreadtoken(void)
12285 pungetc(); 12520 pungetc();
12286 break; /* return readtoken1(...) */ 12521 break; /* return readtoken1(...) */
12287 } 12522 }
12288 startlinno = ++g_parsefile->linno; 12523 nlprompt();
12289 setprompt_if(doprompt, 2);
12290 } else { 12524 } else {
12291 const char *p; 12525 const char *p;
12292 12526
12293 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1; 12527 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12294 if (c != PEOF) { 12528 if (c != PEOF) {
12295 if (c == '\n') { 12529 if (c == '\n') {
12296 g_parsefile->linno++; 12530 nlnoprompt();
12297 needprompt = doprompt;
12298 } 12531 }
12299 12532
12300 p = strchr(xxreadtoken_chars, c); 12533 p = strchr(xxreadtoken_chars, c);
@@ -12335,7 +12568,7 @@ xxreadtoken(void)
12335 setprompt_if(needprompt, 2); 12568 setprompt_if(needprompt, 2);
12336 startlinno = g_parsefile->linno; 12569 startlinno = g_parsefile->linno;
12337 for (;;) { /* until token or start of word found */ 12570 for (;;) { /* until token or start of word found */
12338 c = pgetc_fast(); 12571 c = pgetc();
12339 switch (c) { 12572 switch (c) {
12340 case ' ': case '\t': 12573 case ' ': case '\t':
12341 IF_ASH_ALIAS(case PEOA:) 12574 IF_ASH_ALIAS(case PEOA:)
@@ -12347,15 +12580,13 @@ xxreadtoken(void)
12347 continue; 12580 continue;
12348 case '\\': 12581 case '\\':
12349 if (pgetc() == '\n') { 12582 if (pgetc() == '\n') {
12350 startlinno = ++g_parsefile->linno; 12583 nlprompt();
12351 setprompt_if(doprompt, 2);
12352 continue; 12584 continue;
12353 } 12585 }
12354 pungetc(); 12586 pungetc();
12355 goto breakloop; 12587 goto breakloop;
12356 case '\n': 12588 case '\n':
12357 g_parsefile->linno++; 12589 nlnoprompt();
12358 needprompt = doprompt;
12359 RETURN(TNL); 12590 RETURN(TNL);
12360 case PEOF: 12591 case PEOF:
12361 RETURN(TEOF); 12592 RETURN(TEOF);
@@ -12426,7 +12657,7 @@ readtoken(void)
12426 pp = findkwd(wordtext); 12657 pp = findkwd(wordtext);
12427 if (pp) { 12658 if (pp) {
12428 lasttoken = t = pp - tokname_array; 12659 lasttoken = t = pp - tokname_array;
12429 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1)); 12660 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
12430 goto out; 12661 goto out;
12431 } 12662 }
12432 } 12663 }
@@ -12447,9 +12678,9 @@ readtoken(void)
12447 checkkwd = 0; 12678 checkkwd = 0;
12448#if DEBUG 12679#if DEBUG
12449 if (!alreadyseen) 12680 if (!alreadyseen)
12450 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : "")); 12681 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
12451 else 12682 else
12452 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : "")); 12683 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
12453#endif 12684#endif
12454 return t; 12685 return t;
12455} 12686}
@@ -12536,35 +12767,39 @@ expandstr(const char *ps)
12536 * Execute a command or commands contained in a string. 12767 * Execute a command or commands contained in a string.
12537 */ 12768 */
12538static int 12769static int
12539evalstring(char *s, int mask) 12770evalstring(char *s, int flags)
12540{ 12771{
12541 union node *n; 12772 union node *n;
12542 struct stackmark smark; 12773 struct stackmark smark;
12543 int skip; 12774 int status;
12544 12775
12776 s = sstrdup(s);
12545 setinputstring(s); 12777 setinputstring(s);
12546 setstackmark(&smark); 12778 setstackmark(&smark);
12547 12779
12548 skip = 0; 12780 status = 0;
12549 while ((n = parsecmd(0)) != NODE_EOF) { 12781 while ((n = parsecmd(0)) != NODE_EOF) {
12550 evaltree(n, 0); 12782 int i;
12783
12784 i = evaltree(n, flags);
12785 if (n)
12786 status = i;
12551 popstackmark(&smark); 12787 popstackmark(&smark);
12552 skip = evalskip; 12788 if (evalskip)
12553 if (skip)
12554 break; 12789 break;
12555 } 12790 }
12791 popstackmark(&smark);
12556 popfile(); 12792 popfile();
12793 stunalloc(s);
12557 12794
12558 skip &= mask; 12795 return status;
12559 evalskip = skip;
12560 return skip;
12561} 12796}
12562 12797
12563/* 12798/*
12564 * The eval command. 12799 * The eval command.
12565 */ 12800 */
12566static int FAST_FUNC 12801static int FAST_FUNC
12567evalcmd(int argc UNUSED_PARAM, char **argv) 12802evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
12568{ 12803{
12569 char *p; 12804 char *p;
12570 char *concat; 12805 char *concat;
@@ -12584,9 +12819,9 @@ evalcmd(int argc UNUSED_PARAM, char **argv)
12584 STPUTC('\0', concat); 12819 STPUTC('\0', concat);
12585 p = grabstackstr(concat); 12820 p = grabstackstr(concat);
12586 } 12821 }
12587 evalstring(p, ~SKIPEVAL); 12822 return evalstring(p, flags & EV_TESTED);
12588 } 12823 }
12589 return exitstatus; 12824 return 0;
12590} 12825}
12591 12826
12592/* 12827/*
@@ -12600,6 +12835,7 @@ cmdloop(int top)
12600 union node *n; 12835 union node *n;
12601 struct stackmark smark; 12836 struct stackmark smark;
12602 int inter; 12837 int inter;
12838 int status = 0;
12603 int numeof = 0; 12839 int numeof = 0;
12604 12840
12605 TRACE(("cmdloop(%d) called\n", top)); 12841 TRACE(("cmdloop(%d) called\n", top));
@@ -12631,20 +12867,24 @@ cmdloop(int top)
12631 } 12867 }
12632 numeof++; 12868 numeof++;
12633 } else if (nflag == 0) { 12869 } else if (nflag == 0) {
12870 int i;
12871
12634 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */ 12872 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12635 job_warning >>= 1; 12873 job_warning >>= 1;
12636 numeof = 0; 12874 numeof = 0;
12637 evaltree(n, 0); 12875 i = evaltree(n, 0);
12876 if (n)
12877 status = i;
12638 } 12878 }
12639 popstackmark(&smark); 12879 popstackmark(&smark);
12640 skip = evalskip; 12880 skip = evalskip;
12641 12881
12642 if (skip) { 12882 if (skip) {
12643 evalskip = 0; 12883 evalskip &= ~SKIPFUNC;
12644 return skip & SKIPEVAL; 12884 break;
12645 } 12885 }
12646 } 12886 }
12647 return 0; 12887 return status;
12648} 12888}
12649 12889
12650/* 12890/*
@@ -12689,32 +12929,38 @@ find_dot_file(char *name)
12689} 12929}
12690 12930
12691static int FAST_FUNC 12931static int FAST_FUNC
12692dotcmd(int argc, char **argv) 12932dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
12693{ 12933{
12934 /* "false; . empty_file; echo $?" should print 0, not 1: */
12935 int status = 0;
12694 char *fullname; 12936 char *fullname;
12937 char **argv;
12695 struct strlist *sp; 12938 struct strlist *sp;
12696 volatile struct shparam saveparam; 12939 volatile struct shparam saveparam;
12697 12940
12698 for (sp = cmdenviron; sp; sp = sp->next) 12941 for (sp = cmdenviron; sp; sp = sp->next)
12699 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED); 12942 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
12700 12943
12701 if (!argv[1]) { 12944 nextopt(nullstr); /* handle possible "--" */
12945 argv = argptr;
12946
12947 if (!argv[0]) {
12702 /* bash says: "bash: .: filename argument required" */ 12948 /* bash says: "bash: .: filename argument required" */
12703 return 2; /* bash compat */ 12949 return 2; /* bash compat */
12704 } 12950 }
12705 12951
12706 /* "false; . empty_file; echo $?" should print 0, not 1: */
12707 exitstatus = 0;
12708
12709 /* This aborts if file isn't found, which is POSIXly correct. 12952 /* This aborts if file isn't found, which is POSIXly correct.
12710 * bash returns exitcode 1 instead. 12953 * bash returns exitcode 1 instead.
12711 */ 12954 */
12712 fullname = find_dot_file(argv[1]); 12955 fullname = find_dot_file(argv[0]);
12713 argv += 2; 12956 argv++;
12714 argc -= 2; 12957 if (argv[0]) { /* . FILE ARGS, ARGS exist */
12715 if (argc) { /* argc > 0, argv[0] != NULL */ 12958 int argc;
12716 saveparam = shellparam; 12959 saveparam = shellparam;
12717 shellparam.malloced = 0; 12960 shellparam.malloced = 0;
12961 argc = 1;
12962 while (argv[argc])
12963 argc++;
12718 shellparam.nparam = argc; 12964 shellparam.nparam = argc;
12719 shellparam.p = argv; 12965 shellparam.p = argv;
12720 }; 12966 };
@@ -12724,15 +12970,15 @@ dotcmd(int argc, char **argv)
12724 */ 12970 */
12725 setinputfile(fullname, INPUT_PUSH_FILE); 12971 setinputfile(fullname, INPUT_PUSH_FILE);
12726 commandname = fullname; 12972 commandname = fullname;
12727 cmdloop(0); 12973 status = cmdloop(0);
12728 popfile(); 12974 popfile();
12729 12975
12730 if (argc) { 12976 if (argv[0]) {
12731 freeparam(&shellparam); 12977 freeparam(&shellparam);
12732 shellparam = saveparam; 12978 shellparam = saveparam;
12733 }; 12979 };
12734 12980
12735 return exitstatus; 12981 return status;
12736} 12982}
12737 12983
12738static int FAST_FUNC 12984static int FAST_FUNC
@@ -12994,8 +13240,6 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12994} 13240}
12995 13241
12996 13242
12997/* ============ trap.c */
12998
12999/* 13243/*
13000 * The trap builtin. 13244 * The trap builtin.
13001 */ 13245 */
@@ -13101,7 +13345,7 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13101 } 13345 }
13102 } 13346 }
13103# endif 13347# endif
13104 out1fmt("\n\n"); 13348 newline_and_flush(stdout);
13105 return EXIT_SUCCESS; 13349 return EXIT_SUCCESS;
13106} 13350}
13107#endif 13351#endif
@@ -13421,15 +13665,10 @@ exitshell(void)
13421#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 13665#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13422 save_history(line_input_state); 13666 save_history(line_input_state);
13423#endif 13667#endif
13424
13425 status = exitstatus; 13668 status = exitstatus;
13426 TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); 13669 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13427 if (setjmp(loc.loc)) { 13670 if (setjmp(loc.loc)) {
13428 if (exception_type == EXEXIT) 13671 if (exception_type == EXEXIT)
13429/* dash bug: it just does _exit(exitstatus) here
13430 * but we have to do setjobctl(0) first!
13431 * (bug is still not fixed in dash-0.5.3 - if you run dash
13432 * under Midnight Commander, on exit from dash MC is backgrounded) */
13433 status = exitstatus; 13672 status = exitstatus;
13434 goto out; 13673 goto out;
13435 } 13674 }
@@ -13437,11 +13676,15 @@ exitshell(void)
13437 p = trap[0]; 13676 p = trap[0];
13438 if (p) { 13677 if (p) {
13439 trap[0] = NULL; 13678 trap[0] = NULL;
13679 evalskip = 0;
13440 evalstring(p, 0); 13680 evalstring(p, 0);
13441 free(p); 13681 /*free(p); - we'll exit soon */
13442 } 13682 }
13443 flush_stdout_stderr(); 13683 flush_stdout_stderr();
13444 out: 13684 out:
13685 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13686 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13687 */
13445 setjobctl(0); 13688 setjobctl(0);
13446 _exit(status); 13689 _exit(status);
13447 /* NOTREACHED */ 13690 /* NOTREACHED */
@@ -13454,18 +13697,15 @@ init(int xp)
13454init(void) 13697init(void)
13455#endif 13698#endif
13456{ 13699{
13457 /* from input.c: */
13458 /* we will never free this */ 13700 /* we will never free this */
13459 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); 13701 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
13460 13702
13461 /* from trap.c: */
13462 signal(SIGCHLD, SIG_DFL); 13703 signal(SIGCHLD, SIG_DFL);
13463 /* bash re-enables SIGHUP which is SIG_IGNed on entry. 13704 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13464 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" 13705 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13465 */ 13706 */
13466 signal(SIGHUP, SIG_DFL); 13707 signal(SIGHUP, SIG_DFL);
13467 13708
13468 /* from var.c: */
13469 { 13709 {
13470 char **envp; 13710 char **envp;
13471 const char *p; 13711 const char *p;
@@ -13553,11 +13793,14 @@ init(void)
13553 } 13793 }
13554#endif 13794#endif
13555 for (envp = environ; envp && *envp; envp++) { 13795 for (envp = environ; envp && *envp; envp++) {
13556 if (strchr(*envp, '=')) { 13796 p = endofname(*envp);
13797 if (p != *envp && *p == '=') {
13557 setvareq(*envp, VEXPORT|VTEXTFIXED); 13798 setvareq(*envp, VEXPORT|VTEXTFIXED);
13558 } 13799 }
13559 } 13800 }
13560 13801
13802 setvareq((char*)defoptindvar, VTEXTFIXED);
13803
13561 setvar0("PPID", utoa(getppid())); 13804 setvar0("PPID", utoa(getppid()));
13562#if ENABLE_ASH_BASH_COMPAT 13805#if ENABLE_ASH_BASH_COMPAT
13563 p = lookupvar("SHLVL"); 13806 p = lookupvar("SHLVL");
@@ -13570,10 +13813,10 @@ init(void)
13570#endif 13813#endif
13571 p = lookupvar("PWD"); 13814 p = lookupvar("PWD");
13572 if (p) { 13815 if (p) {
13573 if (*p != '/' || stat(p, &st1) || stat(".", &st2) 13816 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
13574 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino 13817 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13575 ) { 13818 ) {
13576 p = '\0'; 13819 p = NULL;
13577 } 13820 }
13578 } 13821 }
13579 setpwd(p, 0); 13822 setpwd(p, 0);
@@ -13664,14 +13907,10 @@ procargs(char **argv)
13664static void 13907static void
13665read_profile(const char *name) 13908read_profile(const char *name)
13666{ 13909{
13667 int skip;
13668
13669 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0) 13910 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13670 return; 13911 return;
13671 skip = cmdloop(0); 13912 cmdloop(0);
13672 popfile(); 13913 popfile();
13673 if (skip)
13674 exitshell();
13675} 13914}
13676 13915
13677/* 13916/*