aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c202
1 files changed, 106 insertions, 96 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 897548f3c..780900b40 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -418,9 +418,12 @@ static void forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes)
418 418
419/* ============ Shell options */ 419/* ============ Shell options */
420 420
421/* If you add/change options hare, update --help text too */
421static const char *const optletters_optnames[] = { 422static const char *const optletters_optnames[] = {
422 "e" "errexit", 423 "e" "errexit",
423 "f" "noglob", 424 "f" "noglob",
425/* bash has '-o ignoreeof', but no short synonym -I for it */
426/* (in bash, set -I disables invisible variables (what's that?)) */
424 "I" "ignoreeof", 427 "I" "ignoreeof",
425/* The below allowed this invocation: 428/* The below allowed this invocation:
426 * ash -c 'set -i; echo $-; sleep 5; echo $-' 429 * ash -c 'set -i; echo $-; sleep 5; echo $-'
@@ -429,9 +432,10 @@ static const char *const optletters_optnames[] = {
429 * In our code, this is denoted by empty long name: 432 * In our code, this is denoted by empty long name:
430 */ 433 */
431 "i" "", 434 "i" "",
435/* (removing "i" altogether would remove it from "$-", not good) */
432 "m" "monitor", 436 "m" "monitor",
433 "n" "noexec", 437 "n" "noexec",
434/* Ditto: bash has no "set -s" */ 438/* Ditto: bash has no "set -s", "set -c" */
435#if !ENABLE_PLATFORM_MINGW32 439#if !ENABLE_PLATFORM_MINGW32
436 "s" "", 440 "s" "",
437#else 441#else
@@ -707,6 +711,63 @@ var_end(const char *var)
707} 711}
708 712
709 713
714/* ============ Parser data */
715
716/*
717 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
718 */
719struct strlist {
720 struct strlist *next;
721 char *text;
722};
723
724struct alias;
725
726struct strpush {
727 struct strpush *prev; /* preceding string on stack */
728 char *prev_string;
729 int prev_left_in_line;
730#if ENABLE_ASH_ALIAS
731 struct alias *ap; /* if push was associated with an alias */
732#endif
733 char *string; /* remember the string since it may change */
734
735 /* Remember last two characters for pungetc. */
736 int lastc[2];
737
738 /* Number of outstanding calls to pungetc. */
739 int unget;
740};
741
742/*
743 * The parsefile structure pointed to by the global variable parsefile
744 * contains information about the current file being read.
745 */
746struct parsefile {
747 struct parsefile *prev; /* preceding file on stack */
748 int linno; /* current line */
749 int pf_fd; /* file descriptor (or -1 if string) */
750 int left_in_line; /* number of chars left in this line */
751 int left_in_buffer; /* number of chars left in this buffer past the line */
752 char *next_to_pgetc; /* next char in buffer */
753 char *buf; /* input buffer */
754 struct strpush *strpush; /* for pushing strings at this level */
755 struct strpush basestrpush; /* so pushing one is fast */
756
757 /* Remember last two characters for pungetc. */
758 int lastc[2];
759
760 /* Number of outstanding calls to pungetc. */
761 int unget;
762};
763
764static struct parsefile basepf; /* top level input file */
765static struct parsefile *g_parsefile = &basepf; /* current input file */
766#if ENABLE_PLATFORM_POSIX
767static char *commandname; /* currently executing command */
768#endif
769
770
710/* ============ Interrupts / exceptions */ 771/* ============ Interrupts / exceptions */
711 772
712static void exitshell(void) NORETURN; 773static void exitshell(void) NORETURN;
@@ -1466,63 +1527,6 @@ showtree(union node *n)
1466#endif /* DEBUG */ 1527#endif /* DEBUG */
1467 1528
1468 1529
1469/* ============ Parser data */
1470
1471/*
1472 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1473 */
1474struct strlist {
1475 struct strlist *next;
1476 char *text;
1477};
1478
1479struct alias;
1480
1481struct strpush {
1482 struct strpush *prev; /* preceding string on stack */
1483 char *prev_string;
1484 int prev_left_in_line;
1485#if ENABLE_ASH_ALIAS
1486 struct alias *ap; /* if push was associated with an alias */
1487#endif
1488 char *string; /* remember the string since it may change */
1489
1490 /* Remember last two characters for pungetc. */
1491 int lastc[2];
1492
1493 /* Number of outstanding calls to pungetc. */
1494 int unget;
1495};
1496
1497/*
1498 * The parsefile structure pointed to by the global variable parsefile
1499 * contains information about the current file being read.
1500 */
1501struct parsefile {
1502 struct parsefile *prev; /* preceding file on stack */
1503 int linno; /* current line */
1504 int pf_fd; /* file descriptor (or -1 if string) */
1505 int left_in_line; /* number of chars left in this line */
1506 int left_in_buffer; /* number of chars left in this buffer past the line */
1507 char *next_to_pgetc; /* next char in buffer */
1508 char *buf; /* input buffer */
1509 struct strpush *strpush; /* for pushing strings at this level */
1510 struct strpush basestrpush; /* so pushing one is fast */
1511
1512 /* Remember last two characters for pungetc. */
1513 int lastc[2];
1514
1515 /* Number of outstanding calls to pungetc. */
1516 int unget;
1517};
1518
1519static struct parsefile basepf; /* top level input file */
1520static struct parsefile *g_parsefile = &basepf; /* current input file */
1521#if ENABLE_PLATFORM_POSIX
1522static char *commandname; /* currently executing command */
1523#endif
1524
1525
1526/* ============ Message printing */ 1530/* ============ Message printing */
1527 1531
1528static void 1532static void
@@ -2284,7 +2288,7 @@ static const struct {
2284 int flags; 2288 int flags;
2285 const char *var_text; 2289 const char *var_text;
2286 void (*var_func)(const char *) FAST_FUNC; 2290 void (*var_func)(const char *) FAST_FUNC;
2287} varinit_data[] = { 2291} varinit_data[] ALIGN_PTR = {
2288 /* 2292 /*
2289 * Note: VEXPORT would not work correctly here for NOFORK applets: 2293 * Note: VEXPORT would not work correctly here for NOFORK applets:
2290 * some environment strings may be constant. 2294 * some environment strings may be constant.
@@ -5137,7 +5141,7 @@ getstatus(struct job *job)
5137 job->sigint = 1; 5141 job->sigint = 1;
5138#endif 5142#endif
5139 } 5143 }
5140 retval += 128; 5144 retval |= 128;
5141 } 5145 }
5142 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n", 5146 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
5143 jobno(job), job->nprocs, status, retval)); 5147 jobno(job), job->nprocs, status, retval));
@@ -5203,7 +5207,7 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
5203 if (status != -1 && !WIFSTOPPED(status)) { 5207 if (status != -1 && !WIFSTOPPED(status)) {
5204 retval = WEXITSTATUS(status); 5208 retval = WEXITSTATUS(status);
5205 if (WIFSIGNALED(status)) 5209 if (WIFSIGNALED(status))
5206 retval = WTERMSIG(status) + 128; 5210 retval = 128 | WTERMSIG(status);
5207 goto ret; 5211 goto ret;
5208 } 5212 }
5209 } 5213 }
@@ -5238,7 +5242,7 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
5238 ret: 5242 ret:
5239 return retval; 5243 return retval;
5240 sigout: 5244 sigout:
5241 retval = 128 + pending_sig; 5245 retval = 128 | pending_sig;
5242 return retval; 5246 return retval;
5243} 5247}
5244 5248
@@ -5340,7 +5344,7 @@ static char *cmdnextc;
5340static void 5344static void
5341cmdputs(const char *s) 5345cmdputs(const char *s)
5342{ 5346{
5343 static const char vstype[VSTYPE + 1][3] = { 5347 static const char vstype[VSTYPE + 1][3] ALIGN1 = {
5344 "", "}", "-", "+", "?", "=", 5348 "", "}", "-", "+", "?", "=",
5345 "%", "%%", "#", "##" 5349 "%", "%%", "#", "##"
5346 IF_BASH_SUBSTR(, ":") 5350 IF_BASH_SUBSTR(, ":")
@@ -7578,7 +7582,8 @@ subevalvar(char *start, char *str, int strloc,
7578 slash_pos = -1; 7582 slash_pos = -1;
7579 if (repl) { 7583 if (repl) {
7580 slash_pos = expdest - ((char *)stackblock() + strloc); 7584 slash_pos = expdest - ((char *)stackblock() + strloc);
7581 STPUTC('/', expdest); 7585 if (!(flag & EXP_DISCARD))
7586 STPUTC('/', expdest);
7582 //bb_error_msg("repl+1:'%s'", repl + 1); 7587 //bb_error_msg("repl+1:'%s'", repl + 1);
7583 p = argstr(repl + 1, (flag & EXP_DISCARD) | EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */ 7588 p = argstr(repl + 1, (flag & EXP_DISCARD) | EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
7584 *repl = '/'; 7589 *repl = '/';
@@ -7740,7 +7745,7 @@ subevalvar(char *start, char *str, int strloc,
7740 len = 0; 7745 len = 0;
7741 idx = startp; 7746 idx = startp;
7742 end = str - 1; 7747 end = str - 1;
7743 while (idx < end) { 7748 while (idx <= end) {
7744 try_to_match: 7749 try_to_match:
7745 loc = scanright(idx, rmesc, rmescend, str, quotes, 1); 7750 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
7746 //bb_error_msg("scanright('%s'):'%s'", str, loc); 7751 //bb_error_msg("scanright('%s'):'%s'", str, loc);
@@ -7748,6 +7753,8 @@ subevalvar(char *start, char *str, int strloc,
7748 /* No match, advance */ 7753 /* No match, advance */
7749 char *restart_detect = stackblock(); 7754 char *restart_detect = stackblock();
7750 skip_matching: 7755 skip_matching:
7756 if (idx >= end)
7757 break;
7751 STPUTC(*idx, expdest); 7758 STPUTC(*idx, expdest);
7752 if (quotes && (unsigned char)*idx == CTLESC) { 7759 if (quotes && (unsigned char)*idx == CTLESC) {
7753 idx++; 7760 idx++;
@@ -7760,8 +7767,6 @@ subevalvar(char *start, char *str, int strloc,
7760 len++; 7767 len++;
7761 rmesc++; 7768 rmesc++;
7762 /* continue; - prone to quadratic behavior, smarter code: */ 7769 /* continue; - prone to quadratic behavior, smarter code: */
7763 if (idx >= end)
7764 break;
7765 if (str[0] == '*') { 7770 if (str[0] == '*') {
7766 /* Pattern is "*foo". If "*foo" does not match "long_string", 7771 /* Pattern is "*foo". If "*foo" does not match "long_string",
7767 * it would never match "ong_string" etc, no point in trying. 7772 * it would never match "ong_string" etc, no point in trying.
@@ -7844,7 +7849,9 @@ subevalvar(char *start, char *str, int strloc,
7844 out: 7849 out:
7845 amount = loc - expdest; 7850 amount = loc - expdest;
7846 STADJUST(amount, expdest); 7851 STADJUST(amount, expdest);
7852#if BASH_PATTERN_SUBST
7847 out1: 7853 out1:
7854#endif
7848 /* Remove any recorded regions beyond start of variable */ 7855 /* Remove any recorded regions beyond start of variable */
7849 removerecordregions(startloc); 7856 removerecordregions(startloc);
7850 7857
@@ -9127,7 +9134,7 @@ enum {
9127 , /* thus far 29 bits used */ 9134 , /* thus far 29 bits used */
9128}; 9135};
9129 9136
9130static const char *const tokname_array[] = { 9137static const char *const tokname_array[] ALIGN_PTR = {
9131 "end of file", 9138 "end of file",
9132 "newline", 9139 "newline",
9133 "redirection", 9140 "redirection",
@@ -11360,7 +11367,7 @@ preadfd(void)
11360 11367
11361 g_parsefile->next_to_pgetc = buf; 11368 g_parsefile->next_to_pgetc = buf;
11362#if ENABLE_FEATURE_EDITING 11369#if ENABLE_FEATURE_EDITING
11363 retry: 11370 /* retry: */
11364 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) 11371 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
11365 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 11372 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
11366 else { 11373 else {
@@ -11382,17 +11389,16 @@ preadfd(void)
11382 if (nr == 0) { 11389 if (nr == 0) {
11383 /* ^C pressed, "convert" to SIGINT */ 11390 /* ^C pressed, "convert" to SIGINT */
11384 write(STDOUT_FILENO, "^C", 2); 11391 write(STDOUT_FILENO, "^C", 2);
11392# if !ENABLE_PLATFORM_MINGW32
11393 raise(SIGINT);
11394# endif
11385 if (trap[SIGINT]) { 11395 if (trap[SIGINT]) {
11386 buf[0] = '\n'; 11396 buf[0] = '\n';
11387 buf[1] = '\0'; 11397 buf[1] = '\0';
11388# if !ENABLE_PLATFORM_MINGW32
11389 raise(SIGINT);
11390# endif
11391 return 1; 11398 return 1;
11392 } 11399 }
11393 exitstatus = 128 + SIGINT; 11400 exitstatus = 128 + SIGINT;
11394 bb_putchar('\n'); 11401 return -1;
11395 goto retry;
11396 } 11402 }
11397 if (nr < 0) { 11403 if (nr < 0) {
11398 if (errno == 0) { 11404 if (errno == 0) {
@@ -12164,10 +12170,10 @@ static void FAST_FUNC
12164change_epoch(struct var *vepoch, const char *fmt) 12170change_epoch(struct var *vepoch, const char *fmt)
12165{ 12171{
12166 struct timeval tv; 12172 struct timeval tv;
12167 char buffer[sizeof("%lu.nnnnnn") + sizeof(long)*3]; 12173 char buffer[sizeof("%llu.nnnnnn") + sizeof(long long)*3];
12168 12174
12169 gettimeofday(&tv, NULL); 12175 xgettimeofday(&tv);
12170 sprintf(buffer, fmt, (unsigned long)tv.tv_sec, (unsigned)tv.tv_usec); 12176 sprintf(buffer, fmt, (unsigned long long)tv.tv_sec, (unsigned)tv.tv_usec);
12171 setvar(vepoch->var_text, buffer, VNOFUNC); 12177 setvar(vepoch->var_text, buffer, VNOFUNC);
12172 vepoch->flags &= ~VNOFUNC; 12178 vepoch->flags &= ~VNOFUNC;
12173} 12179}
@@ -12175,13 +12181,13 @@ change_epoch(struct var *vepoch, const char *fmt)
12175static void FAST_FUNC 12181static void FAST_FUNC
12176change_seconds(const char *value UNUSED_PARAM) 12182change_seconds(const char *value UNUSED_PARAM)
12177{ 12183{
12178 change_epoch(&vepochs, "%lu"); 12184 change_epoch(&vepochs, "%llu");
12179} 12185}
12180 12186
12181static void FAST_FUNC 12187static void FAST_FUNC
12182change_realtime(const char *value UNUSED_PARAM) 12188change_realtime(const char *value UNUSED_PARAM)
12183{ 12189{
12184 change_epoch(&vepochr, "%lu.%06u"); 12190 change_epoch(&vepochr, "%llu.%06u");
12185} 12191}
12186#endif 12192#endif
12187 12193
@@ -15001,6 +15007,7 @@ reset(void)
15001 /* from input.c: */ 15007 /* from input.c: */
15002 g_parsefile->left_in_buffer = 0; 15008 g_parsefile->left_in_buffer = 0;
15003 g_parsefile->left_in_line = 0; /* clear input buffer */ 15009 g_parsefile->left_in_line = 0; /* clear input buffer */
15010 g_parsefile->unget = 0;
15004 popallfiles(); 15011 popallfiles();
15005 15012
15006 /* from var.c: */ 15013 /* from var.c: */
@@ -15017,8 +15024,7 @@ exitshell(void)
15017 char *p; 15024 char *p;
15018 15025
15019#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 15026#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
15020 if (line_input_state) 15027 save_history(line_input_state); /* may be NULL */
15021 save_history(line_input_state);
15022#endif 15028#endif
15023 savestatus = exitstatus; 15029 savestatus = exitstatus;
15024 TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus)); 15030 TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus));
@@ -15197,7 +15203,8 @@ init(void)
15197 15203
15198 15204
15199//usage:#define ash_trivial_usage 15205//usage:#define ash_trivial_usage
15200//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]" 15206//usage: "[-il] [-/+Cabefmnuvx] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]"
15207//////// comes from ^^^^^^^^^^optletters
15201//usage:#define ash_full_usage "\n\n" 15208//usage:#define ash_full_usage "\n\n"
15202//usage: "Unix shell interpreter" 15209//usage: "Unix shell interpreter"
15203 15210
@@ -15246,9 +15253,9 @@ procargs(char **argv)
15246 } 15253 }
15247 if (mflag == 2) 15254 if (mflag == 2)
15248 mflag = iflag; 15255 mflag = iflag;
15256 /* Unset options which weren't explicitly set or unset */
15249 for (i = 0; i < NOPTS; i++) 15257 for (i = 0; i < NOPTS; i++)
15250 if (optlist[i] == 2) 15258 optlist[i] &= 1; /* same effect as "if (optlist[i] == 2) optlist[i] = 0;" */
15251 optlist[i] = 0;
15252#if DEBUG == 2 15259#if DEBUG == 2
15253 debug = 1; 15260 debug = 1;
15254#endif 15261#endif
@@ -15277,6 +15284,19 @@ procargs(char **argv)
15277 shellparam.nparam++; 15284 shellparam.nparam++;
15278 xargv++; 15285 xargv++;
15279 } 15286 }
15287
15288 /* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry.
15289 * Try:
15290 * trap '' hup; bash; echo RET # type "kill -hup $$", see SIGHUP having effect
15291 * trap '' hup; bash -c 'kill -hup $$; echo ALIVE' # here SIGHUP is SIG_IGNed
15292 * NB: must do it before setting up signals (in optschanged())
15293 * and reading .profile etc (after we return from here):
15294 */
15295#if !ENABLE_PLATFORM_MINGW32
15296 if (iflag)
15297 signal(SIGHUP, SIG_DFL);
15298#endif
15299
15280 optschanged(); 15300 optschanged();
15281 15301
15282 return login_sh; 15302 return login_sh;
@@ -15493,7 +15513,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
15493 15513
15494 if (sflag || minusc == NULL) { 15514 if (sflag || minusc == NULL) {
15495#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY 15515#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
15496 if (iflag) { 15516 if (line_input_state) {
15497 const char *hp = lookupvar("HISTFILE"); 15517 const char *hp = lookupvar("HISTFILE");
15498 if (!hp) { 15518 if (!hp) {
15499 hp = lookupvar("HOME"); 15519 hp = lookupvar("HOME");
@@ -15507,7 +15527,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
15507 } 15527 }
15508 } 15528 }
15509 if (hp) 15529 if (hp)
15510 line_input_state->hist_file = hp; 15530 line_input_state->hist_file = xstrdup(hp);
15511# if ENABLE_FEATURE_SH_HISTFILESIZE 15531# if ENABLE_FEATURE_SH_HISTFILESIZE
15512 hp = lookupvar("HISTFILESIZE"); 15532 hp = lookupvar("HISTFILESIZE");
15513 line_input_state->max_history = size_from_HISTFILESIZE(hp); 15533 line_input_state->max_history = size_from_HISTFILESIZE(hp);
@@ -15515,16 +15535,6 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
15515 } 15535 }
15516#endif 15536#endif
15517 state4: /* XXX ??? - why isn't this before the "if" statement */ 15537 state4: /* XXX ??? - why isn't this before the "if" statement */
15518
15519 /* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry.
15520 * Try:
15521 * trap '' hup; bash; echo RET # type "kill -hup $$", see SIGHUP having effect
15522 * trap '' hup; bash -c 'kill -hup $$; echo ALIVE' # here SIGHUP is SIG_IGNed
15523 */
15524#if !ENABLE_PLATFORM_MINGW32
15525 signal(SIGHUP, SIG_DFL);
15526#endif
15527
15528 cmdloop(1); 15538 cmdloop(1);
15529 } 15539 }
15530#if PROFILE 15540#if PROFILE