aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c127
1 files changed, 74 insertions, 53 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 4bd1c2c9d..7131609e4 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -6272,7 +6272,7 @@ static int substr_atoi(const char *s)
6272#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ 6272#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
6273#define EXP_VARTILDE2 0x20 /* expand tildes after colons only */ 6273#define EXP_VARTILDE2 0x20 /* expand tildes after colons only */
6274#define EXP_WORD 0x40 /* expand word in parameter expansion */ 6274#define EXP_WORD 0x40 /* expand word in parameter expansion */
6275#define EXP_QUOTED 0x80 /* expand word in double quotes */ 6275#define EXP_QUOTED 0x100 /* expand word in double quotes */
6276/* 6276/*
6277 * rmescape() flags 6277 * rmescape() flags
6278 */ 6278 */
@@ -6606,9 +6606,7 @@ memtodest(const char *p, size_t len, int syntax, int quotes)
6606 if (quotes & QUOTES_ESC) { 6606 if (quotes & QUOTES_ESC) {
6607 int n = SIT(c, syntax); 6607 int n = SIT(c, syntax);
6608 if (n == CCTL 6608 if (n == CCTL
6609 || (((quotes & EXP_FULL) || syntax != BASESYNTAX) 6609 || (syntax != BASESYNTAX && n == CBACK)
6610 && n == CBACK
6611 )
6612 ) { 6610 ) {
6613 USTPUTC(CTLESC, q); 6611 USTPUTC(CTLESC, q);
6614 } 6612 }
@@ -7236,8 +7234,15 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7236 if (subtype == VSREPLACE || subtype == VSREPLACEALL) { 7234 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7237 /* Find '/' and replace with NUL */ 7235 /* Find '/' and replace with NUL */
7238 repl = p; 7236 repl = p;
7237 /* The pattern can't be empty.
7238 * IOW: if the first char after "${v//" is a slash,
7239 * it does not terminate the pattern - it's the first char of the pattern:
7240 * v=/dev/ram; echo ${v////-} prints -dev-ram (pattern is "/")
7241 * v=/dev/ram; echo ${v///r/-} prints /dev-am (pattern is "/r")
7242 */
7243 if (*repl == '/')
7244 repl++;
7239 for (;;) { 7245 for (;;) {
7240 /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
7241 if (*repl == '\0') { 7246 if (*repl == '\0') {
7242 repl = NULL; 7247 repl = NULL;
7243 break; 7248 break;
@@ -7246,6 +7251,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7246 *repl = '\0'; 7251 *repl = '\0';
7247 break; 7252 break;
7248 } 7253 }
7254 /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
7249 if ((unsigned char)*repl == CTLESC && repl[1]) 7255 if ((unsigned char)*repl == CTLESC && repl[1])
7250 repl++; 7256 repl++;
7251 repl++; 7257 repl++;
@@ -7549,14 +7555,13 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7549 * ash -c 'echo ${#1#}' name:'1=#' 7555 * ash -c 'echo ${#1#}' name:'1=#'
7550 */ 7556 */
7551static NOINLINE ssize_t 7557static NOINLINE ssize_t
7552varvalue(char *name, int varflags, int flags, int *quotedp) 7558varvalue(char *name, int varflags, int flags, int quoted)
7553{ 7559{
7554 const char *p; 7560 const char *p;
7555 int num; 7561 int num;
7556 int i; 7562 int i;
7557 ssize_t len = 0; 7563 ssize_t len = 0;
7558 int sep; 7564 int sep;
7559 int quoted = *quotedp;
7560 int subtype = varflags & VSTYPE; 7565 int subtype = varflags & VSTYPE;
7561 int discard = subtype == VSPLUS || subtype == VSLENGTH; 7566 int discard = subtype == VSPLUS || subtype == VSLENGTH;
7562 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL; 7567 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
@@ -7604,13 +7609,27 @@ varvalue(char *name, int varflags, int flags, int *quotedp)
7604 case '*': { 7609 case '*': {
7605 char **ap; 7610 char **ap;
7606 char sepc; 7611 char sepc;
7612 char c;
7607 7613
7608 if (quoted) 7614 /* We will set c to 0 or ~0 depending on whether
7609 sep = 0; 7615 * we're doing field splitting. We won't do field
7610 sep |= ifsset() ? ifsval()[0] : ' '; 7616 * splitting if either we're quoted or sep is zero.
7617 *
7618 * Instead of testing (quoted || !sep) the following
7619 * trick optimises away any branches by using the
7620 * fact that EXP_QUOTED (which is the only bit that
7621 * can be set in quoted) is the same as EXP_FULL <<
7622 * CHAR_BIT (which is the only bit that can be set
7623 * in sep).
7624 */
7625#if EXP_QUOTED >> CHAR_BIT != EXP_FULL
7626#error The following two lines expect EXP_QUOTED == EXP_FULL << CHAR_BIT
7627#endif
7628 c = !((quoted | ~sep) & EXP_QUOTED) - 1;
7629 sep &= ~quoted;
7630 sep |= ifsset() ? (unsigned char)(c & ifsval()[0]) : ' ';
7611 param: 7631 param:
7612 sepc = sep; 7632 sepc = sep;
7613 *quotedp = !sepc;
7614 ap = shellparam.p; 7633 ap = shellparam.p;
7615 if (!ap) 7634 if (!ap)
7616 return -1; 7635 return -1;
@@ -7675,7 +7694,6 @@ evalvar(char *p, int flag)
7675 char varflags; 7694 char varflags;
7676 char subtype; 7695 char subtype;
7677 int quoted; 7696 int quoted;
7678 char easy;
7679 char *var; 7697 char *var;
7680 int patloc; 7698 int patloc;
7681 int startloc; 7699 int startloc;
@@ -7689,12 +7707,11 @@ evalvar(char *p, int flag)
7689 7707
7690 quoted = flag & EXP_QUOTED; 7708 quoted = flag & EXP_QUOTED;
7691 var = p; 7709 var = p;
7692 easy = (!quoted || (*var == '@' && shellparam.nparam));
7693 startloc = expdest - (char *)stackblock(); 7710 startloc = expdest - (char *)stackblock();
7694 p = strchr(p, '=') + 1; //TODO: use var_end(p)? 7711 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
7695 7712
7696 again: 7713 again:
7697 varlen = varvalue(var, varflags, flag, &quoted); 7714 varlen = varvalue(var, varflags, flag, quoted);
7698 if (varflags & VSNUL) 7715 if (varflags & VSNUL)
7699 varlen--; 7716 varlen--;
7700 7717
@@ -7740,8 +7757,11 @@ evalvar(char *p, int flag)
7740 7757
7741 if (subtype == VSNORMAL) { 7758 if (subtype == VSNORMAL) {
7742 record: 7759 record:
7743 if (!easy) 7760 if (quoted) {
7744 goto end; 7761 quoted = *var == '@' && shellparam.nparam;
7762 if (!quoted)
7763 goto end;
7764 }
7745 recordregion(startloc, expdest - (char *)stackblock(), quoted); 7765 recordregion(startloc, expdest - (char *)stackblock(), quoted);
7746 goto end; 7766 goto end;
7747 } 7767 }
@@ -7999,7 +8019,7 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
7999 } 8019 }
8000 } 8020 }
8001 } else { 8021 } else {
8002 if (*p == '\\') 8022 if (*p == '\\' && p[1])
8003 esc++; 8023 esc++;
8004 if (p[esc] == '/') { 8024 if (p[esc] == '/') {
8005 if (metaflag) 8025 if (metaflag)
@@ -8013,7 +8033,7 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
8013 return; 8033 return;
8014 p = name; 8034 p = name;
8015 do { 8035 do {
8016 if (*p == '\\') 8036 if (*p == '\\' && p[1])
8017 p++; 8037 p++;
8018 *enddir++ = *p; 8038 *enddir++ = *p;
8019 } while (*p++); 8039 } while (*p++);
@@ -8025,7 +8045,7 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
8025 if (name < start) { 8045 if (name < start) {
8026 p = name; 8046 p = name;
8027 do { 8047 do {
8028 if (*p == '\\') 8048 if (*p == '\\' && p[1])
8029 p++; 8049 p++;
8030 *enddir++ = *p++; 8050 *enddir++ = *p++;
8031 } while (p < start); 8051 } while (p < start);
@@ -8473,15 +8493,15 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
8473 8493
8474 /* Map to POSIX errors */ 8494 /* Map to POSIX errors */
8475 switch (e) { 8495 switch (e) {
8476 case EACCES: 8496 default:
8477 exerrno = 126; 8497 exerrno = 126;
8478 break; 8498 break;
8499 case ELOOP:
8500 case ENAMETOOLONG:
8479 case ENOENT: 8501 case ENOENT:
8502 case ENOTDIR:
8480 exerrno = 127; 8503 exerrno = 127;
8481 break; 8504 break;
8482 default:
8483 exerrno = 2;
8484 break;
8485 } 8505 }
8486 exitstatus = exerrno; 8506 exitstatus = exerrno;
8487 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n", 8507 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
@@ -10083,9 +10103,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
10083 shellparam.optind = 1; 10103 shellparam.optind = 1;
10084 shellparam.optoff = -1; 10104 shellparam.optoff = -1;
10085#endif 10105#endif
10086 pushlocalvars();
10087 evaltree(func->n.ndefun.body, flags & EV_TESTED); 10106 evaltree(func->n.ndefun.body, flags & EV_TESTED);
10088 poplocalvars(0);
10089 funcdone: 10107 funcdone:
10090 INT_OFF; 10108 INT_OFF;
10091 funcline = savefuncline; 10109 funcline = savefuncline;
@@ -10413,6 +10431,7 @@ find_builtin(const char *name)
10413/* 10431/*
10414 * Execute a simple command. 10432 * Execute a simple command.
10415 */ 10433 */
10434static void unwindfiles(struct parsefile *stop);
10416static int 10435static int
10417isassignment(const char *p) 10436isassignment(const char *p)
10418{ 10437{
@@ -10436,6 +10455,7 @@ evalcommand(union node *cmd, int flags)
10436 "\0\0", bltincmd /* why three NULs? */ 10455 "\0\0", bltincmd /* why three NULs? */
10437 }; 10456 };
10438 struct localvar_list *localvar_stop; 10457 struct localvar_list *localvar_stop;
10458 struct parsefile *file_stop;
10439 struct redirtab *redir_stop; 10459 struct redirtab *redir_stop;
10440 struct stackmark smark; 10460 struct stackmark smark;
10441 union node *argp; 10461 union node *argp;
@@ -10461,6 +10481,7 @@ evalcommand(union node *cmd, int flags)
10461 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 10481 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
10462 setstackmark(&smark); 10482 setstackmark(&smark);
10463 localvar_stop = pushlocalvars(); 10483 localvar_stop = pushlocalvars();
10484 file_stop = g_parsefile;
10464 back_exitstatus = 0; 10485 back_exitstatus = 0;
10465 10486
10466 cmdentry.cmdtype = CMDBUILTIN; 10487 cmdentry.cmdtype = CMDBUILTIN;
@@ -10742,7 +10763,6 @@ evalcommand(union node *cmd, int flags)
10742 goto readstatus; 10763 goto readstatus;
10743 10764
10744 case CMDFUNCTION: 10765 case CMDFUNCTION:
10745 poplocalvars(1);
10746 /* See above for the rationale */ 10766 /* See above for the rationale */
10747 dowait(DOWAIT_NONBLOCK, NULL); 10767 dowait(DOWAIT_NONBLOCK, NULL);
10748 if (evalfun(cmdentry.u.func, argc, argv, flags)) 10768 if (evalfun(cmdentry.u.func, argc, argv, flags))
@@ -10756,6 +10776,7 @@ evalcommand(union node *cmd, int flags)
10756 if (cmd->ncmd.redirect) 10776 if (cmd->ncmd.redirect)
10757 popredir(/*drop:*/ cmd_is_exec); 10777 popredir(/*drop:*/ cmd_is_exec);
10758 unwindredir(redir_stop); 10778 unwindredir(redir_stop);
10779 unwindfiles(file_stop);
10759 unwindlocalvars(localvar_stop); 10780 unwindlocalvars(localvar_stop);
10760 if (lastarg) { 10781 if (lastarg) {
10761 /* dsl: I think this is intended to be used to support 10782 /* dsl: I think this is intended to be used to support
@@ -11278,14 +11299,20 @@ popfile(void)
11278 INT_ON; 11299 INT_ON;
11279} 11300}
11280 11301
11302static void
11303unwindfiles(struct parsefile *stop)
11304{
11305 while (g_parsefile != stop)
11306 popfile();
11307}
11308
11281/* 11309/*
11282 * Return to top level. 11310 * Return to top level.
11283 */ 11311 */
11284static void 11312static void
11285popallfiles(void) 11313popallfiles(void)
11286{ 11314{
11287 while (g_parsefile != &basepf) 11315 unwindfiles(&basepf);
11288 popfile();
11289} 11316}
11290 11317
11291#if !ENABLE_PLATFORM_MINGW32 11318#if !ENABLE_PLATFORM_MINGW32
@@ -12929,7 +12956,7 @@ parsesub: {
12929 STPUTC(c, out); 12956 STPUTC(c, out);
12930 c = pgetc_eatbnl(); 12957 c = pgetc_eatbnl();
12931 } while (isdigit(c)); 12958 } while (isdigit(c));
12932 } else { 12959 } else if (c != '}') {
12933 /* $[{[#]]<specialchar>[}] */ 12960 /* $[{[#]]<specialchar>[}] */
12934 int cc = c; 12961 int cc = c;
12935 12962
@@ -12955,7 +12982,8 @@ parsesub: {
12955 } 12982 }
12956 12983
12957 USTPUTC(cc, out); 12984 USTPUTC(cc, out);
12958 } 12985 } else
12986 goto badsub;
12959 12987
12960 if (c != '}' && subtype == VSLENGTH) { 12988 if (c != '}' && subtype == VSLENGTH) {
12961 /* ${#VAR didn't end with } */ 12989 /* ${#VAR didn't end with } */
@@ -14297,38 +14325,35 @@ letcmd(int argc UNUSED_PARAM, char **argv)
14297static int FAST_FUNC 14325static int FAST_FUNC
14298readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 14326readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14299{ 14327{
14300 char *opt_n = NULL; 14328 struct builtin_read_params params;
14301 char *opt_p = NULL;
14302 char *opt_t = NULL;
14303 char *opt_u = NULL;
14304 char *opt_d = NULL; /* optimized out if !BASH */
14305 int read_flags = 0;
14306 const char *r; 14329 const char *r;
14307 int i; 14330 int i;
14308 14331
14332 memset(&params, 0, sizeof(params));
14333
14309 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') { 14334 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
14310 switch (i) { 14335 switch (i) {
14311 case 'p': 14336 case 'p':
14312 opt_p = optionarg; 14337 params.opt_p = optionarg;
14313 break; 14338 break;
14314 case 'n': 14339 case 'n':
14315 opt_n = optionarg; 14340 params.opt_n = optionarg;
14316 break; 14341 break;
14317 case 's': 14342 case 's':
14318 read_flags |= BUILTIN_READ_SILENT; 14343 params.read_flags |= BUILTIN_READ_SILENT;
14319 break; 14344 break;
14320 case 't': 14345 case 't':
14321 opt_t = optionarg; 14346 params.opt_t = optionarg;
14322 break; 14347 break;
14323 case 'r': 14348 case 'r':
14324 read_flags |= BUILTIN_READ_RAW; 14349 params.read_flags |= BUILTIN_READ_RAW;
14325 break; 14350 break;
14326 case 'u': 14351 case 'u':
14327 opt_u = optionarg; 14352 params.opt_u = optionarg;
14328 break; 14353 break;
14329#if BASH_READ_D 14354#if BASH_READ_D
14330 case 'd': 14355 case 'd':
14331 opt_d = optionarg; 14356 params.opt_d = optionarg;
14332 break; 14357 break;
14333#endif 14358#endif
14334 default: 14359 default:
@@ -14336,21 +14361,16 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14336 } 14361 }
14337 } 14362 }
14338 14363
14364 params.argv = argptr;
14365 params.setvar = setvar0;
14366 params.ifs = bltinlookup("IFS"); /* can be NULL */
14367
14339 /* "read -s" needs to save/restore termios, can't allow ^C 14368 /* "read -s" needs to save/restore termios, can't allow ^C
14340 * to jump out of it. 14369 * to jump out of it.
14341 */ 14370 */
14342 again: 14371 again:
14343 INT_OFF; 14372 INT_OFF;
14344 r = shell_builtin_read(setvar0, 14373 r = shell_builtin_read(&params);
14345 argptr,
14346 bltinlookup("IFS"), /* can be NULL */
14347 read_flags,
14348 opt_n,
14349 opt_p,
14350 opt_t,
14351 opt_u,
14352 opt_d
14353 );
14354 INT_ON; 14374 INT_ON;
14355 14375
14356 if ((uintptr_t)r == 1 && errno == EINTR) { 14376 if ((uintptr_t)r == 1 && errno == EINTR) {
@@ -14595,6 +14615,7 @@ init(void)
14595 } 14615 }
14596 } 14616 }
14597 14617
14618 setvareq((char*)defifsvar, VTEXTFIXED);
14598 setvareq((char*)defoptindvar, VTEXTFIXED); 14619 setvareq((char*)defoptindvar, VTEXTFIXED);
14599 14620
14600 setvar0("PPID", utoa(getppid())); 14621 setvar0("PPID", utoa(getppid()));