diff options
author | Ron Yorston <rmy@pobox.com> | 2016-10-26 10:32:18 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2016-10-26 10:32:18 +0100 |
commit | 94eac583b29d56a28bf18d41f56ecb2a9d0bd336 (patch) | |
tree | ff7f398db61a851d5e0af51a92004207707acfab | |
parent | 418f43bea899493bb70a6eec6429b3de412be6e7 (diff) | |
parent | a513bf3c3ce0756c991b21c0ca271e24fedcdb51 (diff) | |
download | busybox-w32-94eac583b29d56a28bf18d41f56ecb2a9d0bd336.tar.gz busybox-w32-94eac583b29d56a28bf18d41f56ecb2a9d0bd336.tar.bz2 busybox-w32-94eac583b29d56a28bf18d41f56ecb2a9d0bd336.zip |
Merge branch 'busybox' into merge
-rw-r--r-- | editors/awk.c | 2 | ||||
-rw-r--r-- | libbb/lineedit.c | 2 | ||||
-rw-r--r-- | miscutils/strings.c | 32 | ||||
-rw-r--r-- | networking/udhcp/common.c | 11 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.c | 4 | ||||
-rw-r--r-- | shell/ash.c | 178 | ||||
-rw-r--r-- | shell/hush.c | 2 | ||||
-rwxr-xr-x | testsuite/awk.tests | 3 |
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 | ||
26 | int strings_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 30 | int strings_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
27 | int strings_main(int argc UNUSED_PARAM, char **argv) | 31 | int 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 | }; |
1477 | extern struct globals_memstack *const ash_ptr_to_globals_memstack; | 1474 | extern 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 * | |||
1677 | growstackstr(void) | 1672 | growstackstr(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; | |||
2030 | struct globals_var { | 2021 | struct 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; | |||
2100 | static void FAST_FUNC | 2089 | static void FAST_FUNC |
2101 | getoptsreset(const char *value) | 2090 | getoptsreset(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 | }; |
5577 | struct redirtab { | 5561 | struct 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) | |||
5827 | static void | 5806 | static void |
5828 | clearredir(int drop) | 5807 | clearredir(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 | ||
5838 | static int | 5813 | static 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); | |||
6236 | static void FAST_FUNC | 6222 | static void FAST_FUNC |
6237 | evalbackcmd(union node *n, struct backcmd *result) | 6223 | evalbackcmd(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) | |||
7737 | static void | 7726 | static void |
7738 | expandhere(union node *arg, int fd) | 7727 | expandhere(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 | */ |
8852 | static void | 8840 | static void |
8853 | defun(char *name, union node *func) | 8841 | defun(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: { | |||
12178 | parsesub: { | 12163 | parsesub: { |
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 * | |||
12746 | expandstr(const char *ps) | 12730 | expandstr(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 | ||
319 | testing "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 | ||
321 | exit $FAILCOUNT | 324 | exit $FAILCOUNT |