From 4135a75ab05f2546f4f9e9b3e69d71f477efc1e8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Oct 2016 13:15:35 +0200 Subject: typo fixes Signed-off-by: Denys Vlasenko --- shell/ash_test/ash-signals/return_in_trap1.tests | 4 ++-- shell/hush_test/hush-signals/return_in_trap1.tests | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'shell') diff --git a/shell/ash_test/ash-signals/return_in_trap1.tests b/shell/ash_test/ash-signals/return_in_trap1.tests index f2498024f..4c0d53bde 100755 --- a/shell/ash_test/ash-signals/return_in_trap1.tests +++ b/shell/ash_test/ash-signals/return_in_trap1.tests @@ -11,8 +11,8 @@ a echo d:$? # It's debatable what is the correct value above. -# Does 'return' in trap sees $? == 2 or $? == 3? +# Does 'return' in trap see $? == 2 or $? == 3? # IOW: after (kill..), does shell first wait for its completion # and sets $?, then checks pending signals and runs a trap handler, -# or does it first checks pending signals and runs handler? +# or does it first check pending signals and runs handler? # hush does the former, and prints 3. diff --git a/shell/hush_test/hush-signals/return_in_trap1.tests b/shell/hush_test/hush-signals/return_in_trap1.tests index f2498024f..4c0d53bde 100755 --- a/shell/hush_test/hush-signals/return_in_trap1.tests +++ b/shell/hush_test/hush-signals/return_in_trap1.tests @@ -11,8 +11,8 @@ a echo d:$? # It's debatable what is the correct value above. -# Does 'return' in trap sees $? == 2 or $? == 3? +# Does 'return' in trap see $? == 2 or $? == 3? # IOW: after (kill..), does shell first wait for its completion # and sets $?, then checks pending signals and runs a trap handler, -# or does it first checks pending signals and runs handler? +# or does it first check pending signals and runs handler? # hush does the former, and prints 3. -- cgit v1.2.3-55-g6feb From 647746076a24a50670a7fab38917606e0ac98be7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Oct 2016 15:24:30 +0200 Subject: ash: [REDIR] Replace copyfd by savefd and use dup2 elsewhere Upstream commit: Date: Sat, 12 May 2007 18:00:57 +1000 [REDIR] Replace copyfd by savefd and use dup2 elsewhere There are two kinds of users to copyfd, those that want to copy an fd to an exact value and those that want to move an fd to a value >= 10. The former can simply use dup2 directly while the latter share a lot of common code that now constitutes savefd. This does not change much, just reducing our divergence from dash code. Signed-off-by: Denys Vlasenko --- shell/ash.c | 58 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 27 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 647fc81b4..0490f7f7d 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -3760,12 +3760,12 @@ setjobctl(int on) if (--fd < 0) goto out; } + /* fd is a tty at this point */ fd = fcntl(fd, F_DUPFD, 10); - if (ofd >= 0) + if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, dont */ close(ofd); if (fd < 0) - goto out; - /* fd is a tty at this point */ + goto out; /* F_DUPFD failed */ close_on_exec_on(fd); while (1) { /* while we are in the background */ pgrp = tcgetpgrp(fd); @@ -5181,26 +5181,31 @@ openredirect(union node *redir) } /* - * Copy a file descriptor to be >= to. Throws exception on error. + * Copy a file descriptor to be >= 10. Throws exception on error. */ -/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD). - * old code was doing close(to) prior to copyfd() to achieve the same */ -enum { - COPYFD_EXACT = (int)~(INT_MAX), - COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1), -}; static int -copyfd(int from, int to) +savefd(int from) { int newfd; + int err; - if (to & COPYFD_EXACT) { - to &= ~COPYFD_EXACT; - /*if (from != to)*/ - newfd = dup2(from, to); - } else { - newfd = fcntl(from, F_DUPFD, to); + newfd = fcntl(from, F_DUPFD, 10); + err = newfd < 0 ? errno : 0; + if (err != EBADF) { + if (err) + ash_msg_and_raise_error("%d: %m", from); + close(from); + fcntl(newfd, F_SETFD, FD_CLOEXEC); } + + return newfd; +} +static int +dup2_or_raise(int from, int to) +{ + int newfd; + + newfd = (from != to) ? dup2(from, to) : to; if (newfd < 0) { /* Happens when source fd is not open: try "echo >&99" */ ash_msg_and_raise_error("%d: %m", from); @@ -5218,6 +5223,9 @@ struct redirtab { struct two_fd_t two_fd[]; }; #define redirlist (G_var.redirlist) +enum { + COPYFD_RESTORE = (int)~(INT_MAX), +}; static int need_to_remember(struct redirtab *rp, int fd) @@ -5391,10 +5399,10 @@ redirect(union node *redir, int flags) if (fd != -1) close(fd); } else { - copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT); + dup2_or_raise(redir->ndup.dupfd, fd); } } else if (fd != newfd) { /* move newfd to fd */ - copyfd(newfd, fd | COPYFD_EXACT); + dup2_or_raise(newfd, fd); #if ENABLE_ASH_BASH_COMPAT if (!(redir->nfile.type == NTO2 && fd == 2)) #endif @@ -5440,7 +5448,7 @@ popredir(int drop, int restore) if (!drop || (restore && (copy & COPYFD_RESTORE))) { copy &= ~COPYFD_RESTORE; /*close(fd);*/ - copyfd(copy, fd | COPYFD_EXACT); + dup2_or_raise(copy, fd); } close(copy & ~COPYFD_RESTORE); } @@ -5894,7 +5902,7 @@ evalbackcmd(union node *n, struct backcmd *result) close(pip[0]); if (pip[1] != 1) { /*close(1);*/ - copyfd(pip[1], 1 | COPYFD_EXACT); + dup2_or_raise(pip[1], 1); close(pip[1]); } /* TODO: eflag clearing makes the following not abort: @@ -10204,7 +10212,6 @@ static int setinputfile(const char *fname, int flags) { int fd; - int fd2; INT_OFF; fd = open(fname, O_RDONLY); @@ -10214,11 +10221,8 @@ setinputfile(const char *fname, int flags) exitstatus = 127; ash_msg_and_raise_error("can't open '%s'", fname); } - if (fd < 10) { - fd2 = copyfd(fd, 10); - close(fd); - fd = fd2; - } + if (fd < 10) + fd = savefd(fd); setinputfd(fd, flags & INPUT_PUSH_FILE); out: INT_ON; -- cgit v1.2.3-55-g6feb From e19923f6652a638ac39c84012e97f52cf5a7568e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Oct 2016 15:38:44 +0200 Subject: ash: [REDIR] Remove redundant CLOEXEC calls Upstream commit: Date: Sun, 6 May 2007 19:28:56 +1000 [REDIR] Remove redundant CLOEXEC calls Now that we're marking file descriptors as CLOEXEC in savefd, we no longer need to close them on exec or in setinputfd. function old new delta ash_main 1478 1492 +14 setinputfile 224 226 +2 readtoken1 2752 2750 -2 shellexec 208 198 -10 clearredir 30 - -30 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 2/2 up/down: 16/-42) Total: -26 bytes Signed-off-by: Denys Vlasenko --- shell/ash.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 0490f7f7d..b404449d0 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -5462,16 +5462,6 @@ popredir(int drop, int restore) * Undo all redirections. Called on error or interrupt. */ -/* - * Discard all saved file descriptors. - */ -static void -clearredir(int drop) -{ - while (redirlist) - popredir(drop, /*restore:*/ 0); -} - static int redirectsafe(union node *redir, int flags) { @@ -7559,7 +7549,6 @@ shellexec(char **argv, const char *path, int idx) int exerrno; int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ - clearredir(/*drop:*/ 1); envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); if (strchr(argv[0], '/') != NULL #if ENABLE_FEATURE_SH_STANDALONE @@ -10191,7 +10180,6 @@ closescript(void) static void setinputfd(int fd, int push) { - close_on_exec_on(fd); if (push) { pushfile(); g_parsefile->buf = NULL; @@ -10223,6 +10211,8 @@ setinputfile(const char *fname, int flags) } if (fd < 10) fd = savefd(fd); + else + close_on_exec_on(fd); setinputfd(fd, flags & INPUT_PUSH_FILE); out: INT_ON; @@ -13339,7 +13329,8 @@ reset(void) tokpushback = 0; checkkwd = 0; /* from redir.c: */ - clearredir(/*drop:*/ 0); + while (redirlist) + popredir(/*drop:*/ 0, /*restore:*/ 0); } #if PROFILE -- cgit v1.2.3-55-g6feb From f15aa57a7f5edcbf3098873b8798c0ea7f496ed7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Oct 2016 15:56:53 +0200 Subject: ash: [PARSER] Fix parsing of ${##1} Upstream commit: Date: Thu, 4 Oct 2007 22:15:10 +0800 [PARSER] Fix parsing of ${##1} Previously dash treated ${##1} as a length operation. This patch fixes that. Test case: set -- a echo ${##1}OK Old result: 1OK New result: OK This was a real bug in ash (but not in hush). Signed-off-by: Denys Vlasenko --- shell/ash.c | 28 +++++++++++++++--------- shell/ash_test/ash-vars/param_expand_len.right | 3 +++ shell/ash_test/ash-vars/param_expand_len.tests | 7 ++++++ shell/hush_test/hush-vars/param_expand_len.right | 3 +++ shell/hush_test/hush-vars/param_expand_len.tests | 7 ++++++ 5 files changed, 38 insertions(+), 10 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index b404449d0..2cebfe2c0 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -11728,16 +11728,9 @@ parsesub: { subtype = VSNORMAL; if (c == '{') { c = pgetc_eatbnl(); - if (c == '#') { - c = pgetc_eatbnl(); - if (c == '}') - c = '#'; /* ${#} - same as $# */ - else - subtype = VSLENGTH; /* ${#VAR} */ - } else { - subtype = 0; - } + subtype = 0; } + varname: if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) { /* $[{[#]]NAME[}] */ do { @@ -11752,8 +11745,23 @@ parsesub: { } while (isdigit(c)); } else if (is_special(c)) { /* $[{[#]][}] */ - USTPUTC(c, out); + int cc = c; + c = pgetc_eatbnl(); + if (!subtype && cc == '#') { + subtype = VSLENGTH; + if (c == '_' || isalnum(c)) + goto varname; + cc = c; + c = pgetc_eatbnl(); + if (cc == '}' || c != '}') { + pungetc(); + subtype = 0; + c = cc; + cc = '#'; + } + } + USTPUTC(cc, out); } else { goto badsub; } diff --git a/shell/ash_test/ash-vars/param_expand_len.right b/shell/ash_test/ash-vars/param_expand_len.right index 96e8cb59b..48d01d2fe 100644 --- a/shell/ash_test/ash-vars/param_expand_len.right +++ b/shell/ash_test/ash-vars/param_expand_len.right @@ -7,3 +7,6 @@ Make sure len parsing doesnt break arg count Testing len op 4 3 2 1 0 0 0 3 0 +Nothing: +Nothing: +One:1 diff --git a/shell/ash_test/ash-vars/param_expand_len.tests b/shell/ash_test/ash-vars/param_expand_len.tests index fe20a45e9..369c8d456 100755 --- a/shell/ash_test/ash-vars/param_expand_len.tests +++ b/shell/ash_test/ash-vars/param_expand_len.tests @@ -15,3 +15,10 @@ unset e f=abc g= echo ${#e} ${#f} ${#g} + +set -- a +# This must be interpreted as: $# ("1"), then remove trailing "1". +# IOW: empty result. +echo Nothing:${##1} +echo Nothing:${#%1} +echo One:${##x} diff --git a/shell/hush_test/hush-vars/param_expand_len.right b/shell/hush_test/hush-vars/param_expand_len.right index 96e8cb59b..48d01d2fe 100644 --- a/shell/hush_test/hush-vars/param_expand_len.right +++ b/shell/hush_test/hush-vars/param_expand_len.right @@ -7,3 +7,6 @@ Make sure len parsing doesnt break arg count Testing len op 4 3 2 1 0 0 0 3 0 +Nothing: +Nothing: +One:1 diff --git a/shell/hush_test/hush-vars/param_expand_len.tests b/shell/hush_test/hush-vars/param_expand_len.tests index fe20a45e9..369c8d456 100755 --- a/shell/hush_test/hush-vars/param_expand_len.tests +++ b/shell/hush_test/hush-vars/param_expand_len.tests @@ -15,3 +15,10 @@ unset e f=abc g= echo ${#e} ${#f} ${#g} + +set -- a +# This must be interpreted as: $# ("1"), then remove trailing "1". +# IOW: empty result. +echo Nothing:${##1} +echo Nothing:${#%1} +echo One:${##x} -- cgit v1.2.3-55-g6feb From 350e686f3b04f41f623316706094f0e18a10c1cf Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Oct 2016 16:26:45 +0200 Subject: ash: [PARSER] Recognise here-doc delimiters terminated by EOF Upstream commit 1: Date: Wed, 26 Sep 2007 17:14:16 +0800 [PARSER] Recognise here-doc delimiters terminated by EOF Previously dash required a character to be present in order for a here-document delimiter to be detected. Allowing EOF in the absence of a to play the same purpose allows some intuitive scripts to succeed. POSIX seems to be silence on this so this should be OK. Test case: eval 'cat <<- NOT test NOT' echo OK Old result: test NOTOK New result: test OK Upstream commit 2: Date: Sat, 20 Oct 2007 18:49:31 +0800 [PARSER] Fix here-doc corruption The change [PARSER] Recognise here-doc delimiters terminated by EOF introduced a regerssion whereby lines starting with eofmark but are not equal to eofmark would be corrupted. This patch fixes it. Test case: cat << _ACEOF _ASBOX _ACEOF Old result: SASBOX New result: _ASBOX Signed-off-by: Denys Vlasenko --- shell/ash.c | 12 +++++++++--- shell/ash_test/ash-heredoc/heredoc6.right | 2 ++ shell/ash_test/ash-heredoc/heredoc6.tests | 4 ++++ shell/ash_test/ash-heredoc/heredoc7.right | 1 + shell/ash_test/ash-heredoc/heredoc7.tests | 3 +++ shell/hush_test/hush-heredoc/heredoc6.right | 2 ++ shell/hush_test/hush-heredoc/heredoc6.tests | 4 ++++ shell/hush_test/hush-heredoc/heredoc7.right | 1 + shell/hush_test/hush-heredoc/heredoc7.tests | 3 +++ 9 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 shell/ash_test/ash-heredoc/heredoc6.right create mode 100755 shell/ash_test/ash-heredoc/heredoc6.tests create mode 100644 shell/ash_test/ash-heredoc/heredoc7.right create mode 100755 shell/ash_test/ash-heredoc/heredoc7.tests create mode 100644 shell/hush_test/hush-heredoc/heredoc6.right create mode 100755 shell/hush_test/hush-heredoc/heredoc6.tests create mode 100644 shell/hush_test/hush-heredoc/heredoc7.right create mode 100755 shell/hush_test/hush-heredoc/heredoc7.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 2cebfe2c0..e0828d4a7 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -11592,11 +11592,17 @@ checkend: { if (c == *eofmark) { if (pfgets(line, sizeof(line)) != NULL) { char *p, *q; + int cc; p = line; - for (q = eofmark + 1; *q && *p == *q; p++, q++) - continue; - if (*p == '\n' && *q == '\0') { + for (q = eofmark + 1;; p++, q++) { + cc = *p; + if (cc == '\n') + cc = 0; + if (!*q || cc != *q) + break; + } + if (cc == *q) { c = PEOF; nlnoprompt(); } else { diff --git a/shell/ash_test/ash-heredoc/heredoc6.right b/shell/ash_test/ash-heredoc/heredoc6.right new file mode 100644 index 000000000..5d0f077cd --- /dev/null +++ b/shell/ash_test/ash-heredoc/heredoc6.right @@ -0,0 +1,2 @@ +test +OK:0 diff --git a/shell/ash_test/ash-heredoc/heredoc6.tests b/shell/ash_test/ash-heredoc/heredoc6.tests new file mode 100755 index 000000000..346f5949a --- /dev/null +++ b/shell/ash_test/ash-heredoc/heredoc6.tests @@ -0,0 +1,4 @@ +eval 'cat <<- NOT +test +NOT' +echo OK:$? diff --git a/shell/ash_test/ash-heredoc/heredoc7.right b/shell/ash_test/ash-heredoc/heredoc7.right new file mode 100644 index 000000000..5d9c6c6c0 --- /dev/null +++ b/shell/ash_test/ash-heredoc/heredoc7.right @@ -0,0 +1 @@ +_ASBOX diff --git a/shell/ash_test/ash-heredoc/heredoc7.tests b/shell/ash_test/ash-heredoc/heredoc7.tests new file mode 100755 index 000000000..abd5941d9 --- /dev/null +++ b/shell/ash_test/ash-heredoc/heredoc7.tests @@ -0,0 +1,3 @@ +cat << _ACEOF +_ASBOX +_ACEOF diff --git a/shell/hush_test/hush-heredoc/heredoc6.right b/shell/hush_test/hush-heredoc/heredoc6.right new file mode 100644 index 000000000..5d0f077cd --- /dev/null +++ b/shell/hush_test/hush-heredoc/heredoc6.right @@ -0,0 +1,2 @@ +test +OK:0 diff --git a/shell/hush_test/hush-heredoc/heredoc6.tests b/shell/hush_test/hush-heredoc/heredoc6.tests new file mode 100755 index 000000000..346f5949a --- /dev/null +++ b/shell/hush_test/hush-heredoc/heredoc6.tests @@ -0,0 +1,4 @@ +eval 'cat <<- NOT +test +NOT' +echo OK:$? diff --git a/shell/hush_test/hush-heredoc/heredoc7.right b/shell/hush_test/hush-heredoc/heredoc7.right new file mode 100644 index 000000000..5d9c6c6c0 --- /dev/null +++ b/shell/hush_test/hush-heredoc/heredoc7.right @@ -0,0 +1 @@ +_ASBOX diff --git a/shell/hush_test/hush-heredoc/heredoc7.tests b/shell/hush_test/hush-heredoc/heredoc7.tests new file mode 100755 index 000000000..abd5941d9 --- /dev/null +++ b/shell/hush_test/hush-heredoc/heredoc7.tests @@ -0,0 +1,3 @@ +cat << _ACEOF +_ASBOX +_ACEOF -- cgit v1.2.3-55-g6feb From 3df1410a00a7a57f3a43373c00cdea2031d7d70c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Oct 2016 16:41:13 +0200 Subject: ash: [PARSER] Size optimisations in parameter expansion parser Upstream commit: Date: Thu, 4 Oct 2007 22:20:38 +0800 [PARSER] Size optimisations in parameter expansion parser Merge flags into subtype. Do not write subtype out twice. Add likely flag on ${ vs. $NAME. Kill unnecessary (and bogus) PEOA check. function old new delta readtoken1 2891 2860 -31 Signed-off-by: Denys Vlasenko --- shell/ash.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index e0828d4a7..21373b65a 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -11701,7 +11701,6 @@ parseredir: { parsesub: { unsigned char subtype; int typeloc; - int flags = 0; c = pgetc_eatbnl(); if (c > 255 /* PEOA or PEOF */ @@ -11730,19 +11729,19 @@ parsesub: { /* $VAR, $, ${...}, or PEOA/PEOF */ USTPUTC(CTLVAR, out); typeloc = out - (char *)stackblock(); - USTPUTC(VSNORMAL, out); + STADJUST(1, out); subtype = VSNORMAL; if (c == '{') { c = pgetc_eatbnl(); subtype = 0; } varname: - if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) { + if (is_name(c)) { /* $[{[#]]NAME[}] */ do { STPUTC(c, out); c = pgetc_eatbnl(); - } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c)); + } while (is_in_name(c)); } else if (isdigit(c)) { /* $[{[#]]NUM[}] */ do { @@ -11776,7 +11775,6 @@ parsesub: { goto badsub; } - flags = 0; if (subtype == 0) { static const char types[] ALIGN1 = "}-+?="; /* ${VAR...} but not $VAR or ${#VAR} */ @@ -11795,13 +11793,13 @@ parsesub: { break; /* "goto badsub" is bigger (!) */ } #endif - flags = VSNUL; + subtype = VSNUL; /*FALLTHROUGH*/ default: { const char *p = strchr(types, c); if (p == NULL) break; - subtype = p - types + VSNORMAL; + subtype |= p - types + VSNORMAL; break; } case '%': @@ -11831,12 +11829,11 @@ parsesub: { badsub: pungetc(); } - ((unsigned char *)stackblock())[typeloc] = subtype | flags; + ((unsigned char *)stackblock())[typeloc] = subtype; if (subtype != VSNORMAL) { varnest++; - if (dblquote) { + if (dblquote) dqvarnest++; - } } STPUTC('=', out); } -- cgit v1.2.3-55-g6feb From 35c2a136cd74402932d94ca69bd5f69ca900d83f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Oct 2016 17:34:26 +0200 Subject: ash: use shellparam.optind/optoff in getopts() directly, not through pointers This is a preparatory patch for next change Signed-off-by: Denys Vlasenko --- shell/ash.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 21373b65a..3effa0c81 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -10554,7 +10554,7 @@ change_random(const char *value) #if ENABLE_ASH_GETOPTS static int -getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff) +getopts(char *optstr, char *optvar, char **optfirst) { char *p, *q; char c = '?'; @@ -10565,12 +10565,15 @@ getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *opt sbuf[1] = '\0'; - optnext = optfirst + *param_optind - 1; + optnext = optfirst + shellparam.optind - 1; - if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff) + if (shellparam.optind <= 1 + || shellparam.optoff < 0 + || (int)strlen(optnext[-1]) < shellparam.optoff + ) { p = NULL; - else - p = optnext[-1] + *optoff; + } else + p = optnext[-1] + shellparam.optoff; if (p == NULL || *p == '\0') { /* Current word is done, advance */ p = *optnext; @@ -10625,15 +10628,15 @@ getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *opt } else err |= setvarsafe("OPTARG", nullstr, 0); out: - *optoff = p ? p - *(optnext - 1) : -1; - *param_optind = optnext - optfirst + 1; - err |= setvarsafe("OPTIND", itoa(*param_optind), VNOFUNC); + shellparam.optoff = p ? p - *(optnext - 1) : -1; + shellparam.optind = optnext - optfirst + 1; + err |= setvarsafe("OPTIND", itoa(shellparam.optind), VNOFUNC); sbuf[0] = c; /*sbuf[1] = '\0'; - already is */ err |= setvarsafe(optvar, sbuf, 0); if (err) { - *param_optind = 1; - *optoff = -1; + shellparam.optind = 1; + shellparam.optoff = -1; flush_stdout_stderr(); raise_exception(EXERROR); } @@ -10667,8 +10670,7 @@ getoptscmd(int argc, char **argv) } } - return getopts(argv[1], argv[2], optbase, &shellparam.optind, - &shellparam.optoff); + return getopts(argv[1], argv[2], optbase); } #endif /* ASH_GETOPTS */ -- cgit v1.2.3-55-g6feb From dbef38a74b825c15dcce737fab51c594d93b6d59 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Oct 2016 17:54:32 +0200 Subject: ash: [VAR] Remove setvarsafe Upstream commit: Date: Sat, 6 Oct 2007 21:18:58 +0800 [VAR] Remove setvarsafe The only user of setvarsafe is getopts. However, we can achieve the same result by pre-setting the value of shellparam.optind. function old new delta getoptscmd 614 515 -99 setvarsafe 147 - -147 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 0/1 up/down: 0/-246) Total: -246 bytes Signed-off-by: Denys Vlasenko --- shell/ash.c | 70 ++++++++++++++++++------------------------------------------- 1 file changed, 20 insertions(+), 50 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 3effa0c81..2c439602a 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -2258,32 +2258,6 @@ setvar0(const char *name, const char *val) setvar(name, val, 0); } -#if ENABLE_ASH_GETOPTS -/* - * Safe version of setvar, returns 1 on success 0 on failure. - */ -static int -setvarsafe(const char *name, const char *val, int flags) -{ - int err; - volatile int saveint; - struct jmploc *volatile savehandler = exception_handler; - struct jmploc jmploc; - - SAVE_INT(saveint); - if (setjmp(jmploc.loc)) - err = 1; - else { - exception_handler = &jmploc; - setvar(name, val, flags); - err = 0; - } - exception_handler = savehandler; - RESTORE_INT(saveint); - return err; -} -#endif - /* * Unset the specified variable. */ @@ -10559,21 +10533,20 @@ getopts(char *optstr, char *optvar, char **optfirst) char *p, *q; char c = '?'; int done = 0; - int err = 0; char sbuf[2]; char **optnext; + int ind = shellparam.optind; + int off = shellparam.optoff; sbuf[1] = '\0'; - optnext = optfirst + shellparam.optind - 1; + shellparam.optind = -1; + optnext = optfirst + ind - 1; - if (shellparam.optind <= 1 - || shellparam.optoff < 0 - || (int)strlen(optnext[-1]) < shellparam.optoff - ) { + if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off) p = NULL; - } else - p = optnext[-1] + shellparam.optoff; + else + p = optnext[-1] + off; if (p == NULL || *p == '\0') { /* Current word is done, advance */ p = *optnext; @@ -10594,7 +10567,7 @@ getopts(char *optstr, char *optvar, char **optfirst) if (optstr[0] == ':') { sbuf[0] = c; /*sbuf[1] = '\0'; - already is */ - err |= setvarsafe("OPTARG", sbuf, 0); + setvar0("OPTARG", sbuf); } else { fprintf(stderr, "Illegal option -%c\n", c); unsetvar("OPTARG"); @@ -10611,7 +10584,7 @@ getopts(char *optstr, char *optvar, char **optfirst) if (optstr[0] == ':') { sbuf[0] = c; /*sbuf[1] = '\0'; - already is */ - err |= setvarsafe("OPTARG", sbuf, 0); + setvar0("OPTARG", sbuf); c = ':'; } else { fprintf(stderr, "No arg for -%c option\n", c); @@ -10623,23 +10596,20 @@ getopts(char *optstr, char *optvar, char **optfirst) if (p == *optnext) optnext++; - err |= setvarsafe("OPTARG", p, 0); + setvar0("OPTARG", p); p = NULL; } else - err |= setvarsafe("OPTARG", nullstr, 0); + setvar0("OPTARG", nullstr); out: - shellparam.optoff = p ? p - *(optnext - 1) : -1; - shellparam.optind = optnext - optfirst + 1; - err |= setvarsafe("OPTIND", itoa(shellparam.optind), VNOFUNC); + ind = optnext - optfirst + 1; + setvar("OPTIND", itoa(ind), VNOFUNC); sbuf[0] = c; /*sbuf[1] = '\0'; - already is */ - err |= setvarsafe(optvar, sbuf, 0); - if (err) { - shellparam.optind = 1; - shellparam.optoff = -1; - flush_stdout_stderr(); - raise_exception(EXERROR); - } + setvar0(optvar, sbuf); + + shellparam.optoff = p ? p - *(optnext - 1) : -1; + shellparam.optind = ind; + return done; } @@ -10658,13 +10628,13 @@ getoptscmd(int argc, char **argv) ash_msg_and_raise_error("usage: getopts optstring var [arg]"); if (argc == 3) { optbase = shellparam.p; - if (shellparam.optind > shellparam.nparam + 1) { + if ((unsigned)shellparam.optind > shellparam.nparam + 1) { shellparam.optind = 1; shellparam.optoff = -1; } } else { optbase = &argv[3]; - if (shellparam.optind > argc - 2) { + if ((unsigned)shellparam.optind > argc - 2) { shellparam.optind = 1; shellparam.optoff = -1; } -- cgit v1.2.3-55-g6feb From a318bba199a08d65c6fb804e26d0993068a4ba16 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Oct 2016 18:26:27 +0200 Subject: ash: [MEMALLOC] Made grabstackblock an inline wrapper for stalloc Upstream patch: Date: Fri, 5 Oct 2007 23:26:45 +0800 [MEMALLOC] Made grabstackblock an inline wrapper for stalloc The function grabstackblock is identical in semantics to stalloc within its input constraints. function old new delta dotcmd 319 321 +2 grabstackblock 19 5 -14 Signed-off-by: Denys Vlasenko --- shell/ash.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 2c439602a..e47c47850 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -1491,12 +1491,10 @@ sstrdup(const char *p) return memcpy(stalloc(len), p, len); } -static void +static inline void grabstackblock(size_t len) { - len = SHELL_ALIGN(len); - g_stacknxt += len; - g_stacknleft -= len; + stalloc(len); } static void -- cgit v1.2.3-55-g6feb From 0e081d01a8ae37df11af612eb65d858c1c0f28be Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Oct 2016 19:56:05 +0200 Subject: ash: [CD] Lookup PWD after going through CDPATH Upstream commit: Date: Mon, 31 Aug 2009 22:06:41 +1000 [CD] Lookup PWD after going through CDPATH On Tue, Jul 14, 2009 at 09:39:03PM +0000, Eric Blake wrote: > For the cd command, POSIX 2008 requires that after all pathnames in CDPATH > have been tested and failed in step 5, then step 6 interprets the directory > argument relative to PWD. In other words, this demonstrates a bug: > > $ dash -c 'cd /tmp; mkdir -p foo; CDPATH=oops; cd foo; echo $?; pwd' > cd: 1: can't cd to foo > 2 > /tmp > > while bash gets it correct: > > $ bash -c 'cd /tmp; mkdir -p foo; CDPATH=oops; cd foo; echo $?; pwd' > 0 > /tmp/foo This patch fixes the problem. Reported-by: Eric Blake Signed-off-by: Herbert Xu function old new delta cdcmd 667 680 +13 Signed-off-by: Denys Vlasenko --- shell/ash.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index e47c47850..8bf02e6a7 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -2638,7 +2638,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) if (!dest) dest = nullstr; if (*dest == '/') - goto step7; + goto step6; if (*dest == '.') { c = dest[1]; dotdot: @@ -2655,13 +2655,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) if (!*dest) dest = "."; path = bltinlookup("CDPATH"); - if (!path) { - step6: - step7: - p = dest; - goto docd; - } - do { + while (path) { c = *path; p = path_advance(&path, dest); if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { @@ -2670,9 +2664,15 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) docd: if (!docd(p, flags)) goto out; - break; + goto err; } - } while (path); + } + + step6: + p = dest; + goto docd; + + err: ash_msg_and_raise_error("can't cd to %s", dest); /* NOTREACHED */ out: -- cgit v1.2.3-55-g6feb From 65a8b859a9a3f2bb4a62c15ca1f4d01288593734 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Oct 2016 22:29:11 +0200 Subject: ash: optimize tryexec(): avoid one allocation There was a bug in tryexec which bbox had fixed in 2003. dash had a smaller fix in 2007. Copy it. It is smaller, although it is also more quirky (requires argv[-1] to exist). Upstream commit 1: Date: Mon, 15 Oct 2007 20:24:28 +0800 [EXEC] Fixed execing of scripts with no hash-bang The function tryexec used the original name instead of the path found through PATH search. This patch fixes that. Test case: trap 'rm -f $TMP' EXIT TMP=$(tempfile -s nosuchthing) cat <<- EOF > $TMP echo OK EOF chmod u+x $TMP cd / PATH=${TMP%/*} ${TMP##*/} Old result: /bin/sh: Can't open filelgY4Fanosuchthing New result: OK Upstream commit 2: Date: Sun, 23 Dec 2007 11:02:26 +0800 [EVAL] Fix bad pointer arithmetic in evalcommand dash dies on sparc with a SIGBUS due to an arithmetic error introduced with commit 03b4958, this patch fixes it. Signed-off-by: Herbert Xu function old new delta evalcommand 1261 1264 +3 dotcmd 321 319 -2 tryexec 115 64 -51 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/2 up/down: 3/-53) Total: -50 bytes Signed-off-by: Denys Vlasenko --- shell/ash.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 8bf02e6a7..133b2d40e 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7467,13 +7467,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** #else execve(cmd, argv, envp); #endif - if (cmd == (char*) bb_busybox_exec_path) { - /* We already visited ENOEXEC branch below, don't do it again */ -//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up? - free(argv); - return; - } - if (errno == ENOEXEC) { + if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) { /* Run "cmd" as a shell script: * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html * "If the execve() function fails with ENOEXEC, the shell @@ -7490,19 +7484,13 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** * message and exit code 126. For one, this prevents attempts * to interpret foreign ELF binaries as shell scripts. */ - char **ap; - char **new; - - for (ap = argv; *ap; ap++) - continue; - new = ckmalloc((ap - argv + 2) * sizeof(new[0])); - new[0] = (char*) "ash"; - new[1] = cmd; - ap = new + 2; - while ((*ap++ = *++argv) != NULL) - continue; + argv[0] = cmd; cmd = (char*) bb_busybox_exec_path; - argv = new; + /* NB: this is only possible because all callers of shellexec() + * ensure that the argv[-1] slot exists! + */ + argv--; + argv[0] = (char*) "ash"; goto repeat; } } @@ -7510,6 +7498,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** /* * Exec a program. Never returns. If you change this routine, you may * have to change the find_command routine as well. + * argv[-1] must exist and be writable! See tryexec() for why. */ static void shellexec(char **, const char *, int) NORETURN; static void @@ -9415,7 +9404,9 @@ evalcommand(union node *cmd, int flags) argc++; } - argv = nargv = stalloc(sizeof(char *) * (argc + 1)); + /* Reserve one extra spot at the front for shellexec. */ + nargv = stalloc(sizeof(char *) * (argc + 2)); + argv = ++nargv; for (sp = arglist.list; sp; sp = sp->next) { TRACE(("evalcommand arg: %s\n", sp->text)); *nargv++ = sp->text; -- cgit v1.2.3-55-g6feb From 70392331a98d266af539be4b910812fc7b0a72d4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 27 Oct 2016 02:31:55 +0200 Subject: ash: comment tweaks, no code changes Signed-off-by: Denys Vlasenko --- shell/ash.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 133b2d40e..864b8f0a4 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -2590,7 +2590,7 @@ setpwd(const char *val, int setold) static void hashcd(void); /* - * Actually do the chdir. We also call hashcd to let the routines in exec.c + * Actually do the chdir. We also call hashcd to let other routines * know that the current directory has changed. */ static int @@ -4679,6 +4679,7 @@ clear_traps(void) static void closescript(void); /* Called after fork(), in child */ +/* jp and n are NULL when called by openhere() for heredoc support */ static NOINLINE void forkchild(struct job *jp, union node *n, int mode) { @@ -4810,6 +4811,7 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) { TRACE(("In parent shell: child = %d\n", pid)); if (!jp) { + /* jp is NULL when called by openhere() for heredoc support */ while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) continue; jobless++; @@ -4843,6 +4845,7 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) } } +/* jp and n are NULL when called by openhere() for heredoc support */ static int forkshell(struct job *jp, union node *n, int mode) { @@ -4972,8 +4975,7 @@ stoppedjobs(void) } -/* ============ redir.c - * +/* * Code for dealing with input/output redirection. */ @@ -5860,6 +5862,7 @@ evalbackcmd(union node *n, struct backcmd *result) ash_msg_and_raise_error("pipe call failed"); jp = makejob(/*n,*/ 1); if (forkshell(jp, n, FORK_NOJOB) == 0) { + /* child */ FORCE_INT_ON; close(pip[0]); if (pip[1] != 1) { @@ -5879,6 +5882,7 @@ evalbackcmd(union node *n, struct backcmd *result) evaltree(n, EV_EXIT); /* actually evaltreenr... */ /* NOTREACHED */ } + /* parent */ close(pip[1]); result->fd = pip[0]; result->jp = jp; @@ -8764,6 +8768,7 @@ evalsubshell(union node *n, int flags) evaltreenr(n->nredir.n, flags); /* never returns */ } + /* parent */ status = 0; if (!backgnd) status = waitforjob(jp); @@ -8869,6 +8874,7 @@ evalpipe(union node *n, int flags) } } if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { + /* child */ INT_ON; if (pip[1] >= 0) { close(pip[0]); @@ -8884,6 +8890,7 @@ evalpipe(union node *n, int flags) evaltreenr(lp->n, flags); /* never returns */ } + /* parent */ if (prevfd >= 0) close(prevfd); prevfd = pip[0]; @@ -9702,8 +9709,7 @@ breakcmd(int argc UNUSED_PARAM, char **argv) } -/* ============ input.c - * +/* * This implements the input routines used by the parser. */ @@ -10198,8 +10204,7 @@ setinputstring(char *string) } -/* ============ mail.c - * +/* * Routines to check for mail. */ -- cgit v1.2.3-55-g6feb