aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c149
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 *
1746stack_nputstr(const char *s, size_t n, char *p) 1745stack_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 */
1836static char * 1835static 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 */
1884static const char *
1885maybe_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 }