diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-21 13:20:14 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-21 13:20:14 +0200 |
commit | 42ba757d5e80ba25cc192939aa3525049f9e092f (patch) | |
tree | c89b3d378eb9f98eed81466122e269554a81400a | |
parent | 168f0ef8ddb6c840662bd15bad86177b0d238120 (diff) | |
download | busybox-w32-42ba757d5e80ba25cc192939aa3525049f9e092f.tar.gz busybox-w32-42ba757d5e80ba25cc192939aa3525049f9e092f.tar.bz2 busybox-w32-42ba757d5e80ba25cc192939aa3525049f9e092f.zip |
ash: improve set -x to quote strings as necessary
Basen on the patch from Martijn Dekker <martijn@inlv.org>
function old new delta
evalcommand 1161 1302 +141
maybe_single_quote - 60 +60
getoptscmd 527 546 +19
readtoken1 2819 2823 +4
localcmd 366 364 -2
evaltreenr 495 479 -16
evaltree 495 479 -16
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 3/3 up/down: 224/-34) Total: 190 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | shell/ash.c | 81 | ||||
-rw-r--r-- | shell/ash_test/ash-quoting/mode_x.right | 10 | ||||
-rwxr-xr-x | shell/ash_test/ash-quoting/mode_x.tests | 14 |
3 files changed, 94 insertions, 11 deletions
diff --git a/shell/ash.c b/shell/ash.c index b28731eb1..a461bb7df 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -1742,7 +1742,7 @@ number(const char *s) | |||
1742 | } | 1742 | } |
1743 | 1743 | ||
1744 | /* | 1744 | /* |
1745 | * Produce a possibly single quoted string suitable as input to the shell. | 1745 | * Produce a single quoted string suitable as input to the shell. |
1746 | * The return string is allocated on the stack. | 1746 | * The return string is allocated on the stack. |
1747 | */ | 1747 | */ |
1748 | static char * | 1748 | static char * |
@@ -1786,6 +1786,47 @@ single_quote(const char *s) | |||
1786 | return stackblock(); | 1786 | return stackblock(); |
1787 | } | 1787 | } |
1788 | 1788 | ||
1789 | /* | ||
1790 | * Produce a possibly single quoted string suitable as input to the shell. | ||
1791 | * If 'conditional' is nonzero, quoting is only done if the string contains | ||
1792 | * non-shellsafe characters, or is identical to a shell keyword (reserved | ||
1793 | * word); if it is zero, quoting is always done. | ||
1794 | * If quoting was done, the return string is allocated on the stack, | ||
1795 | * otherwise a pointer to the original string is returned. | ||
1796 | */ | ||
1797 | static const char * | ||
1798 | maybe_single_quote(const char *s) | ||
1799 | { | ||
1800 | const char *p = s; | ||
1801 | |||
1802 | while (*p) { | ||
1803 | /* Assuming ACSII */ | ||
1804 | /* quote ctrl_chars space !"#$%&'()* */ | ||
1805 | if (*p < '+') | ||
1806 | goto need_quoting; | ||
1807 | /* quote ;<=>? */ | ||
1808 | if (*p >= ';' && *p <= '?') | ||
1809 | goto need_quoting; | ||
1810 | /* quote `[\ */ | ||
1811 | if (*p == '`') | ||
1812 | goto need_quoting; | ||
1813 | if (*p == '[') | ||
1814 | goto need_quoting; | ||
1815 | if (*p == '\\') | ||
1816 | goto need_quoting; | ||
1817 | /* quote {|}~ DEL and high bytes */ | ||
1818 | if (*p > 'z') | ||
1819 | goto need_quoting; | ||
1820 | /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */ | ||
1821 | /* TODO: maybe avoid quoting % */ | ||
1822 | p++; | ||
1823 | } | ||
1824 | return s; | ||
1825 | |||
1826 | need_quoting: | ||
1827 | return single_quote(s); | ||
1828 | } | ||
1829 | |||
1789 | 1830 | ||
1790 | /* ============ nextopt */ | 1831 | /* ============ nextopt */ |
1791 | 1832 | ||
@@ -9700,18 +9741,36 @@ evalcommand(union node *cmd, int flags) | |||
9700 | 9741 | ||
9701 | /* Print the command if xflag is set. */ | 9742 | /* Print the command if xflag is set. */ |
9702 | if (xflag) { | 9743 | if (xflag) { |
9703 | int n; | 9744 | const char *pfx = ""; |
9704 | const char *p = " %s" + 1; | 9745 | |
9746 | fdprintf(preverrout_fd, "%s", expandstr(ps4val())); | ||
9705 | 9747 | ||
9706 | fdprintf(preverrout_fd, p, expandstr(ps4val())); | ||
9707 | sp = varlist.list; | 9748 | sp = varlist.list; |
9708 | for (n = 0; n < 2; n++) { | 9749 | while (sp) { |
9709 | while (sp) { | 9750 | char *varval = sp->text; |
9710 | fdprintf(preverrout_fd, p, sp->text); | 9751 | char *eq = strchrnul(varval, '='); |
9711 | sp = sp->next; | 9752 | if (*eq) |
9712 | p = " %s"; | 9753 | eq++; |
9713 | } | 9754 | fdprintf(preverrout_fd, "%s%.*s%s", |
9714 | sp = arglist.list; | 9755 | pfx, |
9756 | (int)(eq - varval), varval, | ||
9757 | maybe_single_quote(eq) | ||
9758 | ); | ||
9759 | sp = sp->next; | ||
9760 | pfx = " "; | ||
9761 | } | ||
9762 | |||
9763 | sp = arglist.list; | ||
9764 | while (sp) { | ||
9765 | fdprintf(preverrout_fd, "%s%s", | ||
9766 | pfx, | ||
9767 | /* always quote if matches reserved word: */ | ||
9768 | findkwd(sp->text) | ||
9769 | ? single_quote(sp->text) | ||
9770 | : maybe_single_quote(sp->text) | ||
9771 | ); | ||
9772 | sp = sp->next; | ||
9773 | pfx = " "; | ||
9715 | } | 9774 | } |
9716 | safe_write(preverrout_fd, "\n", 1); | 9775 | safe_write(preverrout_fd, "\n", 1); |
9717 | } | 9776 | } |
diff --git a/shell/ash_test/ash-quoting/mode_x.right b/shell/ash_test/ash-quoting/mode_x.right new file mode 100644 index 000000000..c2dd3550c --- /dev/null +++ b/shell/ash_test/ash-quoting/mode_x.right | |||
@@ -0,0 +1,10 @@ | |||
1 | + var1=val | ||
2 | + var2='one two' | ||
3 | + true '%s\n' one 'two '"'"'three' four | ||
4 | + this=command | ||
5 | + 'this=command' | ||
6 | ./mode_x.tests: line 1: this=command: not found | ||
7 | + true | ||
8 | + true | ||
9 | + 'if' true | ||
10 | ./mode_x.tests: line 1: if: not found | ||
diff --git a/shell/ash_test/ash-quoting/mode_x.tests b/shell/ash_test/ash-quoting/mode_x.tests new file mode 100755 index 000000000..16dae3f4b --- /dev/null +++ b/shell/ash_test/ash-quoting/mode_x.tests | |||
@@ -0,0 +1,14 @@ | |||
1 | set -x | ||
2 | |||
3 | var1=val | ||
4 | var2='one two' | ||
5 | true %s\\n one "two 'three" four | ||
6 | |||
7 | # assignment: | ||
8 | this=command | ||
9 | # NOT assignment, +x code should show it quoted: | ||
10 | "this=command" | ||
11 | |||
12 | if true; then true; fi | ||
13 | # +x code should quote 'if' here: | ||
14 | "if" true | ||