summaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2020-02-21 13:27:25 +0000
committerRon Yorston <rmy@pobox.com>2020-02-21 13:27:25 +0000
commit35da75bde8885d1922701a36baa61bc8b01f14d4 (patch)
tree87f6cbac5912e70a9c69b541f39e3b1d02f4394f /shell/ash.c
parent63c8e755021cf35c8a94ea1291c1e123164a7917 (diff)
parent3ced804e3118d138781c3e4baa6bf1589b9f2dfd (diff)
downloadbusybox-w32-35da75bde8885d1922701a36baa61bc8b01f14d4.tar.gz
busybox-w32-35da75bde8885d1922701a36baa61bc8b01f14d4.tar.bz2
busybox-w32-35da75bde8885d1922701a36baa61bc8b01f14d4.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c162
1 files changed, 88 insertions, 74 deletions
diff --git a/shell/ash.c b/shell/ash.c
index f33f72b80..252061dae 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -532,11 +532,11 @@ struct globals_misc {
532 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */ 532 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
533 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */ 533 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
534#endif 534#endif
535 smallint exception_type; /* kind of exception (0..5) */ 535 smallint exception_type; /* kind of exception: */
536 /* exceptions */
537#define EXINT 0 /* SIGINT received */ 536#define EXINT 0 /* SIGINT received */
538#define EXERROR 1 /* a generic error */ 537#define EXERROR 1 /* a generic error */
539#define EXEXIT 4 /* exit the shell */ 538#define EXEND 3 /* exit the shell */
539#define EXEXIT 4 /* exit the shell via exitcmd */
540 540
541 char nullstr[1]; /* zero length string */ 541 char nullstr[1]; /* zero length string */
542 542
@@ -6561,6 +6561,8 @@ static int substr_atoi(const char *s)
6561#define EXP_VARTILDE2 0x20 /* expand tildes after colons only */ 6561#define EXP_VARTILDE2 0x20 /* expand tildes after colons only */
6562#define EXP_WORD 0x40 /* expand word in parameter expansion */ 6562#define EXP_WORD 0x40 /* expand word in parameter expansion */
6563#define EXP_QUOTED 0x100 /* expand word in double quotes */ 6563#define EXP_QUOTED 0x100 /* expand word in double quotes */
6564#define EXP_KEEPNUL 0x200 /* do not skip NUL characters */
6565
6564/* 6566/*
6565 * rmescape() flags 6567 * rmescape() flags
6566 */ 6568 */
@@ -6571,8 +6573,6 @@ static int substr_atoi(const char *s)
6571 6573
6572/* Add CTLESC when necessary. */ 6574/* Add CTLESC when necessary. */
6573#define QUOTES_ESC (EXP_FULL | EXP_CASE) 6575#define QUOTES_ESC (EXP_FULL | EXP_CASE)
6574/* Do not skip NUL characters. */
6575#define QUOTES_KEEPNUL EXP_TILDE
6576 6576
6577/* 6577/*
6578 * Structure specifying which parts of the string should be searched 6578 * Structure specifying which parts of the string should be searched
@@ -6879,27 +6879,28 @@ preglob(const char *pattern, int flag)
6879 * Put a string on the stack. 6879 * Put a string on the stack.
6880 */ 6880 */
6881static void 6881static void
6882memtodest(const char *p, size_t len, int syntax, int quotes) 6882memtodest(const char *p, size_t len, int flags)
6883{ 6883{
6884 int syntax = flags & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
6884 char *q; 6885 char *q;
6885 6886
6886 if (!len) 6887 if (!len)
6887 return; 6888 return;
6888 6889
6889 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest); 6890 q = makestrspace(len * 2, expdest);
6890 6891
6891 do { 6892 do {
6892 unsigned char c = *p++; 6893 unsigned char c = *p++;
6893 if (c) { 6894 if (c) {
6894 if (quotes & QUOTES_ESC) { 6895 if (flags & QUOTES_ESC) {
6895 int n = SIT(c, syntax); 6896 int n = SIT(c, syntax);
6896 if (n == CCTL 6897 if (n == CCTL
6897 || (syntax != BASESYNTAX && n == CBACK) 6898 || ((flags & EXP_QUOTED) && n == CBACK)
6898 ) { 6899 ) {
6899 USTPUTC(CTLESC, q); 6900 USTPUTC(CTLESC, q);
6900 } 6901 }
6901 } 6902 }
6902 } else if (!(quotes & QUOTES_KEEPNUL)) 6903 } else if (!(flags & EXP_KEEPNUL))
6903 continue; 6904 continue;
6904 USTPUTC(c, q); 6905 USTPUTC(c, q);
6905 } while (--len); 6906 } while (--len);
@@ -6908,10 +6909,10 @@ memtodest(const char *p, size_t len, int syntax, int quotes)
6908} 6909}
6909 6910
6910static size_t 6911static size_t
6911strtodest(const char *p, int syntax, int quotes) 6912strtodest(const char *p, int flags)
6912{ 6913{
6913 size_t len = strlen(p); 6914 size_t len = strlen(p);
6914 memtodest(p, len, syntax, quotes); 6915 memtodest(p, len, flags);
6915 return len; 6916 return len;
6916} 6917}
6917 6918
@@ -6979,13 +6980,12 @@ removerecordregions(int endoff)
6979} 6980}
6980 6981
6981static char * 6982static char *
6982exptilde(char *startp, char *p, int flags) 6983exptilde(char *startp, char *p, int flag)
6983{ 6984{
6984 unsigned char c; 6985 unsigned char c;
6985 char *name; 6986 char *name;
6986 struct passwd *pw; 6987 struct passwd *pw;
6987 const char *home; 6988 const char *home;
6988 int quotes = flags & QUOTES_ESC;
6989 6989
6990 name = p + 1; 6990 name = p + 1;
6991 6991
@@ -6996,7 +6996,7 @@ exptilde(char *startp, char *p, int flags)
6996 case CTLQUOTEMARK: 6996 case CTLQUOTEMARK:
6997 return startp; 6997 return startp;
6998 case ':': 6998 case ':':
6999 if (flags & EXP_VARTILDE) 6999 if (flag & EXP_VARTILDE)
7000 goto done; 7000 goto done;
7001 break; 7001 break;
7002 case '/': 7002 case '/':
@@ -7017,7 +7017,7 @@ exptilde(char *startp, char *p, int flags)
7017 if (!home) 7017 if (!home)
7018 goto lose; 7018 goto lose;
7019 *p = c; 7019 *p = c;
7020 strtodest(home, SQSYNTAX, quotes); 7020 strtodest(home, flag | EXP_QUOTED);
7021 return p; 7021 return p;
7022 lose: 7022 lose:
7023 *p = c; 7023 *p = c;
@@ -7127,7 +7127,6 @@ expbackq(union node *cmd, int flag)
7127 char *p; 7127 char *p;
7128 char *dest; 7128 char *dest;
7129 int startloc; 7129 int startloc;
7130 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
7131 struct stackmark smark; 7130 struct stackmark smark;
7132 7131
7133 INT_OFF; 7132 INT_OFF;
@@ -7141,7 +7140,7 @@ expbackq(union node *cmd, int flag)
7141 if (i == 0) 7140 if (i == 0)
7142 goto read; 7141 goto read;
7143 for (;;) { 7142 for (;;) {
7144 memtodest(p, i, syntax, flag & QUOTES_ESC); 7143 memtodest(p, i, flag);
7145 read: 7144 read:
7146 if (in.fd < 0) 7145 if (in.fd < 0)
7147 break; 7146 break;
@@ -7851,11 +7850,10 @@ varvalue(char *name, int varflags, int flags, int quoted)
7851 int sep; 7850 int sep;
7852 int subtype = varflags & VSTYPE; 7851 int subtype = varflags & VSTYPE;
7853 int discard = subtype == VSPLUS || subtype == VSLENGTH; 7852 int discard = subtype == VSPLUS || subtype == VSLENGTH;
7854 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
7855 int syntax;
7856 7853
7854 flags |= EXP_KEEPNUL;
7855 flags &= discard ? ~QUOTES_ESC : ~0;
7857 sep = (flags & EXP_FULL) << CHAR_BIT; 7856 sep = (flags & EXP_FULL) << CHAR_BIT;
7858 syntax = quoted ? DQSYNTAX : BASESYNTAX;
7859 7857
7860 switch (*name) { 7858 switch (*name) {
7861 case '$': 7859 case '$':
@@ -7921,11 +7919,11 @@ varvalue(char *name, int varflags, int flags, int quoted)
7921 if (!ap) 7919 if (!ap)
7922 return -1; 7920 return -1;
7923 while ((p = *ap++) != NULL) { 7921 while ((p = *ap++) != NULL) {
7924 len += strtodest(p, syntax, quotes); 7922 len += strtodest(p, flags);
7925 7923
7926 if (*ap && sep) { 7924 if (*ap && sep) {
7927 len++; 7925 len++;
7928 memtodest(&sepc, 1, syntax, quotes); 7926 memtodest(&sepc, 1, flags);
7929 } 7927 }
7930 } 7928 }
7931 break; 7929 break;
@@ -7952,7 +7950,7 @@ varvalue(char *name, int varflags, int flags, int quoted)
7952 if (!p) 7950 if (!p)
7953 return -1; 7951 return -1;
7954 7952
7955 len = strtodest(p, syntax, quotes); 7953 len = strtodest(p, flags);
7956#if ENABLE_UNICODE_SUPPORT 7954#if ENABLE_UNICODE_SUPPORT
7957 if (subtype == VSLENGTH && len > 0) { 7955 if (subtype == VSLENGTH && len > 0) {
7958 reinit_unicode_for_ash(); 7956 reinit_unicode_for_ash();
@@ -8795,7 +8793,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
8795 exitstatus = exerrno; 8793 exitstatus = exerrno;
8796 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n", 8794 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
8797 prog, e, suppress_int)); 8795 prog, e, suppress_int));
8798 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found")); 8796 ash_msg_and_raise(EXEND, "%s: %s", prog, errmsg(e, "not found"));
8799 /* NOTREACHED */ 8797 /* NOTREACHED */
8800} 8798}
8801 8799
@@ -9742,6 +9740,7 @@ defun(union node *func)
9742#define SKIPBREAK (1 << 0) 9740#define SKIPBREAK (1 << 0)
9743#define SKIPCONT (1 << 1) 9741#define SKIPCONT (1 << 1)
9744#define SKIPFUNC (1 << 2) 9742#define SKIPFUNC (1 << 2)
9743#define SKIPFUNCDEF (1 << 3)
9745static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ 9744static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
9746static int skipcount; /* number of levels to skip */ 9745static int skipcount; /* number of levels to skip */
9747#if ENABLE_PLATFORM_POSIX 9746#if ENABLE_PLATFORM_POSIX
@@ -9802,7 +9801,8 @@ dotrap(void)
9802 if (!p) 9801 if (!p)
9803 continue; 9802 continue;
9804 evalstring(p, 0); 9803 evalstring(p, 0);
9805 exitstatus = status; 9804 if (evalskip != SKIPFUNC)
9805 exitstatus = status;
9806 } 9806 }
9807 9807
9808 savestatus = last_status; 9808 savestatus = last_status;
@@ -9946,9 +9946,9 @@ evaltree(union node *n, int flags)
9946 dotrap(); 9946 dotrap();
9947 9947
9948 if (checkexit & status) 9948 if (checkexit & status)
9949 raise_exception(EXEXIT); 9949 raise_exception(EXEND);
9950 if (flags & EV_EXIT) 9950 if (flags & EV_EXIT)
9951 raise_exception(EXEXIT); 9951 raise_exception(EXEND);
9952 9952
9953 popstackmark(&smark); 9953 popstackmark(&smark);
9954 TRACE(("leaving evaltree (no interrupts)\n")); 9954 TRACE(("leaving evaltree (no interrupts)\n"));
@@ -10462,7 +10462,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
10462 shellparam = saveparam; 10462 shellparam = saveparam;
10463 exception_handler = savehandler; 10463 exception_handler = savehandler;
10464 INT_ON; 10464 INT_ON;
10465 evalskip &= ~SKIPFUNC; 10465 evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
10466 return e; 10466 return e;
10467} 10467}
10468 10468
@@ -10607,12 +10607,23 @@ execcmd(int argc UNUSED_PARAM, char **argv)
10607static int FAST_FUNC 10607static int FAST_FUNC
10608returncmd(int argc UNUSED_PARAM, char **argv) 10608returncmd(int argc UNUSED_PARAM, char **argv)
10609{ 10609{
10610 int skip;
10611 int status;
10612
10610 /* 10613 /*
10611 * If called outside a function, do what ksh does; 10614 * If called outside a function, do what ksh does;
10612 * skip the rest of the file. 10615 * skip the rest of the file.
10613 */ 10616 */
10614 evalskip = SKIPFUNC; 10617 if (argv[1]) {
10615 return argv[1] ? number(argv[1]) : exitstatus; 10618 skip = SKIPFUNC;
10619 status = number(argv[1]);
10620 } else {
10621 skip = SKIPFUNCDEF;
10622 status = exitstatus;
10623 }
10624 evalskip = skip;
10625
10626 return status;
10616} 10627}
10617 10628
10618/* Forward declarations for builtintab[] */ 10629/* Forward declarations for builtintab[] */
@@ -14100,7 +14111,7 @@ cmdloop(int top)
14100 skip = evalskip; 14111 skip = evalskip;
14101 14112
14102 if (skip) { 14113 if (skip) {
14103 evalskip &= ~SKIPFUNC; 14114 evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
14104 break; 14115 break;
14105 } 14116 }
14106 } 14117 }
@@ -14889,6 +14900,47 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv)
14889/* ============ main() and helpers */ 14900/* ============ main() and helpers */
14890 14901
14891/* 14902/*
14903 * This routine is called when an error or an interrupt occurs in an
14904 * interactive shell and control is returned to the main command loop
14905 * but prior to exitshell.
14906 */
14907static void
14908exitreset(void)
14909{
14910 /* from eval.c: */
14911 if (savestatus >= 0) {
14912 if (exception_type == EXEXIT || evalskip == SKIPFUNCDEF)
14913 exitstatus = savestatus;
14914 savestatus = -1;
14915 }
14916 evalskip = 0;
14917 loopnest = 0;
14918
14919 /* from expand.c: */
14920 ifsfree();
14921
14922 /* from redir.c: */
14923 unwindredir(NULL);
14924}
14925
14926/*
14927 * This routine is called when an error or an interrupt occurs in an
14928 * interactive shell and control is returned to the main command loop.
14929 * (In dash, this function is auto-generated by build machinery).
14930 */
14931static void
14932reset(void)
14933{
14934 /* from input.c: */
14935 g_parsefile->left_in_buffer = 0;
14936 g_parsefile->left_in_line = 0; /* clear input buffer */
14937 popallfiles();
14938
14939 /* from var.c: */
14940 unwindlocalvars(NULL);
14941}
14942
14943/*
14892 * Called to exit the shell. 14944 * Called to exit the shell.
14893 */ 14945 */
14894static void 14946static void
@@ -14911,15 +14963,17 @@ exitshell(void)
14911 trap[0] = NULL; 14963 trap[0] = NULL;
14912 evalskip = 0; 14964 evalskip = 0;
14913 evalstring(p, 0); 14965 evalstring(p, 0);
14966 evalskip = SKIPFUNCDEF;
14914 /*free(p); - we'll exit soon */ 14967 /*free(p); - we'll exit soon */
14915 } 14968 }
14916 out: 14969 out:
14970 exitreset();
14917 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". 14971 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
14918 * our setjobctl(0) does not panic if tcsetpgrp fails inside it. 14972 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
14919 */ 14973 */
14920 setjobctl(0); 14974 setjobctl(0);
14921 flush_stdout_stderr(); 14975 flush_stdout_stderr();
14922 _exit(savestatus); 14976 _exit(exitstatus);
14923 /* NOTREACHED */ 14977 /* NOTREACHED */
14924} 14978}
14925 14979
@@ -15174,46 +15228,6 @@ read_profile(const char *name)
15174 popfile(); 15228 popfile();
15175} 15229}
15176 15230
15177/*
15178 * This routine is called when an error or an interrupt occurs in an
15179 * interactive shell and control is returned to the main command loop
15180 * but prior to exitshell.
15181 */
15182static void
15183exitreset(void)
15184{
15185 /* from eval.c: */
15186 evalskip = 0;
15187 loopnest = 0;
15188 if (savestatus >= 0) {
15189 exitstatus = savestatus;
15190 savestatus = -1;
15191 }
15192
15193 /* from expand.c: */
15194 ifsfree();
15195
15196 /* from redir.c: */
15197 unwindredir(NULL);
15198}
15199
15200/*
15201 * This routine is called when an error or an interrupt occurs in an
15202 * interactive shell and control is returned to the main command loop.
15203 * (In dash, this function is auto-generated by build machinery).
15204 */
15205static void
15206reset(void)
15207{
15208 /* from input.c: */
15209 g_parsefile->left_in_buffer = 0;
15210 g_parsefile->left_in_line = 0; /* clear input buffer */
15211 popallfiles();
15212
15213 /* from var.c: */
15214 unwindlocalvars(NULL);
15215}
15216
15217#if PROFILE 15231#if PROFILE
15218static short profile_buf[16384]; 15232static short profile_buf[16384];
15219extern int etext(); 15233extern int etext();
@@ -15264,7 +15278,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
15264 15278
15265 e = exception_type; 15279 e = exception_type;
15266 s = state; 15280 s = state;
15267 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) { 15281 if (e == EXEND || e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
15268 exitshell(); 15282 exitshell();
15269 } 15283 }
15270 15284