aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c1139
1 files changed, 754 insertions, 385 deletions
diff --git a/shell/hush.c b/shell/hush.c
index eabe83ac6..9b51f389e 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -103,6 +103,9 @@
103#else 103#else
104# define CLEAR_RANDOM_T(rnd) ((void)0) 104# define CLEAR_RANDOM_T(rnd) ((void)0)
105#endif 105#endif
106#ifndef F_DUPFD_CLOEXEC
107# define F_DUPFD_CLOEXEC F_DUPFD
108#endif
106#ifndef PIPE_BUF 109#ifndef PIPE_BUF
107# define PIPE_BUF 4096 /* amount of buffering in a pipe */ 110# define PIPE_BUF 4096 /* amount of buffering in a pipe */
108#endif 111#endif
@@ -459,19 +462,17 @@ static const char *const assignment_flag[] = {
459 462
460typedef struct in_str { 463typedef struct in_str {
461 const char *p; 464 const char *p;
462 /* eof_flag=1: last char in ->p is really an EOF */
463 char eof_flag; /* meaningless if ->p == NULL */
464 char peek_buf[2];
465#if ENABLE_HUSH_INTERACTIVE 465#if ENABLE_HUSH_INTERACTIVE
466 smallint promptmode; /* 0: PS1, 1: PS2 */ 466 smallint promptmode; /* 0: PS1, 1: PS2 */
467#endif 467#endif
468 int peek_buf[2];
468 int last_char; 469 int last_char;
469 FILE *file; 470 FILE *file;
470 int (*get) (struct in_str *) FAST_FUNC; 471 int (*get) (struct in_str *) FAST_FUNC;
471 int (*peek) (struct in_str *) FAST_FUNC; 472 int (*peek) (struct in_str *) FAST_FUNC;
472} in_str; 473} in_str;
473#define i_getch(input) ((input)->get(input)) 474#define i_getch(input) ((input)->get(input))
474#define i_peek(input) ((input)->peek(input)) 475#define i_peek(input) ((input)->peek(input))
475 476
476/* The descrip member of this structure is only used to make 477/* The descrip member of this structure is only used to make
477 * debugging output pretty */ 478 * debugging output pretty */
@@ -711,6 +712,13 @@ enum {
711}; 712};
712 713
713 714
715struct FILE_list {
716 struct FILE_list *next;
717 FILE *fp;
718 int fd;
719};
720
721
714/* "Globals" within this file */ 722/* "Globals" within this file */
715/* Sorted roughly by size (smaller offsets == smaller code) */ 723/* Sorted roughly by size (smaller offsets == smaller code) */
716struct globals { 724struct globals {
@@ -769,6 +777,9 @@ struct globals {
769 * 1: return is invoked, skip all till end of func 777 * 1: return is invoked, skip all till end of func
770 */ 778 */
771 smallint flag_return_in_progress; 779 smallint flag_return_in_progress;
780# define G_flag_return_in_progress (G.flag_return_in_progress)
781#else
782# define G_flag_return_in_progress 0
772#endif 783#endif
773 smallint exiting; /* used to prevent EXIT trap recursion */ 784 smallint exiting; /* used to prevent EXIT trap recursion */
774 /* These four support $?, $#, and $1 */ 785 /* These four support $?, $#, and $1 */
@@ -802,6 +813,7 @@ struct globals {
802 unsigned handled_SIGCHLD; 813 unsigned handled_SIGCHLD;
803 smallint we_have_children; 814 smallint we_have_children;
804#endif 815#endif
816 struct FILE_list *FILE_list;
805 /* Which signals have non-DFL handler (even with no traps set)? 817 /* Which signals have non-DFL handler (even with no traps set)?
806 * Set at the start to: 818 * Set at the start to:
807 * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS) 819 * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS)
@@ -823,7 +835,9 @@ struct globals {
823 int debug_indent; 835 int debug_indent;
824#endif 836#endif
825 struct sigaction sa; 837 struct sigaction sa;
826 char user_input_buf[ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 2]; 838#if ENABLE_FEATURE_EDITING
839 char user_input_buf[CONFIG_FEATURE_EDITING_MAX_LEN];
840#endif
827}; 841};
828#define G (*ptr_to_globals) 842#define G (*ptr_to_globals)
829/* Not #defining name to G.name - this quickly gets unwieldy 843/* Not #defining name to G.name - this quickly gets unwieldy
@@ -1252,6 +1266,91 @@ static void free_strings(char **strings)
1252} 1266}
1253 1267
1254 1268
1269static int xdup_and_close(int fd, int F_DUPFD_maybe_CLOEXEC)
1270{
1271 /* We avoid taking stdio fds. Mimicking ash: use fds above 9 */
1272 int newfd = fcntl(fd, F_DUPFD_maybe_CLOEXEC, 10);
1273 if (newfd < 0) {
1274 /* fd was not open? */
1275 if (errno == EBADF)
1276 return fd;
1277 xfunc_die();
1278 }
1279 close(fd);
1280 return newfd;
1281}
1282
1283
1284/* Manipulating the list of open FILEs */
1285static FILE *remember_FILE(FILE *fp)
1286{
1287 if (fp) {
1288 struct FILE_list *n = xmalloc(sizeof(*n));
1289 n->next = G.FILE_list;
1290 G.FILE_list = n;
1291 n->fp = fp;
1292 n->fd = fileno(fp);
1293 close_on_exec_on(n->fd);
1294 }
1295 return fp;
1296}
1297static void fclose_and_forget(FILE *fp)
1298{
1299 struct FILE_list **pp = &G.FILE_list;
1300 while (*pp) {
1301 struct FILE_list *cur = *pp;
1302 if (cur->fp == fp) {
1303 *pp = cur->next;
1304 free(cur);
1305 break;
1306 }
1307 pp = &cur->next;
1308 }
1309 fclose(fp);
1310}
1311static int save_FILEs_on_redirect(int fd)
1312{
1313 struct FILE_list *fl = G.FILE_list;
1314 while (fl) {
1315 if (fd == fl->fd) {
1316 /* We use it only on script files, they are all CLOEXEC */
1317 fl->fd = xdup_and_close(fd, F_DUPFD_CLOEXEC);
1318 return 1;
1319 }
1320 fl = fl->next;
1321 }
1322 return 0;
1323}
1324static void restore_redirected_FILEs(void)
1325{
1326 struct FILE_list *fl = G.FILE_list;
1327 while (fl) {
1328 int should_be = fileno(fl->fp);
1329 if (fl->fd != should_be) {
1330 xmove_fd(fl->fd, should_be);
1331 fl->fd = should_be;
1332 }
1333 fl = fl->next;
1334 }
1335}
1336#if ENABLE_FEATURE_SH_STANDALONE
1337static void close_all_FILE_list(void)
1338{
1339 struct FILE_list *fl = G.FILE_list;
1340 while (fl) {
1341 /* fclose would also free FILE object.
1342 * It is disastrous if we share memory with a vforked parent.
1343 * I'm not sure we never come here after vfork.
1344 * Therefore just close fd, nothing more.
1345 */
1346 /*fclose(fl->fp); - unsafe */
1347 close(fl->fd);
1348 fl = fl->next;
1349 }
1350}
1351#endif
1352
1353
1255/* Helpers for setting new $n and restoring them back 1354/* Helpers for setting new $n and restoring them back
1256 */ 1355 */
1257typedef struct save_arg_t { 1356typedef struct save_arg_t {
@@ -1477,19 +1576,50 @@ static sighandler_t install_sighandler(int sig, sighandler_t handler)
1477 return old_sa.sa_handler; 1576 return old_sa.sa_handler;
1478} 1577}
1479 1578
1579static void hush_exit(int exitcode) NORETURN;
1580static void fflush_and__exit(void) NORETURN;
1581static void restore_ttypgrp_and__exit(void) NORETURN;
1582
1583static void restore_ttypgrp_and__exit(void)
1584{
1585 /* xfunc has failed! die die die */
1586 /* no EXIT traps, this is an escape hatch! */
1587 G.exiting = 1;
1588 hush_exit(xfunc_error_retval);
1589}
1590
1591/* Needed only on some libc:
1592 * It was observed that on exit(), fgetc'ed buffered data
1593 * gets "unwound" via lseek(fd, -NUM, SEEK_CUR).
1594 * With the net effect that even after fork(), not vfork(),
1595 * exit() in NOEXECed applet in "sh SCRIPT":
1596 * noexec_applet_here
1597 * echo END_OF_SCRIPT
1598 * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT".
1599 * This makes "echo END_OF_SCRIPT" executed twice.
1600 * Similar problems can be seen with die_if_script() -> xfunc_die()
1601 * and in `cmd` handling.
1602 * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit():
1603 */
1604static void fflush_and__exit(void)
1605{
1606 fflush_all();
1607 _exit(xfunc_error_retval);
1608}
1609
1480#if ENABLE_HUSH_JOB 1610#if ENABLE_HUSH_JOB
1481 1611
1482static void xfunc_has_died(void);
1483/* After [v]fork, in child: do not restore tty pgrp on xfunc death */ 1612/* After [v]fork, in child: do not restore tty pgrp on xfunc death */
1484# define disable_restore_tty_pgrp_on_exit() (die_func = NULL) 1613# define disable_restore_tty_pgrp_on_exit() (die_func = fflush_and__exit)
1485/* After [v]fork, in parent: restore tty pgrp on xfunc death */ 1614/* After [v]fork, in parent: restore tty pgrp on xfunc death */
1486# define enable_restore_tty_pgrp_on_exit() (die_func = xfunc_has_died) 1615# define enable_restore_tty_pgrp_on_exit() (die_func = restore_ttypgrp_and__exit)
1487 1616
1488/* Restores tty foreground process group, and exits. 1617/* Restores tty foreground process group, and exits.
1489 * May be called as signal handler for fatal signal 1618 * May be called as signal handler for fatal signal
1490 * (will resend signal to itself, producing correct exit state) 1619 * (will resend signal to itself, producing correct exit state)
1491 * or called directly with -EXITCODE. 1620 * or called directly with -EXITCODE.
1492 * We also call it if xfunc is exiting. */ 1621 * We also call it if xfunc is exiting.
1622 */
1493static void sigexit(int sig) NORETURN; 1623static void sigexit(int sig) NORETURN;
1494static void sigexit(int sig) 1624static void sigexit(int sig)
1495{ 1625{
@@ -1544,7 +1674,6 @@ static sighandler_t pick_sighandler(unsigned sig)
1544} 1674}
1545 1675
1546/* Restores tty foreground process group, and exits. */ 1676/* Restores tty foreground process group, and exits. */
1547static void hush_exit(int exitcode) NORETURN;
1548static void hush_exit(int exitcode) 1677static void hush_exit(int exitcode)
1549{ 1678{
1550#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 1679#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
@@ -1580,23 +1709,14 @@ static void hush_exit(int exitcode)
1580 } 1709 }
1581#endif 1710#endif
1582 1711
1583#if ENABLE_HUSH_JOB
1584 fflush_all(); 1712 fflush_all();
1713#if ENABLE_HUSH_JOB
1585 sigexit(- (exitcode & 0xff)); 1714 sigexit(- (exitcode & 0xff));
1586#else 1715#else
1587 exit(exitcode); 1716 _exit(exitcode);
1588#endif 1717#endif
1589} 1718}
1590 1719
1591static void xfunc_has_died(void) NORETURN;
1592static void xfunc_has_died(void)
1593{
1594 /* xfunc has failed! die die die */
1595 /* no EXIT traps, this is an escape hatch! */
1596 G.exiting = 1;
1597 hush_exit(xfunc_error_retval);
1598}
1599
1600 1720
1601//TODO: return a mask of ALL handled sigs? 1721//TODO: return a mask of ALL handled sigs?
1602static int check_and_run_traps(void) 1722static int check_and_run_traps(void)
@@ -1619,6 +1739,7 @@ static int check_and_run_traps(void)
1619 break; 1739 break;
1620 got_sig: 1740 got_sig:
1621 if (G.traps && G.traps[sig]) { 1741 if (G.traps && G.traps[sig]) {
1742 debug_printf_exec("%s: sig:%d handler:'%s'\n", __func__, sig, G.traps[sig]);
1622 if (G.traps[sig][0]) { 1743 if (G.traps[sig][0]) {
1623 /* We have user-defined handler */ 1744 /* We have user-defined handler */
1624 smalluint save_rcode; 1745 smalluint save_rcode;
@@ -1636,6 +1757,7 @@ static int check_and_run_traps(void)
1636 /* not a trap: special action */ 1757 /* not a trap: special action */
1637 switch (sig) { 1758 switch (sig) {
1638 case SIGINT: 1759 case SIGINT:
1760 debug_printf_exec("%s: sig:%d default SIGINT handler\n", __func__, sig);
1639 /* Builtin was ^C'ed, make it look prettier: */ 1761 /* Builtin was ^C'ed, make it look prettier: */
1640 bb_putchar('\n'); 1762 bb_putchar('\n');
1641 G.flag_SIGINT = 1; 1763 G.flag_SIGINT = 1;
@@ -1644,6 +1766,7 @@ static int check_and_run_traps(void)
1644#if ENABLE_HUSH_JOB 1766#if ENABLE_HUSH_JOB
1645 case SIGHUP: { 1767 case SIGHUP: {
1646 struct pipe *job; 1768 struct pipe *job;
1769 debug_printf_exec("%s: sig:%d default SIGHUP handler\n", __func__, sig);
1647 /* bash is observed to signal whole process groups, 1770 /* bash is observed to signal whole process groups,
1648 * not individual processes */ 1771 * not individual processes */
1649 for (job = G.job_list; job; job = job->next) { 1772 for (job = G.job_list; job; job = job->next) {
@@ -1658,6 +1781,7 @@ static int check_and_run_traps(void)
1658#endif 1781#endif
1659#if ENABLE_HUSH_FAST 1782#if ENABLE_HUSH_FAST
1660 case SIGCHLD: 1783 case SIGCHLD:
1784 debug_printf_exec("%s: sig:%d default SIGCHLD handler\n", __func__, sig);
1661 G.count_SIGCHLD++; 1785 G.count_SIGCHLD++;
1662//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); 1786//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
1663 /* Note: 1787 /* Note:
@@ -1667,6 +1791,7 @@ static int check_and_run_traps(void)
1667 break; 1791 break;
1668#endif 1792#endif
1669 default: /* ignored: */ 1793 default: /* ignored: */
1794 debug_printf_exec("%s: sig:%d default handling is to ignore\n", __func__, sig);
1670 /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */ 1795 /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */
1671 /* Note: 1796 /* Note:
1672 * We dont do 'last_sig = sig' here -> NOT returning this sig. 1797 * We dont do 'last_sig = sig' here -> NOT returning this sig.
@@ -1766,6 +1891,7 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_
1766{ 1891{
1767 struct variable **var_pp; 1892 struct variable **var_pp;
1768 struct variable *cur; 1893 struct variable *cur;
1894 char *free_me = NULL;
1769 char *eq_sign; 1895 char *eq_sign;
1770 int name_len; 1896 int name_len;
1771 1897
@@ -1782,6 +1908,7 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_
1782 var_pp = &cur->next; 1908 var_pp = &cur->next;
1783 continue; 1909 continue;
1784 } 1910 }
1911
1785 /* We found an existing var with this name */ 1912 /* We found an existing var with this name */
1786 if (cur->flg_read_only) { 1913 if (cur->flg_read_only) {
1787#if !BB_MMU 1914#if !BB_MMU
@@ -1830,12 +1957,17 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_
1830 strcpy(cur->varstr, str); 1957 strcpy(cur->varstr, str);
1831 goto free_and_exp; 1958 goto free_and_exp;
1832 } 1959 }
1833 } else { 1960 /* Can't reuse */
1834 /* max_len == 0 signifies "malloced" var, which we can 1961 cur->max_len = 0;
1835 * (and has to) free */ 1962 goto set_str_and_exp;
1836 free(cur->varstr); 1963 }
1837 } 1964 /* max_len == 0 signifies "malloced" var, which we can
1838 cur->max_len = 0; 1965 * (and have to) free. But we can't free(cur->varstr) here:
1966 * if cur->flg_export is 1, it is in the environment.
1967 * We should either unsetenv+free, or wait until putenv,
1968 * then putenv(new)+free(old).
1969 */
1970 free_me = cur->varstr;
1839 goto set_str_and_exp; 1971 goto set_str_and_exp;
1840 } 1972 }
1841 1973
@@ -1862,10 +1994,15 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_
1862 cur->flg_export = 0; 1994 cur->flg_export = 0;
1863 /* unsetenv was already done */ 1995 /* unsetenv was already done */
1864 } else { 1996 } else {
1997 int i;
1865 debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr); 1998 debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr);
1866 return putenv(cur->varstr); 1999 i = putenv(cur->varstr);
2000 /* only now we can free old exported malloced string */
2001 free(free_me);
2002 return i;
1867 } 2003 }
1868 } 2004 }
2005 free(free_me);
1869 return 0; 2006 return 0;
1870} 2007}
1871 2008
@@ -2005,28 +2142,19 @@ static void reinit_unicode_for_hush(void)
2005 } 2142 }
2006} 2143}
2007 2144
2008
2009/* 2145/*
2010 * in_str support 2146 * in_str support (strings, and "strings" read from files).
2011 */ 2147 */
2012static int FAST_FUNC static_get(struct in_str *i)
2013{
2014 int ch = *i->p;
2015 if (ch != '\0') {
2016 i->p++;
2017 i->last_char = ch;
2018 return ch;
2019 }
2020 return EOF;
2021}
2022
2023static int FAST_FUNC static_peek(struct in_str *i)
2024{
2025 return *i->p;
2026}
2027 2148
2028#if ENABLE_HUSH_INTERACTIVE 2149#if ENABLE_HUSH_INTERACTIVE
2029 2150/* To test correct lineedit/interactive behavior, type from command line:
2151 * echo $P\
2152 * \
2153 * AT\
2154 * H\
2155 * \
2156 * It excercises a lot of corner cases.
2157 */
2030static void cmdedit_update_prompt(void) 2158static void cmdedit_update_prompt(void)
2031{ 2159{
2032 if (ENABLE_FEATURE_EDITING_FANCY_PROMPT) { 2160 if (ENABLE_FEATURE_EDITING_FANCY_PROMPT) {
@@ -2040,7 +2168,6 @@ static void cmdedit_update_prompt(void)
2040 if (G.PS2 == NULL) 2168 if (G.PS2 == NULL)
2041 G.PS2 = "> "; 2169 G.PS2 = "> ";
2042} 2170}
2043
2044static const char *setup_prompt_string(int promptmode) 2171static const char *setup_prompt_string(int promptmode)
2045{ 2172{
2046 const char *prompt_str; 2173 const char *prompt_str;
@@ -2058,33 +2185,36 @@ static const char *setup_prompt_string(int promptmode)
2058 prompt_str = G.PS2; 2185 prompt_str = G.PS2;
2059 } else 2186 } else
2060 prompt_str = (promptmode == 0) ? G.PS1 : G.PS2; 2187 prompt_str = (promptmode == 0) ? G.PS1 : G.PS2;
2061 debug_printf("result '%s'\n", prompt_str); 2188 debug_printf("prompt_str '%s'\n", prompt_str);
2062 return prompt_str; 2189 return prompt_str;
2063} 2190}
2064 2191static int get_user_input(struct in_str *i)
2065static void get_user_input(struct in_str *i)
2066{ 2192{
2067 int r; 2193 int r;
2068 const char *prompt_str; 2194 const char *prompt_str;
2069 2195
2070 prompt_str = setup_prompt_string(i->promptmode); 2196 prompt_str = setup_prompt_string(i->promptmode);
2071# if ENABLE_FEATURE_EDITING 2197# if ENABLE_FEATURE_EDITING
2072 /* Enable command line editing only while a command line
2073 * is actually being read */
2074 do { 2198 do {
2075 reinit_unicode_for_hush(); 2199 reinit_unicode_for_hush();
2076 G.flag_SIGINT = 0; 2200 G.flag_SIGINT = 0;
2077 /* buglet: SIGINT will not make new prompt to appear _at once_, 2201 /* buglet: SIGINT will not make new prompt to appear _at once_,
2078 * only after <Enter>. (^C will work) */ 2202 * only after <Enter>. (^C will work) */
2079 r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1); 2203 r = read_line_input(G.line_input_state, prompt_str,
2204 G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1,
2205 /*timeout*/ -1
2206 );
2080 /* catch *SIGINT* etc (^C is handled by read_line_input) */ 2207 /* catch *SIGINT* etc (^C is handled by read_line_input) */
2081 check_and_run_traps(); 2208 check_and_run_traps();
2082 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */ 2209 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */
2083 i->eof_flag = (r < 0); 2210 if (r < 0) {
2084 if (i->eof_flag) { /* EOF/error detected */ 2211 /* EOF/error detected */
2085 G.user_input_buf[0] = EOF; /* yes, it will be truncated, it's ok */ 2212 i->p = NULL;
2086 G.user_input_buf[1] = '\0'; 2213 i->peek_buf[0] = r = EOF;
2214 return r;
2087 } 2215 }
2216 i->p = G.user_input_buf;
2217 return (unsigned char)*i->p++;
2088# else 2218# else
2089 do { 2219 do {
2090 G.flag_SIGINT = 0; 2220 G.flag_SIGINT = 0;
@@ -2098,76 +2228,149 @@ static void get_user_input(struct in_str *i)
2098 fputs(prompt_str, stdout); 2228 fputs(prompt_str, stdout);
2099 } 2229 }
2100 fflush_all(); 2230 fflush_all();
2101 G.user_input_buf[0] = r = fgetc(i->file); 2231 r = fgetc(i->file);
2102 /*G.user_input_buf[1] = '\0'; - already is and never changed */ 2232 } while (G.flag_SIGINT || r == '\0');
2103 } while (G.flag_SIGINT); 2233 return r;
2104 i->eof_flag = (r == EOF);
2105# endif 2234# endif
2106 i->p = G.user_input_buf;
2107} 2235}
2108
2109#endif /* INTERACTIVE */
2110
2111/* This is the magic location that prints prompts 2236/* This is the magic location that prints prompts
2112 * and gets data back from the user */ 2237 * and gets data back from the user */
2238static int fgetc_interactive(struct in_str *i)
2239{
2240 int ch;
2241 /* If it's interactive stdin, get new line. */
2242 if (G_interactive_fd && i->file == stdin) {
2243 /* Returns first char (or EOF), the rest is in i->p[] */
2244 ch = get_user_input(i);
2245 i->promptmode = 1; /* PS2 */
2246 } else {
2247 /* Not stdin: script file, sourced file, etc */
2248 do ch = fgetc(i->file); while (ch == '\0');
2249 }
2250 return ch;
2251}
2252#else
2253static inline int fgetc_interactive(struct in_str *i)
2254{
2255 int ch;
2256 do ch = fgetc(i->file); while (ch == '\0');
2257 return ch;
2258}
2259#endif /* INTERACTIVE */
2260
2113static int FAST_FUNC file_get(struct in_str *i) 2261static int FAST_FUNC file_get(struct in_str *i)
2114{ 2262{
2115 int ch; 2263 int ch;
2116 2264
2117 /* If there is data waiting, eat it up */ 2265#if ENABLE_FEATURE_EDITING
2118 if (i->p && *i->p) { 2266 /* This can be stdin, check line editing char[] buffer */
2119#if ENABLE_HUSH_INTERACTIVE 2267 if (i->p && *i->p != '\0') {
2120 take_cached: 2268 ch = (unsigned char)*i->p++;
2121#endif 2269 goto out;
2122 ch = *i->p++; 2270 }
2123 if (i->eof_flag && !*i->p)
2124 ch = EOF;
2125 /* note: ch is never NUL */
2126 } else {
2127 /* need to double check i->file because we might be doing something
2128 * more complicated by now, like sourcing or substituting. */
2129#if ENABLE_HUSH_INTERACTIVE
2130 if (G_interactive_fd && i->file == stdin) {
2131 do {
2132 get_user_input(i);
2133 } while (!*i->p); /* need non-empty line */
2134 i->promptmode = 1; /* PS2 */
2135 goto take_cached;
2136 }
2137#endif 2271#endif
2138 do ch = fgetc(i->file); while (ch == '\0'); 2272 /* peek_buf[] is an int array, not char. Can contain EOF. */
2273 ch = i->peek_buf[0];
2274 if (ch != 0) {
2275 int ch2 = i->peek_buf[1];
2276 i->peek_buf[0] = ch2;
2277 if (ch2 == 0) /* very likely, avoid redundant write */
2278 goto out;
2279 i->peek_buf[1] = 0;
2280 goto out;
2139 } 2281 }
2282
2283 ch = fgetc_interactive(i);
2284 out:
2140 debug_printf("file_get: got '%c' %d\n", ch, ch); 2285 debug_printf("file_get: got '%c' %d\n", ch, ch);
2141 i->last_char = ch; 2286 i->last_char = ch;
2142 return ch; 2287 return ch;
2143} 2288}
2144 2289
2145/* All callers guarantee this routine will never
2146 * be used right after a newline, so prompting is not needed.
2147 */
2148static int FAST_FUNC file_peek(struct in_str *i) 2290static int FAST_FUNC file_peek(struct in_str *i)
2149{ 2291{
2150 int ch; 2292 int ch;
2151 if (i->p && *i->p) { 2293
2152 if (i->eof_flag && !i->p[1]) 2294#if ENABLE_FEATURE_EDITING && ENABLE_HUSH_INTERACTIVE
2153 return EOF; 2295 /* This can be stdin, check line editing char[] buffer */
2154 return *i->p; 2296 if (i->p && *i->p != '\0')
2155 /* note: ch is never NUL */ 2297 return (unsigned char)*i->p;
2298#endif
2299 /* peek_buf[] is an int array, not char. Can contain EOF. */
2300 ch = i->peek_buf[0];
2301 if (ch != 0)
2302 return ch;
2303
2304 /* Need to get a new char */
2305 ch = fgetc_interactive(i);
2306 debug_printf("file_peek: got '%c' %d\n", ch, ch);
2307
2308 /* Save it by either rolling back line editing buffer, or in i->peek_buf[0] */
2309#if ENABLE_FEATURE_EDITING && ENABLE_HUSH_INTERACTIVE
2310 if (i->p) {
2311 i->p -= 1;
2312 return ch;
2156 } 2313 }
2157 do ch = fgetc(i->file); while (ch == '\0'); 2314#endif
2158 i->eof_flag = (ch == EOF);
2159 i->peek_buf[0] = ch; 2315 i->peek_buf[0] = ch;
2160 i->peek_buf[1] = '\0'; 2316 /*i->peek_buf[1] = 0; - already is */
2161 i->p = i->peek_buf; 2317 return ch;
2162 debug_printf("file_peek: got '%c' %d\n", ch, ch); 2318}
2319
2320static int FAST_FUNC static_get(struct in_str *i)
2321{
2322 int ch = (unsigned char)*i->p;
2323 if (ch != '\0') {
2324 i->p++;
2325 i->last_char = ch;
2326 return ch;
2327 }
2328 return EOF;
2329}
2330
2331static int FAST_FUNC static_peek(struct in_str *i)
2332{
2333 /* Doesn't report EOF on NUL. None of the callers care. */
2334 return (unsigned char)*i->p;
2335}
2336
2337/* Only ever called if i_peek() was called, and did not return EOF.
2338 * IOW: we know the previous peek saw an ordinary char, not EOF, not NUL,
2339 * not end-of-line. Therefore we never need to read a new editing line here.
2340 */
2341static int i_peek2(struct in_str *i)
2342{
2343 int ch;
2344
2345 /* There are two cases when i->p[] buffer exists.
2346 * (1) it's a string in_str.
2347 * (2) It's a file, and we have a saved line editing buffer.
2348 * In both cases, we know that i->p[0] exists and not NUL, and
2349 * the peek2 result is in i->p[1].
2350 */
2351 if (i->p)
2352 return (unsigned char)i->p[1];
2353
2354 /* Now we know it is a file-based in_str. */
2355
2356 /* peek_buf[] is an int array, not char. Can contain EOF. */
2357 /* Is there 2nd char? */
2358 ch = i->peek_buf[1];
2359 if (ch == 0) {
2360 /* We did not read it yet, get it now */
2361 do ch = fgetc(i->file); while (ch == '\0');
2362 i->peek_buf[1] = ch;
2363 }
2364
2365 debug_printf("file_peek2: got '%c' %d\n", ch, ch);
2163 return ch; 2366 return ch;
2164} 2367}
2165 2368
2166static void setup_file_in_str(struct in_str *i, FILE *f) 2369static void setup_file_in_str(struct in_str *i, FILE *f)
2167{ 2370{
2168 memset(i, 0, sizeof(*i)); 2371 memset(i, 0, sizeof(*i));
2169 i->peek = file_peek;
2170 i->get = file_get; 2372 i->get = file_get;
2373 i->peek = file_peek;
2171 /* i->promptmode = 0; - PS1 (memset did it) */ 2374 /* i->promptmode = 0; - PS1 (memset did it) */
2172 i->file = f; 2375 i->file = f;
2173 /* i->p = NULL; */ 2376 /* i->p = NULL; */
@@ -2176,11 +2379,10 @@ static void setup_file_in_str(struct in_str *i, FILE *f)
2176static void setup_string_in_str(struct in_str *i, const char *s) 2379static void setup_string_in_str(struct in_str *i, const char *s)
2177{ 2380{
2178 memset(i, 0, sizeof(*i)); 2381 memset(i, 0, sizeof(*i));
2179 i->peek = static_peek;
2180 i->get = static_get; 2382 i->get = static_get;
2383 i->peek = static_peek;
2181 /* i->promptmode = 0; - PS1 (memset did it) */ 2384 /* i->promptmode = 0; - PS1 (memset did it) */
2182 i->p = s; 2385 i->p = s;
2183 /* i->eof_flag = 0; */
2184} 2386}
2185 2387
2186 2388
@@ -2211,7 +2413,7 @@ static ALWAYS_INLINE void o_free_unsafe(o_string *o)
2211static void o_grow_by(o_string *o, int len) 2413static void o_grow_by(o_string *o, int len)
2212{ 2414{
2213 if (o->length + len > o->maxlen) { 2415 if (o->length + len > o->maxlen) {
2214 o->maxlen += (2*len > B_CHUNK ? 2*len : B_CHUNK); 2416 o->maxlen += (2 * len) | (B_CHUNK-1);
2215 o->data = xrealloc(o->data, 1 + o->maxlen); 2417 o->data = xrealloc(o->data, 1 + o->maxlen);
2216 } 2418 }
2217} 2419}
@@ -2219,11 +2421,26 @@ static void o_grow_by(o_string *o, int len)
2219static void o_addchr(o_string *o, int ch) 2421static void o_addchr(o_string *o, int ch)
2220{ 2422{
2221 debug_printf("o_addchr: '%c' o->length=%d o=%p\n", ch, o->length, o); 2423 debug_printf("o_addchr: '%c' o->length=%d o=%p\n", ch, o->length, o);
2424 if (o->length < o->maxlen) {
2425 /* likely. avoid o_grow_by() call */
2426 add:
2427 o->data[o->length] = ch;
2428 o->length++;
2429 o->data[o->length] = '\0';
2430 return;
2431 }
2222 o_grow_by(o, 1); 2432 o_grow_by(o, 1);
2223 o->data[o->length] = ch; 2433 goto add;
2224 o->length++; 2434}
2435
2436#if 0
2437/* Valid only if we know o_string is not empty */
2438static void o_delchr(o_string *o)
2439{
2440 o->length--;
2225 o->data[o->length] = '\0'; 2441 o->data[o->length] = '\0';
2226} 2442}
2443#endif
2227 2444
2228static void o_addblock(o_string *o, const char *str, int len) 2445static void o_addblock(o_string *o, const char *str, int len)
2229{ 2446{
@@ -2937,6 +3154,14 @@ static int done_command(struct parse_context *ctx)
2937 struct pipe *pi = ctx->pipe; 3154 struct pipe *pi = ctx->pipe;
2938 struct command *command = ctx->command; 3155 struct command *command = ctx->command;
2939 3156
3157#if 0 /* Instead we emit error message at run time */
3158 if (ctx->pending_redirect) {
3159 /* For example, "cmd >" (no filename to redirect to) */
3160 die_if_script("syntax error: %s", "invalid redirect");
3161 ctx->pending_redirect = NULL;
3162 }
3163#endif
3164
2940 if (command) { 3165 if (command) {
2941 if (IS_NULL_CMD(command)) { 3166 if (IS_NULL_CMD(command)) {
2942 debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds); 3167 debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds);
@@ -3459,6 +3684,12 @@ static int parse_redirect(struct parse_context *ctx,
3459 debug_printf_parse("duplicating redirect '%d>&%d'\n", 3684 debug_printf_parse("duplicating redirect '%d>&%d'\n",
3460 redir->rd_fd, redir->rd_dup); 3685 redir->rd_fd, redir->rd_dup);
3461 } else { 3686 } else {
3687#if 0 /* Instead we emit error message at run time */
3688 if (ctx->pending_redirect) {
3689 /* For example, "cmd > <file" */
3690 die_if_script("syntax error: %s", "invalid redirect");
3691 }
3692#endif
3462 /* Set ctx->pending_redirect, so we know what to do at the 3693 /* Set ctx->pending_redirect, so we know what to do at the
3463 * end of the next parsed word. */ 3694 * end of the next parsed word. */
3464 ctx->pending_redirect = redir; 3695 ctx->pending_redirect = redir;
@@ -3724,6 +3955,39 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
3724 /* command remains "open", available for possible redirects */ 3955 /* command remains "open", available for possible redirects */
3725} 3956}
3726 3957
3958static int i_getch_and_eat_bkslash_nl(struct in_str *input)
3959{
3960 for (;;) {
3961 int ch, ch2;
3962
3963 ch = i_getch(input);
3964 if (ch != '\\')
3965 return ch;
3966 ch2 = i_peek(input);
3967 if (ch2 != '\n')
3968 return ch;
3969 /* backslash+newline, skip it */
3970 i_getch(input);
3971 }
3972}
3973
3974static int i_peek_and_eat_bkslash_nl(struct in_str *input)
3975{
3976 for (;;) {
3977 int ch, ch2;
3978
3979 ch = i_peek(input);
3980 if (ch != '\\')
3981 return ch;
3982 ch2 = i_peek2(input);
3983 if (ch2 != '\n')
3984 return ch;
3985 /* backslash+newline, skip it */
3986 i_getch(input);
3987 i_getch(input);
3988 }
3989}
3990
3727#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS 3991#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS
3728/* Subroutines for copying $(...) and `...` things */ 3992/* Subroutines for copying $(...) and `...` things */
3729static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); 3993static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote);
@@ -3841,7 +4105,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
3841 if (!dbl) 4105 if (!dbl)
3842 break; 4106 break;
3843 /* we look for closing )) of $((EXPR)) */ 4107 /* we look for closing )) of $((EXPR)) */
3844 if (i_peek(input) == end_ch) { 4108 if (i_peek_and_eat_bkslash_nl(input) == end_ch) {
3845 i_getch(input); /* eat second ')' */ 4109 i_getch(input); /* eat second ')' */
3846 break; 4110 break;
3847 } 4111 }
@@ -3879,6 +4143,13 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
3879 syntax_error_unterm_ch(')'); 4143 syntax_error_unterm_ch(')');
3880 return 0; 4144 return 0;
3881 } 4145 }
4146#if 0
4147 if (ch == '\n') {
4148 /* "backslash+newline", ignore both */
4149 o_delchr(dest); /* undo insertion of '\' */
4150 continue;
4151 }
4152#endif
3882 o_addchr(dest, ch); 4153 o_addchr(dest, ch);
3883 continue; 4154 continue;
3884 } 4155 }
@@ -3897,7 +4168,7 @@ static int parse_dollar(o_string *as_string,
3897 o_string *dest, 4168 o_string *dest,
3898 struct in_str *input, unsigned char quote_mask) 4169 struct in_str *input, unsigned char quote_mask)
3899{ 4170{
3900 int ch = i_peek(input); /* first character after the $ */ 4171 int ch = i_peek_and_eat_bkslash_nl(input); /* first character after the $ */
3901 4172
3902 debug_printf_parse("parse_dollar entered: ch='%c'\n", ch); 4173 debug_printf_parse("parse_dollar entered: ch='%c'\n", ch);
3903 if (isalpha(ch)) { 4174 if (isalpha(ch)) {
@@ -3909,9 +4180,11 @@ static int parse_dollar(o_string *as_string,
3909 debug_printf_parse(": '%c'\n", ch); 4180 debug_printf_parse(": '%c'\n", ch);
3910 o_addchr(dest, ch | quote_mask); 4181 o_addchr(dest, ch | quote_mask);
3911 quote_mask = 0; 4182 quote_mask = 0;
3912 ch = i_peek(input); 4183 ch = i_peek_and_eat_bkslash_nl(input);
3913 if (!isalnum(ch) && ch != '_') 4184 if (!isalnum(ch) && ch != '_') {
4185 /* End of variable name reached */
3914 break; 4186 break;
4187 }
3915 ch = i_getch(input); 4188 ch = i_getch(input);
3916 nommu_addchr(as_string, ch); 4189 nommu_addchr(as_string, ch);
3917 } 4190 }
@@ -3938,7 +4211,7 @@ static int parse_dollar(o_string *as_string,
3938 ch = i_getch(input); /* eat '{' */ 4211 ch = i_getch(input); /* eat '{' */
3939 nommu_addchr(as_string, ch); 4212 nommu_addchr(as_string, ch);
3940 4213
3941 ch = i_getch(input); /* first char after '{' */ 4214 ch = i_getch_and_eat_bkslash_nl(input); /* first char after '{' */
3942 /* It should be ${?}, or ${#var}, 4215 /* It should be ${?}, or ${#var},
3943 * or even ${?+subst} - operator acting on a special variable, 4216 * or even ${?+subst} - operator acting on a special variable,
3944 * or the beginning of variable name. 4217 * or the beginning of variable name.
@@ -4044,7 +4317,7 @@ static int parse_dollar(o_string *as_string,
4044 ch = i_getch(input); 4317 ch = i_getch(input);
4045 nommu_addchr(as_string, ch); 4318 nommu_addchr(as_string, ch);
4046# if ENABLE_SH_MATH_SUPPORT 4319# if ENABLE_SH_MATH_SUPPORT
4047 if (i_peek(input) == '(') { 4320 if (i_peek_and_eat_bkslash_nl(input) == '(') {
4048 ch = i_getch(input); 4321 ch = i_getch(input);
4049 nommu_addchr(as_string, ch); 4322 nommu_addchr(as_string, ch);
4050 o_addchr(dest, SPECIAL_VAR_SYMBOL); 4323 o_addchr(dest, SPECIAL_VAR_SYMBOL);
@@ -4081,7 +4354,7 @@ static int parse_dollar(o_string *as_string,
4081 case '_': 4354 case '_':
4082 ch = i_getch(input); 4355 ch = i_getch(input);
4083 nommu_addchr(as_string, ch); 4356 nommu_addchr(as_string, ch);
4084 ch = i_peek(input); 4357 ch = i_peek_and_eat_bkslash_nl(input);
4085 if (isalnum(ch)) { /* it's $_name or $_123 */ 4358 if (isalnum(ch)) { /* it's $_name or $_123 */
4086 ch = '_'; 4359 ch = '_';
4087 goto make_var; 4360 goto make_var;
@@ -5548,7 +5821,7 @@ static char* expand_strvec_to_string(char **argv)
5548 n++; 5821 n++;
5549 } 5822 }
5550 } 5823 }
5551 overlapping_strcpy((char*)list, list[0]); 5824 overlapping_strcpy((char*)list, list[0] ? list[0] : "");
5552 debug_printf_expand("strvec_to_string='%s'\n", (char*)list); 5825 debug_printf_expand("strvec_to_string='%s'\n", (char*)list);
5553 return (char*)list; 5826 return (char*)list;
5554} 5827}
@@ -5825,10 +6098,8 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger)
5825 debug_printf_exec("parse_and_run_stream: run_and_free_list\n"); 6098 debug_printf_exec("parse_and_run_stream: run_and_free_list\n");
5826 run_and_free_list(pipe_list); 6099 run_and_free_list(pipe_list);
5827 empty = 0; 6100 empty = 0;
5828#if ENABLE_HUSH_FUNCTIONS 6101 if (G_flag_return_in_progress == 1)
5829 if (G.flag_return_in_progress == 1)
5830 break; 6102 break;
5831#endif
5832 } 6103 }
5833} 6104}
5834 6105
@@ -5913,7 +6184,8 @@ static FILE *generate_stream_from_string(const char *s, pid_t *pid_p)
5913 ) { 6184 ) {
5914 static const char *const argv[] = { NULL, NULL }; 6185 static const char *const argv[] = { NULL, NULL };
5915 builtin_trap((char**)argv); 6186 builtin_trap((char**)argv);
5916 exit(0); /* not _exit() - we need to fflush */ 6187 fflush_all(); /* important */
6188 _exit(0);
5917 } 6189 }
5918# if BB_MMU 6190# if BB_MMU
5919 reset_traps_to_defaults(); 6191 reset_traps_to_defaults();
@@ -5946,8 +6218,7 @@ static FILE *generate_stream_from_string(const char *s, pid_t *pid_p)
5946 free(to_free); 6218 free(to_free);
5947# endif 6219# endif
5948 close(channel[1]); 6220 close(channel[1]);
5949 close_on_exec_on(channel[0]); 6221 return remember_FILE(xfdopen_for_read(channel[0]));
5950 return xfdopen_for_read(channel[0]);
5951} 6222}
5952 6223
5953/* Return code is exit status of the process that is run. */ 6224/* Return code is exit status of the process that is run. */
@@ -5976,7 +6247,7 @@ static int process_command_subs(o_string *dest, const char *s)
5976 } 6247 }
5977 6248
5978 debug_printf("done reading from `cmd` pipe, closing it\n"); 6249 debug_printf("done reading from `cmd` pipe, closing it\n");
5979 fclose(fp); 6250 fclose_and_forget(fp);
5980 /* We need to extract exitcode. Test case 6251 /* We need to extract exitcode. Test case
5981 * "true; echo `sleep 1; false` $?" 6252 * "true; echo `sleep 1; false` $?"
5982 * should print 1 */ 6253 * should print 1 */
@@ -6068,6 +6339,74 @@ static void setup_heredoc(struct redir_struct *redir)
6068 wait(NULL); /* wait till child has died */ 6339 wait(NULL); /* wait till child has died */
6069} 6340}
6070 6341
6342/* fd: redirect wants this fd to be used (e.g. 3>file).
6343 * Move all conflicting internally used fds,
6344 * and remember them so that we can restore them later.
6345 */
6346static int save_fds_on_redirect(int fd, int squirrel[3])
6347{
6348 if (squirrel) {
6349 /* Handle redirects of fds 0,1,2 */
6350
6351 /* If we collide with an already moved stdio fd... */
6352 if (fd == squirrel[0]) {
6353 squirrel[0] = xdup_and_close(squirrel[0], F_DUPFD);
6354 return 1;
6355 }
6356 if (fd == squirrel[1]) {
6357 squirrel[1] = xdup_and_close(squirrel[1], F_DUPFD);
6358 return 1;
6359 }
6360 if (fd == squirrel[2]) {
6361 squirrel[2] = xdup_and_close(squirrel[2], F_DUPFD);
6362 return 1;
6363 }
6364 /* If we are about to redirect stdio fd, and did not yet move it... */
6365 if (fd <= 2 && squirrel[fd] < 0) {
6366 /* We avoid taking stdio fds */
6367 squirrel[fd] = fcntl(fd, F_DUPFD, 10);
6368 if (squirrel[fd] < 0 && errno != EBADF)
6369 xfunc_die();
6370 return 0; /* "we did not close fd" */
6371 }
6372 }
6373
6374#if ENABLE_HUSH_INTERACTIVE
6375 if (fd != 0 && fd == G.interactive_fd) {
6376 G.interactive_fd = xdup_and_close(G.interactive_fd, F_DUPFD_CLOEXEC);
6377 return 1;
6378 }
6379#endif
6380
6381 /* Are we called from setup_redirects(squirrel==NULL)? Two cases:
6382 * (1) Redirect in a forked child. No need to save FILEs' fds,
6383 * we aren't going to use them anymore, ok to trash.
6384 * (2) "exec 3>FILE". Bummer. We can save FILEs' fds,
6385 * but how are we doing to use them?
6386 * "fileno(fd) = new_fd" can't be done.
6387 */
6388 if (!squirrel)
6389 return 0;
6390
6391 return save_FILEs_on_redirect(fd);
6392}
6393
6394static void restore_redirects(int squirrel[3])
6395{
6396 int i, fd;
6397 for (i = 0; i <= 2; i++) {
6398 fd = squirrel[i];
6399 if (fd != -1) {
6400 /* We simply die on error */
6401 xmove_fd(fd, i);
6402 }
6403 }
6404
6405 /* Moved G.interactive_fd stays on new fd, not doing anything for it */
6406
6407 restore_redirected_FILEs();
6408}
6409
6071/* squirrel != NULL means we squirrel away copies of stdin, stdout, 6410/* squirrel != NULL means we squirrel away copies of stdin, stdout,
6072 * and stderr if they are redirected. */ 6411 * and stderr if they are redirected. */
6073static int setup_redirects(struct command *prog, int squirrel[]) 6412static int setup_redirects(struct command *prog, int squirrel[])
@@ -6077,12 +6416,8 @@ static int setup_redirects(struct command *prog, int squirrel[])
6077 6416
6078 for (redir = prog->redirects; redir; redir = redir->next) { 6417 for (redir = prog->redirects; redir; redir = redir->next) {
6079 if (redir->rd_type == REDIRECT_HEREDOC2) { 6418 if (redir->rd_type == REDIRECT_HEREDOC2) {
6080 /* rd_fd<<HERE case */ 6419 /* "rd_fd<<HERE" case */
6081 if (squirrel && redir->rd_fd < 3 6420 save_fds_on_redirect(redir->rd_fd, squirrel);
6082 && squirrel[redir->rd_fd] < 0
6083 ) {
6084 squirrel[redir->rd_fd] = dup(redir->rd_fd);
6085 }
6086 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_ 6421 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_
6087 * of the heredoc */ 6422 * of the heredoc */
6088 debug_printf_parse("set heredoc '%s'\n", 6423 debug_printf_parse("set heredoc '%s'\n",
@@ -6092,12 +6427,15 @@ static int setup_redirects(struct command *prog, int squirrel[])
6092 } 6427 }
6093 6428
6094 if (redir->rd_dup == REDIRFD_TO_FILE) { 6429 if (redir->rd_dup == REDIRFD_TO_FILE) {
6095 /* rd_fd<*>file case (<*> is <,>,>>,<>) */ 6430 /* "rd_fd<*>file" case (<*> is <,>,>>,<>) */
6096 char *p; 6431 char *p;
6097 if (redir->rd_filename == NULL) { 6432 if (redir->rd_filename == NULL) {
6098 /* Something went wrong in the parse. 6433 /*
6099 * Pretend it didn't happen */ 6434 * Examples:
6100 bb_error_msg("bug in redirect parse"); 6435 * "cmd >" (no filename)
6436 * "cmd > <file" (2nd redirect starts too early)
6437 */
6438 die_if_script("syntax error: %s", "invalid redirect");
6101 continue; 6439 continue;
6102 } 6440 }
6103 mode = redir_table[redir->rd_type].mode; 6441 mode = redir_table[redir->rd_type].mode;
@@ -6105,47 +6443,39 @@ static int setup_redirects(struct command *prog, int squirrel[])
6105 openfd = open_or_warn(p, mode); 6443 openfd = open_or_warn(p, mode);
6106 free(p); 6444 free(p);
6107 if (openfd < 0) { 6445 if (openfd < 0) {
6108 /* this could get lost if stderr has been redirected, but 6446 /* Error message from open_or_warn can be lost
6109 * bash and ash both lose it as well (though zsh doesn't!) */ 6447 * if stderr has been redirected, but bash
6110//what the above comment tries to say? 6448 * and ash both lose it as well
6449 * (though zsh doesn't!)
6450 */
6111 return 1; 6451 return 1;
6112 } 6452 }
6113 } else { 6453 } else {
6114 /* rd_fd<*>rd_dup or rd_fd<*>- cases */ 6454 /* "rd_fd<*>rd_dup" or "rd_fd<*>-" cases */
6115 openfd = redir->rd_dup; 6455 openfd = redir->rd_dup;
6116 } 6456 }
6117 6457
6118 if (openfd != redir->rd_fd) { 6458 if (openfd != redir->rd_fd) {
6119 if (squirrel && redir->rd_fd < 3 6459 int closed = save_fds_on_redirect(redir->rd_fd, squirrel);
6120 && squirrel[redir->rd_fd] < 0
6121 ) {
6122 squirrel[redir->rd_fd] = dup(redir->rd_fd);
6123 }
6124 if (openfd == REDIRFD_CLOSE) { 6460 if (openfd == REDIRFD_CLOSE) {
6125 /* "n>-" means "close me" */ 6461 /* "rd_fd >&-" means "close me" */
6126 close(redir->rd_fd); 6462 if (!closed) {
6463 /* ^^^ optimization: saving may already
6464 * have closed it. If not... */
6465 close(redir->rd_fd);
6466 }
6127 } else { 6467 } else {
6128 xdup2(openfd, redir->rd_fd); 6468 xdup2(openfd, redir->rd_fd);
6129 if (redir->rd_dup == REDIRFD_TO_FILE) 6469 if (redir->rd_dup == REDIRFD_TO_FILE)
6470 /* "rd_fd > FILE" */
6130 close(openfd); 6471 close(openfd);
6472 /* else: "rd_fd > rd_dup" */
6131 } 6473 }
6132 } 6474 }
6133 } 6475 }
6134 return 0; 6476 return 0;
6135} 6477}
6136 6478
6137static void restore_redirects(int squirrel[])
6138{
6139 int i, fd;
6140 for (i = 0; i < 3; i++) {
6141 fd = squirrel[i];
6142 if (fd != -1) {
6143 /* We simply die on error */
6144 xmove_fd(fd, i);
6145 }
6146 }
6147}
6148
6149static char *find_in_path(const char *arg) 6479static char *find_in_path(const char *arg)
6150{ 6480{
6151 char *ret = NULL; 6481 char *ret = NULL;
@@ -6329,8 +6659,8 @@ static int run_function(const struct function *funcp, char **argv)
6329 save_and_replace_G_args(&sv, argv); 6659 save_and_replace_G_args(&sv, argv);
6330 6660
6331 /* "we are in function, ok to use return" */ 6661 /* "we are in function, ok to use return" */
6332 sv_flg = G.flag_return_in_progress; 6662 sv_flg = G_flag_return_in_progress;
6333 G.flag_return_in_progress = -1; 6663 G_flag_return_in_progress = -1;
6334# if ENABLE_HUSH_LOCAL 6664# if ENABLE_HUSH_LOCAL
6335 G.func_nest_level++; 6665 G.func_nest_level++;
6336# endif 6666# endif
@@ -6371,7 +6701,7 @@ static int run_function(const struct function *funcp, char **argv)
6371 G.func_nest_level--; 6701 G.func_nest_level--;
6372 } 6702 }
6373# endif 6703# endif
6374 G.flag_return_in_progress = sv_flg; 6704 G_flag_return_in_progress = sv_flg;
6375 6705
6376 restore_G_args(&sv, argv); 6706 restore_G_args(&sv, argv);
6377 6707
@@ -6417,13 +6747,17 @@ static void exec_builtin(char ***to_free,
6417static void execvp_or_die(char **argv) NORETURN; 6747static void execvp_or_die(char **argv) NORETURN;
6418static void execvp_or_die(char **argv) 6748static void execvp_or_die(char **argv)
6419{ 6749{
6750 int e;
6420 debug_printf_exec("execing '%s'\n", argv[0]); 6751 debug_printf_exec("execing '%s'\n", argv[0]);
6421 /* Don't propagate SIG_IGN to the child */ 6752 /* Don't propagate SIG_IGN to the child */
6422 if (SPECIAL_JOBSTOP_SIGS != 0) 6753 if (SPECIAL_JOBSTOP_SIGS != 0)
6423 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); 6754 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
6424 execvp(argv[0], argv); 6755 execvp(argv[0], argv);
6756 e = 2;
6757 if (errno == EACCES) e = 126;
6758 if (errno == ENOENT) e = 127;
6425 bb_perror_msg("can't execute '%s'", argv[0]); 6759 bb_perror_msg("can't execute '%s'", argv[0]);
6426 _exit(127); /* bash compat */ 6760 _exit(e);
6427} 6761}
6428 6762
6429#if ENABLE_HUSH_MODE_X 6763#if ENABLE_HUSH_MODE_X
@@ -6466,7 +6800,8 @@ static void dump_cmd_in_x_mode(char **argv)
6466 * Never returns. 6800 * Never returns.
6467 * Don't exit() here. If you don't exec, use _exit instead. 6801 * Don't exit() here. If you don't exec, use _exit instead.
6468 * The at_exit handlers apparently confuse the calling process, 6802 * The at_exit handlers apparently confuse the calling process,
6469 * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ 6803 * in particular stdin handling. Not sure why? -- because of vfork! (vda)
6804 */
6470static void pseudo_exec_argv(nommu_save_t *nommu_save, 6805static void pseudo_exec_argv(nommu_save_t *nommu_save,
6471 char **argv, int assignment_cnt, 6806 char **argv, int assignment_cnt,
6472 char **argv_expanded) NORETURN; 6807 char **argv_expanded) NORETURN;
@@ -6546,6 +6881,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
6546 if (a >= 0) { 6881 if (a >= 0) {
6547# if BB_MMU /* see above why on NOMMU it is not allowed */ 6882# if BB_MMU /* see above why on NOMMU it is not allowed */
6548 if (APPLET_IS_NOEXEC(a)) { 6883 if (APPLET_IS_NOEXEC(a)) {
6884 /* Do not leak open fds from opened script files etc */
6885 close_all_FILE_list();
6549 debug_printf_exec("running applet '%s'\n", argv[0]); 6886 debug_printf_exec("running applet '%s'\n", argv[0]);
6550 run_applet_no_and_exit(a, argv); 6887 run_applet_no_and_exit(a, argv);
6551 } 6888 }
@@ -7121,6 +7458,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
7121 if (x->b_function == builtin_exec && argv_expanded[1] == NULL) { 7458 if (x->b_function == builtin_exec && argv_expanded[1] == NULL) {
7122 debug_printf("exec with redirects only\n"); 7459 debug_printf("exec with redirects only\n");
7123 rcode = setup_redirects(command, NULL); 7460 rcode = setup_redirects(command, NULL);
7461 /* rcode=1 can be if redir file can't be opened */
7124 goto clean_up_and_ret1; 7462 goto clean_up_and_ret1;
7125 } 7463 }
7126 } 7464 }
@@ -7247,9 +7585,20 @@ static NOINLINE int run_pipe(struct pipe *pi)
7247 if (pipefds.rd > 1) 7585 if (pipefds.rd > 1)
7248 close(pipefds.rd); 7586 close(pipefds.rd);
7249 /* Like bash, explicit redirects override pipes, 7587 /* Like bash, explicit redirects override pipes,
7250 * and the pipe fd is available for dup'ing. */ 7588 * and the pipe fd (fd#1) is available for dup'ing:
7251 if (setup_redirects(command, NULL)) 7589 * "cmd1 2>&1 | cmd2": fd#1 is duped to fd#2, thus stderr
7590 * of cmd1 goes into pipe.
7591 */
7592 if (setup_redirects(command, NULL)) {
7593 /* Happens when redir file can't be opened:
7594 * $ hush -c 'echo FOO >&2 | echo BAR 3>/qwe/rty; echo BAZ'
7595 * FOO
7596 * hush: can't open '/qwe/rty': No such file or directory
7597 * BAZ
7598 * (echo BAR is not executed, it hits _exit(1) below)
7599 */
7252 _exit(1); 7600 _exit(1);
7601 }
7253 7602
7254 /* Stores to nommu_save list of env vars putenv'ed 7603 /* Stores to nommu_save list of env vars putenv'ed
7255 * (NOMMU, on MMU we don't need that) */ 7604 * (NOMMU, on MMU we don't need that) */
@@ -7380,6 +7729,8 @@ static int run_list(struct pipe *pi)
7380 for (; pi; pi = IF_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) { 7729 for (; pi; pi = IF_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) {
7381 if (G.flag_SIGINT) 7730 if (G.flag_SIGINT)
7382 break; 7731 break;
7732 if (G_flag_return_in_progress == 1)
7733 break;
7383 7734
7384 IF_HAS_KEYWORDS(rword = pi->res_word;) 7735 IF_HAS_KEYWORDS(rword = pi->res_word;)
7385 debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n", 7736 debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n",
@@ -7550,12 +7901,10 @@ static int run_list(struct pipe *pi)
7550 continue; 7901 continue;
7551 } 7902 }
7552#endif 7903#endif
7553#if ENABLE_HUSH_FUNCTIONS 7904 if (G_flag_return_in_progress == 1) {
7554 if (G.flag_return_in_progress == 1) {
7555 checkjobs(NULL); 7905 checkjobs(NULL);
7556 break; 7906 break;
7557 } 7907 }
7558#endif
7559 } else if (pi->followup == PIPE_BG) { 7908 } else if (pi->followup == PIPE_BG) {
7560 /* What does bash do with attempts to background builtins? */ 7909 /* What does bash do with attempts to background builtins? */
7561 /* even bash 3.2 doesn't do that well with nested bg: 7910 /* even bash 3.2 doesn't do that well with nested bg:
@@ -7787,6 +8136,7 @@ int hush_main(int argc, char **argv)
7787 INIT_G(); 8136 INIT_G();
7788 if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ 8137 if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */
7789 G.last_exitcode = EXIT_SUCCESS; 8138 G.last_exitcode = EXIT_SUCCESS;
8139
7790#if ENABLE_HUSH_FAST 8140#if ENABLE_HUSH_FAST
7791 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ 8141 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
7792#endif 8142#endif
@@ -7876,7 +8226,7 @@ int hush_main(int argc, char **argv)
7876 /* Initialize some more globals to non-zero values */ 8226 /* Initialize some more globals to non-zero values */
7877 cmdedit_update_prompt(); 8227 cmdedit_update_prompt();
7878 8228
7879 die_func = xfunc_has_died; 8229 die_func = restore_ttypgrp_and__exit;
7880 8230
7881 /* Shell is non-interactive at first. We need to call 8231 /* Shell is non-interactive at first. We need to call
7882 * install_special_sighandlers() if we are going to execute "sh <script>", 8232 * install_special_sighandlers() if we are going to execute "sh <script>",
@@ -8035,10 +8385,10 @@ int hush_main(int argc, char **argv)
8035 debug_printf("sourcing /etc/profile\n"); 8385 debug_printf("sourcing /etc/profile\n");
8036 input = fopen_for_read("/etc/profile"); 8386 input = fopen_for_read("/etc/profile");
8037 if (input != NULL) { 8387 if (input != NULL) {
8038 close_on_exec_on(fileno(input)); 8388 remember_FILE(input);
8039 install_special_sighandlers(); 8389 install_special_sighandlers();
8040 parse_and_run_file(input); 8390 parse_and_run_file(input);
8041 fclose(input); 8391 fclose_and_forget(input);
8042 } 8392 }
8043 /* bash: after sourcing /etc/profile, 8393 /* bash: after sourcing /etc/profile,
8044 * tries to source (in the given order): 8394 * tries to source (in the given order):
@@ -8060,11 +8410,11 @@ int hush_main(int argc, char **argv)
8060 G.global_argv++; 8410 G.global_argv++;
8061 debug_printf("running script '%s'\n", G.global_argv[0]); 8411 debug_printf("running script '%s'\n", G.global_argv[0]);
8062 input = xfopen_for_read(G.global_argv[0]); 8412 input = xfopen_for_read(G.global_argv[0]);
8063 close_on_exec_on(fileno(input)); 8413 remember_FILE(input);
8064 install_special_sighandlers(); 8414 install_special_sighandlers();
8065 parse_and_run_file(input); 8415 parse_and_run_file(input);
8066#if ENABLE_FEATURE_CLEAN_UP 8416#if ENABLE_FEATURE_CLEAN_UP
8067 fclose(input); 8417 fclose_and_forget(input);
8068#endif 8418#endif
8069 goto final_return; 8419 goto final_return;
8070 } 8420 }
@@ -8205,7 +8555,7 @@ int hush_main(int argc, char **argv)
8205int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 8555int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
8206int msh_main(int argc, char **argv) 8556int msh_main(int argc, char **argv)
8207{ 8557{
8208 //bb_error_msg("msh is deprecated, please use hush instead"); 8558 bb_error_msg("msh is deprecated, please use hush instead");
8209 return hush_main(argc, argv); 8559 return hush_main(argc, argv);
8210} 8560}
8211#endif 8561#endif
@@ -8399,6 +8749,14 @@ static void helper_export_local(char **argv, int exp, int lvl)
8399 continue; 8749 continue;
8400 } 8750 }
8401 } 8751 }
8752#if ENABLE_HUSH_LOCAL
8753 if (exp == 0 /* local? */
8754 && var && var->func_nest_level == lvl
8755 ) {
8756 /* "local x=abc; ...; local x" - ignore second local decl */
8757 continue;
8758 }
8759#endif
8402 /* Exporting non-existing variable. 8760 /* Exporting non-existing variable.
8403 * bash does not put it in environment, 8761 * bash does not put it in environment,
8404 * but remembers that it is exported, 8762 * but remembers that it is exported,
@@ -8473,6 +8831,212 @@ static int FAST_FUNC builtin_local(char **argv)
8473} 8831}
8474#endif 8832#endif
8475 8833
8834/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */
8835static int FAST_FUNC builtin_unset(char **argv)
8836{
8837 int ret;
8838 unsigned opts;
8839
8840 /* "!": do not abort on errors */
8841 /* "+": stop at 1st non-option */
8842 opts = getopt32(argv, "!+vf");
8843 if (opts == (unsigned)-1)
8844 return EXIT_FAILURE;
8845 if (opts == 3) {
8846 bb_error_msg("unset: -v and -f are exclusive");
8847 return EXIT_FAILURE;
8848 }
8849 argv += optind;
8850
8851 ret = EXIT_SUCCESS;
8852 while (*argv) {
8853 if (!(opts & 2)) { /* not -f */
8854 if (unset_local_var(*argv)) {
8855 /* unset <nonexistent_var> doesn't fail.
8856 * Error is when one tries to unset RO var.
8857 * Message was printed by unset_local_var. */
8858 ret = EXIT_FAILURE;
8859 }
8860 }
8861#if ENABLE_HUSH_FUNCTIONS
8862 else {
8863 unset_func(*argv);
8864 }
8865#endif
8866 argv++;
8867 }
8868 return ret;
8869}
8870
8871/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set
8872 * built-in 'set' handler
8873 * SUSv3 says:
8874 * set [-abCefhmnuvx] [-o option] [argument...]
8875 * set [+abCefhmnuvx] [+o option] [argument...]
8876 * set -- [argument...]
8877 * set -o
8878 * set +o
8879 * Implementations shall support the options in both their hyphen and
8880 * plus-sign forms. These options can also be specified as options to sh.
8881 * Examples:
8882 * Write out all variables and their values: set
8883 * Set $1, $2, and $3 and set "$#" to 3: set c a b
8884 * Turn on the -x and -v options: set -xv
8885 * Unset all positional parameters: set --
8886 * Set $1 to the value of x, even if it begins with '-' or '+': set -- "$x"
8887 * Set the positional parameters to the expansion of x, even if x expands
8888 * with a leading '-' or '+': set -- $x
8889 *
8890 * So far, we only support "set -- [argument...]" and some of the short names.
8891 */
8892static int FAST_FUNC builtin_set(char **argv)
8893{
8894 int n;
8895 char **pp, **g_argv;
8896 char *arg = *++argv;
8897
8898 if (arg == NULL) {
8899 struct variable *e;
8900 for (e = G.top_var; e; e = e->next)
8901 puts(e->varstr);
8902 return EXIT_SUCCESS;
8903 }
8904
8905 do {
8906 if (strcmp(arg, "--") == 0) {
8907 ++argv;
8908 goto set_argv;
8909 }
8910 if (arg[0] != '+' && arg[0] != '-')
8911 break;
8912 for (n = 1; arg[n]; ++n) {
8913 if (set_mode((arg[0] == '-'), arg[n], argv[1]))
8914 goto error;
8915 if (arg[n] == 'o' && argv[1])
8916 argv++;
8917 }
8918 } while ((arg = *++argv) != NULL);
8919 /* Now argv[0] is 1st argument */
8920
8921 if (arg == NULL)
8922 return EXIT_SUCCESS;
8923 set_argv:
8924
8925 /* NB: G.global_argv[0] ($0) is never freed/changed */
8926 g_argv = G.global_argv;
8927 if (G.global_args_malloced) {
8928 pp = g_argv;
8929 while (*++pp)
8930 free(*pp);
8931 g_argv[1] = NULL;
8932 } else {
8933 G.global_args_malloced = 1;
8934 pp = xzalloc(sizeof(pp[0]) * 2);
8935 pp[0] = g_argv[0]; /* retain $0 */
8936 g_argv = pp;
8937 }
8938 /* This realloc's G.global_argv */
8939 G.global_argv = pp = add_strings_to_strings(g_argv, argv, /*dup:*/ 1);
8940
8941 n = 1;
8942 while (*++pp)
8943 n++;
8944 G.global_argc = n;
8945
8946 return EXIT_SUCCESS;
8947
8948 /* Nothing known, so abort */
8949 error:
8950 bb_error_msg("set: %s: invalid option", arg);
8951 return EXIT_FAILURE;
8952}
8953
8954static int FAST_FUNC builtin_shift(char **argv)
8955{
8956 int n = 1;
8957 argv = skip_dash_dash(argv);
8958 if (argv[0]) {
8959 n = atoi(argv[0]);
8960 }
8961 if (n >= 0 && n < G.global_argc) {
8962 if (G.global_args_malloced) {
8963 int m = 1;
8964 while (m <= n)
8965 free(G.global_argv[m++]);
8966 }
8967 G.global_argc -= n;
8968 memmove(&G.global_argv[1], &G.global_argv[n+1],
8969 G.global_argc * sizeof(G.global_argv[0]));
8970 return EXIT_SUCCESS;
8971 }
8972 return EXIT_FAILURE;
8973}
8974
8975/* Interruptibility of read builtin in bash
8976 * (tested on bash-4.2.8 by sending signals (not by ^C)):
8977 *
8978 * Empty trap makes read ignore corresponding signal, for any signal.
8979 *
8980 * SIGINT:
8981 * - terminates non-interactive shell;
8982 * - interrupts read in interactive shell;
8983 * if it has non-empty trap:
8984 * - executes trap and returns to command prompt in interactive shell;
8985 * - executes trap and returns to read in non-interactive shell;
8986 * SIGTERM:
8987 * - is ignored (does not interrupt) read in interactive shell;
8988 * - terminates non-interactive shell;
8989 * if it has non-empty trap:
8990 * - executes trap and returns to read;
8991 * SIGHUP:
8992 * - terminates shell (regardless of interactivity);
8993 * if it has non-empty trap:
8994 * - executes trap and returns to read;
8995 */
8996static int FAST_FUNC builtin_read(char **argv)
8997{
8998 const char *r;
8999 char *opt_n = NULL;
9000 char *opt_p = NULL;
9001 char *opt_t = NULL;
9002 char *opt_u = NULL;
9003 const char *ifs;
9004 int read_flags;
9005
9006 /* "!": do not abort on errors.
9007 * Option string must start with "sr" to match BUILTIN_READ_xxx
9008 */
9009 read_flags = getopt32(argv, "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u);
9010 if (read_flags == (uint32_t)-1)
9011 return EXIT_FAILURE;
9012 argv += optind;
9013 ifs = get_local_var_value("IFS"); /* can be NULL */
9014
9015 again:
9016 r = shell_builtin_read(set_local_var_from_halves,
9017 argv,
9018 ifs,
9019 read_flags,
9020 opt_n,
9021 opt_p,
9022 opt_t,
9023 opt_u
9024 );
9025
9026 if ((uintptr_t)r == 1 && errno == EINTR) {
9027 unsigned sig = check_and_run_traps();
9028 if (sig && sig != SIGINT)
9029 goto again;
9030 }
9031
9032 if ((uintptr_t)r > 1) {
9033 bb_error_msg("%s", r);
9034 r = (char*)(uintptr_t)1;
9035 }
9036
9037 return (uintptr_t)r;
9038}
9039
8476static int FAST_FUNC builtin_trap(char **argv) 9040static int FAST_FUNC builtin_trap(char **argv)
8477{ 9041{
8478 int sig; 9042 int sig;
@@ -8671,7 +9235,6 @@ static int FAST_FUNC builtin_help(char **argv UNUSED_PARAM)
8671 if (x->b_descr) 9235 if (x->b_descr)
8672 printf("%-10s%s\n", x->b_cmd, x->b_descr); 9236 printf("%-10s%s\n", x->b_cmd, x->b_descr);
8673 } 9237 }
8674 bb_putchar('\n');
8675 return EXIT_SUCCESS; 9238 return EXIT_SUCCESS;
8676} 9239}
8677#endif 9240#endif
@@ -8721,6 +9284,15 @@ static int FAST_FUNC builtin_memleak(char **argv UNUSED_PARAM)
8721 if (l < (unsigned long)p) l = (unsigned long)p; 9284 if (l < (unsigned long)p) l = (unsigned long)p;
8722 free(p); 9285 free(p);
8723 9286
9287
9288# if 0 /* debug */
9289 {
9290 struct mallinfo mi = mallinfo();
9291 printf("top alloc:0x%lx malloced:%d+%d=%d\n", l,
9292 mi.arena, mi.hblkhd, mi.arena + mi.hblkhd);
9293 }
9294# endif
9295
8724 if (!G.memleak_value) 9296 if (!G.memleak_value)
8725 G.memleak_value = l; 9297 G.memleak_value = l;
8726 9298
@@ -8742,175 +9314,6 @@ static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM)
8742 return EXIT_SUCCESS; 9314 return EXIT_SUCCESS;
8743} 9315}
8744 9316
8745/* Interruptibility of read builtin in bash
8746 * (tested on bash-4.2.8 by sending signals (not by ^C)):
8747 *
8748 * Empty trap makes read ignore corresponding signal, for any signal.
8749 *
8750 * SIGINT:
8751 * - terminates non-interactive shell;
8752 * - interrupts read in interactive shell;
8753 * if it has non-empty trap:
8754 * - executes trap and returns to command prompt in interactive shell;
8755 * - executes trap and returns to read in non-interactive shell;
8756 * SIGTERM:
8757 * - is ignored (does not interrupt) read in interactive shell;
8758 * - terminates non-interactive shell;
8759 * if it has non-empty trap:
8760 * - executes trap and returns to read;
8761 * SIGHUP:
8762 * - terminates shell (regardless of interactivity);
8763 * if it has non-empty trap:
8764 * - executes trap and returns to read;
8765 */
8766static int FAST_FUNC builtin_read(char **argv)
8767{
8768 const char *r;
8769 char *opt_n = NULL;
8770 char *opt_p = NULL;
8771 char *opt_t = NULL;
8772 char *opt_u = NULL;
8773 const char *ifs;
8774 int read_flags;
8775
8776 /* "!": do not abort on errors.
8777 * Option string must start with "sr" to match BUILTIN_READ_xxx
8778 */
8779 read_flags = getopt32(argv, "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u);
8780 if (read_flags == (uint32_t)-1)
8781 return EXIT_FAILURE;
8782 argv += optind;
8783 ifs = get_local_var_value("IFS"); /* can be NULL */
8784
8785 again:
8786 r = shell_builtin_read(set_local_var_from_halves,
8787 argv,
8788 ifs,
8789 read_flags,
8790 opt_n,
8791 opt_p,
8792 opt_t,
8793 opt_u
8794 );
8795
8796 if ((uintptr_t)r == 1 && errno == EINTR) {
8797 unsigned sig = check_and_run_traps();
8798 if (sig && sig != SIGINT)
8799 goto again;
8800 }
8801
8802 if ((uintptr_t)r > 1) {
8803 bb_error_msg("%s", r);
8804 r = (char*)(uintptr_t)1;
8805 }
8806
8807 return (uintptr_t)r;
8808}
8809
8810/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set
8811 * built-in 'set' handler
8812 * SUSv3 says:
8813 * set [-abCefhmnuvx] [-o option] [argument...]
8814 * set [+abCefhmnuvx] [+o option] [argument...]
8815 * set -- [argument...]
8816 * set -o
8817 * set +o
8818 * Implementations shall support the options in both their hyphen and
8819 * plus-sign forms. These options can also be specified as options to sh.
8820 * Examples:
8821 * Write out all variables and their values: set
8822 * Set $1, $2, and $3 and set "$#" to 3: set c a b
8823 * Turn on the -x and -v options: set -xv
8824 * Unset all positional parameters: set --
8825 * Set $1 to the value of x, even if it begins with '-' or '+': set -- "$x"
8826 * Set the positional parameters to the expansion of x, even if x expands
8827 * with a leading '-' or '+': set -- $x
8828 *
8829 * So far, we only support "set -- [argument...]" and some of the short names.
8830 */
8831static int FAST_FUNC builtin_set(char **argv)
8832{
8833 int n;
8834 char **pp, **g_argv;
8835 char *arg = *++argv;
8836
8837 if (arg == NULL) {
8838 struct variable *e;
8839 for (e = G.top_var; e; e = e->next)
8840 puts(e->varstr);
8841 return EXIT_SUCCESS;
8842 }
8843
8844 do {
8845 if (strcmp(arg, "--") == 0) {
8846 ++argv;
8847 goto set_argv;
8848 }
8849 if (arg[0] != '+' && arg[0] != '-')
8850 break;
8851 for (n = 1; arg[n]; ++n) {
8852 if (set_mode((arg[0] == '-'), arg[n], argv[1]))
8853 goto error;
8854 if (arg[n] == 'o' && argv[1])
8855 argv++;
8856 }
8857 } while ((arg = *++argv) != NULL);
8858 /* Now argv[0] is 1st argument */
8859
8860 if (arg == NULL)
8861 return EXIT_SUCCESS;
8862 set_argv:
8863
8864 /* NB: G.global_argv[0] ($0) is never freed/changed */
8865 g_argv = G.global_argv;
8866 if (G.global_args_malloced) {
8867 pp = g_argv;
8868 while (*++pp)
8869 free(*pp);
8870 g_argv[1] = NULL;
8871 } else {
8872 G.global_args_malloced = 1;
8873 pp = xzalloc(sizeof(pp[0]) * 2);
8874 pp[0] = g_argv[0]; /* retain $0 */
8875 g_argv = pp;
8876 }
8877 /* This realloc's G.global_argv */
8878 G.global_argv = pp = add_strings_to_strings(g_argv, argv, /*dup:*/ 1);
8879
8880 n = 1;
8881 while (*++pp)
8882 n++;
8883 G.global_argc = n;
8884
8885 return EXIT_SUCCESS;
8886
8887 /* Nothing known, so abort */
8888 error:
8889 bb_error_msg("set: %s: invalid option", arg);
8890 return EXIT_FAILURE;
8891}
8892
8893static int FAST_FUNC builtin_shift(char **argv)
8894{
8895 int n = 1;
8896 argv = skip_dash_dash(argv);
8897 if (argv[0]) {
8898 n = atoi(argv[0]);
8899 }
8900 if (n >= 0 && n < G.global_argc) {
8901 if (G.global_args_malloced) {
8902 int m = 1;
8903 while (m <= n)
8904 free(G.global_argv[m++]);
8905 }
8906 G.global_argc -= n;
8907 memmove(&G.global_argv[1], &G.global_argv[n+1],
8908 G.global_argc * sizeof(G.global_argv[0]));
8909 return EXIT_SUCCESS;
8910 }
8911 return EXIT_FAILURE;
8912}
8913
8914static int FAST_FUNC builtin_source(char **argv) 9317static int FAST_FUNC builtin_source(char **argv)
8915{ 9318{
8916 char *arg_path, *filename; 9319 char *arg_path, *filename;
@@ -8932,7 +9335,7 @@ static int FAST_FUNC builtin_source(char **argv)
8932 if (arg_path) 9335 if (arg_path)
8933 filename = arg_path; 9336 filename = arg_path;
8934 } 9337 }
8935 input = fopen_or_warn(filename, "r"); 9338 input = remember_FILE(fopen_or_warn(filename, "r"));
8936 free(arg_path); 9339 free(arg_path);
8937 if (!input) { 9340 if (!input) {
8938 /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */ 9341 /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */
@@ -8941,23 +9344,24 @@ static int FAST_FUNC builtin_source(char **argv)
8941 */ 9344 */
8942 return EXIT_FAILURE; 9345 return EXIT_FAILURE;
8943 } 9346 }
8944 close_on_exec_on(fileno(input));
8945 9347
8946#if ENABLE_HUSH_FUNCTIONS 9348#if ENABLE_HUSH_FUNCTIONS
8947 sv_flg = G.flag_return_in_progress; 9349 sv_flg = G_flag_return_in_progress;
8948 /* "we are inside sourced file, ok to use return" */ 9350 /* "we are inside sourced file, ok to use return" */
8949 G.flag_return_in_progress = -1; 9351 G_flag_return_in_progress = -1;
8950#endif 9352#endif
8951 if (argv[1]) 9353 if (argv[1])
8952 save_and_replace_G_args(&sv, argv); 9354 save_and_replace_G_args(&sv, argv);
8953 9355
9356 /* "false; . ./empty_line; echo Zero:$?" should print 0 */
9357 G.last_exitcode = 0;
8954 parse_and_run_file(input); 9358 parse_and_run_file(input);
8955 fclose(input); 9359 fclose_and_forget(input);
8956 9360
8957 if (argv[1]) 9361 if (argv[1])
8958 restore_G_args(&sv, argv); 9362 restore_G_args(&sv, argv);
8959#if ENABLE_HUSH_FUNCTIONS 9363#if ENABLE_HUSH_FUNCTIONS
8960 G.flag_return_in_progress = sv_flg; 9364 G_flag_return_in_progress = sv_flg;
8961#endif 9365#endif
8962 9366
8963 return G.last_exitcode; 9367 return G.last_exitcode;
@@ -9000,43 +9404,6 @@ static int FAST_FUNC builtin_umask(char **argv)
9000 return !rc; /* rc != 0 - success */ 9404 return !rc; /* rc != 0 - success */
9001} 9405}
9002 9406
9003/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */
9004static int FAST_FUNC builtin_unset(char **argv)
9005{
9006 int ret;
9007 unsigned opts;
9008
9009 /* "!": do not abort on errors */
9010 /* "+": stop at 1st non-option */
9011 opts = getopt32(argv, "!+vf");
9012 if (opts == (unsigned)-1)
9013 return EXIT_FAILURE;
9014 if (opts == 3) {
9015 bb_error_msg("unset: -v and -f are exclusive");
9016 return EXIT_FAILURE;
9017 }
9018 argv += optind;
9019
9020 ret = EXIT_SUCCESS;
9021 while (*argv) {
9022 if (!(opts & 2)) { /* not -f */
9023 if (unset_local_var(*argv)) {
9024 /* unset <nonexistent_var> doesn't fail.
9025 * Error is when one tries to unset RO var.
9026 * Message was printed by unset_local_var. */
9027 ret = EXIT_FAILURE;
9028 }
9029 }
9030#if ENABLE_HUSH_FUNCTIONS
9031 else {
9032 unset_func(*argv);
9033 }
9034#endif
9035 argv++;
9036 }
9037 return ret;
9038}
9039
9040/* http://www.opengroup.org/onlinepubs/9699919799/utilities/wait.html */ 9407/* http://www.opengroup.org/onlinepubs/9699919799/utilities/wait.html */
9041static int FAST_FUNC builtin_wait(char **argv) 9408static int FAST_FUNC builtin_wait(char **argv)
9042{ 9409{
@@ -9153,9 +9520,11 @@ static int FAST_FUNC builtin_break(char **argv)
9153 unsigned depth; 9520 unsigned depth;
9154 if (G.depth_of_loop == 0) { 9521 if (G.depth_of_loop == 0) {
9155 bb_error_msg("%s: only meaningful in a loop", argv[0]); 9522 bb_error_msg("%s: only meaningful in a loop", argv[0]);
9523 /* if we came from builtin_continue(), need to undo "= 1" */
9524 G.flag_break_continue = 0;
9156 return EXIT_SUCCESS; /* bash compat */ 9525 return EXIT_SUCCESS; /* bash compat */
9157 } 9526 }
9158 G.flag_break_continue++; /* BC_BREAK = 1 */ 9527 G.flag_break_continue++; /* BC_BREAK = 1, or BC_CONTINUE = 2 */
9159 9528
9160 G.depth_break_continue = depth = parse_numeric_argv1(argv, 1, 1); 9529 G.depth_break_continue = depth = parse_numeric_argv1(argv, 1, 1);
9161 if (depth == UINT_MAX) 9530 if (depth == UINT_MAX)
@@ -9178,12 +9547,12 @@ static int FAST_FUNC builtin_return(char **argv)
9178{ 9547{
9179 int rc; 9548 int rc;
9180 9549
9181 if (G.flag_return_in_progress != -1) { 9550 if (G_flag_return_in_progress != -1) {
9182 bb_error_msg("%s: not in a function or sourced script", argv[0]); 9551 bb_error_msg("%s: not in a function or sourced script", argv[0]);
9183 return EXIT_FAILURE; /* bash compat */ 9552 return EXIT_FAILURE; /* bash compat */
9184 } 9553 }
9185 9554
9186 G.flag_return_in_progress = 1; 9555 G_flag_return_in_progress = 1;
9187 9556
9188 /* bash: 9557 /* bash:
9189 * out of range: wraps around at 256, does not error out 9558 * out of range: wraps around at 256, does not error out