diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 149 |
1 files changed, 103 insertions, 46 deletions
diff --git a/shell/ash.c b/shell/ash.c index dc5561765..28b522d7c 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -31,15 +31,14 @@ | |||
31 | */ | 31 | */ |
32 | 32 | ||
33 | //config:config ASH | 33 | //config:config ASH |
34 | //config: bool "ash" | 34 | //config: bool "ash (77 kb)" |
35 | //config: default y | 35 | //config: default y |
36 | //config: depends on !NOMMU | 36 | //config: depends on !NOMMU |
37 | //config: help | 37 | //config: help |
38 | //config: Tha 'ash' shell adds about 60k in the default configuration and is | 38 | //config: The most complete and most pedantically correct shell included with |
39 | //config: the most complete and most pedantically correct shell included with | 39 | //config: busybox. This shell is actually a derivative of the Debian 'dash' |
40 | //config: busybox. This shell is actually a derivative of the Debian 'dash' | 40 | //config: shell (by Herbert Xu), which was created by porting the 'ash' shell |
41 | //config: shell (by Herbert Xu), which was created by porting the 'ash' shell | 41 | //config: (written by Kenneth Almquist) from NetBSD. |
42 | //config: (written by Kenneth Almquist) from NetBSD. | ||
43 | //config: | 42 | //config: |
44 | //config:# ash options | 43 | //config:# ash options |
45 | //config:# note: Don't remove !NOMMU part in the next line; it would break | 44 | //config:# note: Don't remove !NOMMU part in the next line; it would break |
@@ -56,11 +55,11 @@ | |||
56 | //config: default y # Y is bigger, but because of uclibc glob() bug, let Y be default for now | 55 | //config: default y # Y is bigger, but because of uclibc glob() bug, let Y be default for now |
57 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 56 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
58 | //config: help | 57 | //config: help |
59 | //config: Do not use glob() function from libc, use internal implementation. | 58 | //config: Do not use glob() function from libc, use internal implementation. |
60 | //config: Use this if you are getting "glob.h: No such file or directory" | 59 | //config: Use this if you are getting "glob.h: No such file or directory" |
61 | //config: or similar build errors. | 60 | //config: or similar build errors. |
62 | //config: Note that as of now (2017-01), uclibc and musl glob() both have bugs | 61 | //config: Note that as of now (2017-01), uclibc and musl glob() both have bugs |
63 | //config: which would break ash if you select N here. | 62 | //config: which would break ash if you select N here. |
64 | //config: | 63 | //config: |
65 | //config:config ASH_BASH_COMPAT | 64 | //config:config ASH_BASH_COMPAT |
66 | //config: bool "bash-compatible extensions" | 65 | //config: bool "bash-compatible extensions" |
@@ -82,37 +81,37 @@ | |||
82 | //config: default y | 81 | //config: default y |
83 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 82 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
84 | //config: help | 83 | //config: help |
85 | //config: Enable pseudorandom generator and dynamic variable "$RANDOM". | 84 | //config: Enable pseudorandom generator and dynamic variable "$RANDOM". |
86 | //config: Each read of "$RANDOM" will generate a new pseudorandom value. | 85 | //config: Each read of "$RANDOM" will generate a new pseudorandom value. |
87 | //config: You can reset the generator by using a specified start value. | 86 | //config: You can reset the generator by using a specified start value. |
88 | //config: After "unset RANDOM" the generator will switch off and this | 87 | //config: After "unset RANDOM" the generator will switch off and this |
89 | //config: variable will no longer have special treatment. | 88 | //config: variable will no longer have special treatment. |
90 | //config: | 89 | //config: |
91 | //config:config ASH_EXPAND_PRMT | 90 | //config:config ASH_EXPAND_PRMT |
92 | //config: bool "Expand prompt string" | 91 | //config: bool "Expand prompt string" |
93 | //config: default y | 92 | //config: default y |
94 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 93 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
95 | //config: help | 94 | //config: help |
96 | //config: $PS# may contain volatile content, such as backquote commands. | 95 | //config: $PS# may contain volatile content, such as backquote commands. |
97 | //config: This option recreates the prompt string from the environment | 96 | //config: This option recreates the prompt string from the environment |
98 | //config: variable each time it is displayed. | 97 | //config: variable each time it is displayed. |
99 | //config: | 98 | //config: |
100 | //config:config ASH_IDLE_TIMEOUT | 99 | //config:config ASH_IDLE_TIMEOUT |
101 | //config: bool "Idle timeout variable $TMOUT" | 100 | //config: bool "Idle timeout variable $TMOUT" |
102 | //config: default y | 101 | //config: default y |
103 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 102 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
104 | //config: help | 103 | //config: help |
105 | //config: Enable bash-like auto-logout after $TMOUT seconds of idle time. | 104 | //config: Enable bash-like auto-logout after $TMOUT seconds of idle time. |
106 | //config: | 105 | //config: |
107 | //config:config ASH_MAIL | 106 | //config:config ASH_MAIL |
108 | //config: bool "Check for new mail in interactive shell" | 107 | //config: bool "Check for new mail in interactive shell" |
109 | //config: default y | 108 | //config: default y |
110 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 109 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
111 | //config: help | 110 | //config: help |
112 | //config: Enable "check for new mail" function: | 111 | //config: Enable "check for new mail" function: |
113 | //config: if set, $MAIL file and $MAILPATH list of files | 112 | //config: if set, $MAIL file and $MAILPATH list of files |
114 | //config: are checked for mtime changes, and "you have mail" | 113 | //config: are checked for mtime changes, and "you have mail" |
115 | //config: message is printed if change is detected. | 114 | //config: message is printed if change is detected. |
116 | //config: | 115 | //config: |
117 | //config:config ASH_ECHO | 116 | //config:config ASH_ECHO |
118 | //config: bool "echo builtin" | 117 | //config: bool "echo builtin" |
@@ -144,9 +143,9 @@ | |||
144 | //config: default y | 143 | //config: default y |
145 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 144 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
146 | //config: help | 145 | //config: help |
147 | //config: Enable support for the 'command' builtin, which allows | 146 | //config: Enable support for the 'command' builtin, which allows |
148 | //config: you to run the specified command or builtin, | 147 | //config: you to run the specified command or builtin, |
149 | //config: even when there is a function with the same name. | 148 | //config: even when there is a function with the same name. |
150 | //config: | 149 | //config: |
151 | //config: | 150 | //config: |
152 | //config:config ASH_NOCONSOLE | 151 | //config:config ASH_NOCONSOLE |
@@ -1746,7 +1745,7 @@ static char * | |||
1746 | stack_nputstr(const char *s, size_t n, char *p) | 1745 | stack_nputstr(const char *s, size_t n, char *p) |
1747 | { | 1746 | { |
1748 | p = makestrspace(n, p); | 1747 | p = makestrspace(n, p); |
1749 | p = (char *)memcpy(p, s, n) + n; | 1748 | p = (char *)mempcpy(p, s, n); |
1750 | return p; | 1749 | return p; |
1751 | } | 1750 | } |
1752 | 1751 | ||
@@ -1830,7 +1829,7 @@ number(const char *s) | |||
1830 | } | 1829 | } |
1831 | 1830 | ||
1832 | /* | 1831 | /* |
1833 | * Produce a possibly single quoted string suitable as input to the shell. | 1832 | * Produce a single quoted string suitable as input to the shell. |
1834 | * The return string is allocated on the stack. | 1833 | * The return string is allocated on the stack. |
1835 | */ | 1834 | */ |
1836 | static char * | 1835 | static char * |
@@ -1849,7 +1848,7 @@ single_quote(const char *s) | |||
1849 | q = p = makestrspace(len + 3, p); | 1848 | q = p = makestrspace(len + 3, p); |
1850 | 1849 | ||
1851 | *q++ = '\''; | 1850 | *q++ = '\''; |
1852 | q = (char *)memcpy(q, s, len) + len; | 1851 | q = (char *)mempcpy(q, s, len); |
1853 | *q++ = '\''; | 1852 | *q++ = '\''; |
1854 | s += len; | 1853 | s += len; |
1855 | 1854 | ||
@@ -1863,7 +1862,7 @@ single_quote(const char *s) | |||
1863 | q = p = makestrspace(len + 3, p); | 1862 | q = p = makestrspace(len + 3, p); |
1864 | 1863 | ||
1865 | *q++ = '"'; | 1864 | *q++ = '"'; |
1866 | q = (char *)memcpy(q, s - len, len) + len; | 1865 | q = (char *)mempcpy(q, s - len, len); |
1867 | *q++ = '"'; | 1866 | *q++ = '"'; |
1868 | 1867 | ||
1869 | STADJUST(q - p, p); | 1868 | STADJUST(q - p, p); |
@@ -1874,6 +1873,47 @@ single_quote(const char *s) | |||
1874 | return stackblock(); | 1873 | return stackblock(); |
1875 | } | 1874 | } |
1876 | 1875 | ||
1876 | /* | ||
1877 | * Produce a possibly single quoted string suitable as input to the shell. | ||
1878 | * If 'conditional' is nonzero, quoting is only done if the string contains | ||
1879 | * non-shellsafe characters, or is identical to a shell keyword (reserved | ||
1880 | * word); if it is zero, quoting is always done. | ||
1881 | * If quoting was done, the return string is allocated on the stack, | ||
1882 | * otherwise a pointer to the original string is returned. | ||
1883 | */ | ||
1884 | static const char * | ||
1885 | maybe_single_quote(const char *s) | ||
1886 | { | ||
1887 | const char *p = s; | ||
1888 | |||
1889 | while (*p) { | ||
1890 | /* Assuming ACSII */ | ||
1891 | /* quote ctrl_chars space !"#$%&'()* */ | ||
1892 | if (*p < '+') | ||
1893 | goto need_quoting; | ||
1894 | /* quote ;<=>? */ | ||
1895 | if (*p >= ';' && *p <= '?') | ||
1896 | goto need_quoting; | ||
1897 | /* quote `[\ */ | ||
1898 | if (*p == '`') | ||
1899 | goto need_quoting; | ||
1900 | if (*p == '[') | ||
1901 | goto need_quoting; | ||
1902 | if (*p == '\\') | ||
1903 | goto need_quoting; | ||
1904 | /* quote {|}~ DEL and high bytes */ | ||
1905 | if (*p > 'z') | ||
1906 | goto need_quoting; | ||
1907 | /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */ | ||
1908 | /* TODO: maybe avoid quoting % */ | ||
1909 | p++; | ||
1910 | } | ||
1911 | return s; | ||
1912 | |||
1913 | need_quoting: | ||
1914 | return single_quote(s); | ||
1915 | } | ||
1916 | |||
1877 | 1917 | ||
1878 | /* ============ nextopt */ | 1918 | /* ============ nextopt */ |
1879 | 1919 | ||
@@ -2362,10 +2402,10 @@ setvar(const char *name, const char *val, int flags) | |||
2362 | 2402 | ||
2363 | INT_OFF; | 2403 | INT_OFF; |
2364 | nameeq = ckmalloc(namelen + vallen + 2); | 2404 | nameeq = ckmalloc(namelen + vallen + 2); |
2365 | p = memcpy(nameeq, name, namelen) + namelen; | 2405 | p = mempcpy(nameeq, name, namelen); |
2366 | if (val) { | 2406 | if (val) { |
2367 | *p++ = '='; | 2407 | *p++ = '='; |
2368 | p = memcpy(p, val, vallen) + vallen; | 2408 | p = mempcpy(p, val, vallen); |
2369 | } | 2409 | } |
2370 | *p = '\0'; | 2410 | *p = '\0'; |
2371 | setvareq(nameeq, flags | VNOSAVE); | 2411 | setvareq(nameeq, flags | VNOSAVE); |
@@ -2512,8 +2552,7 @@ path_advance(const char **path, const char *name) | |||
2512 | growstackblock(); | 2552 | growstackblock(); |
2513 | q = stackblock(); | 2553 | q = stackblock(); |
2514 | if (p != start) { | 2554 | if (p != start) { |
2515 | memcpy(q, start, p - start); | 2555 | q = mempcpy(q, start, p - start); |
2516 | q += p - start; | ||
2517 | *q++ = '/'; | 2556 | *q++ = '/'; |
2518 | } | 2557 | } |
2519 | strcpy(q, name); | 2558 | strcpy(q, name); |
@@ -6277,7 +6316,7 @@ rmescapes(char *str, int flag) | |||
6277 | } | 6316 | } |
6278 | q = r; | 6317 | q = r; |
6279 | if (len > 0) { | 6318 | if (len > 0) { |
6280 | q = (char *)memcpy(q, str, len) + len; | 6319 | q = (char *)mempcpy(q, str, len); |
6281 | } | 6320 | } |
6282 | } | 6321 | } |
6283 | 6322 | ||
@@ -10161,18 +10200,36 @@ evalcommand(union node *cmd, int flags) | |||
10161 | 10200 | ||
10162 | /* Print the command if xflag is set. */ | 10201 | /* Print the command if xflag is set. */ |
10163 | if (xflag) { | 10202 | if (xflag) { |
10164 | int n; | 10203 | const char *pfx = ""; |
10165 | const char *p = " %s" + 1; | 10204 | |
10205 | fdprintf(preverrout_fd, "%s", expandstr(ps4val())); | ||
10166 | 10206 | ||
10167 | fdprintf(preverrout_fd, p, expandstr(ps4val())); | ||
10168 | sp = varlist.list; | 10207 | sp = varlist.list; |
10169 | for (n = 0; n < 2; n++) { | 10208 | while (sp) { |
10170 | while (sp) { | 10209 | char *varval = sp->text; |
10171 | fdprintf(preverrout_fd, p, sp->text); | 10210 | char *eq = strchrnul(varval, '='); |
10172 | sp = sp->next; | 10211 | if (*eq) |
10173 | p = " %s"; | 10212 | eq++; |
10174 | } | 10213 | fdprintf(preverrout_fd, "%s%.*s%s", |
10175 | sp = arglist.list; | 10214 | pfx, |
10215 | (int)(eq - varval), varval, | ||
10216 | maybe_single_quote(eq) | ||
10217 | ); | ||
10218 | sp = sp->next; | ||
10219 | pfx = " "; | ||
10220 | } | ||
10221 | |||
10222 | sp = arglist.list; | ||
10223 | while (sp) { | ||
10224 | fdprintf(preverrout_fd, "%s%s", | ||
10225 | pfx, | ||
10226 | /* always quote if matches reserved word: */ | ||
10227 | findkwd(sp->text) | ||
10228 | ? single_quote(sp->text) | ||
10229 | : maybe_single_quote(sp->text) | ||
10230 | ); | ||
10231 | sp = sp->next; | ||
10232 | pfx = " "; | ||
10176 | } | 10233 | } |
10177 | safe_write(preverrout_fd, "\n", 1); | 10234 | safe_write(preverrout_fd, "\n", 1); |
10178 | } | 10235 | } |