diff options
author | Ron Yorston <rmy@pobox.com> | 2021-09-10 14:47:27 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2021-09-10 14:47:27 +0100 |
commit | 3eb1d088e09db204f456ad7b76eced21e429f001 (patch) | |
tree | a81b5bb422db5ee97475a8f1a4b5236442ed6f14 | |
parent | 12bc40da28f85cbe97673671f315f847f1dbbabf (diff) | |
parent | 40f2dd7dd2e50c9d81dda4d72bf9c85c4c479a89 (diff) | |
download | busybox-w32-3eb1d088e09db204f456ad7b76eced21e429f001.tar.gz busybox-w32-3eb1d088e09db204f456ad7b76eced21e429f001.tar.bz2 busybox-w32-3eb1d088e09db204f456ad7b76eced21e429f001.zip |
Merge branch 'busybox' into merge
53 files changed, 683 insertions, 437 deletions
diff --git a/coreutils/basename.c b/coreutils/basename.c index 0dd2c43c7..0b721c03c 100644 --- a/coreutils/basename.c +++ b/coreutils/basename.c | |||
@@ -29,9 +29,11 @@ | |||
29 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/basename.html */ | 29 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/basename.html */ |
30 | 30 | ||
31 | //usage:#define basename_trivial_usage | 31 | //usage:#define basename_trivial_usage |
32 | //usage: "FILE [SUFFIX]" | 32 | //usage: "FILE [SUFFIX] | -a FILE... | -s SUFFIX FILE..." |
33 | //usage:#define basename_full_usage "\n\n" | 33 | //usage:#define basename_full_usage "\n\n" |
34 | //usage: "Strip directory path and .SUFFIX from FILE" | 34 | //usage: "Strip directory path and SUFFIX from FILE\n" |
35 | //usage: "\n -a All arguments are FILEs" | ||
36 | //usage: "\n -s SUFFIX Remove SUFFIX (implies -a)" | ||
35 | //usage: | 37 | //usage: |
36 | //usage:#define basename_example_usage | 38 | //usage:#define basename_example_usage |
37 | //usage: "$ basename /usr/local/bin/foo\n" | 39 | //usage: "$ basename /usr/local/bin/foo\n" |
@@ -48,31 +50,43 @@ | |||
48 | int basename_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 50 | int basename_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
49 | int basename_main(int argc UNUSED_PARAM, char **argv) | 51 | int basename_main(int argc UNUSED_PARAM, char **argv) |
50 | { | 52 | { |
51 | size_t m, n; | 53 | unsigned opts; |
52 | char *s; | 54 | const char *suffix = NULL; |
53 | 55 | ||
54 | if (argv[1] && strcmp(argv[1], "--") == 0) { | 56 | /* '+': stop at first non-option */ |
55 | argv++; | 57 | opts = getopt32(argv, "^+" "as:" |
56 | } | 58 | "\0" "-1" /* At least one argument */ |
57 | if (!argv[1]) | 59 | , &suffix |
58 | bb_show_usage(); | 60 | ); |
61 | argv += optind; | ||
59 | 62 | ||
60 | /* It should strip slash: /abc/def/ -> def */ | 63 | do { |
61 | s = bb_get_last_path_component_strip(*++argv); | 64 | char *s; |
65 | size_t m; | ||
62 | 66 | ||
63 | m = strlen(s); | 67 | /* It should strip slash: /abc/def/ -> def */ |
64 | if (*++argv) { | 68 | s = bb_get_last_path_component_strip(*argv++); |
65 | if (argv[1]) | 69 | m = strlen(s); |
66 | bb_show_usage(); | 70 | if (!opts) { |
67 | n = strlen(*argv); | 71 | if (*argv) { |
68 | if ((m > n) && (strcmp(s+m-n, *argv) == 0)) { | 72 | suffix = *argv; |
69 | m -= n; | 73 | if (argv[1]) |
70 | /*s[m] = '\0'; - redundant */ | 74 | bb_show_usage(); |
75 | } | ||
71 | } | 76 | } |
72 | } | 77 | if (suffix) { |
78 | size_t n = strlen(suffix); | ||
79 | if ((m > n) && (strcmp(s + m - n, suffix) == 0)) { | ||
80 | m -= n; | ||
81 | /*s[m] = '\0'; - redundant */ | ||
82 | } | ||
83 | } | ||
84 | /* puts(s) will do, but we can do without stdio this way: */ | ||
85 | s[m++] = '\n'; | ||
86 | /* NB: != is correct here: */ | ||
87 | if (full_write(STDOUT_FILENO, s, m) != (ssize_t)m) | ||
88 | return EXIT_FAILURE; | ||
89 | } while (opts && *argv); | ||
73 | 90 | ||
74 | /* puts(s) will do, but we can do without stdio this way: */ | 91 | return EXIT_SUCCESS; |
75 | s[m++] = '\n'; | ||
76 | /* NB: != is correct here: */ | ||
77 | return full_write(STDOUT_FILENO, s, m) != (ssize_t)m; | ||
78 | } | 92 | } |
diff --git a/coreutils/shuf.c b/coreutils/shuf.c index 71b27f497..81b0df453 100644 --- a/coreutils/shuf.c +++ b/coreutils/shuf.c | |||
@@ -44,21 +44,25 @@ | |||
44 | */ | 44 | */ |
45 | static void shuffle_lines(char **lines, unsigned numlines, unsigned outlines) | 45 | static void shuffle_lines(char **lines, unsigned numlines, unsigned outlines) |
46 | { | 46 | { |
47 | unsigned i; | ||
48 | unsigned r; | ||
49 | char *tmp; | ||
50 | |||
51 | srand(monotonic_us()); | 47 | srand(monotonic_us()); |
52 | 48 | ||
53 | for (i = numlines - 1; outlines > 0; i--, outlines--) { | 49 | while (outlines != 0) { |
54 | r = rand(); | 50 | char *tmp; |
51 | unsigned r = rand(); | ||
55 | /* RAND_MAX can be as small as 32767 */ | 52 | /* RAND_MAX can be as small as 32767 */ |
56 | if (i > RAND_MAX) | 53 | if (numlines > RAND_MAX) |
57 | r ^= rand() << 15; | 54 | r ^= rand() << 15; |
58 | r %= i + 1; | 55 | r %= numlines; |
59 | tmp = lines[i]; | 56 | //TODO: the above method is seriously non-uniform when numlines is very large. |
60 | lines[i] = lines[r]; | 57 | //For example, with numlines of 0xf0000000, |
58 | //values of (r % numlines) in [0, 0x0fffffff] range | ||
59 | //are more likely: e.g. r=1 and r=0xf0000001 both map to 1, | ||
60 | //whereas only one value, r=0xefffffff, maps to 0xefffffff. | ||
61 | numlines--; | ||
62 | tmp = lines[numlines]; | ||
63 | lines[numlines] = lines[r]; | ||
61 | lines[r] = tmp; | 64 | lines[r] = tmp; |
65 | outlines--; | ||
62 | } | 66 | } |
63 | } | 67 | } |
64 | 68 | ||
@@ -67,9 +71,10 @@ int shuf_main(int argc, char **argv) | |||
67 | { | 71 | { |
68 | unsigned opts; | 72 | unsigned opts; |
69 | char *opt_i_str, *opt_n_str, *opt_o_str; | 73 | char *opt_i_str, *opt_n_str, *opt_o_str; |
70 | unsigned i; | ||
71 | char **lines; | 74 | char **lines; |
75 | unsigned long long lo = lo; | ||
72 | unsigned numlines, outlines; | 76 | unsigned numlines, outlines; |
77 | unsigned i; | ||
73 | char eol; | 78 | char eol; |
74 | 79 | ||
75 | opts = getopt32(argv, "^" | 80 | opts = getopt32(argv, "^" |
@@ -89,8 +94,8 @@ int shuf_main(int argc, char **argv) | |||
89 | } else | 94 | } else |
90 | if (opts & OPT_i) { | 95 | if (opts & OPT_i) { |
91 | /* create a range of numbers */ | 96 | /* create a range of numbers */ |
97 | unsigned long long hi; | ||
92 | char *dash; | 98 | char *dash; |
93 | uintptr_t lo, hi; | ||
94 | 99 | ||
95 | if (argv[0]) | 100 | if (argv[0]) |
96 | bb_show_usage(); | 101 | bb_show_usage(); |
@@ -100,27 +105,24 @@ int shuf_main(int argc, char **argv) | |||
100 | bb_error_msg_and_die("bad range '%s'", opt_i_str); | 105 | bb_error_msg_and_die("bad range '%s'", opt_i_str); |
101 | } | 106 | } |
102 | *dash = '\0'; | 107 | *dash = '\0'; |
103 | if (sizeof(lo) == sizeof(int)) { | 108 | lo = xatoull(opt_i_str); |
104 | lo = xatou(opt_i_str); | 109 | hi = xatoull(dash + 1); |
105 | hi = xatou(dash + 1); | ||
106 | } else | ||
107 | if (sizeof(lo) == sizeof(long)) { | ||
108 | lo = xatoul(opt_i_str); | ||
109 | hi = xatoul(dash + 1); | ||
110 | } else { | ||
111 | lo = xatoull(opt_i_str); | ||
112 | hi = xatoull(dash + 1); | ||
113 | } | ||
114 | *dash = '-'; | 110 | *dash = '-'; |
115 | if (hi < lo) { | 111 | if (hi < lo) |
116 | bb_error_msg_and_die("bad range '%s'", opt_i_str); | 112 | bb_error_msg_and_die("bad range '%s'", opt_i_str); |
113 | hi -= lo; | ||
114 | if (sizeof(size_t) > sizeof(numlines)) { | ||
115 | if (hi >= UINT_MAX) | ||
116 | bb_error_msg_and_die("bad range '%s'", opt_i_str); | ||
117 | } else { | ||
118 | if (hi >= UINT_MAX / sizeof(lines[0])) | ||
119 | bb_error_msg_and_die("bad range '%s'", opt_i_str); | ||
117 | } | 120 | } |
118 | 121 | ||
119 | numlines = (hi+1) - lo; | 122 | numlines = hi + 1; |
120 | lines = xmalloc(numlines * sizeof(lines[0])); | 123 | lines = xmalloc((size_t)numlines * sizeof(lines[0])); |
121 | for (i = 0; i < numlines; i++) { | 124 | for (i = 0; i < numlines; i++) { |
122 | lines[i] = (char*)lo; | 125 | lines[i] = (char*)(uintptr_t)i; |
123 | lo++; | ||
124 | } | 126 | } |
125 | } else { | 127 | } else { |
126 | /* default - read lines from stdin or the input file */ | 128 | /* default - read lines from stdin or the input file */ |
@@ -163,14 +165,9 @@ int shuf_main(int argc, char **argv) | |||
163 | eol = '\0'; | 165 | eol = '\0'; |
164 | 166 | ||
165 | for (i = numlines - outlines; i < numlines; i++) { | 167 | for (i = numlines - outlines; i < numlines; i++) { |
166 | if (opts & OPT_i) { | 168 | if (opts & OPT_i) |
167 | if (sizeof(lines[0]) == sizeof(int)) | 169 | printf("%"LL_FMT"u%c", lo + (uintptr_t)lines[i], eol); |
168 | printf("%u%c", (unsigned)(uintptr_t)lines[i], eol); | 170 | else |
169 | else if (sizeof(lines[0]) == sizeof(long)) | ||
170 | printf("%lu%c", (unsigned long)(uintptr_t)lines[i], eol); | ||
171 | else | ||
172 | printf("%"LL_FMT"u%c", (unsigned long long)(uintptr_t)lines[i], eol); | ||
173 | } else | ||
174 | printf("%s%c", lines[i], eol); | 171 | printf("%s%c", lines[i], eol); |
175 | } | 172 | } |
176 | 173 | ||
diff --git a/editors/awk.c b/editors/awk.c index 75f757dbb..17710e57e 100644 --- a/editors/awk.c +++ b/editors/awk.c | |||
@@ -2357,36 +2357,55 @@ static char *awk_printf(node *n, size_t *len) | |||
2357 | 2357 | ||
2358 | b = NULL; | 2358 | b = NULL; |
2359 | i = 0; | 2359 | i = 0; |
2360 | while (*f) { /* "print one format spec" loop */ | 2360 | while (1) { /* "print one format spec" loop */ |
2361 | char *s; | 2361 | char *s; |
2362 | char c; | 2362 | char c; |
2363 | char sv; | 2363 | char sv; |
2364 | var *arg; | 2364 | var *arg; |
2365 | size_t slen; | 2365 | size_t slen; |
2366 | 2366 | ||
2367 | /* Find end of the next format spec, or end of line */ | ||
2367 | s = f; | 2368 | s = f; |
2368 | while (*f && (*f != '%' || *++f == '%')) | 2369 | while (1) { |
2369 | f++; | 2370 | c = *f; |
2370 | while (*f && !isalpha(*f)) { | 2371 | if (!c) /* no percent chars found at all */ |
2371 | if (*f == '*') | 2372 | goto nul; |
2372 | syntax_error("%*x formats are not supported"); | ||
2373 | f++; | 2373 | f++; |
2374 | if (c == '%') | ||
2375 | break; | ||
2374 | } | 2376 | } |
2377 | /* we are past % in "....%..." */ | ||
2375 | c = *f; | 2378 | c = *f; |
2376 | if (!c) { | 2379 | if (!c) /* "....%" */ |
2377 | /* Tail of fmt with no percent chars, | 2380 | goto nul; |
2378 | * or "....%" (percent seen, but no format specifier char found) | 2381 | if (c == '%') { /* "....%%...." */ |
2379 | */ | 2382 | slen = f - s; |
2380 | slen = strlen(s); | 2383 | s = xstrndup(s, slen); |
2381 | goto tail; | 2384 | f++; |
2385 | goto append; /* print "....%" part verbatim */ | ||
2382 | } | 2386 | } |
2383 | sv = *++f; | 2387 | while (1) { |
2384 | *f = '\0'; | 2388 | if (isalpha(c)) |
2389 | break; | ||
2390 | if (c == '*') | ||
2391 | syntax_error("%*x formats are not supported"); | ||
2392 | c = *++f; | ||
2393 | if (!c) { /* "....%...." and no letter found after % */ | ||
2394 | /* Example: awk 'BEGIN { printf "^^^%^^^\n"; }' */ | ||
2395 | nul: | ||
2396 | slen = f - s; | ||
2397 | goto tail; /* print remaining string, exit loop */ | ||
2398 | } | ||
2399 | } | ||
2400 | /* we are at A in "....%...A..." */ | ||
2401 | |||
2385 | arg = evaluate(nextarg(&n), TMPVAR); | 2402 | arg = evaluate(nextarg(&n), TMPVAR); |
2386 | 2403 | ||
2387 | /* Result can be arbitrarily long. Example: | 2404 | /* Result can be arbitrarily long. Example: |
2388 | * printf "%99999s", "BOOM" | 2405 | * printf "%99999s", "BOOM" |
2389 | */ | 2406 | */ |
2407 | sv = *++f; | ||
2408 | *f = '\0'; | ||
2390 | if (c == 'c') { | 2409 | if (c == 'c') { |
2391 | char cc = is_numeric(arg) ? getvar_i(arg) : *getvar_s(arg); | 2410 | char cc = is_numeric(arg) ? getvar_i(arg) : *getvar_s(arg); |
2392 | char *r = xasprintf(s, cc ? cc : '^' /* else strlen will be wrong */); | 2411 | char *r = xasprintf(s, cc ? cc : '^' /* else strlen will be wrong */); |
@@ -2405,13 +2424,14 @@ static char *awk_printf(node *n, size_t *len) | |||
2405 | } else if (strchr("eEfFgGaA", c)) { | 2424 | } else if (strchr("eEfFgGaA", c)) { |
2406 | s = xasprintf(s, d); | 2425 | s = xasprintf(s, d); |
2407 | } else { | 2426 | } else { |
2427 | //TODO: GNU Awk 5.0.1: printf "%W" prints "%W", does not error out | ||
2408 | syntax_error(EMSG_INV_FMT); | 2428 | syntax_error(EMSG_INV_FMT); |
2409 | } | 2429 | } |
2410 | } | 2430 | } |
2411 | slen = strlen(s); | 2431 | slen = strlen(s); |
2412 | } | 2432 | } |
2413 | *f = sv; | 2433 | *f = sv; |
2414 | 2434 | append: | |
2415 | if (i == 0) { | 2435 | if (i == 0) { |
2416 | b = s; | 2436 | b = s; |
2417 | i = slen; | 2437 | i = slen; |
@@ -2421,7 +2441,7 @@ static char *awk_printf(node *n, size_t *len) | |||
2421 | b = xrealloc(b, i + slen + 1); | 2441 | b = xrealloc(b, i + slen + 1); |
2422 | strcpy(b + i, s); | 2442 | strcpy(b + i, s); |
2423 | i += slen; | 2443 | i += slen; |
2424 | if (!c) /* tail? */ | 2444 | if (!c) /* s is NOT allocated and this is the last part of string? */ |
2425 | break; | 2445 | break; |
2426 | free(s); | 2446 | free(s); |
2427 | } | 2447 | } |
diff --git a/examples/var_service/fw/run b/examples/var_service/fw/run index 41078d0ab..15c2b2f0a 100755 --- a/examples/var_service/fw/run +++ b/examples/var_service/fw/run | |||
@@ -179,7 +179,9 @@ ipt="iptables -t nat -A OUTPUT" | |||
179 | # OUTGOING TRAFFIC | 179 | # OUTGOING TRAFFIC |
180 | ipt="iptables -t nat -A POSTROUTING" | 180 | ipt="iptables -t nat -A POSTROUTING" |
181 | # Masquerade boxes on my private net | 181 | # Masquerade boxes on my private net |
182 | doit $ipt -s 192.168.0.0/24 -o $extif -j MASQUERADE | 182 | for e in $extif; do |
183 | doit $ipt -s 192.168.0.0/24 -o $e -j MASQUERADE | ||
184 | done | ||
183 | 185 | ||
184 | # *** mangle *** | 186 | # *** mangle *** |
185 | ### DEBUG | 187 | ### DEBUG |
@@ -204,7 +206,9 @@ fi | |||
204 | doit $ipt -p tcp -j REJECT # Anything else isn't ok. REJECT = irc opens faster | 206 | doit $ipt -p tcp -j REJECT # Anything else isn't ok. REJECT = irc opens faster |
205 | # (it probes proxy ports, DROP will incur timeout delays) | 207 | # (it probes proxy ports, DROP will incur timeout delays) |
206 | ipt="iptables -t filter -A INPUT" | 208 | ipt="iptables -t filter -A INPUT" |
207 | doit $ipt -i $extif -j iext | 209 | for e in $extif; do |
210 | doit $ipt -i $e -j iext | ||
211 | done | ||
208 | 212 | ||
209 | 213 | ||
210 | echo; echo "* Enabling forwarding" | 214 | echo; echo "* Enabling forwarding" |
@@ -222,12 +226,12 @@ echo; echo "* Routing:" | |||
222 | ip r l | 226 | ip r l |
223 | echo; echo "* Firewall:" | 227 | echo; echo "* Firewall:" |
224 | { | 228 | { |
225 | echo '---FILTER--'; | 229 | echo '---FILTER--' |
226 | iptables -v -L -x -n; | 230 | iptables -v -L -x -n |
227 | echo '---NAT-----'; | 231 | echo '---NAT-----' |
228 | iptables -t nat -v -L -x -n; | 232 | iptables -t nat -v -L -x -n |
229 | echo '---MANGLE--'; | 233 | echo '---MANGLE--' |
230 | iptables -t mangle -v -L -x -n; | 234 | iptables -t mangle -v -L -x -n |
231 | } \ | 235 | } \ |
232 | | grep -v '^$' | grep -Fv 'bytes target' | 236 | | grep -v '^$' | grep -Fv 'bytes target' |
233 | echo | 237 | echo |
diff --git a/include/usage.src.h b/include/usage.src.h index 1ac252d1b..5d2038834 100644 --- a/include/usage.src.h +++ b/include/usage.src.h | |||
@@ -31,6 +31,9 @@ | |||
31 | # define ADJTIME_PATH "/etc/adjtime" | 31 | # define ADJTIME_PATH "/etc/adjtime" |
32 | #endif | 32 | #endif |
33 | 33 | ||
34 | #define STR1(s) #s | ||
35 | #define STR(s) STR1(s) | ||
36 | |||
34 | INSERT | 37 | INSERT |
35 | 38 | ||
36 | #define busybox_notes_usage \ | 39 | #define busybox_notes_usage \ |
diff --git a/libbb/xconnect.c b/libbb/xconnect.c index f5c514b2c..65b1cb8de 100644 --- a/libbb/xconnect.c +++ b/libbb/xconnect.c | |||
@@ -117,27 +117,19 @@ void FAST_FUNC xconnect(int s, const struct sockaddr *saddr, socklen_t addrlen) | |||
117 | 117 | ||
118 | /* Return port number for a service. | 118 | /* Return port number for a service. |
119 | * If "port" is a number use it as the port. | 119 | * If "port" is a number use it as the port. |
120 | * If "port" is a name it is looked up in /etc/services, | 120 | * If "port" is a name it is looked up in /etc/services. |
121 | * if it isnt found return default_port | 121 | * if NULL, return default_port |
122 | */ | 122 | */ |
123 | unsigned FAST_FUNC bb_lookup_port(const char *port, const char *protocol, unsigned default_port) | 123 | unsigned FAST_FUNC bb_lookup_port(const char *port, const char *protocol, unsigned port_nr) |
124 | { | 124 | { |
125 | unsigned port_nr = default_port; | ||
126 | if (port) { | 125 | if (port) { |
127 | int old_errno; | ||
128 | |||
129 | /* Since this is a lib function, we're not allowed to reset errno to 0. | ||
130 | * Doing so could break an app that is deferring checking of errno. */ | ||
131 | old_errno = errno; | ||
132 | port_nr = bb_strtou(port, NULL, 10); | 126 | port_nr = bb_strtou(port, NULL, 10); |
133 | if (errno || port_nr > 65535) { | 127 | if (errno || port_nr > 65535) { |
134 | struct servent *tserv = getservbyname(port, protocol); | 128 | struct servent *tserv = getservbyname(port, protocol); |
135 | port_nr = default_port; | 129 | if (!tserv) |
136 | if (tserv) | 130 | bb_error_msg_and_die("bad port '%s'", port); |
137 | port_nr = ntohs(tserv->s_port); | 131 | port_nr = ntohs(tserv->s_port); |
138 | //FIXME: else: port string was garbage, but we don't report that??? | ||
139 | } | 132 | } |
140 | errno = old_errno; | ||
141 | } | 133 | } |
142 | return (uint16_t)port_nr; | 134 | return (uint16_t)port_nr; |
143 | } | 135 | } |
@@ -241,7 +233,7 @@ IF_NOT_FEATURE_IPV6(sa_family_t af = AF_INET;) | |||
241 | cp++; /* skip ':' */ | 233 | cp++; /* skip ':' */ |
242 | port = bb_strtou(cp, NULL, 10); | 234 | port = bb_strtou(cp, NULL, 10); |
243 | if (errno || (unsigned)port > 0xffff) { | 235 | if (errno || (unsigned)port > 0xffff) { |
244 | bb_error_msg("bad port spec '%s'", org_host); | 236 | bb_error_msg("bad port '%s'", cp); |
245 | if (ai_flags & DIE_ON_ERROR) | 237 | if (ai_flags & DIE_ON_ERROR) |
246 | xfunc_die(); | 238 | xfunc_die(); |
247 | return NULL; | 239 | return NULL; |
diff --git a/miscutils/chat.c b/miscutils/chat.c index f9e12a4ac..83aac37de 100644 --- a/miscutils/chat.c +++ b/miscutils/chat.c | |||
@@ -201,6 +201,9 @@ int chat_main(int argc UNUSED_PARAM, char **argv) | |||
201 | DIR_RECORD, | 201 | DIR_RECORD, |
202 | }; | 202 | }; |
203 | 203 | ||
204 | #define inbuf bb_common_bufsiz1 | ||
205 | setup_common_bufsiz(); | ||
206 | |||
204 | // make x* functions fail with correct exitcode | 207 | // make x* functions fail with correct exitcode |
205 | xfunc_error_retval = ERR_IO; | 208 | xfunc_error_retval = ERR_IO; |
206 | 209 | ||
@@ -361,35 +364,36 @@ int chat_main(int argc UNUSED_PARAM, char **argv) | |||
361 | // get reply | 364 | // get reply |
362 | pfd.fd = STDIN_FILENO; | 365 | pfd.fd = STDIN_FILENO; |
363 | pfd.events = POLLIN; | 366 | pfd.events = POLLIN; |
364 | while (!exitcode | 367 | while (exitcode == ERR_OK |
365 | && poll(&pfd, 1, timeout) > 0 | 368 | && poll(&pfd, 1, timeout) > 0 |
366 | && (pfd.revents & POLLIN) | 369 | /* && (pfd.revents & POLLIN) - may be untrue (e.g. only POLLERR set) */ |
367 | ) { | 370 | ) { |
368 | llist_t *l; | 371 | llist_t *l; |
369 | ssize_t delta; | 372 | ssize_t delta; |
370 | #define buf bb_common_bufsiz1 | ||
371 | setup_common_bufsiz(); | ||
372 | 373 | ||
373 | // read next char from device | 374 | // read next char from device |
374 | if (safe_read(STDIN_FILENO, buf+buf_len, 1) > 0) { | 375 | if (safe_read(STDIN_FILENO, inbuf + buf_len, 1) <= 0) { |
375 | // dump device input if RECORD fname | 376 | exitcode = ERR_IO; |
376 | if (record_fd > 0) { | 377 | goto expect_done; |
377 | full_write(record_fd, buf+buf_len, 1); | 378 | } |
378 | } | 379 | |
379 | // dump device input if ECHO ON | 380 | // dump device input if RECORD fname |
380 | if (echo) { | 381 | if (record_fd > 0) { |
381 | // if (buf[buf_len] < ' ') { | 382 | full_write(record_fd, inbuf + buf_len, 1); |
382 | // full_write2_str("^"); | 383 | } |
383 | // buf[buf_len] += '@'; | 384 | // dump device input if ECHO ON |
384 | // } | 385 | if (echo) { |
385 | full_write(STDERR_FILENO, buf+buf_len, 1); | 386 | // if (inbuf[buf_len] < ' ') { |
386 | } | 387 | // full_write2_str("^"); |
387 | buf_len++; | 388 | // inbuf[buf_len] += '@'; |
388 | // move input frame if we've reached higher bound | 389 | // } |
389 | if (buf_len > COMMON_BUFSIZE) { | 390 | full_write(STDERR_FILENO, inbuf + buf_len, 1); |
390 | memmove(buf, buf+buf_len-max_len, max_len); | 391 | } |
391 | buf_len = max_len; | 392 | buf_len++; |
392 | } | 393 | // move input frame if we've reached higher bound |
394 | if (buf_len > COMMON_BUFSIZE) { | ||
395 | memmove(inbuf, inbuf + buf_len - max_len, max_len); | ||
396 | buf_len = max_len; | ||
393 | } | 397 | } |
394 | // N.B. rule of thumb: values being looked for can | 398 | // N.B. rule of thumb: values being looked for can |
395 | // be found only at the end of input buffer | 399 | // be found only at the end of input buffer |
@@ -399,20 +403,20 @@ int chat_main(int argc UNUSED_PARAM, char **argv) | |||
399 | // abort condition is met? -> bail out | 403 | // abort condition is met? -> bail out |
400 | for (l = aborts, exitcode = ERR_ABORT; l; l = l->link, ++exitcode) { | 404 | for (l = aborts, exitcode = ERR_ABORT; l; l = l->link, ++exitcode) { |
401 | size_t len = strlen(l->data); | 405 | size_t len = strlen(l->data); |
402 | delta = buf_len-len; | 406 | delta = buf_len - len; |
403 | if (delta >= 0 && !memcmp(buf+delta, l->data, len)) | 407 | if (delta >= 0 && !memcmp(inbuf + delta, l->data, len)) |
404 | goto expect_done; | 408 | goto expect_done; |
405 | } | 409 | } |
406 | exitcode = ERR_OK; | 410 | exitcode = ERR_OK; |
407 | 411 | ||
408 | // expected reply received? -> goto next command | 412 | // expected reply received? -> goto next command |
409 | delta = buf_len - expect_len; | 413 | delta = buf_len - expect_len; |
410 | if (delta >= 0 && !memcmp(buf+delta, expect, expect_len)) | 414 | if (delta >= 0 && memcmp(inbuf + delta, expect, expect_len) == 0) |
411 | goto expect_done; | 415 | goto expect_done; |
412 | #undef buf | ||
413 | } /* while (have data) */ | 416 | } /* while (have data) */ |
414 | 417 | ||
415 | // device timed out or unexpected reply received | 418 | // device timed out, or unexpected reply received, |
419 | // or we got a signal (poll() returned -1 with EINTR). | ||
416 | exitcode = ERR_TIMEOUT; | 420 | exitcode = ERR_TIMEOUT; |
417 | expect_done: | 421 | expect_done: |
418 | #if ENABLE_FEATURE_CHAT_NOFAIL | 422 | #if ENABLE_FEATURE_CHAT_NOFAIL |
@@ -434,7 +438,7 @@ int chat_main(int argc UNUSED_PARAM, char **argv) | |||
434 | } | 438 | } |
435 | #endif | 439 | #endif |
436 | // bail out unless we expected successfully | 440 | // bail out unless we expected successfully |
437 | if (exitcode) | 441 | if (exitcode != ERR_OK) |
438 | break; | 442 | break; |
439 | 443 | ||
440 | //----------------------- | 444 | //----------------------- |
@@ -478,7 +482,7 @@ int chat_main(int argc UNUSED_PARAM, char **argv) | |||
478 | continue; | 482 | continue; |
479 | } | 483 | } |
480 | if ('p' == c) { | 484 | if ('p' == c) { |
481 | usleep(10000); | 485 | msleep(10); |
482 | len--; | 486 | len--; |
483 | continue; | 487 | continue; |
484 | } | 488 | } |
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c index f1d5ca571..ef0973a84 100644 --- a/networking/ftpgetput.c +++ b/networking/ftpgetput.c | |||
@@ -296,8 +296,7 @@ static const char ftpgetput_longopts[] ALIGN1 = | |||
296 | int ftpgetput_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 296 | int ftpgetput_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
297 | int ftpgetput_main(int argc UNUSED_PARAM, char **argv) | 297 | int ftpgetput_main(int argc UNUSED_PARAM, char **argv) |
298 | { | 298 | { |
299 | const char *port = "ftp"; | 299 | const char *port = NULL; |
300 | /* socket to ftp server */ | ||
301 | 300 | ||
302 | #if ENABLE_FTPPUT && !ENABLE_FTPGET | 301 | #if ENABLE_FTPPUT && !ENABLE_FTPGET |
303 | # define ftp_action ftp_send | 302 | # define ftp_action ftp_send |
diff --git a/networking/httpd.c b/networking/httpd.c index fcd1627b1..71e3a723f 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -102,6 +102,12 @@ | |||
102 | //config: help | 102 | //config: help |
103 | //config: HTTP server. | 103 | //config: HTTP server. |
104 | //config: | 104 | //config: |
105 | //config:config FEATURE_HTTPD_PORT_DEFAULT | ||
106 | //config: int "Default port" | ||
107 | //config: default 80 | ||
108 | //config: range 1 65535 | ||
109 | //config: depends on HTTPD | ||
110 | //config: | ||
105 | //config:config FEATURE_HTTPD_RANGES | 111 | //config:config FEATURE_HTTPD_RANGES |
106 | //config: bool "Support 'Ranges:' header" | 112 | //config: bool "Support 'Ranges:' header" |
107 | //config: default y | 113 | //config: default y |
@@ -277,7 +283,7 @@ | |||
277 | //usage: ) | 283 | //usage: ) |
278 | //usage: "\n -f Don't daemonize" | 284 | //usage: "\n -f Don't daemonize" |
279 | //usage: "\n -v[v] Verbose" | 285 | //usage: "\n -v[v] Verbose" |
280 | //usage: "\n -p [IP:]PORT Bind to IP:PORT (default *:80)" | 286 | //usage: "\n -p [IP:]PORT Bind to IP:PORT (default *:"STR(CONFIG_FEATURE_HTTPD_PORT_DEFAULT)")" |
281 | //usage: IF_FEATURE_HTTPD_SETUID( | 287 | //usage: IF_FEATURE_HTTPD_SETUID( |
282 | //usage: "\n -u USER[:GRP] Set uid/gid after binding to port") | 288 | //usage: "\n -u USER[:GRP] Set uid/gid after binding to port") |
283 | //usage: IF_FEATURE_HTTPD_BASIC_AUTH( | 289 | //usage: IF_FEATURE_HTTPD_BASIC_AUTH( |
@@ -325,6 +331,9 @@ | |||
325 | 331 | ||
326 | static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN; | 332 | static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN; |
327 | 333 | ||
334 | #define STR1(s) #s | ||
335 | #define STR(s) STR1(s) | ||
336 | |||
328 | static const char DEFAULT_PATH_HTTPD_CONF[] ALIGN1 = "/etc"; | 337 | static const char DEFAULT_PATH_HTTPD_CONF[] ALIGN1 = "/etc"; |
329 | static const char HTTPD_CONF[] ALIGN1 = "httpd.conf"; | 338 | static const char HTTPD_CONF[] ALIGN1 = "httpd.conf"; |
330 | static const char HTTP_200[] ALIGN1 = "HTTP/1.1 200 OK\r\n"; | 339 | static const char HTTP_200[] ALIGN1 = "HTTP/1.1 200 OK\r\n"; |
@@ -551,7 +560,7 @@ enum { | |||
551 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ | 560 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ |
552 | IF_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \ | 561 | IF_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \ |
553 | IF_FEATURE_HTTPD_RANGES(range_start = -1;) \ | 562 | IF_FEATURE_HTTPD_RANGES(range_start = -1;) \ |
554 | bind_addr_or_port = "80"; \ | 563 | bind_addr_or_port = STR(CONFIG_FEATURE_HTTPD_PORT_DEFAULT); \ |
555 | index_page = index_html; \ | 564 | index_page = index_html; \ |
556 | file_size = -1; \ | 565 | file_size = -1; \ |
557 | } while (0) | 566 | } while (0) |
diff --git a/networking/nc.c b/networking/nc.c index 3483edb01..5525e41f9 100644 --- a/networking/nc.c +++ b/networking/nc.c | |||
@@ -226,7 +226,7 @@ int nc_main(int argc, char **argv) | |||
226 | close(sfd); | 226 | close(sfd); |
227 | } else { | 227 | } else { |
228 | cfd = create_and_connect_stream_or_die(argv[0], | 228 | cfd = create_and_connect_stream_or_die(argv[0], |
229 | argv[1] ? bb_lookup_port(argv[1], "tcp", 0) : 0); | 229 | bb_lookup_port(argv[1], "tcp", 0)); |
230 | } | 230 | } |
231 | } | 231 | } |
232 | 232 | ||
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c index 25b95246f..cfa133eae 100644 --- a/networking/nc_bloaty.c +++ b/networking/nc_bloaty.c | |||
@@ -813,8 +813,6 @@ int nc_main(int argc UNUSED_PARAM, char **argv) | |||
813 | //if (option_mask32 & OPT_o) /* hexdump log */ | 813 | //if (option_mask32 & OPT_o) /* hexdump log */ |
814 | if (option_mask32 & OPT_p) { /* local source port */ | 814 | if (option_mask32 & OPT_p) { /* local source port */ |
815 | o_lport = bb_lookup_port(str_p, o_udpmode ? "udp" : "tcp", 0); | 815 | o_lport = bb_lookup_port(str_p, o_udpmode ? "udp" : "tcp", 0); |
816 | if (!o_lport) | ||
817 | bb_error_msg_and_die("bad local port '%s'", str_p); | ||
818 | } | 816 | } |
819 | //if (option_mask32 & OPT_r) /* randomize various things */ | 817 | //if (option_mask32 & OPT_r) /* randomize various things */ |
820 | //if (option_mask32 & OPT_u) /* use UDP */ | 818 | //if (option_mask32 & OPT_u) /* use UDP */ |
@@ -827,9 +825,8 @@ int nc_main(int argc UNUSED_PARAM, char **argv) | |||
827 | 825 | ||
828 | if (argv[0]) { | 826 | if (argv[0]) { |
829 | themaddr = xhost2sockaddr(argv[0], | 827 | themaddr = xhost2sockaddr(argv[0], |
830 | argv[1] | 828 | bb_lookup_port(argv[1], o_udpmode ? "udp" : "tcp", 0) |
831 | ? bb_lookup_port(argv[1], o_udpmode ? "udp" : "tcp", 0) | 829 | ); |
832 | : 0); | ||
833 | } | 830 | } |
834 | 831 | ||
835 | /* create & bind network socket */ | 832 | /* create & bind network socket */ |
diff --git a/networking/telnetd.c b/networking/telnetd.c index de4d733f9..581da1924 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c | |||
@@ -68,6 +68,12 @@ | |||
68 | //config: help | 68 | //config: help |
69 | //config: Selecting this will make telnetd able to run standalone. | 69 | //config: Selecting this will make telnetd able to run standalone. |
70 | //config: | 70 | //config: |
71 | //config:config FEATURE_TELNETD_PORT_DEFAULT | ||
72 | //config: int "Default port" | ||
73 | //config: default 23 | ||
74 | //config: range 1 65535 | ||
75 | //config: depends on FEATURE_TELNETD_STANDALONE | ||
76 | //config: | ||
71 | //config:config FEATURE_TELNETD_INETD_WAIT | 77 | //config:config FEATURE_TELNETD_INETD_WAIT |
72 | //config: bool "Support -w SEC option (inetd wait mode)" | 78 | //config: bool "Support -w SEC option (inetd wait mode)" |
73 | //config: default y | 79 | //config: default y |
@@ -103,7 +109,7 @@ | |||
103 | //usage: "\n -K Close connection as soon as login exits" | 109 | //usage: "\n -K Close connection as soon as login exits" |
104 | //usage: "\n (normally wait until all programs close slave pty)" | 110 | //usage: "\n (normally wait until all programs close slave pty)" |
105 | //usage: IF_FEATURE_TELNETD_STANDALONE( | 111 | //usage: IF_FEATURE_TELNETD_STANDALONE( |
106 | //usage: "\n -p PORT Port to listen on" | 112 | //usage: "\n -p PORT Port to listen on. Default "STR(CONFIG_FEATURE_TELNETD_PORT_DEFAULT) |
107 | //usage: "\n -b ADDR[:PORT] Address to bind to" | 113 | //usage: "\n -b ADDR[:PORT] Address to bind to" |
108 | //usage: "\n -F Run in foreground" | 114 | //usage: "\n -F Run in foreground" |
109 | //usage: "\n -i Inetd mode" | 115 | //usage: "\n -i Inetd mode" |
@@ -708,7 +714,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv) | |||
708 | } else { | 714 | } else { |
709 | master_fd = 0; | 715 | master_fd = 0; |
710 | if (!(opt & OPT_WAIT)) { | 716 | if (!(opt & OPT_WAIT)) { |
711 | unsigned portnbr = 23; | 717 | unsigned portnbr = CONFIG_FEATURE_TELNETD_PORT_DEFAULT; |
712 | if (opt & OPT_PORT) | 718 | if (opt & OPT_PORT) |
713 | portnbr = xatou16(opt_portnbr); | 719 | portnbr = xatou16(opt_portnbr); |
714 | master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr); | 720 | master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr); |
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index ca778dab8..e374771cb 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h | |||
@@ -38,13 +38,27 @@ struct dhcp_packet { | |||
38 | #define BROADCAST_FLAG 0x8000 /* "I need broadcast replies" */ | 38 | #define BROADCAST_FLAG 0x8000 /* "I need broadcast replies" */ |
39 | uint32_t ciaddr; /* client IP (if client is in BOUND, RENEW or REBINDING state) */ | 39 | uint32_t ciaddr; /* client IP (if client is in BOUND, RENEW or REBINDING state) */ |
40 | uint32_t yiaddr; /* 'your' (client) IP address */ | 40 | uint32_t yiaddr; /* 'your' (client) IP address */ |
41 | /* IP address of next server to use in bootstrap, returned in DHCPOFFER, DHCPACK by server */ | 41 | /* IP address of "next server" (usually meant to be an TFTP server) |
42 | * to use in bootstrap, returned in DHCPOFFER, DHCPACK by server: */ | ||
42 | uint32_t siaddr_nip; | 43 | uint32_t siaddr_nip; |
43 | uint32_t gateway_nip; /* aka 'giaddr': relay agent IP address */ | 44 | /* RFC 951 (BOOTP): "place my (server) IP address in the 'siaddr' field" |
45 | * (IOW: unconditionally, not just if we are also a TFTP server). | ||
46 | * DHCP servers don't have to do this, they add SERVER_ID option | ||
47 | * to their reply packets to let client identify lease-giving server. | ||
48 | */ | ||
49 | uint32_t gateway_nip; /* aka 'giaddr': relay agent IP address, else 0 */ | ||
44 | uint8_t chaddr[16]; /* link-layer client hardware address (MAC) */ | 50 | uint8_t chaddr[16]; /* link-layer client hardware address (MAC) */ |
45 | uint8_t sname[64]; /* server host name (ASCIZ) */ | 51 | uint8_t sname[64]; /* server host name (ASCIZ) */ |
52 | /* RFC 951 (BOOTP): "If the client wishes to restrict booting | ||
53 | * to a particular server name, it may place [it] in 'sname'" | ||
54 | */ | ||
46 | uint8_t file[128]; /* boot file name (ASCIZ) */ | 55 | uint8_t file[128]; /* boot file name (ASCIZ) */ |
47 | uint32_t cookie; /* fixed first four option bytes (99,130,83,99 dec) */ | 56 | /* RFC 951 (BOOTP): in client requests, "...can be a 'generic' name |
57 | * such as 'unix' or 'gateway'; this means 'boot the named program | ||
58 | * configured for my machine'" | ||
59 | */ | ||
60 | /* BOOTP fields end here, BOOTP says optional uint8_t vend[64] follows */ | ||
61 | uint32_t cookie; /* DHCP magic bytes: 99,130,83,99 decimal */ | ||
48 | uint8_t options[DHCP_OPTIONS_BUFSIZE + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS]; | 62 | uint8_t options[DHCP_OPTIONS_BUFSIZE + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS]; |
49 | }; | 63 | }; |
50 | #define DHCP_PKT_SNAME_LEN 64 | 64 | #define DHCP_PKT_SNAME_LEN 64 |
@@ -142,18 +156,21 @@ struct dhcp_scan_state { | |||
142 | //#define DHCP_NTP_SERVER 0x2a | 156 | //#define DHCP_NTP_SERVER 0x2a |
143 | //#define DHCP_WINS_SERVER 0x2c | 157 | //#define DHCP_WINS_SERVER 0x2c |
144 | #define DHCP_REQUESTED_IP 0x32 /* 50: sent by client if specific IP is wanted */ | 158 | #define DHCP_REQUESTED_IP 0x32 /* 50: sent by client if specific IP is wanted */ |
145 | #define DHCP_LEASE_TIME 0x33 /* 51: */ | 159 | #define DHCP_LEASE_TIME 0x33 /* 51: 32bit big-endian */ |
146 | #define DHCP_OPTION_OVERLOAD 0x34 /* 52: */ | 160 | #define DHCP_OPTION_OVERLOAD 0x34 /* 52: 1 byte */ |
147 | #define DHCP_MESSAGE_TYPE 0x35 /* 53: */ | 161 | #define DHCP_MESSAGE_TYPE 0x35 /* 53: 1 byte */ |
148 | #define DHCP_SERVER_ID 0x36 /* 54: server's IP */ | 162 | #define DHCP_SERVER_ID 0x36 /* 54: server's IP */ |
149 | #define DHCP_PARAM_REQ 0x37 /* 55: list of options client wants */ | 163 | #define DHCP_PARAM_REQ 0x37 /* 55: list of options client wants */ |
150 | //#define DHCP_ERR_MESSAGE 0x38 /* 56: error message when sending NAK etc */ | 164 | //#define DHCP_ERR_MESSAGE 0x38 /* 56: error message when sending NAK etc */ |
151 | #define DHCP_MAX_SIZE 0x39 /* 57: */ | 165 | #define DHCP_MAX_SIZE 0x39 /* 57: 16bit big-endian */ |
166 | // 0x3a /* 58: from server: renew time, 32bit big-endian */ | ||
167 | // 0x3b /* 59: from server: rebind time, 32bit big-endian */ | ||
152 | #define DHCP_VENDOR 0x3c /* 60: client's vendor (a string) */ | 168 | #define DHCP_VENDOR 0x3c /* 60: client's vendor (a string) */ |
153 | #define DHCP_CLIENT_ID 0x3d /* 61: by default client's MAC addr, but may be arbitrarily long */ | 169 | #define DHCP_CLIENT_ID 0x3d /* 61: by default client's MAC addr, but may be arbitrarily long */ |
154 | //#define DHCP_TFTP_SERVER_NAME 0x42 /* 66: same as 'sname' field */ | 170 | //#define DHCP_TFTP_SERVER_NAME 0x42 /* 66: same as 'sname' field */ |
155 | //#define DHCP_BOOT_FILE 0x43 /* 67: same as 'file' field */ | 171 | //#define DHCP_BOOT_FILE 0x43 /* 67: same as 'file' field */ |
156 | //#define DHCP_USER_CLASS 0x4d /* 77: RFC 3004. set of LASCII strings. "I am a printer" etc */ | 172 | //#define DHCP_USER_CLASS 0x4d /* 77: RFC 3004. set of LASCII strings. "I am a printer" etc */ |
173 | // 0x50 /* 80: rapid commit ("I'm ok with getting immediate ACK, not just OFFER"), 0 bytes */ | ||
157 | #define DHCP_FQDN 0x51 /* 81: client asks to update DNS to map its FQDN to its new IP */ | 174 | #define DHCP_FQDN 0x51 /* 81: client asks to update DNS to map its FQDN to its new IP */ |
158 | //#define DHCP_PCODE 0x64 /* 100: RFC 4833. IEEE 1003.1 TZ string */ | 175 | //#define DHCP_PCODE 0x64 /* 100: RFC 4833. IEEE 1003.1 TZ string */ |
159 | //#define DHCP_TCODE 0x65 /* 101: RFC 4833. Reference to the TZ database string */ | 176 | //#define DHCP_TCODE 0x65 /* 101: RFC 4833. Reference to the TZ database string */ |
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 91f70970a..0f5edb75c 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c | |||
@@ -27,7 +27,7 @@ | |||
27 | //kbuild:lib-$(CONFIG_FEATURE_UDHCP_RFC3397) += domain_codec.o | 27 | //kbuild:lib-$(CONFIG_FEATURE_UDHCP_RFC3397) += domain_codec.o |
28 | 28 | ||
29 | //usage:#define udhcpd_trivial_usage | 29 | //usage:#define udhcpd_trivial_usage |
30 | //usage: "[-fS] [-I ADDR]" IF_FEATURE_UDHCP_PORT(" [-P PORT]") " [CONFFILE]" | 30 | //usage: "[-fS] [-I ADDR] [-a MSEC]" IF_FEATURE_UDHCP_PORT(" [-P PORT]") " [CONFFILE]" |
31 | //usage:#define udhcpd_full_usage "\n\n" | 31 | //usage:#define udhcpd_full_usage "\n\n" |
32 | //usage: "DHCP server\n" | 32 | //usage: "DHCP server\n" |
33 | //usage: "\n -f Run in foreground" | 33 | //usage: "\n -f Run in foreground" |
@@ -451,6 +451,8 @@ static NOINLINE void read_config(const char *file) | |||
451 | 451 | ||
452 | server_data.start_ip = ntohl(server_data.start_ip); | 452 | server_data.start_ip = ntohl(server_data.start_ip); |
453 | server_data.end_ip = ntohl(server_data.end_ip); | 453 | server_data.end_ip = ntohl(server_data.end_ip); |
454 | if (server_data.start_ip > server_data.end_ip) | ||
455 | bb_error_msg_and_die("bad start/end IP range in %s", file); | ||
454 | } | 456 | } |
455 | 457 | ||
456 | static void write_leases(void) | 458 | static void write_leases(void) |
@@ -612,6 +614,10 @@ static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt) | |||
612 | udhcp_send_kernel_packet(dhcp_pkt, | 614 | udhcp_send_kernel_packet(dhcp_pkt, |
613 | server_data.server_nip, SERVER_PORT, | 615 | server_data.server_nip, SERVER_PORT, |
614 | dhcp_pkt->gateway_nip, SERVER_PORT, | 616 | dhcp_pkt->gateway_nip, SERVER_PORT, |
617 | /* Yes, relay agents receive (and send) all their packets on SERVER_PORT, | ||
618 | * even those which are clients' requests and would normally | ||
619 | * (i.e. without relay) use CLIENT_PORT. See RFC 1542. | ||
620 | */ | ||
615 | server_data.interface); | 621 | server_data.interface); |
616 | } | 622 | } |
617 | 623 | ||
@@ -858,7 +864,6 @@ int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
858 | int udhcpd_main(int argc UNUSED_PARAM, char **argv) | 864 | int udhcpd_main(int argc UNUSED_PARAM, char **argv) |
859 | { | 865 | { |
860 | int server_socket = -1, retval; | 866 | int server_socket = -1, retval; |
861 | uint8_t *state; | ||
862 | unsigned timeout_end; | 867 | unsigned timeout_end; |
863 | unsigned num_ips; | 868 | unsigned num_ips; |
864 | unsigned opt; | 869 | unsigned opt; |
@@ -877,6 +882,12 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
877 | /* Setup the signal pipe on fds 3,4 - must be before openlog() */ | 882 | /* Setup the signal pipe on fds 3,4 - must be before openlog() */ |
878 | udhcp_sp_setup(); | 883 | udhcp_sp_setup(); |
879 | 884 | ||
885 | #define OPT_f (1 << 0) | ||
886 | #define OPT_S (1 << 1) | ||
887 | #define OPT_I (1 << 2) | ||
888 | #define OPT_v (1 << 3) | ||
889 | #define OPT_a (1 << 4) | ||
890 | #define OPT_P (1 << 5) | ||
880 | opt = getopt32(argv, "^" | 891 | opt = getopt32(argv, "^" |
881 | "fSI:va:"IF_FEATURE_UDHCP_PORT("P:") | 892 | "fSI:va:"IF_FEATURE_UDHCP_PORT("P:") |
882 | "\0" | 893 | "\0" |
@@ -887,24 +898,24 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
887 | , &str_a | 898 | , &str_a |
888 | IF_FEATURE_UDHCP_PORT(, &str_P) | 899 | IF_FEATURE_UDHCP_PORT(, &str_P) |
889 | IF_UDHCP_VERBOSE(, &dhcp_verbose) | 900 | IF_UDHCP_VERBOSE(, &dhcp_verbose) |
890 | ); | 901 | ); |
891 | if (!(opt & 1)) { /* no -f */ | 902 | if (!(opt & OPT_f)) { /* no -f */ |
892 | bb_daemonize_or_rexec(0, argv); | 903 | bb_daemonize_or_rexec(0, argv); |
893 | logmode = LOGMODE_NONE; | 904 | logmode = LOGMODE_NONE; |
894 | } | 905 | } |
895 | /* update argv after the possible vfork+exec in daemonize */ | 906 | /* update argv after the possible vfork+exec in daemonize */ |
896 | argv += optind; | 907 | argv += optind; |
897 | if (opt & 2) { /* -S */ | 908 | if (opt & OPT_S) { |
898 | openlog(applet_name, LOG_PID, LOG_DAEMON); | 909 | openlog(applet_name, LOG_PID, LOG_DAEMON); |
899 | logmode |= LOGMODE_SYSLOG; | 910 | logmode |= LOGMODE_SYSLOG; |
900 | } | 911 | } |
901 | if (opt & 4) { /* -I */ | 912 | if (opt & OPT_I) { |
902 | len_and_sockaddr *lsa = xhost_and_af2sockaddr(str_I, 0, AF_INET); | 913 | len_and_sockaddr *lsa = xhost_and_af2sockaddr(str_I, 0, AF_INET); |
903 | server_data.server_nip = lsa->u.sin.sin_addr.s_addr; | 914 | server_data.server_nip = lsa->u.sin.sin_addr.s_addr; |
904 | free(lsa); | 915 | free(lsa); |
905 | } | 916 | } |
906 | #if ENABLE_FEATURE_UDHCP_PORT | 917 | #if ENABLE_FEATURE_UDHCP_PORT |
907 | if (opt & 32) { /* -P */ | 918 | if (opt & OPT_P) { |
908 | SERVER_PORT = xatou16(str_P); | 919 | SERVER_PORT = xatou16(str_P); |
909 | CLIENT_PORT = SERVER_PORT + 1; | 920 | CLIENT_PORT = SERVER_PORT + 1; |
910 | } | 921 | } |
@@ -960,6 +971,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
960 | struct dhcp_packet packet; | 971 | struct dhcp_packet packet; |
961 | int bytes; | 972 | int bytes; |
962 | int tv; | 973 | int tv; |
974 | uint8_t *msg_type; | ||
963 | uint8_t *server_id_opt; | 975 | uint8_t *server_id_opt; |
964 | uint8_t *requested_ip_opt; | 976 | uint8_t *requested_ip_opt; |
965 | uint32_t requested_nip; | 977 | uint32_t requested_nip; |
@@ -1017,6 +1029,9 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
1017 | * socket read inside this call is restarted on caught signals. | 1029 | * socket read inside this call is restarted on caught signals. |
1018 | */ | 1030 | */ |
1019 | bytes = udhcp_recv_kernel_packet(&packet, server_socket); | 1031 | bytes = udhcp_recv_kernel_packet(&packet, server_socket); |
1032 | //NB: we do not check source port here. Should we? | ||
1033 | //It should be CLIENT_PORT for clients, | ||
1034 | //or SERVER_PORT for relay agents (in which case giaddr must be != 0.0.0.0) | ||
1020 | if (bytes < 0) { | 1035 | if (bytes < 0) { |
1021 | /* bytes can also be -2 ("bad packet data") */ | 1036 | /* bytes can also be -2 ("bad packet data") */ |
1022 | if (bytes == -1 && errno != EINTR) { | 1037 | if (bytes == -1 && errno != EINTR) { |
@@ -1034,8 +1049,8 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
1034 | bb_info_msg("not a REQUEST%s", ", ignoring packet"); | 1049 | bb_info_msg("not a REQUEST%s", ", ignoring packet"); |
1035 | continue; | 1050 | continue; |
1036 | } | 1051 | } |
1037 | state = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE); | 1052 | msg_type = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE); |
1038 | if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) { | 1053 | if (!msg_type || msg_type[0] < DHCP_MINTYPE || msg_type[0] > DHCP_MAXTYPE) { |
1039 | bb_info_msg("no or bad message type option%s", ", ignoring packet"); | 1054 | bb_info_msg("no or bad message type option%s", ", ignoring packet"); |
1040 | continue; | 1055 | continue; |
1041 | } | 1056 | } |
@@ -1071,7 +1086,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
1071 | move_from_unaligned32(requested_nip, requested_ip_opt); | 1086 | move_from_unaligned32(requested_nip, requested_ip_opt); |
1072 | } | 1087 | } |
1073 | 1088 | ||
1074 | switch (state[0]) { | 1089 | switch (msg_type[0]) { |
1075 | 1090 | ||
1076 | case DHCPDISCOVER: | 1091 | case DHCPDISCOVER: |
1077 | log1("received %s", "DISCOVER"); | 1092 | log1("received %s", "DISCOVER"); |
diff --git a/networking/udhcp/dhcprelay.c b/networking/udhcp/dhcprelay.c index ef9447b4b..2352c34a2 100644 --- a/networking/udhcp/dhcprelay.c +++ b/networking/udhcp/dhcprelay.c | |||
@@ -17,7 +17,8 @@ | |||
17 | //usage:#define dhcprelay_trivial_usage | 17 | //usage:#define dhcprelay_trivial_usage |
18 | //usage: "CLIENT_IFACE[,CLIENT_IFACE2]... SERVER_IFACE [SERVER_IP]" | 18 | //usage: "CLIENT_IFACE[,CLIENT_IFACE2]... SERVER_IFACE [SERVER_IP]" |
19 | //usage:#define dhcprelay_full_usage "\n\n" | 19 | //usage:#define dhcprelay_full_usage "\n\n" |
20 | //usage: "Relay DHCP requests between clients and server" | 20 | //usage: "Relay DHCP requests between clients and server.\n" |
21 | //usage: "Without SERVER_IP, requests are broadcast on SERVER_IFACE." | ||
21 | 22 | ||
22 | #include "common.h" | 23 | #include "common.h" |
23 | 24 | ||
@@ -31,7 +32,7 @@ | |||
31 | /* This list holds information about clients. The xid_* functions manipulate this list. */ | 32 | /* This list holds information about clients. The xid_* functions manipulate this list. */ |
32 | struct xid_item { | 33 | struct xid_item { |
33 | unsigned timestamp; | 34 | unsigned timestamp; |
34 | int client; | 35 | unsigned iface_no; |
35 | uint32_t xid; | 36 | uint32_t xid; |
36 | struct sockaddr_in ip; | 37 | struct sockaddr_in ip; |
37 | struct xid_item *next; | 38 | struct xid_item *next; |
@@ -40,7 +41,7 @@ struct xid_item { | |||
40 | #define dhcprelay_xid_list (*(struct xid_item*)bb_common_bufsiz1) | 41 | #define dhcprelay_xid_list (*(struct xid_item*)bb_common_bufsiz1) |
41 | #define INIT_G() do { setup_common_bufsiz(); } while (0) | 42 | #define INIT_G() do { setup_common_bufsiz(); } while (0) |
42 | 43 | ||
43 | static struct xid_item *xid_add(uint32_t xid, struct sockaddr_in *ip, int client) | 44 | static struct xid_item *xid_add(uint32_t xid, struct sockaddr_in *ip, unsigned iface_no) |
44 | { | 45 | { |
45 | struct xid_item *item; | 46 | struct xid_item *item; |
46 | 47 | ||
@@ -50,7 +51,7 @@ static struct xid_item *xid_add(uint32_t xid, struct sockaddr_in *ip, int client | |||
50 | /* add xid entry */ | 51 | /* add xid entry */ |
51 | item->ip = *ip; | 52 | item->ip = *ip; |
52 | item->xid = xid; | 53 | item->xid = xid; |
53 | item->client = client; | 54 | item->iface_no = iface_no; |
54 | item->timestamp = monotonic_sec(); | 55 | item->timestamp = monotonic_sec(); |
55 | item->next = dhcprelay_xid_list.next; | 56 | item->next = dhcprelay_xid_list.next; |
56 | dhcprelay_xid_list.next = item; | 57 | dhcprelay_xid_list.next = item; |
@@ -127,10 +128,10 @@ static int get_dhcp_packet_type(struct dhcp_packet *p) | |||
127 | * make_iface_list - parses client/server interface names | 128 | * make_iface_list - parses client/server interface names |
128 | * returns array | 129 | * returns array |
129 | */ | 130 | */ |
130 | static char **make_iface_list(char **client_and_server_ifaces, int *client_number) | 131 | static char **make_iface_list(char **client_and_server_ifaces, unsigned *client_number) |
131 | { | 132 | { |
132 | char *s, **iface_list; | 133 | char *s, **iface_list; |
133 | int i, cn; | 134 | unsigned i, cn; |
134 | 135 | ||
135 | /* get number of items */ | 136 | /* get number of items */ |
136 | cn = 2; /* 1 server iface + at least 1 client one */ | 137 | cn = 2; /* 1 server iface + at least 1 client one */ |
@@ -165,9 +166,9 @@ static char **make_iface_list(char **client_and_server_ifaces, int *client_numbe | |||
165 | /* Creates listen sockets (in fds) bound to client and server ifaces, | 166 | /* Creates listen sockets (in fds) bound to client and server ifaces, |
166 | * and returns numerically max fd. | 167 | * and returns numerically max fd. |
167 | */ | 168 | */ |
168 | static int init_sockets(char **iface_list, int num_clients, int *fds) | 169 | static unsigned init_sockets(char **iface_list, unsigned num_clients, int *fds) |
169 | { | 170 | { |
170 | int i, n; | 171 | unsigned i, n; |
171 | 172 | ||
172 | n = 0; | 173 | n = 0; |
173 | for (i = 0; i < num_clients; i++) { | 174 | for (i = 0; i < num_clients; i++) { |
@@ -195,13 +196,14 @@ static int sendto_ip4(int sock, const void *msg, int msg_len, struct sockaddr_in | |||
195 | * p - packet to send | 196 | * p - packet to send |
196 | * client - number of the client | 197 | * client - number of the client |
197 | */ | 198 | */ |
198 | static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, int *fds, | 199 | static void pass_to_server(struct dhcp_packet *p, int packet_len, unsigned from_iface_no, int *fds, |
199 | struct sockaddr_in *client_addr, struct sockaddr_in *server_addr) | 200 | struct sockaddr_in *client_addr, struct sockaddr_in *server_addr) |
200 | { | 201 | { |
201 | int type; | 202 | int type; |
202 | 203 | ||
203 | /* check packet_type */ | 204 | /* check packet_type */ |
204 | type = get_dhcp_packet_type(p); | 205 | type = get_dhcp_packet_type(p); |
206 | //FIXME: the above does not consider packet_len! | ||
205 | if (type != DHCPDISCOVER && type != DHCPREQUEST | 207 | if (type != DHCPDISCOVER && type != DHCPREQUEST |
206 | && type != DHCPDECLINE && type != DHCPRELEASE | 208 | && type != DHCPDECLINE && type != DHCPRELEASE |
207 | && type != DHCPINFORM | 209 | && type != DHCPINFORM |
@@ -210,7 +212,10 @@ static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, in | |||
210 | } | 212 | } |
211 | 213 | ||
212 | /* create new xid entry */ | 214 | /* create new xid entry */ |
213 | xid_add(p->xid, client_addr, client); | 215 | xid_add(p->xid, client_addr, from_iface_no); |
216 | //TODO: since we key request/reply pairs on xid values, shouldn't we drop new requests | ||
217 | //with xid accidentally matching a xid of one of requests we currently hold | ||
218 | //waiting for their replies? | ||
214 | 219 | ||
215 | /* forward request to server */ | 220 | /* forward request to server */ |
216 | /* note that we send from fds[0] which is bound to SERVER_PORT (67). | 221 | /* note that we send from fds[0] which is bound to SERVER_PORT (67). |
@@ -229,25 +234,30 @@ static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds) | |||
229 | int type; | 234 | int type; |
230 | struct xid_item *item; | 235 | struct xid_item *item; |
231 | 236 | ||
232 | /* check xid */ | ||
233 | item = xid_find(p->xid); | ||
234 | if (!item) { | ||
235 | return; | ||
236 | } | ||
237 | |||
238 | /* check packet type */ | 237 | /* check packet type */ |
239 | type = get_dhcp_packet_type(p); | 238 | type = get_dhcp_packet_type(p); |
239 | //FIXME: the above does not consider packet_len! | ||
240 | if (type != DHCPOFFER && type != DHCPACK && type != DHCPNAK) { | 240 | if (type != DHCPOFFER && type != DHCPACK && type != DHCPNAK) { |
241 | return; | 241 | return; |
242 | } | 242 | } |
243 | 243 | ||
244 | /* check xid */ | ||
245 | item = xid_find(p->xid); | ||
246 | if (!item) { | ||
247 | return; | ||
248 | } | ||
249 | //NB: RFC 1542 section 4.1 seems to envision the logic that | ||
250 | //relay agents use giaddr (dhcp_msg.gateway_nip in our code) | ||
251 | //to find out on which interface to reply. | ||
252 | //(server is meant to copy giaddr from our request packet to its reply). | ||
253 | //Above, we don't use that logic, instead we use xid as a key. | ||
254 | |||
244 | //TODO: also do it if (p->flags & htons(BROADCAST_FLAG)) is set! | 255 | //TODO: also do it if (p->flags & htons(BROADCAST_FLAG)) is set! |
245 | if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY)) | 256 | if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY)) |
246 | item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST); | 257 | item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST); |
247 | 258 | ||
248 | if (sendto_ip4(fds[item->client], p, packet_len, &item->ip) != 0) { | 259 | sendto_ip4(fds[item->iface_no], p, packet_len, &item->ip); |
249 | return; /* send error occurred */ | 260 | /* ^^^ if send error occurred, we can't do much, hence no check */ |
250 | } | ||
251 | 261 | ||
252 | /* remove xid entry */ | 262 | /* remove xid entry */ |
253 | xid_del(p->xid); | 263 | xid_del(p->xid); |
@@ -259,7 +269,7 @@ int dhcprelay_main(int argc UNUSED_PARAM, char **argv) | |||
259 | struct sockaddr_in server_addr; | 269 | struct sockaddr_in server_addr; |
260 | char **iface_list; | 270 | char **iface_list; |
261 | int *fds; | 271 | int *fds; |
262 | int num_sockets, max_socket; | 272 | unsigned num_sockets, max_socket; |
263 | uint32_t our_nip; | 273 | uint32_t our_nip; |
264 | 274 | ||
265 | INIT_G(); | 275 | INIT_G(); |
@@ -293,7 +303,7 @@ int dhcprelay_main(int argc UNUSED_PARAM, char **argv) | |||
293 | // every N minutes? | 303 | // every N minutes? |
294 | fd_set rfds; | 304 | fd_set rfds; |
295 | struct timeval tv; | 305 | struct timeval tv; |
296 | int i; | 306 | unsigned i; |
297 | 307 | ||
298 | FD_ZERO(&rfds); | 308 | FD_ZERO(&rfds); |
299 | for (i = 0; i < num_sockets; i++) | 309 | for (i = 0; i < num_sockets; i++) |
@@ -304,15 +314,17 @@ int dhcprelay_main(int argc UNUSED_PARAM, char **argv) | |||
304 | int packlen; | 314 | int packlen; |
305 | struct dhcp_packet dhcp_msg; | 315 | struct dhcp_packet dhcp_msg; |
306 | 316 | ||
307 | /* server */ | 317 | /* from server */ |
308 | if (FD_ISSET(fds[0], &rfds)) { | 318 | if (FD_ISSET(fds[0], &rfds)) { |
309 | packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]); | 319 | packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]); |
320 | //NB: we do not check source port here. Should we? | ||
321 | //It should be SERVER_PORT. | ||
310 | if (packlen > 0) { | 322 | if (packlen > 0) { |
311 | pass_to_client(&dhcp_msg, packlen, fds); | 323 | pass_to_client(&dhcp_msg, packlen, fds); |
312 | } | 324 | } |
313 | } | 325 | } |
314 | 326 | ||
315 | /* clients */ | 327 | /* from clients */ |
316 | for (i = 1; i < num_sockets; i++) { | 328 | for (i = 1; i < num_sockets; i++) { |
317 | struct sockaddr_in client_addr; | 329 | struct sockaddr_in client_addr; |
318 | socklen_t addr_size; | 330 | socklen_t addr_size; |
@@ -325,6 +337,11 @@ int dhcprelay_main(int argc UNUSED_PARAM, char **argv) | |||
325 | (struct sockaddr *)(&client_addr), &addr_size); | 337 | (struct sockaddr *)(&client_addr), &addr_size); |
326 | if (packlen <= 0) | 338 | if (packlen <= 0) |
327 | continue; | 339 | continue; |
340 | //NB: we do not check source port here. Should we? | ||
341 | //It should be CLIENT_PORT for clients. | ||
342 | //It can be SERVER_PORT for relay agents (in which case giaddr must be != 0.0.0.0), | ||
343 | //but is it even supported to chain relay agents like this? | ||
344 | //(we still copy client_addr.port and use it to reply to the port we got request from) | ||
328 | 345 | ||
329 | /* Get our IP on corresponding client_iface */ | 346 | /* Get our IP on corresponding client_iface */ |
330 | // RFC 1542 | 347 | // RFC 1542 |
diff --git a/shell/ash.c b/shell/ash.c index 508633689..7544204d1 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -329,6 +329,10 @@ typedef long arith_t; | |||
329 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ | 329 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ |
330 | #endif | 330 | #endif |
331 | 331 | ||
332 | #ifndef unlikely | ||
333 | # define unlikely(cond) (cond) | ||
334 | #endif | ||
335 | |||
332 | #if !ENABLE_PLATFORM_MINGW32 | 336 | #if !ENABLE_PLATFORM_MINGW32 |
333 | # define is_absolute_path(path) ((path)[0] == '/') | 337 | # define is_absolute_path(path) ((path)[0] == '/') |
334 | #endif | 338 | #endif |
@@ -456,6 +460,7 @@ static const char *const optletters_optnames[] = { | |||
456 | "a" "allexport", | 460 | "a" "allexport", |
457 | "b" "notify", | 461 | "b" "notify", |
458 | "u" "nounset", | 462 | "u" "nounset", |
463 | "E" "errtrace", | ||
459 | "\0" "vi" | 464 | "\0" "vi" |
460 | #if BASH_PIPEFAIL | 465 | #if BASH_PIPEFAIL |
461 | ,"\0" "pipefail" | 466 | ,"\0" "pipefail" |
@@ -518,6 +523,7 @@ struct globals_misc { | |||
518 | #if !ENABLE_PLATFORM_MINGW32 | 523 | #if !ENABLE_PLATFORM_MINGW32 |
519 | smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ | 524 | smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ |
520 | #endif | 525 | #endif |
526 | smallint inps4; /* Prevent PS4 nesting. */ | ||
521 | int savestatus; /* exit status of last command outside traps */ | 527 | int savestatus; /* exit status of last command outside traps */ |
522 | int rootpid; /* pid of main shell */ | 528 | int rootpid; /* pid of main shell */ |
523 | /* shell level: 0 for the main shell, 1 for its children, and so on */ | 529 | /* shell level: 0 for the main shell, 1 for its children, and so on */ |
@@ -573,23 +579,24 @@ struct globals_misc { | |||
573 | #define aflag optlist[11] | 579 | #define aflag optlist[11] |
574 | #define bflag optlist[12] | 580 | #define bflag optlist[12] |
575 | #define uflag optlist[13] | 581 | #define uflag optlist[13] |
576 | #define viflag optlist[14] | 582 | #define Eflag optlist[14] |
583 | #define viflag optlist[15] | ||
577 | #if BASH_PIPEFAIL | 584 | #if BASH_PIPEFAIL |
578 | # define pipefail optlist[15] | 585 | # define pipefail optlist[16] |
579 | #else | 586 | #else |
580 | # define pipefail 0 | 587 | # define pipefail 0 |
581 | #endif | 588 | #endif |
582 | #if DEBUG | 589 | #if DEBUG |
583 | # define nolog optlist[15 + BASH_PIPEFAIL] | 590 | # define nolog optlist[16 + BASH_PIPEFAIL] |
584 | # define debug optlist[16 + BASH_PIPEFAIL] | 591 | # define debug optlist[17 + BASH_PIPEFAIL] |
585 | #endif | 592 | #endif |
586 | #if ENABLE_PLATFORM_MINGW32 | 593 | #if ENABLE_PLATFORM_MINGW32 |
587 | # define winxp optlist[15 + BASH_PIPEFAIL + 2*DEBUG] | 594 | # define winxp optlist[16 + BASH_PIPEFAIL + 2*DEBUG] |
588 | # if ENABLE_ASH_NOCONSOLE | 595 | # if ENABLE_ASH_NOCONSOLE |
589 | # define noconsole optlist[16 + BASH_PIPEFAIL + 2*DEBUG] | 596 | # define noconsole optlist[17 + BASH_PIPEFAIL + 2*DEBUG] |
590 | # endif | 597 | # endif |
591 | # if ENABLE_ASH_NOCASEGLOB | 598 | # if ENABLE_ASH_NOCASEGLOB |
592 | # define nocaseglob optlist[16 + BASH_PIPEFAIL + 2*DEBUG+ENABLE_ASH_NOCONSOLE] | 599 | # define nocaseglob optlist[17 + BASH_PIPEFAIL + 2*DEBUG+ENABLE_ASH_NOCONSOLE] |
593 | # endif | 600 | # endif |
594 | #endif | 601 | #endif |
595 | 602 | ||
@@ -610,7 +617,11 @@ struct globals_misc { | |||
610 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ | 617 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ |
611 | uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ | 618 | uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ |
612 | #endif | 619 | #endif |
613 | char *trap[NSIG]; | 620 | char *trap[NSIG + 1]; |
621 | /* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */ | ||
622 | #define NTRAP_ERR NSIG | ||
623 | #define NTRAP_LAST NSIG | ||
624 | |||
614 | #if !ENABLE_PLATFORM_MINGW32 | 625 | #if !ENABLE_PLATFORM_MINGW32 |
615 | char **trap_ptr; /* used only by "trap hack" */ | 626 | char **trap_ptr; /* used only by "trap hack" */ |
616 | #endif | 627 | #endif |
@@ -626,6 +637,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
626 | #define exitstatus (G_misc.exitstatus ) | 637 | #define exitstatus (G_misc.exitstatus ) |
627 | #define back_exitstatus (G_misc.back_exitstatus ) | 638 | #define back_exitstatus (G_misc.back_exitstatus ) |
628 | #define job_warning (G_misc.job_warning) | 639 | #define job_warning (G_misc.job_warning) |
640 | #define inps4 (G_misc.inps4 ) | ||
629 | #define savestatus (G_misc.savestatus ) | 641 | #define savestatus (G_misc.savestatus ) |
630 | #define rootpid (G_misc.rootpid ) | 642 | #define rootpid (G_misc.rootpid ) |
631 | #define shlvl (G_misc.shlvl ) | 643 | #define shlvl (G_misc.shlvl ) |
@@ -742,6 +754,9 @@ struct strpush { | |||
742 | #endif | 754 | #endif |
743 | char *string; /* remember the string since it may change */ | 755 | char *string; /* remember the string since it may change */ |
744 | 756 | ||
757 | /* Delay freeing so we can stop nested aliases. */ | ||
758 | struct strpush *spfree; | ||
759 | |||
745 | /* Remember last two characters for pungetc. */ | 760 | /* Remember last two characters for pungetc. */ |
746 | int lastc[2]; | 761 | int lastc[2]; |
747 | 762 | ||
@@ -764,6 +779,9 @@ struct parsefile { | |||
764 | struct strpush *strpush; /* for pushing strings at this level */ | 779 | struct strpush *strpush; /* for pushing strings at this level */ |
765 | struct strpush basestrpush; /* so pushing one is fast */ | 780 | struct strpush basestrpush; /* so pushing one is fast */ |
766 | 781 | ||
782 | /* Delay freeing so we can stop nested aliases. */ | ||
783 | struct strpush *spfree; | ||
784 | |||
767 | /* Remember last two characters for pungetc. */ | 785 | /* Remember last two characters for pungetc. */ |
768 | int lastc[2]; | 786 | int lastc[2]; |
769 | 787 | ||
@@ -2366,6 +2384,8 @@ struct globals_var { | |||
2366 | struct var varinit[ARRAY_SIZE(varinit_data)]; | 2384 | struct var varinit[ARRAY_SIZE(varinit_data)]; |
2367 | int lineno; | 2385 | int lineno; |
2368 | char linenovar[sizeof("LINENO=") + sizeof(int)*3]; | 2386 | char linenovar[sizeof("LINENO=") + sizeof(int)*3]; |
2387 | unsigned trap_depth; | ||
2388 | bool in_trap_ERR; /* ERR cannot recurse, no need to be a counter */ | ||
2369 | }; | 2389 | }; |
2370 | extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var; | 2390 | extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var; |
2371 | #define G_var (*ash_ptr_to_globals_var) | 2391 | #define G_var (*ash_ptr_to_globals_var) |
@@ -2376,6 +2396,8 @@ extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var; | |||
2376 | #define varinit (G_var.varinit ) | 2396 | #define varinit (G_var.varinit ) |
2377 | #define lineno (G_var.lineno ) | 2397 | #define lineno (G_var.lineno ) |
2378 | #define linenovar (G_var.linenovar ) | 2398 | #define linenovar (G_var.linenovar ) |
2399 | #define trap_depth (G_var.trap_depth ) | ||
2400 | #define in_trap_ERR (G_var.in_trap_ERR ) | ||
2379 | #define vifs varinit[0] | 2401 | #define vifs varinit[0] |
2380 | #if ENABLE_ASH_MAIL | 2402 | #if ENABLE_ASH_MAIL |
2381 | # define vmail varinit[1] | 2403 | # define vmail varinit[1] |
@@ -2547,7 +2569,7 @@ lookupvar(const char *name) | |||
2547 | v->var_func(NULL); | 2569 | v->var_func(NULL); |
2548 | #endif | 2570 | #endif |
2549 | if (!(v->flags & VUNSET)) { | 2571 | if (!(v->flags & VUNSET)) { |
2550 | if (v == &vlineno && v->var_text == linenovar) { | 2572 | if (v->var_text == linenovar) { |
2551 | fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno); | 2573 | fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno); |
2552 | } | 2574 | } |
2553 | return var_end(v->var_text); | 2575 | return var_end(v->var_text); |
@@ -3439,12 +3461,8 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
3439 | #define CENDFILE 11 /* end of file */ | 3461 | #define CENDFILE 11 /* end of file */ |
3440 | #define CCTL 12 /* like CWORD, except it must be escaped */ | 3462 | #define CCTL 12 /* like CWORD, except it must be escaped */ |
3441 | #define CSPCL 13 /* these terminate a word */ | 3463 | #define CSPCL 13 /* these terminate a word */ |
3442 | #define CIGN 14 /* character should be ignored */ | ||
3443 | 3464 | ||
3444 | #define PEOF 256 | 3465 | #define PEOF 256 |
3445 | #if ENABLE_ASH_ALIAS | ||
3446 | # define PEOA 257 | ||
3447 | #endif | ||
3448 | 3466 | ||
3449 | #define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE | 3467 | #define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE |
3450 | 3468 | ||
@@ -3454,49 +3472,43 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
3454 | # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8)) | 3472 | # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8)) |
3455 | #endif | 3473 | #endif |
3456 | static const uint16_t S_I_T[] ALIGN2 = { | 3474 | static const uint16_t S_I_T[] ALIGN2 = { |
3457 | #if ENABLE_ASH_ALIAS | 3475 | SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 0, ' ' */ |
3458 | SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */ | 3476 | SIT_ITEM(CNL , CNL , CNL , CNL ), /* 1, \n */ |
3459 | #endif | 3477 | SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 2, !*-/:=?[]~ */ |
3460 | SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */ | 3478 | SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 3, '"' */ |
3461 | SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */ | 3479 | SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 4, $ */ |
3462 | SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */ | 3480 | SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 5, "'" */ |
3463 | SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */ | 3481 | SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 6, ( */ |
3464 | SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */ | 3482 | SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 7, ) */ |
3465 | SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */ | 3483 | SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 8, \ */ |
3466 | SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */ | 3484 | SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 9, ` */ |
3467 | SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */ | 3485 | SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 10, } */ |
3468 | SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */ | ||
3469 | SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */ | ||
3470 | SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */ | ||
3471 | #if !USE_SIT_FUNCTION | 3486 | #if !USE_SIT_FUNCTION |
3472 | SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */ | 3487 | SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 11, PEOF */ |
3473 | SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */ | 3488 | SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 12, 0-9A-Za-z */ |
3474 | SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */ | 3489 | SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 13, CTLESC ... */ |
3475 | #endif | 3490 | #endif |
3476 | #undef SIT_ITEM | 3491 | #undef SIT_ITEM |
3477 | }; | 3492 | }; |
3478 | /* Constants below must match table above */ | 3493 | /* Constants below must match table above */ |
3479 | enum { | 3494 | enum { |
3480 | #if ENABLE_ASH_ALIAS | 3495 | CSPCL_CWORD_CWORD_CWORD , /* 0 */ |
3481 | CSPCL_CIGN_CIGN_CIGN , /* 0 */ | 3496 | CNL_CNL_CNL_CNL , /* 1 */ |
3482 | #endif | 3497 | CWORD_CCTL_CCTL_CWORD , /* 2 */ |
3483 | CSPCL_CWORD_CWORD_CWORD , /* 1 */ | 3498 | CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 3 */ |
3484 | CNL_CNL_CNL_CNL , /* 2 */ | 3499 | CVAR_CVAR_CWORD_CVAR , /* 4 */ |
3485 | CWORD_CCTL_CCTL_CWORD , /* 3 */ | 3500 | CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 5 */ |
3486 | CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */ | 3501 | CSPCL_CWORD_CWORD_CLP , /* 6 */ |
3487 | CVAR_CVAR_CWORD_CVAR , /* 5 */ | 3502 | CSPCL_CWORD_CWORD_CRP , /* 7 */ |
3488 | CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */ | 3503 | CBACK_CBACK_CCTL_CBACK , /* 8 */ |
3489 | CSPCL_CWORD_CWORD_CLP , /* 7 */ | 3504 | CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 9 */ |
3490 | CSPCL_CWORD_CWORD_CRP , /* 8 */ | 3505 | CENDVAR_CENDVAR_CWORD_CENDVAR , /* 10 */ |
3491 | CBACK_CBACK_CCTL_CBACK , /* 9 */ | 3506 | CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 11 */ |
3492 | CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */ | 3507 | CWORD_CWORD_CWORD_CWORD , /* 12 */ |
3493 | CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */ | 3508 | CCTL_CCTL_CCTL_CCTL , /* 13 */ |
3494 | CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */ | ||
3495 | CWORD_CWORD_CWORD_CWORD , /* 13 */ | ||
3496 | CCTL_CCTL_CCTL_CCTL , /* 14 */ | ||
3497 | }; | 3509 | }; |
3498 | 3510 | ||
3499 | /* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF, | 3511 | /* c in SIT(c, syntax) must be an *unsigned char* or PEOF, |
3500 | * caller must ensure proper cast on it if c is *char_ptr! | 3512 | * caller must ensure proper cast on it if c is *char_ptr! |
3501 | */ | 3513 | */ |
3502 | #if USE_SIT_FUNCTION | 3514 | #if USE_SIT_FUNCTION |
@@ -3514,44 +3526,28 @@ SIT(int c, int syntax) | |||
3514 | * but glibc one isn't. With '/' always treated as CWORD, | 3526 | * but glibc one isn't. With '/' always treated as CWORD, |
3515 | * both work fine. | 3527 | * both work fine. |
3516 | */ | 3528 | */ |
3517 | # if ENABLE_ASH_ALIAS | ||
3518 | static const uint8_t syntax_index_table[] ALIGN1 = { | ||
3519 | 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */ | ||
3520 | 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */ | ||
3521 | 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */ | ||
3522 | 11, 3 /* "}~" */ | ||
3523 | }; | ||
3524 | # else | ||
3525 | static const uint8_t syntax_index_table[] ALIGN1 = { | 3529 | static const uint8_t syntax_index_table[] ALIGN1 = { |
3526 | 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */ | 3530 | 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */ |
3527 | 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */ | 3531 | 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */ |
3528 | 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */ | 3532 | 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */ |
3529 | 10, 2 /* "}~" */ | 3533 | 10, 2 /* "}~" */ |
3530 | }; | 3534 | }; |
3531 | # endif | ||
3532 | const char *s; | 3535 | const char *s; |
3533 | int indx; | 3536 | int indx; |
3534 | 3537 | ||
3535 | if (c == PEOF) | 3538 | if (c == PEOF) |
3536 | return CENDFILE; | 3539 | return CENDFILE; |
3537 | # if ENABLE_ASH_ALIAS | 3540 | /* Cast is purely for paranoia here, |
3538 | if (c == PEOA) | 3541 | * just in case someone passed signed char to us */ |
3539 | indx = 0; | 3542 | if ((unsigned char)c >= CTL_FIRST |
3540 | else | 3543 | && (unsigned char)c <= CTL_LAST |
3541 | # endif | 3544 | ) { |
3542 | { | 3545 | return CCTL; |
3543 | /* Cast is purely for paranoia here, | ||
3544 | * just in case someone passed signed char to us */ | ||
3545 | if ((unsigned char)c >= CTL_FIRST | ||
3546 | && (unsigned char)c <= CTL_LAST | ||
3547 | ) { | ||
3548 | return CCTL; | ||
3549 | } | ||
3550 | s = strchrnul(spec_symbls, c); | ||
3551 | if (*s == '\0') | ||
3552 | return CWORD; | ||
3553 | indx = syntax_index_table[s - spec_symbls]; | ||
3554 | } | 3546 | } |
3547 | s = strchrnul(spec_symbls, c); | ||
3548 | if (*s == '\0') | ||
3549 | return CWORD; | ||
3550 | indx = syntax_index_table[s - spec_symbls]; | ||
3555 | return (S_I_T[indx] >> (syntax*4)) & 0xf; | 3551 | return (S_I_T[indx] >> (syntax*4)) & 0xf; |
3556 | } | 3552 | } |
3557 | 3553 | ||
@@ -3822,9 +3818,6 @@ static const uint8_t syntax_index_table[] ALIGN1 = { | |||
3822 | /* 254 */ CWORD_CWORD_CWORD_CWORD, | 3818 | /* 254 */ CWORD_CWORD_CWORD_CWORD, |
3823 | /* 255 */ CWORD_CWORD_CWORD_CWORD, | 3819 | /* 255 */ CWORD_CWORD_CWORD_CWORD, |
3824 | /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE, | 3820 | /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE, |
3825 | # if ENABLE_ASH_ALIAS | ||
3826 | /* PEOA */ CSPCL_CIGN_CIGN_CIGN, | ||
3827 | # endif | ||
3828 | }; | 3821 | }; |
3829 | 3822 | ||
3830 | #if 1 | 3823 | #if 1 |
@@ -5712,13 +5705,13 @@ clear_traps(void) | |||
5712 | char **tp; | 5705 | char **tp; |
5713 | 5706 | ||
5714 | INT_OFF; | 5707 | INT_OFF; |
5715 | for (tp = trap; tp < &trap[NSIG]; tp++) { | 5708 | for (tp = trap; tp <= &trap[NTRAP_LAST]; tp++) { |
5716 | if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */ | 5709 | if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */ |
5717 | if (trap_ptr == trap) | 5710 | if (trap_ptr == trap) |
5718 | free(*tp); | 5711 | free(*tp); |
5719 | /* else: it "belongs" to trap_ptr vector, don't free */ | 5712 | /* else: it "belongs" to trap_ptr vector, don't free */ |
5720 | *tp = NULL; | 5713 | *tp = NULL; |
5721 | if ((tp - trap) != 0) | 5714 | if ((tp - trap) != 0 && (tp - trap) < NSIG) |
5722 | setsignal(tp - trap); | 5715 | setsignal(tp - trap); |
5723 | } | 5716 | } |
5724 | } | 5717 | } |
@@ -10007,7 +10000,9 @@ dotrap(void) | |||
10007 | *g = 0; | 10000 | *g = 0; |
10008 | if (!p) | 10001 | if (!p) |
10009 | continue; | 10002 | continue; |
10003 | trap_depth++; | ||
10010 | evalstring(p, 0); | 10004 | evalstring(p, 0); |
10005 | trap_depth--; | ||
10011 | if (evalskip != SKIPFUNC) | 10006 | if (evalskip != SKIPFUNC) |
10012 | exitstatus = status; | 10007 | exitstatus = status; |
10013 | } | 10008 | } |
@@ -10044,6 +10039,9 @@ evaltree(union node *n, int flags) | |||
10044 | 10039 | ||
10045 | setstackmark(&smark); | 10040 | setstackmark(&smark); |
10046 | 10041 | ||
10042 | if (nflag) | ||
10043 | goto out; | ||
10044 | |||
10047 | if (n == NULL) { | 10045 | if (n == NULL) { |
10048 | TRACE(("evaltree(NULL) called\n")); | 10046 | TRACE(("evaltree(NULL) called\n")); |
10049 | goto out; | 10047 | goto out; |
@@ -10064,8 +10062,6 @@ evaltree(union node *n, int flags) | |||
10064 | goto setstatus; | 10062 | goto setstatus; |
10065 | case NREDIR: | 10063 | case NREDIR: |
10066 | errlinno = lineno = n->nredir.linno; | 10064 | errlinno = lineno = n->nredir.linno; |
10067 | if (funcline) | ||
10068 | lineno -= funcline - 1; | ||
10069 | expredir(n->nredir.redirect); | 10065 | expredir(n->nredir.redirect); |
10070 | pushredir(n->nredir.redirect); | 10066 | pushredir(n->nredir.redirect); |
10071 | status = redirectsafe(n->nredir.redirect, REDIR_PUSH); | 10067 | status = redirectsafe(n->nredir.redirect, REDIR_PUSH); |
@@ -10078,8 +10074,7 @@ evaltree(union node *n, int flags) | |||
10078 | case NCMD: | 10074 | case NCMD: |
10079 | evalfn = evalcommand; | 10075 | evalfn = evalcommand; |
10080 | checkexit: | 10076 | checkexit: |
10081 | if (eflag && !(flags & EV_TESTED)) | 10077 | checkexit = ~flags & EV_TESTED; |
10082 | checkexit = ~0; | ||
10083 | goto calleval; | 10078 | goto calleval; |
10084 | case NFOR: | 10079 | case NFOR: |
10085 | evalfn = evalfor; | 10080 | evalfn = evalfor; |
@@ -10101,7 +10096,6 @@ evaltree(union node *n, int flags) | |||
10101 | case NAND: | 10096 | case NAND: |
10102 | case NOR: | 10097 | case NOR: |
10103 | case NSEMI: { | 10098 | case NSEMI: { |
10104 | |||
10105 | #if NAND + 1 != NOR | 10099 | #if NAND + 1 != NOR |
10106 | #error NAND + 1 != NOR | 10100 | #error NAND + 1 != NOR |
10107 | #endif | 10101 | #endif |
@@ -10129,8 +10123,7 @@ evaltree(union node *n, int flags) | |||
10129 | if (!status) { | 10123 | if (!status) { |
10130 | n = n->nif.ifpart; | 10124 | n = n->nif.ifpart; |
10131 | goto evaln; | 10125 | goto evaln; |
10132 | } | 10126 | } else if (n->nif.elsepart) { |
10133 | if (n->nif.elsepart) { | ||
10134 | n = n->nif.elsepart; | 10127 | n = n->nif.elsepart; |
10135 | goto evaln; | 10128 | goto evaln; |
10136 | } | 10129 | } |
@@ -10152,10 +10145,36 @@ evaltree(union node *n, int flags) | |||
10152 | */ | 10145 | */ |
10153 | dotrap(); | 10146 | dotrap(); |
10154 | 10147 | ||
10155 | if (checkexit & status) | 10148 | if (checkexit && status) { |
10156 | raise_exception(EXEND); | 10149 | if (trap[NTRAP_ERR] && !in_trap_ERR) { |
10157 | if (flags & EV_EXIT) | 10150 | int err; |
10151 | struct jmploc *volatile savehandler = exception_handler; | ||
10152 | struct jmploc jmploc; | ||
10153 | |||
10154 | in_trap_ERR = 1; | ||
10155 | trap_depth++; | ||
10156 | err = setjmp(jmploc.loc); | ||
10157 | if (!err) { | ||
10158 | exception_handler = &jmploc; | ||
10159 | savestatus = exitstatus; | ||
10160 | evalstring(trap[NTRAP_ERR], 0); | ||
10161 | } | ||
10162 | trap_depth--; | ||
10163 | in_trap_ERR = 0; | ||
10164 | |||
10165 | exception_handler = savehandler; | ||
10166 | if (err && exception_type != EXERROR) | ||
10167 | longjmp(exception_handler->loc, 1); | ||
10168 | |||
10169 | exitstatus = savestatus; | ||
10170 | } | ||
10171 | if (eflag) | ||
10172 | goto exexit; | ||
10173 | } | ||
10174 | if (flags & EV_EXIT) { | ||
10175 | exexit: | ||
10158 | raise_exception(EXEND); | 10176 | raise_exception(EXEND); |
10177 | } | ||
10159 | 10178 | ||
10160 | popstackmark(&smark); | 10179 | popstackmark(&smark); |
10161 | TRACE(("leaving evaltree (no interrupts)\n")); | 10180 | TRACE(("leaving evaltree (no interrupts)\n")); |
@@ -10221,8 +10240,6 @@ evalfor(union node *n, int flags) | |||
10221 | int status = 0; | 10240 | int status = 0; |
10222 | 10241 | ||
10223 | errlinno = lineno = n->ncase.linno; | 10242 | errlinno = lineno = n->ncase.linno; |
10224 | if (funcline) | ||
10225 | lineno -= funcline - 1; | ||
10226 | 10243 | ||
10227 | arglist.list = NULL; | 10244 | arglist.list = NULL; |
10228 | arglist.lastp = &arglist.list; | 10245 | arglist.lastp = &arglist.list; |
@@ -10253,8 +10270,6 @@ evalcase(union node *n, int flags) | |||
10253 | int status = 0; | 10270 | int status = 0; |
10254 | 10271 | ||
10255 | errlinno = lineno = n->ncase.linno; | 10272 | errlinno = lineno = n->ncase.linno; |
10256 | if (funcline) | ||
10257 | lineno -= funcline - 1; | ||
10258 | 10273 | ||
10259 | arglist.list = NULL; | 10274 | arglist.list = NULL; |
10260 | arglist.lastp = &arglist.list; | 10275 | arglist.lastp = &arglist.list; |
@@ -10289,8 +10304,6 @@ evalsubshell(union node *n, int flags) | |||
10289 | int status; | 10304 | int status; |
10290 | 10305 | ||
10291 | errlinno = lineno = n->nredir.linno; | 10306 | errlinno = lineno = n->nredir.linno; |
10292 | if (funcline) | ||
10293 | lineno -= funcline - 1; | ||
10294 | 10307 | ||
10295 | expredir(n->nredir.redirect); | 10308 | expredir(n->nredir.redirect); |
10296 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) | 10309 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) |
@@ -10639,8 +10652,15 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | |||
10639 | struct jmploc *volatile savehandler; | 10652 | struct jmploc *volatile savehandler; |
10640 | struct jmploc jmploc; | 10653 | struct jmploc jmploc; |
10641 | int e; | 10654 | int e; |
10655 | int savelineno; | ||
10642 | int savefuncline; | 10656 | int savefuncline; |
10657 | char *savetrap = NULL; | ||
10643 | 10658 | ||
10659 | if (!Eflag) { | ||
10660 | savetrap = trap[NTRAP_ERR]; | ||
10661 | trap[NTRAP_ERR] = NULL; | ||
10662 | } | ||
10663 | savelineno = lineno; | ||
10644 | saveparam = shellparam; | 10664 | saveparam = shellparam; |
10645 | savefuncline = funcline; | 10665 | savefuncline = funcline; |
10646 | savehandler = exception_handler; | 10666 | savehandler = exception_handler; |
@@ -10663,7 +10683,14 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | |||
10663 | evaltree(func->n.ndefun.body, flags & EV_TESTED); | 10683 | evaltree(func->n.ndefun.body, flags & EV_TESTED); |
10664 | funcdone: | 10684 | funcdone: |
10665 | INT_OFF; | 10685 | INT_OFF; |
10686 | if (savetrap) { | ||
10687 | if (!trap[NTRAP_ERR]) | ||
10688 | trap[NTRAP_ERR] = savetrap; | ||
10689 | else | ||
10690 | free(savetrap); | ||
10691 | } | ||
10666 | funcline = savefuncline; | 10692 | funcline = savefuncline; |
10693 | lineno = savelineno; | ||
10667 | freefunc(func); | 10694 | freefunc(func); |
10668 | freeparam(&shellparam); | 10695 | freeparam(&shellparam); |
10669 | shellparam = saveparam; | 10696 | shellparam = saveparam; |
@@ -11076,11 +11103,12 @@ evalcommand(union node *cmd, int flags) | |||
11076 | int vlocal; | 11103 | int vlocal; |
11077 | 11104 | ||
11078 | errlinno = lineno = cmd->ncmd.linno; | 11105 | errlinno = lineno = cmd->ncmd.linno; |
11079 | if (funcline) | ||
11080 | lineno -= funcline - 1; | ||
11081 | 11106 | ||
11082 | /* First expand the arguments. */ | 11107 | /* First expand the arguments. */ |
11083 | TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); | 11108 | TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); |
11109 | #if BASH_PROCESS_SUBST | ||
11110 | redir_stop = redirlist; | ||
11111 | #endif | ||
11084 | file_stop = g_parsefile; | 11112 | file_stop = g_parsefile; |
11085 | back_exitstatus = 0; | 11113 | back_exitstatus = 0; |
11086 | 11114 | ||
@@ -11159,7 +11187,11 @@ evalcommand(union node *cmd, int flags) | |||
11159 | lastarg = nargv[-1]; | 11187 | lastarg = nargv[-1]; |
11160 | 11188 | ||
11161 | expredir(cmd->ncmd.redirect); | 11189 | expredir(cmd->ncmd.redirect); |
11190 | #if !BASH_PROCESS_SUBST | ||
11162 | redir_stop = pushredir(cmd->ncmd.redirect); | 11191 | redir_stop = pushredir(cmd->ncmd.redirect); |
11192 | #else | ||
11193 | pushredir(cmd->ncmd.redirect); | ||
11194 | #endif | ||
11163 | preverrout_fd = 2; | 11195 | preverrout_fd = 2; |
11164 | if (BASH_XTRACEFD && xflag) { | 11196 | if (BASH_XTRACEFD && xflag) { |
11165 | /* NB: bash closes fd == $BASH_XTRACEFD when it is changed. | 11197 | /* NB: bash closes fd == $BASH_XTRACEFD when it is changed. |
@@ -11196,10 +11228,12 @@ evalcommand(union node *cmd, int flags) | |||
11196 | } | 11228 | } |
11197 | 11229 | ||
11198 | /* Print the command if xflag is set. */ | 11230 | /* Print the command if xflag is set. */ |
11199 | if (xflag) { | 11231 | if (xflag && !inps4) { |
11200 | const char *pfx = ""; | 11232 | const char *pfx = ""; |
11201 | 11233 | ||
11234 | inps4 = 1; | ||
11202 | fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX)); | 11235 | fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX)); |
11236 | inps4 = 0; | ||
11203 | 11237 | ||
11204 | sp = varlist.list; | 11238 | sp = varlist.list; |
11205 | while (sp) { | 11239 | while (sp) { |
@@ -11483,7 +11517,7 @@ pushstring(char *s, struct alias *ap) | |||
11483 | 11517 | ||
11484 | len = strlen(s); | 11518 | len = strlen(s); |
11485 | INT_OFF; | 11519 | INT_OFF; |
11486 | if (g_parsefile->strpush) { | 11520 | if (g_parsefile->strpush || g_parsefile->spfree) { |
11487 | sp = ckzalloc(sizeof(*sp)); | 11521 | sp = ckzalloc(sizeof(*sp)); |
11488 | sp->prev = g_parsefile->strpush; | 11522 | sp->prev = g_parsefile->strpush; |
11489 | } else { | 11523 | } else { |
@@ -11493,6 +11527,7 @@ pushstring(char *s, struct alias *ap) | |||
11493 | sp->prev_string = g_parsefile->next_to_pgetc; | 11527 | sp->prev_string = g_parsefile->next_to_pgetc; |
11494 | sp->prev_left_in_line = g_parsefile->left_in_line; | 11528 | sp->prev_left_in_line = g_parsefile->left_in_line; |
11495 | sp->unget = g_parsefile->unget; | 11529 | sp->unget = g_parsefile->unget; |
11530 | sp->spfree = g_parsefile->spfree; | ||
11496 | memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc)); | 11531 | memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc)); |
11497 | #if ENABLE_ASH_ALIAS | 11532 | #if ENABLE_ASH_ALIAS |
11498 | sp->ap = ap; | 11533 | sp->ap = ap; |
@@ -11504,11 +11539,11 @@ pushstring(char *s, struct alias *ap) | |||
11504 | g_parsefile->next_to_pgetc = s; | 11539 | g_parsefile->next_to_pgetc = s; |
11505 | g_parsefile->left_in_line = len; | 11540 | g_parsefile->left_in_line = len; |
11506 | g_parsefile->unget = 0; | 11541 | g_parsefile->unget = 0; |
11542 | g_parsefile->spfree = NULL; | ||
11507 | INT_ON; | 11543 | INT_ON; |
11508 | } | 11544 | } |
11509 | 11545 | ||
11510 | static void | 11546 | static void popstring(void) |
11511 | popstring(void) | ||
11512 | { | 11547 | { |
11513 | struct strpush *sp = g_parsefile->strpush; | 11548 | struct strpush *sp = g_parsefile->strpush; |
11514 | 11549 | ||
@@ -11523,10 +11558,6 @@ popstring(void) | |||
11523 | if (sp->string != sp->ap->val) { | 11558 | if (sp->string != sp->ap->val) { |
11524 | free(sp->string); | 11559 | free(sp->string); |
11525 | } | 11560 | } |
11526 | sp->ap->flag &= ~ALIASINUSE; | ||
11527 | if (sp->ap->flag & ALIASDEAD) { | ||
11528 | unalias(sp->ap->name); | ||
11529 | } | ||
11530 | } | 11561 | } |
11531 | #endif | 11562 | #endif |
11532 | g_parsefile->next_to_pgetc = sp->prev_string; | 11563 | g_parsefile->next_to_pgetc = sp->prev_string; |
@@ -11534,8 +11565,7 @@ popstring(void) | |||
11534 | g_parsefile->unget = sp->unget; | 11565 | g_parsefile->unget = sp->unget; |
11535 | memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc)); | 11566 | memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc)); |
11536 | g_parsefile->strpush = sp->prev; | 11567 | g_parsefile->strpush = sp->prev; |
11537 | if (sp != &(g_parsefile->basestrpush)) | 11568 | g_parsefile->spfree = sp; |
11538 | free(sp); | ||
11539 | INT_ON; | 11569 | INT_ON; |
11540 | } | 11570 | } |
11541 | 11571 | ||
@@ -11628,26 +11658,16 @@ preadfd(void) | |||
11628 | */ | 11658 | */ |
11629 | //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__) | 11659 | //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__) |
11630 | #define pgetc_debug(...) ((void)0) | 11660 | #define pgetc_debug(...) ((void)0) |
11631 | static int pgetc(void); | 11661 | static int __pgetc(void); |
11632 | static int | 11662 | static int |
11633 | preadbuffer(void) | 11663 | preadbuffer(void) |
11634 | { | 11664 | { |
11635 | char *q; | 11665 | char *q; |
11636 | int more; | 11666 | int more; |
11637 | 11667 | ||
11638 | if (g_parsefile->strpush) { | 11668 | if (unlikely(g_parsefile->strpush)) { |
11639 | #if ENABLE_ASH_ALIAS | ||
11640 | if (g_parsefile->left_in_line == -1 | ||
11641 | && g_parsefile->strpush->ap | ||
11642 | && g_parsefile->next_to_pgetc[-1] != ' ' | ||
11643 | && g_parsefile->next_to_pgetc[-1] != '\t' | ||
11644 | ) { | ||
11645 | pgetc_debug("preadbuffer PEOA"); | ||
11646 | return PEOA; | ||
11647 | } | ||
11648 | #endif | ||
11649 | popstring(); | 11669 | popstring(); |
11650 | return pgetc(); | 11670 | return __pgetc(); |
11651 | } | 11671 | } |
11652 | /* on both branches above g_parsefile->left_in_line < 0. | 11672 | /* on both branches above g_parsefile->left_in_line < 0. |
11653 | * "pgetc" needs refilling. | 11673 | * "pgetc" needs refilling. |
@@ -11729,18 +11749,43 @@ preadbuffer(void) | |||
11729 | static void | 11749 | static void |
11730 | nlprompt(void) | 11750 | nlprompt(void) |
11731 | { | 11751 | { |
11732 | g_parsefile->linno++; | 11752 | if (trap_depth == 0) |
11753 | g_parsefile->linno++; | ||
11733 | setprompt_if(doprompt, 2); | 11754 | setprompt_if(doprompt, 2); |
11734 | } | 11755 | } |
11735 | static void | 11756 | static void |
11736 | nlnoprompt(void) | 11757 | nlnoprompt(void) |
11737 | { | 11758 | { |
11738 | g_parsefile->linno++; | 11759 | if (trap_depth == 0) |
11760 | g_parsefile->linno++; | ||
11739 | needprompt = doprompt; | 11761 | needprompt = doprompt; |
11740 | } | 11762 | } |
11741 | 11763 | ||
11742 | static int | 11764 | static void freestrings(struct strpush *sp) |
11743 | pgetc(void) | 11765 | { |
11766 | INT_OFF; | ||
11767 | do { | ||
11768 | struct strpush *psp; | ||
11769 | |||
11770 | if (sp->ap) { | ||
11771 | sp->ap->flag &= ~ALIASINUSE; | ||
11772 | if (sp->ap->flag & ALIASDEAD) { | ||
11773 | unalias(sp->ap->name); | ||
11774 | } | ||
11775 | } | ||
11776 | |||
11777 | psp = sp; | ||
11778 | sp = sp->spfree; | ||
11779 | |||
11780 | if (psp != &(g_parsefile->basestrpush)) | ||
11781 | free(psp); | ||
11782 | } while (sp); | ||
11783 | |||
11784 | g_parsefile->spfree = NULL; | ||
11785 | INT_ON; | ||
11786 | } | ||
11787 | |||
11788 | static int __pgetc(void) | ||
11744 | { | 11789 | { |
11745 | int c; | 11790 | int c; |
11746 | 11791 | ||
@@ -11762,23 +11807,19 @@ pgetc(void) | |||
11762 | return c; | 11807 | return c; |
11763 | } | 11808 | } |
11764 | 11809 | ||
11765 | #if ENABLE_ASH_ALIAS | 11810 | /* |
11766 | static int | 11811 | * Read a character from the script, returning PEOF on end of file. |
11767 | pgetc_without_PEOA(void) | 11812 | * Nul characters in the input are silently discarded. |
11813 | */ | ||
11814 | static int pgetc(void) | ||
11768 | { | 11815 | { |
11769 | int c; | 11816 | struct strpush *sp = g_parsefile->spfree; |
11770 | do { | 11817 | |
11771 | pgetc_debug("pgetc at %d:%p'%s'", | 11818 | if (unlikely(sp)) |
11772 | g_parsefile->left_in_line, | 11819 | freestrings(sp); |
11773 | g_parsefile->next_to_pgetc, | 11820 | |
11774 | g_parsefile->next_to_pgetc); | 11821 | return __pgetc(); |
11775 | c = pgetc(); | ||
11776 | } while (c == PEOA); | ||
11777 | return c; | ||
11778 | } | 11822 | } |
11779 | #else | ||
11780 | # define pgetc_without_PEOA() pgetc() | ||
11781 | #endif | ||
11782 | 11823 | ||
11783 | /* | 11824 | /* |
11784 | * Undo a call to pgetc. Only two characters may be pushed back. | 11825 | * Undo a call to pgetc. Only two characters may be pushed back. |
@@ -11855,6 +11896,7 @@ pushfile(void) | |||
11855 | pf->prev = g_parsefile; | 11896 | pf->prev = g_parsefile; |
11856 | pf->pf_fd = -1; | 11897 | pf->pf_fd = -1; |
11857 | /*pf->strpush = NULL; - ckzalloc did it */ | 11898 | /*pf->strpush = NULL; - ckzalloc did it */ |
11899 | /*pf->spfree = NULL;*/ | ||
11858 | /*pf->basestrpush.prev = NULL;*/ | 11900 | /*pf->basestrpush.prev = NULL;*/ |
11859 | /*pf->unget = 0;*/ | 11901 | /*pf->unget = 0;*/ |
11860 | g_parsefile = pf; | 11902 | g_parsefile = pf; |
@@ -11872,8 +11914,12 @@ popfile(void) | |||
11872 | if (pf->pf_fd >= 0) | 11914 | if (pf->pf_fd >= 0) |
11873 | close(pf->pf_fd); | 11915 | close(pf->pf_fd); |
11874 | free(pf->buf); | 11916 | free(pf->buf); |
11875 | while (pf->strpush) | 11917 | if (g_parsefile->spfree) |
11918 | freestrings(g_parsefile->spfree); | ||
11919 | while (pf->strpush) { | ||
11876 | popstring(); | 11920 | popstring(); |
11921 | freestrings(g_parsefile->spfree); | ||
11922 | } | ||
11877 | g_parsefile = pf->prev; | 11923 | g_parsefile = pf->prev; |
11878 | free(pf); | 11924 | free(pf); |
11879 | INT_ON; | 11925 | INT_ON; |
@@ -11969,7 +12015,7 @@ setinputstring(char *string) | |||
11969 | g_parsefile->next_to_pgetc = string; | 12015 | g_parsefile->next_to_pgetc = string; |
11970 | g_parsefile->left_in_line = strlen(string); | 12016 | g_parsefile->left_in_line = strlen(string); |
11971 | g_parsefile->buf = NULL; | 12017 | g_parsefile->buf = NULL; |
11972 | g_parsefile->linno = 1; | 12018 | g_parsefile->linno = lineno; |
11973 | INT_ON; | 12019 | INT_ON; |
11974 | } | 12020 | } |
11975 | 12021 | ||
@@ -12553,27 +12599,28 @@ static union node *andor(void); | |||
12553 | static union node *pipeline(void); | 12599 | static union node *pipeline(void); |
12554 | static union node *parse_command(void); | 12600 | static union node *parse_command(void); |
12555 | static void parseheredoc(void); | 12601 | static void parseheredoc(void); |
12556 | static int peektoken(void); | ||
12557 | static int readtoken(void); | 12602 | static int readtoken(void); |
12558 | 12603 | ||
12559 | static union node * | 12604 | static union node * |
12560 | list(int nlflag) | 12605 | list(int nlflag) |
12561 | { | 12606 | { |
12607 | int chknl = nlflag & 1 ? 0 : CHKNL; | ||
12562 | union node *n1, *n2, *n3; | 12608 | union node *n1, *n2, *n3; |
12563 | int tok; | 12609 | int tok; |
12564 | 12610 | ||
12565 | n1 = NULL; | 12611 | n1 = NULL; |
12566 | for (;;) { | 12612 | for (;;) { |
12567 | switch (readtoken()) { | 12613 | checkkwd = chknl | CHKKWD | CHKALIAS; |
12614 | tok = readtoken(); | ||
12615 | switch (tok) { | ||
12568 | case TNL: | 12616 | case TNL: |
12569 | if (!(nlflag & 1)) | ||
12570 | break; | ||
12571 | parseheredoc(); | 12617 | parseheredoc(); |
12572 | return n1; | 12618 | return n1; |
12573 | 12619 | ||
12574 | case TEOF: | 12620 | case TEOF: |
12575 | if (!n1 && (nlflag & 1)) | 12621 | if (!n1 && !chknl) |
12576 | n1 = NODE_EOF; | 12622 | n1 = NODE_EOF; |
12623 | out_eof: | ||
12577 | parseheredoc(); | 12624 | parseheredoc(); |
12578 | tokpushback++; | 12625 | tokpushback++; |
12579 | lasttoken = TEOF; | 12626 | lasttoken = TEOF; |
@@ -12581,8 +12628,7 @@ list(int nlflag) | |||
12581 | } | 12628 | } |
12582 | 12629 | ||
12583 | tokpushback++; | 12630 | tokpushback++; |
12584 | checkkwd = CHKNL | CHKKWD | CHKALIAS; | 12631 | if (nlflag == 2 && ((1 << tok) & tokendlist)) |
12585 | if (nlflag == 2 && ((1 << peektoken()) & tokendlist)) | ||
12586 | return n1; | 12632 | return n1; |
12587 | nlflag |= 2; | 12633 | nlflag |= 2; |
12588 | 12634 | ||
@@ -12611,15 +12657,16 @@ list(int nlflag) | |||
12611 | n1 = n3; | 12657 | n1 = n3; |
12612 | } | 12658 | } |
12613 | switch (tok) { | 12659 | switch (tok) { |
12614 | case TNL: | ||
12615 | case TEOF: | 12660 | case TEOF: |
12661 | goto out_eof; | ||
12662 | case TNL: | ||
12616 | tokpushback = 1; | 12663 | tokpushback = 1; |
12617 | /* fall through */ | 12664 | /* fall through */ |
12618 | case TBACKGND: | 12665 | case TBACKGND: |
12619 | case TSEMI: | 12666 | case TSEMI: |
12620 | break; | 12667 | break; |
12621 | default: | 12668 | default: |
12622 | if ((nlflag & 1)) | 12669 | if (!chknl) |
12623 | raise_error_unexpected_syntax(-1); | 12670 | raise_error_unexpected_syntax(-1); |
12624 | tokpushback = 1; | 12671 | tokpushback = 1; |
12625 | return n1; | 12672 | return n1; |
@@ -12793,8 +12840,9 @@ simplecmd(void) | |||
12793 | switch (t) { | 12840 | switch (t) { |
12794 | #if BASH_FUNCTION | 12841 | #if BASH_FUNCTION |
12795 | case TFUNCTION: | 12842 | case TFUNCTION: |
12796 | if (peektoken() != TWORD) | 12843 | if (readtoken() != TWORD) |
12797 | raise_error_unexpected_syntax(TWORD); | 12844 | raise_error_unexpected_syntax(TWORD); |
12845 | tokpushback = 1; | ||
12798 | function_flag = 1; | 12846 | function_flag = 1; |
12799 | break; | 12847 | break; |
12800 | #endif | 12848 | #endif |
@@ -12831,7 +12879,9 @@ simplecmd(void) | |||
12831 | #if BASH_FUNCTION | 12879 | #if BASH_FUNCTION |
12832 | if (function_flag) { | 12880 | if (function_flag) { |
12833 | checkkwd = CHKNL | CHKKWD; | 12881 | checkkwd = CHKNL | CHKKWD; |
12834 | switch (peektoken()) { | 12882 | t = readtoken(); |
12883 | tokpushback = 1; | ||
12884 | switch (t) { | ||
12835 | case TBEGIN: | 12885 | case TBEGIN: |
12836 | case TIF: | 12886 | case TIF: |
12837 | case TCASE: | 12887 | case TCASE: |
@@ -13184,7 +13234,7 @@ static int | |||
13184 | readtoken1(int c, int syntax, char *eofmark, int striptabs) | 13234 | readtoken1(int c, int syntax, char *eofmark, int striptabs) |
13185 | { | 13235 | { |
13186 | /* NB: syntax parameter fits into smallint */ | 13236 | /* NB: syntax parameter fits into smallint */ |
13187 | /* c parameter is an unsigned char or PEOF or PEOA */ | 13237 | /* c parameter is an unsigned char or PEOF */ |
13188 | char *out; | 13238 | char *out; |
13189 | size_t len; | 13239 | size_t len; |
13190 | struct nodelist *bqlist; | 13240 | struct nodelist *bqlist; |
@@ -13254,7 +13304,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
13254 | USTPUTC(c, out); | 13304 | USTPUTC(c, out); |
13255 | break; | 13305 | break; |
13256 | case CBACK: /* backslash */ | 13306 | case CBACK: /* backslash */ |
13257 | c = pgetc_without_PEOA(); | 13307 | c = pgetc(); |
13258 | if (c == PEOF) { | 13308 | if (c == PEOF) { |
13259 | USTPUTC(CTLESC, out); | 13309 | USTPUTC(CTLESC, out); |
13260 | USTPUTC('\\', out); | 13310 | USTPUTC('\\', out); |
@@ -13361,8 +13411,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
13361 | break; | 13411 | break; |
13362 | case CENDFILE: | 13412 | case CENDFILE: |
13363 | goto endword; /* exit outer loop */ | 13413 | goto endword; /* exit outer loop */ |
13364 | case CIGN: | ||
13365 | break; | ||
13366 | default: | 13414 | default: |
13367 | if (synstack->varnest == 0) { | 13415 | if (synstack->varnest == 0) { |
13368 | #if BASH_REDIR_OUTPUT | 13416 | #if BASH_REDIR_OUTPUT |
@@ -13384,8 +13432,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
13384 | #endif | 13432 | #endif |
13385 | goto endword; /* exit outer loop */ | 13433 | goto endword; /* exit outer loop */ |
13386 | } | 13434 | } |
13387 | IF_ASH_ALIAS(if (c != PEOA)) | 13435 | USTPUTC(c, out); |
13388 | USTPUTC(c, out); | ||
13389 | } | 13436 | } |
13390 | c = pgetc_top(synstack); | 13437 | c = pgetc_top(synstack); |
13391 | } /* for (;;) */ | 13438 | } /* for (;;) */ |
@@ -13436,14 +13483,9 @@ checkend: { | |||
13436 | int markloc; | 13483 | int markloc; |
13437 | char *p; | 13484 | char *p; |
13438 | 13485 | ||
13439 | #if ENABLE_ASH_ALIAS | ||
13440 | if (c == PEOA) | ||
13441 | c = pgetc_without_PEOA(); | ||
13442 | #endif | ||
13443 | if (striptabs) { | 13486 | if (striptabs) { |
13444 | while (c == '\t') { | 13487 | while (c == '\t') |
13445 | c = pgetc_without_PEOA(); | 13488 | c = pgetc(); |
13446 | } | ||
13447 | } | 13489 | } |
13448 | 13490 | ||
13449 | markloc = out - (char *)stackblock(); | 13491 | markloc = out - (char *)stackblock(); |
@@ -13457,12 +13499,13 @@ checkend: { | |||
13457 | * F | 13499 | * F |
13458 | * (see heredoc_bkslash_newline2.tests) | 13500 | * (see heredoc_bkslash_newline2.tests) |
13459 | */ | 13501 | */ |
13460 | c = pgetc_without_PEOA(); | 13502 | c = pgetc(); |
13461 | } | 13503 | } |
13462 | 13504 | ||
13463 | if (c == '\n' || c == PEOF) { | 13505 | if (c == '\n' || c == PEOF) { |
13464 | c = PEOF; | 13506 | c = PEOF; |
13465 | g_parsefile->linno++; | 13507 | if (trap_depth == 0) |
13508 | g_parsefile->linno++; | ||
13466 | needprompt = doprompt; | 13509 | needprompt = doprompt; |
13467 | } else { | 13510 | } else { |
13468 | int len_here; | 13511 | int len_here; |
@@ -13581,7 +13624,6 @@ parsesub: { | |||
13581 | 13624 | ||
13582 | c = pgetc_eatbnl(); | 13625 | c = pgetc_eatbnl(); |
13583 | if ((checkkwd & CHKEOFMARK) | 13626 | if ((checkkwd & CHKEOFMARK) |
13584 | || c > 255 /* PEOA or PEOF */ | ||
13585 | || (c != '(' && c != '{' && !is_name(c) && !is_special(c)) | 13627 | || (c != '(' && c != '{' && !is_name(c) && !is_special(c)) |
13586 | ) { | 13628 | ) { |
13587 | #if BASH_DOLLAR_SQUOTE | 13629 | #if BASH_DOLLAR_SQUOTE |
@@ -13604,7 +13646,7 @@ parsesub: { | |||
13604 | PARSEBACKQNEW(); | 13646 | PARSEBACKQNEW(); |
13605 | } | 13647 | } |
13606 | } else { | 13648 | } else { |
13607 | /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */ | 13649 | /* $VAR, $<specialchar>, ${...}, or PEOF */ |
13608 | smalluint newsyn = synstack->syntax; | 13650 | smalluint newsyn = synstack->syntax; |
13609 | 13651 | ||
13610 | USTPUTC(CTLVAR, out); | 13652 | USTPUTC(CTLVAR, out); |
@@ -13799,13 +13841,9 @@ parsebackq: { | |||
13799 | ) { | 13841 | ) { |
13800 | STPUTC('\\', pout); | 13842 | STPUTC('\\', pout); |
13801 | } | 13843 | } |
13802 | if (pc <= 255 /* not PEOA or PEOF */) { | 13844 | break; |
13803 | break; | ||
13804 | } | ||
13805 | /* fall through */ | ||
13806 | 13845 | ||
13807 | case PEOF: | 13846 | case PEOF: |
13808 | IF_ASH_ALIAS(case PEOA:) | ||
13809 | raise_error_syntax("EOF in backquote substitution"); | 13847 | raise_error_syntax("EOF in backquote substitution"); |
13810 | 13848 | ||
13811 | case '\n': | 13849 | case '\n': |
@@ -13940,7 +13978,7 @@ xxreadtoken(void) | |||
13940 | setprompt_if(needprompt, 2); | 13978 | setprompt_if(needprompt, 2); |
13941 | for (;;) { /* until token or start of word found */ | 13979 | for (;;) { /* until token or start of word found */ |
13942 | c = pgetc_eatbnl(); | 13980 | c = pgetc_eatbnl(); |
13943 | if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA)) | 13981 | if (c == ' ' || c == '\t') |
13944 | continue; | 13982 | continue; |
13945 | 13983 | ||
13946 | if (c == '#') { | 13984 | if (c == '#') { |
@@ -13998,7 +14036,6 @@ xxreadtoken(void) | |||
13998 | c = pgetc_eatbnl(); | 14036 | c = pgetc_eatbnl(); |
13999 | switch (c) { | 14037 | switch (c) { |
14000 | case ' ': case '\t': | 14038 | case ' ': case '\t': |
14001 | IF_ASH_ALIAS(case PEOA:) | ||
14002 | continue; | 14039 | continue; |
14003 | case '#': | 14040 | case '#': |
14004 | while ((c = pgetc()) != '\n' && c != PEOF) | 14041 | while ((c = pgetc()) != '\n' && c != PEOF) |
@@ -14058,10 +14095,14 @@ readtoken(void) | |||
14058 | if (kwd & CHKNL) { | 14095 | if (kwd & CHKNL) { |
14059 | while (t == TNL) { | 14096 | while (t == TNL) { |
14060 | parseheredoc(); | 14097 | parseheredoc(); |
14098 | checkkwd = 0; | ||
14061 | t = xxreadtoken(); | 14099 | t = xxreadtoken(); |
14062 | } | 14100 | } |
14063 | } | 14101 | } |
14064 | 14102 | ||
14103 | kwd |= checkkwd; | ||
14104 | checkkwd = 0; | ||
14105 | |||
14065 | if (t != TWORD || quoteflag) { | 14106 | if (t != TWORD || quoteflag) { |
14066 | goto out; | 14107 | goto out; |
14067 | } | 14108 | } |
@@ -14080,7 +14121,7 @@ readtoken(void) | |||
14080 | } | 14121 | } |
14081 | } | 14122 | } |
14082 | 14123 | ||
14083 | if (checkkwd & CHKALIAS) { | 14124 | if (kwd & CHKALIAS) { |
14084 | #if ENABLE_ASH_ALIAS | 14125 | #if ENABLE_ASH_ALIAS |
14085 | struct alias *ap; | 14126 | struct alias *ap; |
14086 | ap = lookupalias(wordtext, 1); | 14127 | ap = lookupalias(wordtext, 1); |
@@ -14093,7 +14134,6 @@ readtoken(void) | |||
14093 | #endif | 14134 | #endif |
14094 | } | 14135 | } |
14095 | out: | 14136 | out: |
14096 | checkkwd = 0; | ||
14097 | #if DEBUG | 14137 | #if DEBUG |
14098 | if (!alreadyseen) | 14138 | if (!alreadyseen) |
14099 | TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : "")); | 14139 | TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : "")); |
@@ -14103,16 +14143,6 @@ readtoken(void) | |||
14103 | return t; | 14143 | return t; |
14104 | } | 14144 | } |
14105 | 14145 | ||
14106 | static int | ||
14107 | peektoken(void) | ||
14108 | { | ||
14109 | int t; | ||
14110 | |||
14111 | t = readtoken(); | ||
14112 | tokpushback = 1; | ||
14113 | return t; | ||
14114 | } | ||
14115 | |||
14116 | /* | 14146 | /* |
14117 | * Read and parse a command. Returns NODE_EOF on end of file. | 14147 | * Read and parse a command. Returns NODE_EOF on end of file. |
14118 | * (NULL is a valid parse tree indicating a blank line.) | 14148 | * (NULL is a valid parse tree indicating a blank line.) |
@@ -14162,23 +14192,26 @@ parseheredoc(void) | |||
14162 | static const char * | 14192 | static const char * |
14163 | expandstr(const char *ps, int syntax_type) | 14193 | expandstr(const char *ps, int syntax_type) |
14164 | { | 14194 | { |
14165 | union node n; | 14195 | struct parsefile *file_stop; |
14196 | struct jmploc *volatile savehandler; | ||
14197 | struct heredoc *saveheredoclist; | ||
14198 | const char *result; | ||
14166 | int saveprompt; | 14199 | int saveprompt; |
14167 | struct parsefile *file_stop = g_parsefile; | ||
14168 | volatile int saveint; | ||
14169 | struct jmploc *volatile savehandler = exception_handler; | ||
14170 | struct jmploc jmploc; | 14200 | struct jmploc jmploc; |
14171 | const char *volatile result; | 14201 | union node n; |
14172 | int err; | 14202 | int err; |
14173 | 14203 | ||
14204 | file_stop = g_parsefile; | ||
14205 | |||
14174 | /* XXX Fix (char *) cast. */ | 14206 | /* XXX Fix (char *) cast. */ |
14175 | setinputstring((char *)ps); | 14207 | setinputstring((char *)ps); |
14176 | 14208 | ||
14209 | saveheredoclist = heredoclist; | ||
14210 | heredoclist = NULL; | ||
14177 | saveprompt = doprompt; | 14211 | saveprompt = doprompt; |
14178 | doprompt = 0; | 14212 | doprompt = 0; |
14179 | result = ps; | 14213 | result = ps; |
14180 | 14214 | savehandler = exception_handler; | |
14181 | SAVE_INT(saveint); | ||
14182 | err = setjmp(jmploc.loc); | 14215 | err = setjmp(jmploc.loc); |
14183 | if (err) | 14216 | if (err) |
14184 | goto out; | 14217 | goto out; |
@@ -14188,7 +14221,7 @@ expandstr(const char *ps, int syntax_type) | |||
14188 | * PS1='$(date "+%H:%M:%S) > ' | 14221 | * PS1='$(date "+%H:%M:%S) > ' |
14189 | */ | 14222 | */ |
14190 | exception_handler = &jmploc; | 14223 | exception_handler = &jmploc; |
14191 | readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0); | 14224 | readtoken1(pgetc_eatbnl(), syntax_type, FAKEEOFMARK, 0); |
14192 | 14225 | ||
14193 | n.narg.type = NARG; | 14226 | n.narg.type = NARG; |
14194 | n.narg.next = NULL; | 14227 | n.narg.next = NULL; |
@@ -14205,11 +14238,11 @@ out: | |||
14205 | exception_handler = savehandler; | 14238 | exception_handler = savehandler; |
14206 | if (err && exception_type != EXERROR) | 14239 | if (err && exception_type != EXERROR) |
14207 | longjmp(exception_handler->loc, 1); | 14240 | longjmp(exception_handler->loc, 1); |
14208 | RESTORE_INT(saveint); | ||
14209 | 14241 | ||
14210 | doprompt = saveprompt; | 14242 | doprompt = saveprompt; |
14211 | /* Try: PS1='`xxx(`' */ | 14243 | /* Try: PS1='`xxx(`' */ |
14212 | unwindfiles(file_stop); | 14244 | unwindfiles(file_stop); |
14245 | heredoclist = saveheredoclist; | ||
14213 | 14246 | ||
14214 | return result; | 14247 | return result; |
14215 | } | 14248 | } |
@@ -14329,9 +14362,6 @@ cmdloop(int top) | |||
14329 | if (doing_jobctl) | 14362 | if (doing_jobctl) |
14330 | showjobs(SHOW_CHANGED|SHOW_STDERR); | 14363 | showjobs(SHOW_CHANGED|SHOW_STDERR); |
14331 | #endif | 14364 | #endif |
14332 | #if BASH_PROCESS_SUBST | ||
14333 | unwindredir(NULL); | ||
14334 | #endif | ||
14335 | inter = 0; | 14365 | inter = 0; |
14336 | if (iflag && top) { | 14366 | if (iflag && top) { |
14337 | inter++; | 14367 | inter++; |
@@ -14355,7 +14385,7 @@ cmdloop(int top) | |||
14355 | out2str("\nUse \"exit\" to leave shell.\n"); | 14385 | out2str("\nUse \"exit\" to leave shell.\n"); |
14356 | } | 14386 | } |
14357 | numeof++; | 14387 | numeof++; |
14358 | } else if (nflag == 0) { | 14388 | } else { |
14359 | int i; | 14389 | int i; |
14360 | 14390 | ||
14361 | #if !ENABLE_PLATFORM_MINGW32 | 14391 | #if !ENABLE_PLATFORM_MINGW32 |
@@ -14746,7 +14776,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14746 | nextopt(nullstr); | 14776 | nextopt(nullstr); |
14747 | ap = argptr; | 14777 | ap = argptr; |
14748 | if (!*ap) { | 14778 | if (!*ap) { |
14749 | for (signo = 0; signo < NSIG; signo++) { | 14779 | for (signo = 0; signo <= NTRAP_LAST; signo++) { |
14750 | char *tr = trap_ptr[signo]; | 14780 | char *tr = trap_ptr[signo]; |
14751 | if (tr) { | 14781 | if (tr) { |
14752 | /* note: bash adds "SIG", but only if invoked | 14782 | /* note: bash adds "SIG", but only if invoked |
@@ -14755,7 +14785,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14755 | * We are printing short names: */ | 14785 | * We are printing short names: */ |
14756 | out1fmt("trap -- %s %s\n", | 14786 | out1fmt("trap -- %s %s\n", |
14757 | single_quote(tr), | 14787 | single_quote(tr), |
14758 | get_signame(signo)); | 14788 | (signo == NTRAP_ERR) ? "ERR" : get_signame(signo)); |
14759 | /* trap_ptr != trap only if we are in special-cased `trap` code. | 14789 | /* trap_ptr != trap only if we are in special-cased `trap` code. |
14760 | * In this case, we will exit very soon, no need to free(). */ | 14790 | * In this case, we will exit very soon, no need to free(). */ |
14761 | /* if (trap_ptr != trap && tp[0]) */ | 14791 | /* if (trap_ptr != trap && tp[0]) */ |
@@ -14781,7 +14811,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14781 | 14811 | ||
14782 | exitcode = 0; | 14812 | exitcode = 0; |
14783 | while (*ap) { | 14813 | while (*ap) { |
14784 | signo = get_signum(*ap); | 14814 | signo = strcmp(*ap, "ERR") == 0 ? NTRAP_ERR : get_signum(*ap); |
14785 | if (signo < 0) { | 14815 | if (signo < 0) { |
14786 | /* Mimic bash message exactly */ | 14816 | /* Mimic bash message exactly */ |
14787 | ash_msg("%s: invalid signal specification", *ap); | 14817 | ash_msg("%s: invalid signal specification", *ap); |
@@ -14802,7 +14832,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14802 | } | 14832 | } |
14803 | free(trap[signo]); | 14833 | free(trap[signo]); |
14804 | trap[signo] = action; | 14834 | trap[signo] = action; |
14805 | if (signo != 0) | 14835 | if (signo != 0 && signo < NSIG) |
14806 | setsignal(signo); | 14836 | setsignal(signo); |
14807 | INT_ON; | 14837 | INT_ON; |
14808 | next: | 14838 | next: |
@@ -15197,6 +15227,7 @@ exitreset(void) | |||
15197 | } | 15227 | } |
15198 | evalskip = 0; | 15228 | evalskip = 0; |
15199 | loopnest = 0; | 15229 | loopnest = 0; |
15230 | inps4 = 0; | ||
15200 | 15231 | ||
15201 | /* from expand.c: */ | 15232 | /* from expand.c: */ |
15202 | ifsfree(); | 15233 | ifsfree(); |
@@ -15244,7 +15275,9 @@ exitshell(void) | |||
15244 | if (p) { | 15275 | if (p) { |
15245 | trap[0] = NULL; | 15276 | trap[0] = NULL; |
15246 | evalskip = 0; | 15277 | evalskip = 0; |
15278 | trap_depth++; | ||
15247 | evalstring(p, 0); | 15279 | evalstring(p, 0); |
15280 | trap_depth--; | ||
15248 | evalskip = SKIPFUNCDEF; | 15281 | evalskip = SKIPFUNCDEF; |
15249 | /*free(p); - we'll exit soon */ | 15282 | /*free(p); - we'll exit soon */ |
15250 | } | 15283 | } |
@@ -15704,6 +15737,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
15704 | // ^^ not necessary since now we special-case fd 0 | 15737 | // ^^ not necessary since now we special-case fd 0 |
15705 | // in save_fd_on_redirect() | 15738 | // in save_fd_on_redirect() |
15706 | 15739 | ||
15740 | lineno = 0; // bash compat | ||
15707 | // dash: evalstring(minusc, sflag ? 0 : EV_EXIT); | 15741 | // dash: evalstring(minusc, sflag ? 0 : EV_EXIT); |
15708 | // The above makes | 15742 | // The above makes |
15709 | // ash -sc 'echo $-' | 15743 | // ash -sc 'echo $-' |
diff --git a/shell/ash_test/ash-alias/alias_brace.right b/shell/ash_test/ash-alias/alias_brace.right new file mode 100644 index 000000000..7326d9603 --- /dev/null +++ b/shell/ash_test/ash-alias/alias_brace.right | |||
@@ -0,0 +1 @@ | |||
Ok | |||
diff --git a/shell/ash_test/ash-alias/alias_brace.tests b/shell/ash_test/ash-alias/alias_brace.tests new file mode 100755 index 000000000..7571b64ac --- /dev/null +++ b/shell/ash_test/ash-alias/alias_brace.tests | |||
@@ -0,0 +1,16 @@ | |||
1 | # Note: bash would need: | ||
2 | #shopt -s expand_aliases | ||
3 | # to enable aliases in non-interactive mode | ||
4 | alias BEGIN={ END=} | ||
5 | BEGIN | ||
6 | cat <<- EOF > /dev/null | ||
7 | $(:) | ||
8 | EOF | ||
9 | END | ||
10 | |||
11 | : <<- EOF && | ||
12 | $(:) | ||
13 | EOF | ||
14 | BEGIN | ||
15 | echo Ok | ||
16 | END | ||
diff --git a/shell/ash_test/ash-alias/alias_case.right b/shell/ash_test/ash-alias/alias_case.right new file mode 100644 index 000000000..7326d9603 --- /dev/null +++ b/shell/ash_test/ash-alias/alias_case.right | |||
@@ -0,0 +1 @@ | |||
Ok | |||
diff --git a/shell/ash_test/ash-alias/alias_case.tests b/shell/ash_test/ash-alias/alias_case.tests new file mode 100755 index 000000000..ed8275875 --- /dev/null +++ b/shell/ash_test/ash-alias/alias_case.tests | |||
@@ -0,0 +1,8 @@ | |||
1 | # Note: bash would need: | ||
2 | #shopt -s expand_aliases | ||
3 | # to enable aliases in non-interactive mode | ||
4 | alias a="case x in " b=x | ||
5 | a | ||
6 | b) echo BAD;; | ||
7 | *) echo Ok;; | ||
8 | esac | ||
diff --git a/shell/ash_test/ash-misc/control_char3.right b/shell/ash_test/ash-misc/control_char3.right index 283e02cbb..654005d24 100644 --- a/shell/ash_test/ash-misc/control_char3.right +++ b/shell/ash_test/ash-misc/control_char3.right | |||
@@ -1 +1 @@ | |||
SHELL: line 1: : not found | SHELL: line 0: : not found | ||
diff --git a/shell/ash_test/ash-misc/control_char4.right b/shell/ash_test/ash-misc/control_char4.right index 2bf18e684..ec9d5fc98 100644 --- a/shell/ash_test/ash-misc/control_char4.right +++ b/shell/ash_test/ash-misc/control_char4.right | |||
@@ -1 +1 @@ | |||
SHELL: line 1: -: not found | SHELL: line 0: -: not found | ||
diff --git a/shell/ash_test/ash-misc/exitcode_trap7.right b/shell/ash_test/ash-misc/exitcode_trap7.right new file mode 100644 index 000000000..07d66e9d9 --- /dev/null +++ b/shell/ash_test/ash-misc/exitcode_trap7.right | |||
@@ -0,0 +1,2 @@ | |||
1 | Start | ||
2 | Ok:0 | ||
diff --git a/shell/ash_test/ash-misc/exitcode_trap7.tests b/shell/ash_test/ash-misc/exitcode_trap7.tests new file mode 100755 index 000000000..f4b0eb544 --- /dev/null +++ b/shell/ash_test/ash-misc/exitcode_trap7.tests | |||
@@ -0,0 +1,7 @@ | |||
1 | $THIS_SH -c ' | ||
2 | cleanup() { set +e; false; } | ||
3 | set -e | ||
4 | trap cleanup EXIT | ||
5 | echo Start | ||
6 | ' | ||
7 | echo Ok:$? | ||
diff --git a/shell/ash_test/ash-misc/set-n1.right b/shell/ash_test/ash-misc/set-n1.right new file mode 100644 index 000000000..ac01831a7 --- /dev/null +++ b/shell/ash_test/ash-misc/set-n1.right | |||
@@ -0,0 +1,3 @@ | |||
1 | set -n stops in -c? | ||
2 | YES | ||
3 | Ok:0 | ||
diff --git a/shell/ash_test/ash-misc/set-n1.tests b/shell/ash_test/ash-misc/set-n1.tests new file mode 100755 index 000000000..90d0f9146 --- /dev/null +++ b/shell/ash_test/ash-misc/set-n1.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | $THIS_SH -c "echo 'set -n stops in -c?'; set -n; echo NO" && echo YES | ||
2 | echo Ok:$? | ||
diff --git a/shell/ash_test/ash-misc/shift1.right b/shell/ash_test/ash-misc/shift1.right index b53453c3a..fdba79fd3 100644 --- a/shell/ash_test/ash-misc/shift1.right +++ b/shell/ash_test/ash-misc/shift1.right | |||
@@ -1,5 +1,5 @@ | |||
1 | 2 3 4 | 1 | 2 3 4 |
2 | 0: shift: line 1: Illegal number: -1 | 2 | 0: shift: line 0: Illegal number: -1 |
3 | 1 2 3 4 | 3 | 1 2 3 4 |
4 | 2 3 4 | 4 | 2 3 4 |
5 | 3 4 | 5 | 3 4 |
diff --git a/shell/ash_test/ash-misc/tickquote1.right b/shell/ash_test/ash-misc/tickquote1.right index 2e661bfe3..e55a31c2d 100644 --- a/shell/ash_test/ash-misc/tickquote1.right +++ b/shell/ash_test/ash-misc/tickquote1.right | |||
@@ -1 +1 @@ | |||
./tickquote1.tests: line 1: syntax error: unterminated quoted string | ./tickquote1.tests: line 0: syntax error: unterminated quoted string | ||
diff --git a/shell/ash_test/ash-parsing/groups_and_keywords2.right b/shell/ash_test/ash-parsing/groups_and_keywords2.right index 3fcbeb662..2ce38fe6e 100644 --- a/shell/ash_test/ash-parsing/groups_and_keywords2.right +++ b/shell/ash_test/ash-parsing/groups_and_keywords2.right | |||
@@ -1,3 +1,3 @@ | |||
1 | ./groups_and_keywords2.tests: eval: line 1: syntax error: unexpected ")" | 1 | ./groups_and_keywords2.tests: eval: line 2: syntax error: unexpected ")" |
2 | Fail:2 | 2 | Fail:2 |
3 | ./groups_and_keywords2.tests: line 8: syntax error: unexpected ")" | 3 | ./groups_and_keywords2.tests: line 8: syntax error: unexpected ")" |
diff --git a/shell/ash_test/ash-psubst/emptytick.right b/shell/ash_test/ash-psubst/emptytick.right index 459c4f735..8fe9839ca 100644 --- a/shell/ash_test/ash-psubst/emptytick.right +++ b/shell/ash_test/ash-psubst/emptytick.right | |||
@@ -1,8 +1,8 @@ | |||
1 | 0 | 1 | 0 |
2 | 0 | 2 | 0 |
3 | ./emptytick.tests: line 1: : Permission denied | 3 | ./emptytick.tests: line 2: : Permission denied |
4 | 127 | 4 | 127 |
5 | ./emptytick.tests: line 1: : Permission denied | 5 | ./emptytick.tests: line 3: : Permission denied |
6 | 127 | 6 | 127 |
7 | 0 | 7 | 0 |
8 | 0 | 8 | 0 |
diff --git a/shell/ash_test/ash-vars/param_expand_alt.right b/shell/ash_test/ash-vars/param_expand_alt.right index 1303f8064..d10f1206f 100644 --- a/shell/ash_test/ash-vars/param_expand_alt.right +++ b/shell/ash_test/ash-vars/param_expand_alt.right | |||
@@ -1,5 +1,5 @@ | |||
1 | SHELL: line 1: syntax error: bad substitution | 1 | SHELL: line 0: syntax error: bad substitution |
2 | SHELL: line 1: syntax error: bad substitution | 2 | SHELL: line 0: syntax error: bad substitution |
3 | __ | 3 | __ |
4 | _z_ _z_ | 4 | _z_ _z_ |
5 | _ _ _ _ _ | 5 | _ _ _ _ _ |
diff --git a/shell/ash_test/ash-vars/param_expand_assign.right b/shell/ash_test/ash-vars/param_expand_assign.right index 6e9ea1379..52eaef9f8 100644 --- a/shell/ash_test/ash-vars/param_expand_assign.right +++ b/shell/ash_test/ash-vars/param_expand_assign.right | |||
@@ -1,11 +1,11 @@ | |||
1 | SHELL: line 1: syntax error: bad substitution | 1 | SHELL: line 0: syntax error: bad substitution |
2 | SHELL: line 1: syntax error: bad substitution | 2 | SHELL: line 0: syntax error: bad substitution |
3 | SHELL: line 1: syntax error: bad substitution | 3 | SHELL: line 0: syntax error: bad substitution |
4 | 0 | 4 | 0 |
5 | SHELL: line 1: 1: bad variable name | 5 | SHELL: line 0: 1: bad variable name |
6 | SHELL: line 1: 1: bad variable name | 6 | SHELL: line 0: 1: bad variable name |
7 | SHELL: line 1: 1: bad variable name | 7 | SHELL: line 0: 1: bad variable name |
8 | SHELL: line 1: 1: bad variable name | 8 | SHELL: line 0: 1: bad variable name |
9 | _aa | 9 | _aa |
10 | _aa | 10 | _aa |
11 | _aa | 11 | _aa |
diff --git a/shell/ash_test/ash-vars/param_expand_bash_substring.right b/shell/ash_test/ash-vars/param_expand_bash_substring.right index 687dd9002..22a0b2881 100644 --- a/shell/ash_test/ash-vars/param_expand_bash_substring.right +++ b/shell/ash_test/ash-vars/param_expand_bash_substring.right | |||
@@ -1,8 +1,8 @@ | |||
1 | SHELL: line 1: syntax error: bad substitution | 1 | SHELL: line 0: syntax error: bad substitution |
2 | SHELL: line 1: syntax error: bad substitution | 2 | SHELL: line 0: syntax error: bad substitution |
3 | SHELL: line 1: syntax error: bad substitution | 3 | SHELL: line 0: syntax error: bad substitution |
4 | SHELL: line 1: syntax error: bad substitution | 4 | SHELL: line 0: syntax error: bad substitution |
5 | SHELL: line 1: syntax error: missing '}' | 5 | SHELL: line 0: syntax error: missing '}' |
6 | 0 | 6 | 0 |
7 | 1 =|| | 7 | 1 =|| |
8 | 1:1 =|| | 8 | 1:1 =|| |
diff --git a/shell/ash_test/ash-vars/param_expand_default.right b/shell/ash_test/ash-vars/param_expand_default.right index 7a42f67e8..0852105ca 100644 --- a/shell/ash_test/ash-vars/param_expand_default.right +++ b/shell/ash_test/ash-vars/param_expand_default.right | |||
@@ -1,4 +1,4 @@ | |||
1 | SHELL: line 1: syntax error: bad substitution | 1 | SHELL: line 0: syntax error: bad substitution |
2 | _0 _0 | 2 | _0 _0 |
3 | _ _ _ _word _word | 3 | _ _ _ _word _word |
4 | _aaaa _aaaa _aaaa _aaaa _aaaa | 4 | _aaaa _aaaa _aaaa _aaaa _aaaa |
diff --git a/shell/ash_test/ash-vars/param_expand_indicate_error.right b/shell/ash_test/ash-vars/param_expand_indicate_error.right index 33afacee0..53ea07181 100644 --- a/shell/ash_test/ash-vars/param_expand_indicate_error.right +++ b/shell/ash_test/ash-vars/param_expand_indicate_error.right | |||
@@ -1,14 +1,14 @@ | |||
1 | SHELL: line 1: syntax error: bad substitution | 1 | SHELL: line 0: syntax error: bad substitution |
2 | 1 | 2 | 1 |
3 | 0 | 3 | 0 |
4 | ==== | 4 | ==== |
5 | _ | 5 | _ |
6 | SHELL: line 1: 1: parameter not set | 6 | SHELL: line 0: 1: parameter not set |
7 | SHELL: line 1: 1: parameter not set or null | 7 | SHELL: line 0: 1: parameter not set or null |
8 | SHELL: line 1: 1: message1 | 8 | SHELL: line 0: 1: message1 |
9 | SHELL: line 1: 1: message1 | 9 | SHELL: line 0: 1: message1 |
10 | SHELL: line 1: 1: unset! | 10 | SHELL: line 0: 1: unset! |
11 | SHELL: line 1: 1: null or unset! | 11 | SHELL: line 0: 1: null or unset! |
12 | ==== | 12 | ==== |
13 | _aaaa | 13 | _aaaa |
14 | _aaaa | 14 | _aaaa |
@@ -19,20 +19,20 @@ _aaaa | |||
19 | _aaaa | 19 | _aaaa |
20 | ==== | 20 | ==== |
21 | _ | 21 | _ |
22 | SHELL: line 1: f: parameter not set | 22 | SHELL: line 0: f: parameter not set |
23 | SHELL: line 1: f: parameter not set or null | 23 | SHELL: line 0: f: parameter not set or null |
24 | SHELL: line 1: f: message3 | 24 | SHELL: line 0: f: message3 |
25 | SHELL: line 1: f: message3 | 25 | SHELL: line 0: f: message3 |
26 | SHELL: line 1: f: unset! | 26 | SHELL: line 0: f: unset! |
27 | SHELL: line 1: f: null or unset! | 27 | SHELL: line 0: f: null or unset! |
28 | ==== | 28 | ==== |
29 | _ | 29 | _ |
30 | _ | 30 | _ |
31 | SHELL: line 1: f: parameter not set or null | 31 | SHELL: line 0: f: parameter not set or null |
32 | _ | 32 | _ |
33 | SHELL: line 1: f: message4 | 33 | SHELL: line 0: f: message4 |
34 | _ | 34 | _ |
35 | SHELL: line 1: f: null or unset! | 35 | SHELL: line 0: f: null or unset! |
36 | ==== | 36 | ==== |
37 | _fff | 37 | _fff |
38 | _fff | 38 | _fff |
diff --git a/shell/ash_test/ash-vars/var6.right b/shell/ash_test/ash-vars/var6.right index b37417fa1..e83f7b5eb 100644 --- a/shell/ash_test/ash-vars/var6.right +++ b/shell/ash_test/ash-vars/var6.right | |||
@@ -1,2 +1,2 @@ | |||
1 | SHELL: line 1: syntax error: bad substitution | 1 | SHELL: line 0: syntax error: bad substitution |
2 | SHELL: line 1: syntax error: bad substitution | 2 | SHELL: line 0: syntax error: bad substitution |
diff --git a/shell/ash_test/ash-vars/var_LINENO2.right b/shell/ash_test/ash-vars/var_LINENO2.right new file mode 100644 index 000000000..73656647c --- /dev/null +++ b/shell/ash_test/ash-vars/var_LINENO2.right | |||
@@ -0,0 +1,3 @@ | |||
1 | Start LINENO=6, calling function | ||
2 | In function: LINENO=4 | ||
3 | After function: LINENO=8 | ||
diff --git a/shell/ash_test/ash-vars/var_LINENO2.tests b/shell/ash_test/ash-vars/var_LINENO2.tests new file mode 100755 index 000000000..7036dbdc8 --- /dev/null +++ b/shell/ash_test/ash-vars/var_LINENO2.tests | |||
@@ -0,0 +1,8 @@ | |||
1 | #skip lines: make "line number within function" differ from overall line number | ||
2 | #skip lines | ||
3 | f() { | ||
4 | echo "In function: LINENO=$LINENO" | ||
5 | } | ||
6 | echo "Start LINENO=$LINENO, calling function" | ||
7 | f | ||
8 | echo "After function: LINENO=$LINENO" | ||
diff --git a/shell/ash_test/ash-vars/var_LINENO3.right b/shell/ash_test/ash-vars/var_LINENO3.right new file mode 100644 index 000000000..198c3cc99 --- /dev/null +++ b/shell/ash_test/ash-vars/var_LINENO3.right | |||
@@ -0,0 +1,2 @@ | |||
1 | LINENO starts from 0 in -c | ||
2 | and increments on next line: 1 | ||
diff --git a/shell/ash_test/ash-vars/var_LINENO3.tests b/shell/ash_test/ash-vars/var_LINENO3.tests new file mode 100755 index 000000000..4502edfe0 --- /dev/null +++ b/shell/ash_test/ash-vars/var_LINENO3.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | $THIS_SH -c 'echo "LINENO starts from $LINENO in -c" | ||
2 | echo "and increments on next line: $LINENO"' | ||
diff --git a/shell/ash_test/run-all b/shell/ash_test/run-all index caf033577..96703ef12 100755 --- a/shell/ash_test/run-all +++ b/shell/ash_test/run-all | |||
@@ -1,5 +1,14 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | 2 | ||
3 | unset LANG LANGUAGE | ||
4 | unset LC_COLLATE | ||
5 | unset LC_CTYPE | ||
6 | unset LC_MONETARY | ||
7 | unset LC_MESSAGES | ||
8 | unset LC_NUMERIC | ||
9 | unset LC_TIME | ||
10 | unset LC_ALL | ||
11 | |||
3 | TOPDIR=`pwd` | 12 | TOPDIR=`pwd` |
4 | 13 | ||
5 | if test ! -x ash; then | 14 | if test ! -x ash; then |
@@ -61,11 +70,12 @@ do_test() | |||
61 | # echo Running test: "$x" | 70 | # echo Running test: "$x" |
62 | echo -n "$1/$x:" | 71 | echo -n "$1/$x:" |
63 | { | 72 | { |
64 | "$THIS_SH" "./$x" >"$name.xx" 2>&1 | 73 | "$THIS_SH" "./$x" 2>&1 | \ |
74 | grep -va "^ash: using fallback suid method$" >"$name.xx" | ||
65 | diff -u "$name.xx" "$name.right" >"$TOPDIR/$noslash-$x.fail" \ | 75 | diff -u "$name.xx" "$name.right" >"$TOPDIR/$noslash-$x.fail" \ |
66 | && rm -f "$name.xx" "$TOPDIR/$noslash-$x.fail" | 76 | && rm -f "$name.xx" "$TOPDIR/$noslash-$x.fail" |
67 | } && echo " ok" || echo " fail" | 77 | } && echo " ok" || echo " fail" |
68 | done | 78 | done |
69 | ) | 79 | ) |
70 | } | 80 | } |
71 | 81 | ||
diff --git a/shell/hush.c b/shell/hush.c index 27092c12f..6d472337f 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -2753,6 +2753,12 @@ static int i_getch(struct in_str *i) | |||
2753 | if (ch != '\0') { | 2753 | if (ch != '\0') { |
2754 | i->p++; | 2754 | i->p++; |
2755 | i->last_char = ch; | 2755 | i->last_char = ch; |
2756 | #if ENABLE_HUSH_LINENO_VAR | ||
2757 | if (ch == '\n') { | ||
2758 | G.parse_lineno++; | ||
2759 | debug_printf_parse("G.parse_lineno++ = %u\n", G.parse_lineno); | ||
2760 | } | ||
2761 | #endif | ||
2756 | return ch; | 2762 | return ch; |
2757 | } | 2763 | } |
2758 | return EOF; | 2764 | return EOF; |
@@ -7540,11 +7546,11 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger) | |||
7540 | static void parse_and_run_string(const char *s) | 7546 | static void parse_and_run_string(const char *s) |
7541 | { | 7547 | { |
7542 | struct in_str input; | 7548 | struct in_str input; |
7543 | //IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;) | 7549 | IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;) |
7544 | 7550 | ||
7545 | setup_string_in_str(&input, s); | 7551 | setup_string_in_str(&input, s); |
7546 | parse_and_run_stream(&input, '\0'); | 7552 | parse_and_run_stream(&input, '\0'); |
7547 | //IF_HUSH_LINENO_VAR(G.parse_lineno = sv;) | 7553 | IF_HUSH_LINENO_VAR(G.parse_lineno = sv;) |
7548 | } | 7554 | } |
7549 | 7555 | ||
7550 | static void parse_and_run_file(HFILE *fp) | 7556 | static void parse_and_run_file(HFILE *fp) |
@@ -9898,7 +9904,8 @@ static int run_list(struct pipe *pi) | |||
9898 | #if ENABLE_HUSH_LOOPS | 9904 | #if ENABLE_HUSH_LOOPS |
9899 | G.flag_break_continue = 0; | 9905 | G.flag_break_continue = 0; |
9900 | #endif | 9906 | #endif |
9901 | rcode = r = run_pipe(pi); /* NB: rcode is a smalluint, r is int */ | 9907 | rcode = r = G.o_opt[OPT_O_NOEXEC] ? 0 : run_pipe(pi); |
9908 | /* NB: rcode is a smalluint, r is int */ | ||
9902 | if (r != -1) { | 9909 | if (r != -1) { |
9903 | /* We ran a builtin, function, or group. | 9910 | /* We ran a builtin, function, or group. |
9904 | * rcode is already known | 9911 | * rcode is already known |
@@ -10137,7 +10144,10 @@ static int set_mode(int state, char mode, const char *o_opt) | |||
10137 | int idx; | 10144 | int idx; |
10138 | switch (mode) { | 10145 | switch (mode) { |
10139 | case 'n': | 10146 | case 'n': |
10140 | G.o_opt[OPT_O_NOEXEC] = state; | 10147 | /* set -n has no effect in interactive shell */ |
10148 | /* Try: while set -n; do echo $-; done */ | ||
10149 | if (!G_interactive_fd) | ||
10150 | G.o_opt[OPT_O_NOEXEC] = state; | ||
10141 | break; | 10151 | break; |
10142 | case 'x': | 10152 | case 'x': |
10143 | IF_HUSH_MODE_X(G_x_mode = state;) | 10153 | IF_HUSH_MODE_X(G_x_mode = state;) |
diff --git a/shell/hush_test/hush-misc/exitcode_trap7.right b/shell/hush_test/hush-misc/exitcode_trap7.right new file mode 100644 index 000000000..07d66e9d9 --- /dev/null +++ b/shell/hush_test/hush-misc/exitcode_trap7.right | |||
@@ -0,0 +1,2 @@ | |||
1 | Start | ||
2 | Ok:0 | ||
diff --git a/shell/hush_test/hush-misc/exitcode_trap7.tests b/shell/hush_test/hush-misc/exitcode_trap7.tests new file mode 100755 index 000000000..f4b0eb544 --- /dev/null +++ b/shell/hush_test/hush-misc/exitcode_trap7.tests | |||
@@ -0,0 +1,7 @@ | |||
1 | $THIS_SH -c ' | ||
2 | cleanup() { set +e; false; } | ||
3 | set -e | ||
4 | trap cleanup EXIT | ||
5 | echo Start | ||
6 | ' | ||
7 | echo Ok:$? | ||
diff --git a/shell/hush_test/hush-misc/set-n1.right b/shell/hush_test/hush-misc/set-n1.right new file mode 100644 index 000000000..ac01831a7 --- /dev/null +++ b/shell/hush_test/hush-misc/set-n1.right | |||
@@ -0,0 +1,3 @@ | |||
1 | set -n stops in -c? | ||
2 | YES | ||
3 | Ok:0 | ||
diff --git a/shell/hush_test/hush-misc/set-n1.tests b/shell/hush_test/hush-misc/set-n1.tests new file mode 100755 index 000000000..90d0f9146 --- /dev/null +++ b/shell/hush_test/hush-misc/set-n1.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | $THIS_SH -c "echo 'set -n stops in -c?'; set -n; echo NO" && echo YES | ||
2 | echo Ok:$? | ||
diff --git a/shell/hush_test/hush-vars/var_LINENO2.right b/shell/hush_test/hush-vars/var_LINENO2.right new file mode 100644 index 000000000..73656647c --- /dev/null +++ b/shell/hush_test/hush-vars/var_LINENO2.right | |||
@@ -0,0 +1,3 @@ | |||
1 | Start LINENO=6, calling function | ||
2 | In function: LINENO=4 | ||
3 | After function: LINENO=8 | ||
diff --git a/shell/hush_test/hush-vars/var_LINENO2.tests b/shell/hush_test/hush-vars/var_LINENO2.tests new file mode 100755 index 000000000..7036dbdc8 --- /dev/null +++ b/shell/hush_test/hush-vars/var_LINENO2.tests | |||
@@ -0,0 +1,8 @@ | |||
1 | #skip lines: make "line number within function" differ from overall line number | ||
2 | #skip lines | ||
3 | f() { | ||
4 | echo "In function: LINENO=$LINENO" | ||
5 | } | ||
6 | echo "Start LINENO=$LINENO, calling function" | ||
7 | f | ||
8 | echo "After function: LINENO=$LINENO" | ||
diff --git a/shell/hush_test/hush-vars/var_LINENO3.right b/shell/hush_test/hush-vars/var_LINENO3.right new file mode 100644 index 000000000..198c3cc99 --- /dev/null +++ b/shell/hush_test/hush-vars/var_LINENO3.right | |||
@@ -0,0 +1,2 @@ | |||
1 | LINENO starts from 0 in -c | ||
2 | and increments on next line: 1 | ||
diff --git a/shell/hush_test/hush-vars/var_LINENO3.tests b/shell/hush_test/hush-vars/var_LINENO3.tests new file mode 100755 index 000000000..4502edfe0 --- /dev/null +++ b/shell/hush_test/hush-vars/var_LINENO3.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | $THIS_SH -c 'echo "LINENO starts from $LINENO in -c" | ||
2 | echo "and increments on next line: $LINENO"' | ||
diff --git a/testsuite/awk.tests b/testsuite/awk.tests index dc2ae2e11..bcaafe8fd 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests | |||
@@ -463,4 +463,10 @@ testing "awk \"cmd\" | getline" \ | |||
463 | "HELLO\n" \ | 463 | "HELLO\n" \ |
464 | '' '' | 464 | '' '' |
465 | 465 | ||
466 | # printf %% should print one % (had a bug where it didn't) | ||
467 | testing 'awk printf %% prints one %' \ | ||
468 | "awk 'BEGIN { printf \"%%\n\" }'" \ | ||
469 | "%\n" \ | ||
470 | '' '' | ||
471 | |||
466 | exit $FAILCOUNT | 472 | exit $FAILCOUNT |
diff --git a/testsuite/printf.tests b/testsuite/printf.tests index 34a65926e..050edef71 100755 --- a/testsuite/printf.tests +++ b/testsuite/printf.tests | |||
@@ -79,6 +79,11 @@ testing "printf understands %Ld" \ | |||
79 | "-5\n""0\n" \ | 79 | "-5\n""0\n" \ |
80 | "" "" | 80 | "" "" |
81 | 81 | ||
82 | testing "printf understands %%" \ | ||
83 | "${bb}printf '%%\n' 2>&1; echo \$?" \ | ||
84 | "%\n""0\n" \ | ||
85 | "" "" | ||
86 | |||
82 | testing "printf handles positive numbers for %d" \ | 87 | testing "printf handles positive numbers for %d" \ |
83 | "${bb}printf '%d\n' 3 +3 ' 3' ' +3' 2>&1; echo \$?" \ | 88 | "${bb}printf '%d\n' 3 +3 ' 3' ' +3' 2>&1; echo \$?" \ |
84 | "3\n"\ | 89 | "3\n"\ |
diff --git a/util-linux/blkdiscard.c b/util-linux/blkdiscard.c index ff2101ed0..7ac8045f9 100644 --- a/util-linux/blkdiscard.c +++ b/util-linux/blkdiscard.c | |||
@@ -18,10 +18,12 @@ | |||
18 | //usage:#define blkdiscard_trivial_usage | 18 | //usage:#define blkdiscard_trivial_usage |
19 | //usage: "[-o OFS] [-l LEN] [-s] DEVICE" | 19 | //usage: "[-o OFS] [-l LEN] [-s] DEVICE" |
20 | //usage:#define blkdiscard_full_usage "\n\n" | 20 | //usage:#define blkdiscard_full_usage "\n\n" |
21 | //usage: "Discard sectors on DEVICE\n" | 21 | //usage: "Discard sectors on DEVICE\n" |
22 | //usage: "\n -o OFS Byte offset into device" | 22 | //usage: "\n -o OFS Byte offset into device" |
23 | //usage: "\n -l LEN Number of bytes to discard" | 23 | //usage: "\n -l LEN Number of bytes to discard" |
24 | //usage: "\n -s Perform a secure discard" | 24 | //usage: "\n -s Perform a secure discard" |
25 | ///////: "\n -f Disable check for mounted filesystem" | ||
26 | //////////////// -f: accepted but is a nop (we do no check anyway) | ||
25 | //usage: | 27 | //usage: |
26 | //usage:#define blkdiscard_example_usage | 28 | //usage:#define blkdiscard_example_usage |
27 | //usage: "$ blkdiscard -o 0 -l 1G /dev/sdb" | 29 | //usage: "$ blkdiscard -o 0 -l 1G /dev/sdb" |
@@ -51,9 +53,10 @@ int blkdiscard_main(int argc UNUSED_PARAM, char **argv) | |||
51 | OPT_OFFSET = (1 << 0), | 53 | OPT_OFFSET = (1 << 0), |
52 | OPT_LENGTH = (1 << 1), | 54 | OPT_LENGTH = (1 << 1), |
53 | OPT_SECURE = (1 << 2), | 55 | OPT_SECURE = (1 << 2), |
56 | OPT_FORCE = (1 << 3), //nop | ||
54 | }; | 57 | }; |
55 | 58 | ||
56 | opts = getopt32(argv, "^" "o:l:s" "\0" "=1", &offset_str, &length_str); | 59 | opts = getopt32(argv, "^" "o:l:sf" "\0" "=1", &offset_str, &length_str); |
57 | argv += optind; | 60 | argv += optind; |
58 | 61 | ||
59 | fd = xopen(argv[0], O_RDWR|O_EXCL); | 62 | fd = xopen(argv[0], O_RDWR|O_EXCL); |