aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2016-10-26 10:32:18 +0100
committerRon Yorston <rmy@pobox.com>2016-10-26 10:32:18 +0100
commit94eac583b29d56a28bf18d41f56ecb2a9d0bd336 (patch)
treeff7f398db61a851d5e0af51a92004207707acfab
parent418f43bea899493bb70a6eec6429b3de412be6e7 (diff)
parenta513bf3c3ce0756c991b21c0ca271e24fedcdb51 (diff)
downloadbusybox-w32-94eac583b29d56a28bf18d41f56ecb2a9d0bd336.tar.gz
busybox-w32-94eac583b29d56a28bf18d41f56ecb2a9d0bd336.tar.bz2
busybox-w32-94eac583b29d56a28bf18d41f56ecb2a9d0bd336.zip
Merge branch 'busybox' into merge
-rw-r--r--editors/awk.c2
-rw-r--r--libbb/lineedit.c2
-rw-r--r--miscutils/strings.c32
-rw-r--r--networking/udhcp/common.c11
-rw-r--r--networking/udhcp/dhcpc.c4
-rw-r--r--shell/ash.c178
-rw-r--r--shell/hush.c2
-rwxr-xr-xtestsuite/awk.tests3
8 files changed, 124 insertions, 110 deletions
diff --git a/editors/awk.c b/editors/awk.c
index de3362cff..84ba125cd 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -1518,7 +1518,7 @@ static void chain_group(void)
1518 next_token(TC_SEQSTART); 1518 next_token(TC_SEQSTART);
1519 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM); 1519 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
1520 if (t_tclass & TC_SEQTERM) { /* for-in */ 1520 if (t_tclass & TC_SEQTERM) { /* for-in */
1521 if ((n2->info & OPCLSMASK) != OC_IN) 1521 if (!n2 || (n2->info & OPCLSMASK) != OC_IN)
1522 syntax_error(EMSG_UNEXP_TOKEN); 1522 syntax_error(EMSG_UNEXP_TOKEN);
1523 n = chain_node(OC_WALKINIT | VV); 1523 n = chain_node(OC_WALKINIT | VV);
1524 n->l.n = n2->l.n; 1524 n->l.n = n2->l.n;
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 34eb16e6b..06f708b62 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -840,7 +840,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
840 pf_len = strlen(pfind); 840 pf_len = strlen(pfind);
841 841
842#if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1 842#if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1
843 if (type == FIND_EXE_ONLY && dirbuf == NULL) { 843 if (type == FIND_EXE_ONLY && !dirbuf) {
844 const char *p = applet_names; 844 const char *p = applet_names;
845 845
846 while (*p) { 846 while (*p) {
diff --git a/miscutils/strings.c b/miscutils/strings.c
index 9f5018244..ee6649625 100644
--- a/miscutils/strings.c
+++ b/miscutils/strings.c
@@ -8,13 +8,16 @@
8 */ 8 */
9 9
10//usage:#define strings_trivial_usage 10//usage:#define strings_trivial_usage
11//usage: "[-afo] [-n LEN] [FILE]..." 11//usage: "[-fo] [-t o/d/x] [-n LEN] [FILE]..."
12//usage:#define strings_full_usage "\n\n" 12//usage:#define strings_full_usage "\n\n"
13//usage: "Display printable strings in a binary file\n" 13//usage: "Display printable strings in a binary file\n"
14//usage: "\n -a Scan whole file (default)" 14//We usually don't bother user with "nop" options. They work, but are not shown:
15//usage: "\n -f Precede strings with filenames" 15////usage: "\n -a Scan whole file (default)"
16//usage: "\n -n LEN At least LEN characters form a string (default 4)" 16//unimplemented alternative is -d: Only strings from initialized, loaded data sections
17//usage: "\n -o Precede strings with decimal offsets" 17//usage: "\n -f Precede strings with filenames"
18//usage: "\n -o Precede strings with octal offsets"
19//usage: "\n -t o/d/x Precede strings with offsets in base 8/10/16"
20//usage: "\n -n LEN At least LEN characters form a string (default 4)"
18 21
19#include "libbb.h" 22#include "libbb.h"
20 23
@@ -22,6 +25,7 @@
22#define PRINT_NAME 2 25#define PRINT_NAME 2
23#define PRINT_OFFSET 4 26#define PRINT_OFFSET 4
24#define SIZE 8 27#define SIZE 8
28#define PRINT_RADIX 16
25 29
26int strings_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 30int strings_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
27int strings_main(int argc UNUSED_PARAM, char **argv) 31int strings_main(int argc UNUSED_PARAM, char **argv)
@@ -33,8 +37,11 @@ int strings_main(int argc UNUSED_PARAM, char **argv)
33 char *string; 37 char *string;
34 const char *fmt = "%s: "; 38 const char *fmt = "%s: ";
35 const char *n_arg = "4"; 39 const char *n_arg = "4";
40 /* default for -o */
41 const char *radix = "o";
42 char *radix_fmt;
36 43
37 getopt32(argv, "afon:", &n_arg); 44 getopt32(argv, "afon:t:", &n_arg, &radix);
38 /* -a is our default behaviour */ 45 /* -a is our default behaviour */
39 /*argc -= optind;*/ 46 /*argc -= optind;*/
40 argv += optind; 47 argv += optind;
@@ -43,6 +50,11 @@ int strings_main(int argc UNUSED_PARAM, char **argv)
43 string = xzalloc(n + 1); 50 string = xzalloc(n + 1);
44 n--; 51 n--;
45 52
53 if ((radix[0] != 'd' && radix[0] != 'o' && radix[0] != 'x') || radix[1] != 0)
54 bb_show_usage();
55
56 radix_fmt = xasprintf("%%7"OFF_FMT"%s ", radix);
57
46 if (!*argv) { 58 if (!*argv) {
47 fmt = "{%s}: "; 59 fmt = "{%s}: ";
48 *--argv = (char *)bb_msg_standard_input; 60 *--argv = (char *)bb_msg_standard_input;
@@ -67,8 +79,8 @@ int strings_main(int argc UNUSED_PARAM, char **argv)
67 if (option_mask32 & PRINT_NAME) { 79 if (option_mask32 & PRINT_NAME) {
68 printf(fmt, *argv); 80 printf(fmt, *argv);
69 } 81 }
70 if (option_mask32 & PRINT_OFFSET) { 82 if (option_mask32 & (PRINT_OFFSET | PRINT_RADIX)) {
71 printf("%7"OFF_FMT"o ", offset - n); 83 printf(radix_fmt, offset - n);
72 } 84 }
73 fputs(string, stdout); 85 fputs(string, stdout);
74 } 86 }
@@ -85,8 +97,10 @@ int strings_main(int argc UNUSED_PARAM, char **argv)
85 fclose_if_not_stdin(file); 97 fclose_if_not_stdin(file);
86 } while (*++argv); 98 } while (*++argv);
87 99
88 if (ENABLE_FEATURE_CLEAN_UP) 100 if (ENABLE_FEATURE_CLEAN_UP) {
89 free(string); 101 free(string);
102 free(radix_fmt);
103 }
90 104
91 fflush_stdout_and_exit(status); 105 fflush_stdout_and_exit(status);
92} 106}
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index 0cf4dab63..1aaf5255c 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -226,9 +226,12 @@ uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code)
226 rem = sizeof(packet->options); 226 rem = sizeof(packet->options);
227 while (1) { 227 while (1) {
228 if (rem <= 0) { 228 if (rem <= 0) {
229 complain:
229 bb_error_msg("bad packet, malformed option field"); 230 bb_error_msg("bad packet, malformed option field");
230 return NULL; 231 return NULL;
231 } 232 }
233
234 /* DHCP_PADDING and DHCP_END have no [len] byte */
232 if (optionptr[OPT_CODE] == DHCP_PADDING) { 235 if (optionptr[OPT_CODE] == DHCP_PADDING) {
233 rem--; 236 rem--;
234 optionptr++; 237 optionptr++;
@@ -251,10 +254,13 @@ uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code)
251 } 254 }
252 break; 255 break;
253 } 256 }
257
258 if (rem <= OPT_LEN)
259 goto complain; /* complain and return NULL */
254 len = 2 + optionptr[OPT_LEN]; 260 len = 2 + optionptr[OPT_LEN];
255 rem -= len; 261 rem -= len;
256 if (rem < 0) 262 if (rem < 0)
257 continue; /* complain and return NULL */ 263 goto complain; /* complain and return NULL */
258 264
259 if (optionptr[OPT_CODE] == code) { 265 if (optionptr[OPT_CODE] == code) {
260 log_option("option found", optionptr); 266 log_option("option found", optionptr);
@@ -262,7 +268,8 @@ uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code)
262 } 268 }
263 269
264 if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) { 270 if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
265 overload |= optionptr[OPT_DATA]; 271 if (len >= 3)
272 overload |= optionptr[OPT_DATA];
266 /* fall through */ 273 /* fall through */
267 } 274 }
268 optionptr += len; 275 optionptr += len;
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index bef73277a..1c1051107 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -450,7 +450,7 @@ static char **fill_envp(struct dhcp_packet *packet)
450 temp = udhcp_get_option(packet, i); 450 temp = udhcp_get_option(packet, i);
451 if (temp) { 451 if (temp) {
452 if (i == DHCP_OPTION_OVERLOAD) 452 if (i == DHCP_OPTION_OVERLOAD)
453 overload = *temp; 453 overload |= *temp;
454 else if (i == DHCP_SUBNET) 454 else if (i == DHCP_SUBNET)
455 envc++; /* for $mask */ 455 envc++; /* for $mask */
456 envc++; 456 envc++;
@@ -476,7 +476,7 @@ static char **fill_envp(struct dhcp_packet *packet)
476 * uint16_t secs; // elapsed since client began acquisition/renewal 476 * uint16_t secs; // elapsed since client began acquisition/renewal
477 * uint16_t flags; // only one flag so far: bcast. Never set by server 477 * uint16_t flags; // only one flag so far: bcast. Never set by server
478 * uint32_t ciaddr; // client IP (usually == yiaddr. can it be different 478 * uint32_t ciaddr; // client IP (usually == yiaddr. can it be different
479 * // if during renew server wants to give us differn IP?) 479 * // if during renew server wants to give us different IP?)
480 * uint32_t gateway_nip; // relay agent IP address 480 * uint32_t gateway_nip; // relay agent IP address
481 * uint8_t chaddr[16]; // link-layer client hardware address (MAC) 481 * uint8_t chaddr[16]; // link-layer client hardware address (MAC)
482 * TODO: export gateway_nip as $giaddr? 482 * TODO: export gateway_nip as $giaddr?
diff --git a/shell/ash.c b/shell/ash.c
index 1485a35c9..a7b65ffc7 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -367,8 +367,6 @@ struct globals_misc {
367 /* exceptions */ 367 /* exceptions */
368#define EXINT 0 /* SIGINT received */ 368#define EXINT 0 /* SIGINT received */
369#define EXERROR 1 /* a generic error */ 369#define EXERROR 1 /* a generic error */
370#define EXSHELLPROC 2 /* execute a shell procedure */
371#define EXEXEC 3 /* command execution failed */
372#define EXEXIT 4 /* exit the shell */ 370#define EXEXIT 4 /* exit the shell */
373#define EXSIG 5 /* trapped signal in wait(1) */ 371#define EXSIG 5 /* trapped signal in wait(1) */
374 372
@@ -1471,7 +1469,6 @@ struct globals_memstack {
1471 char *g_stacknxt; // = stackbase.space; 1469 char *g_stacknxt; // = stackbase.space;
1472 char *sstrend; // = stackbase.space + MINSIZE; 1470 char *sstrend; // = stackbase.space + MINSIZE;
1473 size_t g_stacknleft; // = MINSIZE; 1471 size_t g_stacknleft; // = MINSIZE;
1474 int herefd; // = -1;
1475 struct stack_block stackbase; 1472 struct stack_block stackbase;
1476}; 1473};
1477extern struct globals_memstack *const ash_ptr_to_globals_memstack; 1474extern struct globals_memstack *const ash_ptr_to_globals_memstack;
@@ -1480,7 +1477,6 @@ extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1480#define g_stacknxt (G_memstack.g_stacknxt ) 1477#define g_stacknxt (G_memstack.g_stacknxt )
1481#define sstrend (G_memstack.sstrend ) 1478#define sstrend (G_memstack.sstrend )
1482#define g_stacknleft (G_memstack.g_stacknleft) 1479#define g_stacknleft (G_memstack.g_stacknleft)
1483#define herefd (G_memstack.herefd )
1484#define stackbase (G_memstack.stackbase ) 1480#define stackbase (G_memstack.stackbase )
1485#define INIT_G_memstack() do { \ 1481#define INIT_G_memstack() do { \
1486 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \ 1482 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
@@ -1489,7 +1485,6 @@ extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1489 g_stacknxt = stackbase.space; \ 1485 g_stacknxt = stackbase.space; \
1490 g_stacknleft = MINSIZE; \ 1486 g_stacknleft = MINSIZE; \
1491 sstrend = stackbase.space + MINSIZE; \ 1487 sstrend = stackbase.space + MINSIZE; \
1492 herefd = -1; \
1493} while (0) 1488} while (0)
1494 1489
1495 1490
@@ -1677,10 +1672,6 @@ static void *
1677growstackstr(void) 1672growstackstr(void)
1678{ 1673{
1679 size_t len = stackblocksize(); 1674 size_t len = stackblocksize();
1680 if (herefd >= 0 && len >= 1024) {
1681 full_write(herefd, stackblock(), len);
1682 return stackblock();
1683 }
1684 growstackblock(); 1675 growstackblock();
1685 return (char *)stackblock() + len; 1676 return (char *)stackblock() + len;
1686} 1677}
@@ -2030,7 +2021,6 @@ struct redirtab;
2030struct globals_var { 2021struct globals_var {
2031 struct shparam shellparam; /* $@ current positional parameters */ 2022 struct shparam shellparam; /* $@ current positional parameters */
2032 struct redirtab *redirlist; 2023 struct redirtab *redirlist;
2033 int g_nullredirs;
2034 int preverrout_fd; /* save fd2 before print debug if xflag is set. */ 2024 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
2035 struct var *vartab[VTABSIZE]; 2025 struct var *vartab[VTABSIZE];
2036 struct var varinit[ARRAY_SIZE(varinit_data)]; 2026 struct var varinit[ARRAY_SIZE(varinit_data)];
@@ -2039,7 +2029,6 @@ extern struct globals_var *const ash_ptr_to_globals_var;
2039#define G_var (*ash_ptr_to_globals_var) 2029#define G_var (*ash_ptr_to_globals_var)
2040#define shellparam (G_var.shellparam ) 2030#define shellparam (G_var.shellparam )
2041//#define redirlist (G_var.redirlist ) 2031//#define redirlist (G_var.redirlist )
2042#define g_nullredirs (G_var.g_nullredirs )
2043#define preverrout_fd (G_var.preverrout_fd) 2032#define preverrout_fd (G_var.preverrout_fd)
2044#define vartab (G_var.vartab ) 2033#define vartab (G_var.vartab )
2045#define varinit (G_var.varinit ) 2034#define varinit (G_var.varinit )
@@ -2100,7 +2089,7 @@ extern struct globals_var *const ash_ptr_to_globals_var;
2100static void FAST_FUNC 2089static void FAST_FUNC
2101getoptsreset(const char *value) 2090getoptsreset(const char *value)
2102{ 2091{
2103 shellparam.optind = number(value); 2092 shellparam.optind = number(value) ?: 1;
2104 shellparam.optoff = -1; 2093 shellparam.optoff = -1;
2105} 2094}
2106#endif 2095#endif
@@ -4963,8 +4952,7 @@ commandtext(union node *n)
4963 STARTSTACKSTR(cmdnextc); 4952 STARTSTACKSTR(cmdnextc);
4964 cmdtxt(n); 4953 cmdtxt(n);
4965 name = stackblock(); 4954 name = stackblock();
4966 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n", 4955 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
4967 name, cmdnextc, cmdnextc));
4968 return ckstrdup(name); 4956 return ckstrdup(name);
4969} 4957}
4970#endif /* JOBS */ 4958#endif /* JOBS */
@@ -5539,9 +5527,7 @@ openredirect(union node *redir)
5539} 5527}
5540 5528
5541/* 5529/*
5542 * Copy a file descriptor to be >= to. Returns -1 5530 * Copy a file descriptor to be >= to. Throws exception on error.
5543 * if the source file descriptor is closed, EMPTY if there are no unused
5544 * file descriptors left.
5545 */ 5531 */
5546/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD). 5532/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5547 * old code was doing close(to) prior to copyfd() to achieve the same */ 5533 * old code was doing close(to) prior to copyfd() to achieve the same */
@@ -5562,8 +5548,6 @@ copyfd(int from, int to)
5562 newfd = fcntl(from, F_DUPFD, to); 5548 newfd = fcntl(from, F_DUPFD, to);
5563 } 5549 }
5564 if (newfd < 0) { 5550 if (newfd < 0) {
5565 if (errno == EMFILE)
5566 return EMPTY;
5567 /* Happens when source fd is not open: try "echo >&99" */ 5551 /* Happens when source fd is not open: try "echo >&99" */
5568 ash_msg_and_raise_error("%d: %m", from); 5552 ash_msg_and_raise_error("%d: %m", from);
5569 } 5553 }
@@ -5576,7 +5560,6 @@ struct two_fd_t {
5576}; 5560};
5577struct redirtab { 5561struct redirtab {
5578 struct redirtab *next; 5562 struct redirtab *next;
5579 int nullredirs;
5580 int pair_count; 5563 int pair_count;
5581 struct two_fd_t two_fd[]; 5564 struct two_fd_t two_fd[];
5582}; 5565};
@@ -5655,7 +5638,6 @@ redirect(union node *redir, int flags)
5655 int newfd; 5638 int newfd;
5656 int copied_fd2 = -1; 5639 int copied_fd2 = -1;
5657 5640
5658 g_nullredirs++;
5659 if (!redir) { 5641 if (!redir) {
5660 return; 5642 return;
5661 } 5643 }
@@ -5677,8 +5659,6 @@ redirect(union node *redir, int flags)
5677 sv->next = redirlist; 5659 sv->next = redirlist;
5678 sv->pair_count = sv_pos; 5660 sv->pair_count = sv_pos;
5679 redirlist = sv; 5661 redirlist = sv;
5680 sv->nullredirs = g_nullredirs - 1;
5681 g_nullredirs = 0;
5682 while (sv_pos > 0) { 5662 while (sv_pos > 0) {
5683 sv_pos--; 5663 sv_pos--;
5684 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY; 5664 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
@@ -5790,7 +5770,7 @@ popredir(int drop, int restore)
5790 struct redirtab *rp; 5770 struct redirtab *rp;
5791 int i; 5771 int i;
5792 5772
5793 if (--g_nullredirs >= 0 || redirlist == NULL) 5773 if (redirlist == NULL)
5794 return; 5774 return;
5795 INT_OFF; 5775 INT_OFF;
5796 rp = redirlist; 5776 rp = redirlist;
@@ -5812,7 +5792,6 @@ popredir(int drop, int restore)
5812 } 5792 }
5813 } 5793 }
5814 redirlist = rp->next; 5794 redirlist = rp->next;
5815 g_nullredirs = rp->nullredirs;
5816 free(rp); 5795 free(rp);
5817 INT_ON; 5796 INT_ON;
5818} 5797}
@@ -5827,12 +5806,8 @@ popredir(int drop, int restore)
5827static void 5806static void
5828clearredir(int drop) 5807clearredir(int drop)
5829{ 5808{
5830 for (;;) { 5809 while (redirlist)
5831 g_nullredirs = 0;
5832 if (!redirlist)
5833 break;
5834 popredir(drop, /*restore:*/ 0); 5810 popredir(drop, /*restore:*/ 0);
5835 }
5836} 5811}
5837 5812
5838static int 5813static int
@@ -5891,6 +5866,17 @@ ash_arith(const char *s)
5891#define EXP_TILDE 0x2 /* do normal tilde expansion */ 5866#define EXP_TILDE 0x2 /* do normal tilde expansion */
5892#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ 5867#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5893#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ 5868#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5869/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5870 * POSIX says for this case:
5871 * Pathname expansion shall not be performed on the word by a
5872 * non-interactive shell; an interactive shell may perform it, but shall
5873 * do so only when the expansion would result in one word.
5874 * Currently, our code complies to the above rule by never globbing
5875 * redirection filenames.
5876 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5877 * (this means that on a typical Linux distro, bash almost always
5878 * performs globbing, and thus diverges from what we do).
5879 */
5894#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ 5880#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5895#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */ 5881#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
5896#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ 5882#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
@@ -6236,52 +6222,54 @@ static int evaltree(union node *, int);
6236static void FAST_FUNC 6222static void FAST_FUNC
6237evalbackcmd(union node *n, struct backcmd *result) 6223evalbackcmd(union node *n, struct backcmd *result)
6238{ 6224{
6239 int saveherefd; 6225 int pip[2];
6226 struct job *jp;
6240 6227
6241 result->fd = -1; 6228 result->fd = -1;
6242 result->buf = NULL; 6229 result->buf = NULL;
6243 result->nleft = 0; 6230 result->nleft = 0;
6244 IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs))); 6231 IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs)));
6245 result->jp = NULL; 6232 result->jp = NULL;
6246 if (n == NULL) 6233 if (n == NULL) {
6247 goto out; 6234 goto out;
6235 }
6248 6236
6249 saveherefd = herefd; 6237 if (pipe(pip) < 0)
6250 herefd = -1; 6238 ash_msg_and_raise_error("pipe call failed");
6251 6239 jp = makejob(/*n,*/ 1);
6252 {
6253 int pip[2];
6254 struct job *jp;
6255
6256 if (pipe(pip) < 0)
6257 ash_msg_and_raise_error("pipe call failed");
6258 jp = makejob(/*n,*/ 1);
6259#if ENABLE_PLATFORM_MINGW32 6240#if ENABLE_PLATFORM_MINGW32
6260 result->fs.fpid = FS_EVALBACKCMD; 6241 result->fs.fpid = FS_EVALBACKCMD;
6261 result->fs.n = n; 6242 result->fs.n = n;
6262 result->fs.fd[0] = pip[0]; 6243 result->fs.fd[0] = pip[0];
6263 result->fs.fd[1] = pip[1]; 6244 result->fs.fd[1] = pip[1];
6264 if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0) 6245 if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0)
6265 ash_msg_and_raise_error("unable to spawn shell"); 6246 ash_msg_and_raise_error("unable to spawn shell");
6266#else 6247#else
6267 if (forkshell(jp, n, FORK_NOJOB) == 0) { 6248 if (forkshell(jp, n, FORK_NOJOB) == 0) {
6268 FORCE_INT_ON; 6249 FORCE_INT_ON;
6269 close(pip[0]); 6250 close(pip[0]);
6270 if (pip[1] != 1) { 6251 if (pip[1] != 1) {
6271 /*close(1);*/ 6252 /*close(1);*/
6272 copyfd(pip[1], 1 | COPYFD_EXACT); 6253 copyfd(pip[1], 1 | COPYFD_EXACT);
6273 close(pip[1]); 6254 close(pip[1]);
6274 }
6275 eflag = 0;
6276 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6277 /* NOTREACHED */
6278 } 6255 }
6279#endif 6256/* TODO: eflag clearing makes the following not abort:
6280 close(pip[1]); 6257 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6281 result->fd = pip[0]; 6258 * which is what bash does (unless it is in POSIX mode).
6282 result->jp = jp; 6259 * dash deleted "eflag = 0" line in the commit
6260 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6261 * [EVAL] Don't clear eflag in evalbackcmd
6262 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6263 */
6264 eflag = 0;
6265 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6266 /* NOTREACHED */
6283 } 6267 }
6284 herefd = saveherefd; 6268#endif
6269 close(pip[1]);
6270 result->fd = pip[0];
6271 result->jp = jp;
6272
6285 out: 6273 out:
6286 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 6274 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6287 result->fd, result->buf, result->nleft, result->jp)); 6275 result->fd, result->buf, result->nleft, result->jp));
@@ -6689,7 +6677,6 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6689 char *str; 6677 char *str;
6690 IF_ASH_BASH_COMPAT(char *repl = NULL;) 6678 IF_ASH_BASH_COMPAT(char *repl = NULL;)
6691 IF_ASH_BASH_COMPAT(int pos, len, orig_len;) 6679 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
6692 int saveherefd = herefd;
6693 int amount, resetloc; 6680 int amount, resetloc;
6694 IF_ASH_BASH_COMPAT(int workloc;) 6681 IF_ASH_BASH_COMPAT(int workloc;)
6695 int zero; 6682 int zero;
@@ -6698,12 +6685,10 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6698 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)", 6685 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6699 // p, varname, strloc, subtype, startloc, varflags, quotes); 6686 // p, varname, strloc, subtype, startloc, varflags, quotes);
6700 6687
6701 herefd = -1;
6702 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? 6688 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
6703 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0), 6689 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6704 var_str_list); 6690 var_str_list);
6705 STPUTC('\0', expdest); 6691 STPUTC('\0', expdest);
6706 herefd = saveherefd;
6707 argbackq = saveargbackq; 6692 argbackq = saveargbackq;
6708 startp = (char *)stackblock() + startloc; 6693 startp = (char *)stackblock() + startloc;
6709 6694
@@ -7125,6 +7110,10 @@ evalvar(char *p, int flag, struct strlist *var_str_list)
7125 7110
7126 varflags = (unsigned char) *p++; 7111 varflags = (unsigned char) *p++;
7127 subtype = varflags & VSTYPE; 7112 subtype = varflags & VSTYPE;
7113
7114 if (!subtype)
7115 raise_error_syntax("bad substitution");
7116
7128 quoted = flag & EXP_QUOTED; 7117 quoted = flag & EXP_QUOTED;
7129 var = p; 7118 var = p;
7130 easy = (!quoted || (*var == '@' && shellparam.nparam)); 7119 easy = (!quoted || (*var == '@' && shellparam.nparam));
@@ -7737,7 +7726,6 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
7737static void 7726static void
7738expandhere(union node *arg, int fd) 7727expandhere(union node *arg, int fd)
7739{ 7728{
7740 herefd = fd;
7741 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED); 7729 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
7742 full_write(fd, stackblock(), expdest - (char *)stackblock()); 7730 full_write(fd, stackblock(), expdest - (char *)stackblock());
7743} 7731}
@@ -7970,7 +7958,7 @@ shellexec(char **argv, const char *path, int idx)
7970 exitstatus = exerrno; 7958 exitstatus = exerrno;
7971 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n", 7959 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7972 argv[0], e, suppress_int)); 7960 argv[0], e, suppress_int));
7973 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found")); 7961 ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found"));
7974 /* NOTREACHED */ 7962 /* NOTREACHED */
7975} 7963}
7976 7964
@@ -8850,14 +8838,14 @@ copyfunc(union node *n)
8850 * Define a shell function. 8838 * Define a shell function.
8851 */ 8839 */
8852static void 8840static void
8853defun(char *name, union node *func) 8841defun(union node *func)
8854{ 8842{
8855 struct cmdentry entry; 8843 struct cmdentry entry;
8856 8844
8857 INT_OFF; 8845 INT_OFF;
8858 entry.cmdtype = CMDFUNCTION; 8846 entry.cmdtype = CMDFUNCTION;
8859 entry.u.func = copyfunc(func); 8847 entry.u.func = copyfunc(func);
8860 addcmdentry(name, &entry); 8848 addcmdentry(func->narg.text, &entry);
8861 INT_ON; 8849 INT_ON;
8862} 8850}
8863 8851
@@ -8991,7 +8979,8 @@ evaltree(union node *n, int flags)
8991 if (!status) { 8979 if (!status) {
8992 status = evaltree(n->nredir.n, flags & EV_TESTED); 8980 status = evaltree(n->nredir.n, flags & EV_TESTED);
8993 } 8981 }
8994 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */); 8982 if (n->nredir.redirect)
8983 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
8995 goto setstatus; 8984 goto setstatus;
8996 case NCMD: 8985 case NCMD:
8997 evalfn = evalcommand; 8986 evalfn = evalcommand;
@@ -9007,11 +8996,9 @@ evaltree(union node *n, int flags)
9007 evalfn = evalloop; 8996 evalfn = evalloop;
9008 goto calleval; 8997 goto calleval;
9009 case NSUBSHELL: 8998 case NSUBSHELL:
9010 evalfn = evalsubshell;
9011 goto checkexit;
9012 case NBACKGND: 8999 case NBACKGND:
9013 evalfn = evalsubshell; 9000 evalfn = evalsubshell;
9014 goto calleval; 9001 goto checkexit;
9015 case NPIPE: 9002 case NPIPE:
9016 evalfn = evalpipe; 9003 evalfn = evalpipe;
9017 goto checkexit; 9004 goto checkexit;
@@ -9057,7 +9044,7 @@ evaltree(union node *n, int flags)
9057 status = 0; 9044 status = 0;
9058 goto setstatus; 9045 goto setstatus;
9059 case NDEFUN: 9046 case NDEFUN:
9060 defun(n->narg.text, n->narg.next); 9047 defun(n);
9061 /* Not necessary. To test it: 9048 /* Not necessary. To test it:
9062 * "false; f() { qwerty; }; echo $?" should print 0. 9049 * "false; f() { qwerty; }; echo $?" should print 0.
9063 */ 9050 */
@@ -9506,7 +9493,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
9506 shellparam.optind = 1; 9493 shellparam.optind = 1;
9507 shellparam.optoff = -1; 9494 shellparam.optoff = -1;
9508#endif 9495#endif
9509 evaltree(&func->n, flags & EV_TESTED); 9496 evaltree(func->n.narg.next, flags & EV_TESTED);
9510 funcdone: 9497 funcdone:
9511 INT_OFF; 9498 INT_OFF;
9512 funcnest--; 9499 funcnest--;
@@ -10084,7 +10071,7 @@ evalcommand(union node *cmd, int flags)
10084 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) { 10071 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
10085 int exit_status; 10072 int exit_status;
10086 int i = exception_type; 10073 int i = exception_type;
10087 if (i == EXEXIT || i == EXEXEC) 10074 if (i == EXEXIT)
10088 goto raise; 10075 goto raise;
10089 exit_status = 2; 10076 exit_status = 2;
10090 if (i == EXINT) 10077 if (i == EXINT)
@@ -10112,7 +10099,8 @@ evalcommand(union node *cmd, int flags)
10112 } /* switch */ 10099 } /* switch */
10113 10100
10114 out: 10101 out:
10115 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec); 10102 if (cmd->ncmd.redirect)
10103 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
10116 if (lastarg) { 10104 if (lastarg) {
10117 /* dsl: I think this is intended to be used to support 10105 /* dsl: I think this is intended to be used to support
10118 * '_' in 'vi' command mode during line editing... 10106 * '_' in 'vi' command mode during line editing...
@@ -10685,13 +10673,12 @@ setinputfile(const char *fname, int flags)
10685 if (fd < 0) { 10673 if (fd < 0) {
10686 if (flags & INPUT_NOFILE_OK) 10674 if (flags & INPUT_NOFILE_OK)
10687 goto out; 10675 goto out;
10676 exitstatus = 127;
10688 ash_msg_and_raise_error("can't open '%s'", fname); 10677 ash_msg_and_raise_error("can't open '%s'", fname);
10689 } 10678 }
10690 if (fd < 10) { 10679 if (fd < 10) {
10691 fd2 = copyfd(fd, 10); 10680 fd2 = copyfd(fd, 10);
10692 close(fd); 10681 close(fd);
10693 if (fd2 < 0)
10694 ash_msg_and_raise_error("out of file descriptors");
10695 fd = fd2; 10682 fd = fd2;
10696 } 10683 }
10697 setinputfd(fd, flags & INPUT_PUSH_FILE); 10684 setinputfd(fd, flags & INPUT_PUSH_FILE);
@@ -11046,8 +11033,6 @@ getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *opt
11046 11033
11047 sbuf[1] = '\0'; 11034 sbuf[1] = '\0';
11048 11035
11049 if (*param_optind < 1)
11050 return 1;
11051 optnext = optfirst + *param_optind - 1; 11036 optnext = optfirst + *param_optind - 1;
11052 11037
11053 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff) 11038 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
@@ -12178,7 +12163,7 @@ parseredir: {
12178parsesub: { 12163parsesub: {
12179 unsigned char subtype; 12164 unsigned char subtype;
12180 int typeloc; 12165 int typeloc;
12181 int flags; 12166 int flags = 0;
12182 12167
12183 c = pgetc_eatbnl(); 12168 c = pgetc_eatbnl();
12184 if (c > 255 /* PEOA or PEOF */ 12169 if (c > 255 /* PEOA or PEOF */
@@ -12238,15 +12223,13 @@ parsesub: {
12238 USTPUTC(c, out); 12223 USTPUTC(c, out);
12239 c = pgetc_eatbnl(); 12224 c = pgetc_eatbnl();
12240 } else { 12225 } else {
12241 badsub: 12226 goto badsub;
12242 raise_error_syntax("bad substitution");
12243 } 12227 }
12244 if (c != '}' && subtype == VSLENGTH) { 12228 if (c != '}' && subtype == VSLENGTH) {
12245 /* ${#VAR didn't end with } */ 12229 /* ${#VAR didn't end with } */
12246 goto badsub; 12230 goto badsub;
12247 } 12231 }
12248 12232
12249 STPUTC('=', out);
12250 flags = 0; 12233 flags = 0;
12251 if (subtype == 0) { 12234 if (subtype == 0) {
12252 static const char types[] ALIGN1 = "}-+?="; 12235 static const char types[] ALIGN1 = "}-+?=";
@@ -12263,7 +12246,7 @@ parsesub: {
12263 if (!strchr(types, c)) { 12246 if (!strchr(types, c)) {
12264 subtype = VSSUBSTR; 12247 subtype = VSSUBSTR;
12265 pungetc(); 12248 pungetc();
12266 break; /* "goto do_pungetc" is bigger (!) */ 12249 break; /* "goto badsub" is bigger (!) */
12267 } 12250 }
12268#endif 12251#endif
12269 flags = VSNUL; 12252 flags = VSNUL;
@@ -12271,7 +12254,7 @@ parsesub: {
12271 default: { 12254 default: {
12272 const char *p = strchr(types, c); 12255 const char *p = strchr(types, c);
12273 if (p == NULL) 12256 if (p == NULL)
12274 goto badsub; 12257 break;
12275 subtype = p - types + VSNORMAL; 12258 subtype = p - types + VSNORMAL;
12276 break; 12259 break;
12277 } 12260 }
@@ -12281,7 +12264,7 @@ parsesub: {
12281 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT); 12264 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
12282 c = pgetc_eatbnl(); 12265 c = pgetc_eatbnl();
12283 if (c != cc) 12266 if (c != cc)
12284 goto do_pungetc; 12267 goto badsub;
12285 subtype++; 12268 subtype++;
12286 break; 12269 break;
12287 } 12270 }
@@ -12293,13 +12276,13 @@ parsesub: {
12293 subtype = VSREPLACE; 12276 subtype = VSREPLACE;
12294 c = pgetc_eatbnl(); 12277 c = pgetc_eatbnl();
12295 if (c != '/') 12278 if (c != '/')
12296 goto do_pungetc; 12279 goto badsub;
12297 subtype++; /* VSREPLACEALL */ 12280 subtype++; /* VSREPLACEALL */
12298 break; 12281 break;
12299#endif 12282#endif
12300 } 12283 }
12301 } else { 12284 } else {
12302 do_pungetc: 12285 badsub:
12303 pungetc(); 12286 pungetc();
12304 } 12287 }
12305 ((unsigned char *)stackblock())[typeloc] = subtype | flags; 12288 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
@@ -12309,6 +12292,7 @@ parsesub: {
12309 dqvarnest++; 12292 dqvarnest++;
12310 } 12293 }
12311 } 12294 }
12295 STPUTC('=', out);
12312 } 12296 }
12313 goto parsesub_return; 12297 goto parsesub_return;
12314} 12298}
@@ -12746,11 +12730,17 @@ static const char *
12746expandstr(const char *ps) 12730expandstr(const char *ps)
12747{ 12731{
12748 union node n; 12732 union node n;
12733 int saveprompt;
12749 12734
12750 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value, 12735 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12751 * and token processing _can_ alter it (delete NULs etc). */ 12736 * and token processing _can_ alter it (delete NULs etc). */
12752 setinputstring((char *)ps); 12737 setinputstring((char *)ps);
12738
12739 saveprompt = doprompt;
12740 doprompt = 0;
12753 readtoken1(pgetc(), PSSYNTAX, nullstr, 0); 12741 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
12742 doprompt = saveprompt;
12743
12754 popfile(); 12744 popfile();
12755 12745
12756 n.narg.type = NARG; 12746 n.narg.type = NARG;
@@ -13680,12 +13670,12 @@ exitshell(void)
13680 evalstring(p, 0); 13670 evalstring(p, 0);
13681 /*free(p); - we'll exit soon */ 13671 /*free(p); - we'll exit soon */
13682 } 13672 }
13683 flush_stdout_stderr();
13684 out: 13673 out:
13685 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". 13674 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13686 * our setjobctl(0) does not panic if tcsetpgrp fails inside it. 13675 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13687 */ 13676 */
13688 setjobctl(0); 13677 setjobctl(0);
13678 flush_stdout_stderr();
13689 _exit(status); 13679 _exit(status);
13690 /* NOTREACHED */ 13680 /* NOTREACHED */
13691} 13681}
@@ -13978,8 +13968,6 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13978 reset(); 13968 reset();
13979 13969
13980 e = exception_type; 13970 e = exception_type;
13981 if (e == EXERROR)
13982 exitstatus = 2;
13983 s = state; 13971 s = state;
13984 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) { 13972 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
13985 exitshell(); 13973 exitshell();
diff --git a/shell/hush.c b/shell/hush.c
index 9b51f389e..d7a0d761e 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -8409,7 +8409,9 @@ int hush_main(int argc, char **argv)
8409 G.global_argc--; 8409 G.global_argc--;
8410 G.global_argv++; 8410 G.global_argv++;
8411 debug_printf("running script '%s'\n", G.global_argv[0]); 8411 debug_printf("running script '%s'\n", G.global_argv[0]);
8412 xfunc_error_retval = 127; /* for "hush /does/not/exist" case */
8412 input = xfopen_for_read(G.global_argv[0]); 8413 input = xfopen_for_read(G.global_argv[0]);
8414 xfunc_error_retval = 1;
8413 remember_FILE(input); 8415 remember_FILE(input);
8414 install_special_sighandlers(); 8416 install_special_sighandlers();
8415 parse_and_run_file(input); 8417 parse_and_run_file(input);
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index adab4ae1e..82937bc10 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -316,6 +316,9 @@ testing "awk continue" \
316 "" \ 316 "" \
317 'BEGIN { if (1) continue; else a = 1 }' 317 'BEGIN { if (1) continue; else a = 1 }'
318 318
319testing "awk handles invalid for loop" \
320 "awk '{ for() }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
321
319# testing "description" "command" "result" "infile" "stdin" 322# testing "description" "command" "result" "infile" "stdin"
320 323
321exit $FAILCOUNT 324exit $FAILCOUNT