summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2019-04-20 07:50:02 +0100
committerRon Yorston <rmy@pobox.com>2019-04-20 07:50:02 +0100
commit241d4d4ac319d4b0507dbc70434545418fd74b79 (patch)
tree3d1d8b92eb7f015f5e102cd472a330ec784a5d43
parente4bc2cb29c5465cbec2dec1ba3b325139007d03a (diff)
parente49a572b529dc7dcfb052c679074b9b87577e388 (diff)
downloadbusybox-w32-FRP-3128-g241d4d4ac.tar.gz
busybox-w32-FRP-3128-g241d4d4ac.tar.bz2
busybox-w32-FRP-3128-g241d4d4ac.zip
Merge branch 'busybox' into mergeFRP-3128-g241d4d4ac
-rw-r--r--networking/httpd.c260
-rw-r--r--shell/ash.c36
-rw-r--r--shell/hush.c3
-rwxr-xr-xtestsuite/dc.tests6
4 files changed, 172 insertions, 133 deletions
diff --git a/networking/httpd.c b/networking/httpd.c
index 2b0acd7dc..3f1e02ec8 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -259,18 +259,11 @@
259#if ENABLE_FEATURE_USE_SENDFILE 259#if ENABLE_FEATURE_USE_SENDFILE
260# include <sys/sendfile.h> 260# include <sys/sendfile.h>
261#endif 261#endif
262/* amount of buffering in a pipe */
263#ifndef PIPE_BUF
264# define PIPE_BUF 4096
265#endif
266 262
267#define DEBUG 0 263#define DEBUG 0
268 264
269#define IOBUF_SIZE 8192 265#define IOBUF_SIZE 8192
270#define MAX_HTTP_HEADERS_SIZE ((8*1024) - 16) 266#define MAX_HTTP_HEADERS_SIZE (32*1024)
271#if PIPE_BUF >= IOBUF_SIZE
272# error "PIPE_BUF >= IOBUF_SIZE"
273#endif
274 267
275#define HEADER_READ_TIMEOUT 60 268#define HEADER_READ_TIMEOUT 60
276 269
@@ -1150,18 +1143,61 @@ static void send_headers(unsigned responseNum)
1150 file_size = range_end - range_start + 1; 1143 file_size = range_end - range_start + 1;
1151 } 1144 }
1152#endif 1145#endif
1146
1147//RFC 2616 4.4 Message Length
1148// The transfer-length of a message is the length of the message-body as
1149// it appears in the message; that is, after any transfer-codings have
1150// been applied. When a message-body is included with a message, the
1151// transfer-length of that body is determined by one of the following
1152// (in order of precedence):
1153// 1.Any response message which "MUST NOT" include a message-body (such
1154// as the 1xx, 204, and 304 responses and any response to a HEAD
1155// request) is always terminated by the first empty line after the
1156// header fields, regardless of the entity-header fields present in
1157// the message.
1158// 2.If a Transfer-Encoding header field (section 14.41) is present and
1159// has any value other than "identity", then the transfer-length is
1160// defined by use of the "chunked" transfer-coding (section 3.6),
1161// unless the message is terminated by closing the connection.
1162// 3.If a Content-Length header field (section 14.13) is present, its
1163// decimal value in OCTETs represents both the entity-length and the
1164// transfer-length. The Content-Length header field MUST NOT be sent
1165// if these two lengths are different (i.e., if a Transfer-Encoding
1166// header field is present). If a message is received with both a
1167// Transfer-Encoding header field and a Content-Length header field,
1168// the latter MUST be ignored.
1169// 4.If the message uses the media type "multipart/byteranges" ...
1170// 5.By the server closing the connection.
1171//
1172// (NB: standards do not define "Transfer-Length:" _header_,
1173// transfer-length above is just a concept).
1174
1153 len += sprintf(iobuf + len, 1175 len += sprintf(iobuf + len,
1154#if ENABLE_FEATURE_HTTPD_RANGES 1176#if ENABLE_FEATURE_HTTPD_RANGES
1155 "Accept-Ranges: bytes\r\n" 1177 "Accept-Ranges: bytes\r\n"
1156#endif 1178#endif
1157 "Last-Modified: %s\r\n" 1179 "Last-Modified: %s\r\n"
1158 "%s-Length: %"OFF_FMT"u\r\n", 1180 /* Because of 4.4 (5), we can forgo sending of "Content-Length"
1181 * since we close connection afterwards, but it helps clients
1182 * to e.g. estimate download times, show progress bars etc.
1183 * Theoretically we should not send it if page is compressed,
1184 * but de-facto standard is to send it (see comment below).
1185 */
1186 "Content-Length: %"OFF_FMT"u\r\n",
1159 date_str, 1187 date_str,
1160 content_gzip ? "Transfer" : "Content",
1161 file_size 1188 file_size
1162 ); 1189 );
1163 } 1190 }
1164 1191
1192 /* This should be "Transfer-Encoding", not "Content-Encoding":
1193 * "data is compressed for transfer", not "data is an archive".
1194 * But many clients were not handling "Transfer-Encoding" correctly
1195 * (they were not uncompressing gzipped pages, tried to show
1196 * raw compressed data), and servers worked around it by using
1197 * "Content-Encoding" instead... and this become de-facto standard.
1198 * https://bugzilla.mozilla.org/show_bug.cgi?id=68517
1199 * https://bugs.chromium.org/p/chromium/issues/detail?id=94730
1200 */
1165 if (content_gzip) 1201 if (content_gzip)
1166 len += sprintf(iobuf + len, "Content-Encoding: gzip\r\n"); 1202 len += sprintf(iobuf + len, "Content-Encoding: gzip\r\n");
1167 1203
@@ -1210,10 +1246,10 @@ static unsigned get_line(void)
1210 unsigned count; 1246 unsigned count;
1211 char c; 1247 char c;
1212 1248
1213 alarm(HEADER_READ_TIMEOUT);
1214 count = 0; 1249 count = 0;
1215 while (1) { 1250 while (1) {
1216 if (hdr_cnt <= 0) { 1251 if (hdr_cnt <= 0) {
1252 alarm(HEADER_READ_TIMEOUT);
1217 hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf); 1253 hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf);
1218 if (hdr_cnt <= 0) 1254 if (hdr_cnt <= 0)
1219 goto ret; 1255 goto ret;
@@ -1370,10 +1406,10 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
1370 * CGI may output a few first bytes and then wait 1406 * CGI may output a few first bytes and then wait
1371 * for POSTDATA without closing stdout. 1407 * for POSTDATA without closing stdout.
1372 * With full_read we may wait here forever. */ 1408 * With full_read we may wait here forever. */
1373 count = safe_read(fromCgi_rd, rbuf + out_cnt, PIPE_BUF - 8); 1409 count = safe_read(fromCgi_rd, rbuf + out_cnt, IOBUF_SIZE - 8);
1374 if (count <= 0) { 1410 if (count <= 0) {
1375 /* eof (or error) and there was no "HTTP", 1411 /* eof (or error) and there was no "HTTP",
1376 * so write it, then write received data */ 1412 * send "HTTP/1.0 200 OK\r\n", then send received data */
1377 if (out_cnt) { 1413 if (out_cnt) {
1378 full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1); 1414 full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1);
1379 full_write(STDOUT_FILENO, rbuf, out_cnt); 1415 full_write(STDOUT_FILENO, rbuf, out_cnt);
@@ -1411,7 +1447,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
1411 out_cnt = -1; /* buffering off */ 1447 out_cnt = -1; /* buffering off */
1412 } 1448 }
1413 } else { 1449 } else {
1414 count = safe_read(fromCgi_rd, rbuf, PIPE_BUF); 1450 count = safe_read(fromCgi_rd, rbuf, IOBUF_SIZE);
1415 if (count <= 0) 1451 if (count <= 0)
1416 break; /* eof (or error) */ 1452 break; /* eof (or error) */
1417 } 1453 }
@@ -2085,7 +2121,6 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2085#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 2121#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
2086 smallint authorized = -1; 2122 smallint authorized = -1;
2087#endif 2123#endif
2088 char http_major_version;
2089 char *HTTP_slash; 2124 char *HTTP_slash;
2090 2125
2091 /* Allocation of iobuf is postponed until now 2126 /* Allocation of iobuf is postponed until now
@@ -2148,16 +2183,12 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2148 if (urlp[0] != '/') 2183 if (urlp[0] != '/')
2149 send_headers_and_exit(HTTP_BAD_REQUEST); 2184 send_headers_and_exit(HTTP_BAD_REQUEST);
2150 2185
2151 /* Find end of URL and parse HTTP version, if any */ 2186 /* Find end of URL */
2152//TODO: maybe just reject all queries which have no " HTTP/xyz" suffix? 2187 HTTP_slash = strchr(urlp, ' ');
2153//Then 'http_major_version' can be deleted
2154 http_major_version = ('0' - 1); /* "less than 0th" version */
2155 HTTP_slash = strchrnul(urlp, ' ');
2156 /* Is it " HTTP/"? */ 2188 /* Is it " HTTP/"? */
2157 if (HTTP_slash[0] && strncmp(HTTP_slash + 1, HTTP_200, 5) == 0) { 2189 if (!HTTP_slash || strncmp(HTTP_slash + 1, HTTP_200, 5) != 0)
2158 http_major_version = HTTP_slash[6]; 2190 send_headers_and_exit(HTTP_BAD_REQUEST);
2159 *HTTP_slash++ = '\0'; 2191 *HTTP_slash++ = '\0';
2160 }
2161 2192
2162 /* Copy URL from after "GET "/"POST " to stack-allocated char[] */ 2193 /* Copy URL from after "GET "/"POST " to stack-allocated char[] */
2163 urlcopy = alloca((HTTP_slash - urlp) + 2 + strlen(index_page)); 2194 urlcopy = alloca((HTTP_slash - urlp) + 2 + strlen(index_page));
@@ -2173,6 +2204,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2173 Htaccess_Proxy *proxy_entry = find_proxy_entry(urlcopy); 2204 Htaccess_Proxy *proxy_entry = find_proxy_entry(urlcopy);
2174 2205
2175 if (proxy_entry) { 2206 if (proxy_entry) {
2207 if (verbose > 1)
2208 bb_error_msg("proxy:%s", urlcopy);
2176 lsa = host2sockaddr(proxy_entry->host_port, 80); 2209 lsa = host2sockaddr(proxy_entry->host_port, 80);
2177 if (!lsa) 2210 if (!lsa)
2178 send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); 2211 send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
@@ -2181,6 +2214,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2181 send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); 2214 send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
2182 if (connect(proxy_fd, &lsa->u.sa, lsa->len) < 0) 2215 if (connect(proxy_fd, &lsa->u.sa, lsa->len) < 0)
2183 send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); 2216 send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
2217 /* Disable peer header reading timeout */
2218 alarm(0);
2184 /* Config directive was of the form: 2219 /* Config directive was of the form:
2185 * P:/url:[http://]hostname[:port]/new/path 2220 * P:/url:[http://]hostname[:port]/new/path
2186 * When /urlSFX is requested, reverse proxy it 2221 * When /urlSFX is requested, reverse proxy it
@@ -2190,7 +2225,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2190 prequest, /* "GET" or "POST" */ 2225 prequest, /* "GET" or "POST" */
2191 proxy_entry->url_to, /* "/new/path" */ 2226 proxy_entry->url_to, /* "/new/path" */
2192 urlcopy + strlen(proxy_entry->url_from), /* "SFX" */ 2227 urlcopy + strlen(proxy_entry->url_from), /* "SFX" */
2193 HTTP_slash /* HTTP/xyz" or "" */ 2228 HTTP_slash /* "HTTP/xyz" */
2194 ); 2229 );
2195 cgi_io_loop_and_exit(proxy_fd, proxy_fd, /*max POST length:*/ INT_MAX); 2230 cgi_io_loop_and_exit(proxy_fd, proxy_fd, /*max POST length:*/ INT_MAX);
2196 } 2231 }
@@ -2323,125 +2358,122 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2323#if ENABLE_FEATURE_HTTPD_CGI 2358#if ENABLE_FEATURE_HTTPD_CGI
2324 total_headers_len = 0; 2359 total_headers_len = 0;
2325#endif 2360#endif
2326 if (http_major_version >= '0') {
2327 /* Request was with "... HTTP/nXXX", and n >= 0 */
2328 2361
2329 /* Read until blank line */ 2362 /* Read until blank line */
2330 while (1) { 2363 while (1) {
2331 unsigned iobuf_len = get_line(); 2364 unsigned iobuf_len = get_line();
2332 if (!iobuf_len) 2365 if (!iobuf_len)
2333 break; /* EOF or error or empty line */ 2366 break; /* EOF or error or empty line */
2334#if ENABLE_FEATURE_HTTPD_CGI 2367#if ENABLE_FEATURE_HTTPD_CGI
2335 /* Prevent unlimited growth of HTTP_xyz envvars */ 2368 /* Prevent unlimited growth of HTTP_xyz envvars */
2336 total_headers_len += iobuf_len; 2369 total_headers_len += iobuf_len;
2337 if (total_headers_len >= MAX_HTTP_HEADERS_SIZE) 2370 if (total_headers_len >= MAX_HTTP_HEADERS_SIZE)
2338 send_headers_and_exit(HTTP_ENTITY_TOO_LARGE); 2371 send_headers_and_exit(HTTP_ENTITY_TOO_LARGE);
2339#endif 2372#endif
2340 if (DEBUG) 2373 if (DEBUG)
2341 bb_error_msg("header: '%s'", iobuf); 2374 bb_error_msg("header: '%s'", iobuf);
2342#if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY 2375#if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY
2343 /* Try and do our best to parse more lines */ 2376 /* Try and do our best to parse more lines */
2344 if ((STRNCASECMP(iobuf, "Content-Length:") == 0)) { 2377 if (STRNCASECMP(iobuf, "Content-Length:") == 0) {
2345 /* extra read only for POST */ 2378 /* extra read only for POST */
2346 if (prequest != request_GET 2379 if (prequest != request_GET
2347# if ENABLE_FEATURE_HTTPD_CGI 2380# if ENABLE_FEATURE_HTTPD_CGI
2348 && prequest != request_HEAD 2381 && prequest != request_HEAD
2349# endif 2382# endif
2350 ) { 2383 ) {
2351 tptr = skip_whitespace(iobuf + sizeof("Content-Length:") - 1); 2384 tptr = skip_whitespace(iobuf + sizeof("Content-Length:") - 1);
2352 if (!tptr[0]) 2385 if (!tptr[0])
2353 send_headers_and_exit(HTTP_BAD_REQUEST); 2386 send_headers_and_exit(HTTP_BAD_REQUEST);
2354 /* not using strtoul: it ignores leading minus! */ 2387 /* not using strtoul: it ignores leading minus! */
2355 length = bb_strtou(tptr, NULL, 10); 2388 length = bb_strtou(tptr, NULL, 10);
2356 /* length is "ulong", but we need to pass it to int later */ 2389 /* length is "ulong", but we need to pass it to int later */
2357 if (errno || length > INT_MAX) 2390 if (errno || length > INT_MAX)
2358 send_headers_and_exit(HTTP_BAD_REQUEST); 2391 send_headers_and_exit(HTTP_BAD_REQUEST);
2359 }
2360 continue;
2361 } 2392 }
2393 continue;
2394 }
2362#endif 2395#endif
2363#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 2396#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
2364 if (STRNCASECMP(iobuf, "Authorization:") == 0) { 2397 if (STRNCASECMP(iobuf, "Authorization:") == 0) {
2365 /* We only allow Basic credentials. 2398 /* We only allow Basic credentials.
2366 * It shows up as "Authorization: Basic <user>:<passwd>" where 2399 * It shows up as "Authorization: Basic <user>:<passwd>" where
2367 * "<user>:<passwd>" is base64 encoded. 2400 * "<user>:<passwd>" is base64 encoded.
2368 */ 2401 */
2369 tptr = skip_whitespace(iobuf + sizeof("Authorization:")-1); 2402 tptr = skip_whitespace(iobuf + sizeof("Authorization:")-1);
2370 if (STRNCASECMP(tptr, "Basic") != 0) 2403 if (STRNCASECMP(tptr, "Basic") == 0) {
2371 continue;
2372 tptr += sizeof("Basic")-1; 2404 tptr += sizeof("Basic")-1;
2373 /* decodeBase64() skips whitespace itself */ 2405 /* decodeBase64() skips whitespace itself */
2374 decodeBase64(tptr); 2406 decodeBase64(tptr);
2375 authorized = check_user_passwd(urlcopy, tptr); 2407 authorized = check_user_passwd(urlcopy, tptr);
2376 continue; 2408 continue;
2377 } 2409 }
2410 }
2378#endif 2411#endif
2379#if ENABLE_FEATURE_HTTPD_RANGES 2412#if ENABLE_FEATURE_HTTPD_RANGES
2380 if (STRNCASECMP(iobuf, "Range:") == 0) { 2413 if (STRNCASECMP(iobuf, "Range:") == 0) {
2381 /* We know only bytes=NNN-[MMM] */ 2414 /* We know only bytes=NNN-[MMM] */
2382 char *s = skip_whitespace(iobuf + sizeof("Range:")-1); 2415 char *s = skip_whitespace(iobuf + sizeof("Range:")-1);
2383 if (is_prefixed_with(s, "bytes=")) { 2416 if (is_prefixed_with(s, "bytes=")) {
2384 s += sizeof("bytes=")-1; 2417 s += sizeof("bytes=")-1;
2385 range_start = BB_STRTOOFF(s, &s, 10); 2418 range_start = BB_STRTOOFF(s, &s, 10);
2386 if (s[0] != '-' || range_start < 0) { 2419 if (s[0] != '-' || range_start < 0) {
2420 range_start = -1;
2421 } else if (s[1]) {
2422 range_end = BB_STRTOOFF(s+1, NULL, 10);
2423 if (errno || range_end < range_start)
2387 range_start = -1; 2424 range_start = -1;
2388 } else if (s[1]) {
2389 range_end = BB_STRTOOFF(s+1, NULL, 10);
2390 if (errno || range_end < range_start)
2391 range_start = -1;
2392 }
2393 } 2425 }
2394 continue;
2395 } 2426 }
2427 continue;
2428 }
2396#endif 2429#endif
2397#if ENABLE_FEATURE_HTTPD_GZIP 2430#if ENABLE_FEATURE_HTTPD_GZIP
2398 if (STRNCASECMP(iobuf, "Accept-Encoding:") == 0) { 2431 if (STRNCASECMP(iobuf, "Accept-Encoding:") == 0) {
2399 /* Note: we do not support "gzip;q=0" 2432 /* Note: we do not support "gzip;q=0"
2400 * method of _disabling_ gzip 2433 * method of _disabling_ gzip
2401 * delivery. No one uses that, though */ 2434 * delivery. No one uses that, though */
2402 const char *s = strstr(iobuf, "gzip"); 2435 const char *s = strstr(iobuf, "gzip");
2403 if (s) { 2436 if (s) {
2404 // want more thorough checks? 2437 // want more thorough checks?
2405 //if (s[-1] == ' ' 2438 //if (s[-1] == ' '
2406 // || s[-1] == ',' 2439 // || s[-1] == ','
2407 // || s[-1] == ':' 2440 // || s[-1] == ':'
2408 //) { 2441 //) {
2409 content_gzip = 1; 2442 content_gzip = 1;
2410 //} 2443 //}
2411 }
2412 continue;
2413 } 2444 }
2445 continue;
2446 }
2414#endif 2447#endif
2415#if ENABLE_FEATURE_HTTPD_CGI 2448#if ENABLE_FEATURE_HTTPD_CGI
2416 if (cgi_type != CGI_NONE) { 2449 if (cgi_type != CGI_NONE) {
2417 bool ct = (STRNCASECMP(iobuf, "Content-Type:") == 0); 2450 bool ct = (STRNCASECMP(iobuf, "Content-Type:") == 0);
2418 char *cp; 2451 char *cp;
2419 char *colon = strchr(iobuf, ':'); 2452 char *colon = strchr(iobuf, ':');
2420 2453
2421 if (!colon) 2454 if (!colon)
2455 continue;
2456 cp = iobuf;
2457 while (cp < colon) {
2458 /* a-z => A-Z, not-alnum => _ */
2459 char c = (*cp & ~0x20); /* toupper for A-Za-z, undef for others */
2460 if ((unsigned)(c - 'A') <= ('Z' - 'A')) {
2461 *cp++ = c;
2422 continue; 2462 continue;
2423 cp = iobuf;
2424 while (cp < colon) {
2425 /* a-z => A-Z, not-alnum => _ */
2426 char c = (*cp & ~0x20); /* toupper for A-Za-z, undef for others */
2427 if ((unsigned)(c - 'A') <= ('Z' - 'A')) {
2428 *cp++ = c;
2429 continue;
2430 }
2431 if (!isdigit(*cp))
2432 *cp = '_';
2433 cp++;
2434 } 2463 }
2435 /* "Content-Type:" gets no HTTP_ prefix, all others do */ 2464 if (!isdigit(*cp))
2436 cp = xasprintf(ct ? "HTTP_%.*s=%s" + 5 : "HTTP_%.*s=%s", 2465 *cp = '_';
2437 (int)(colon - iobuf), iobuf, 2466 cp++;
2438 skip_whitespace(colon + 1)
2439 );
2440 putenv(cp);
2441 } 2467 }
2468 /* "Content-Type:" gets no HTTP_ prefix, all others do */
2469 cp = xasprintf(ct ? "HTTP_%.*s=%s" + 5 : "HTTP_%.*s=%s",
2470 (int)(colon - iobuf), iobuf,
2471 skip_whitespace(colon + 1)
2472 );
2473 putenv(cp);
2474 }
2442#endif 2475#endif
2443 } /* while extra header reading */ 2476 } /* while extra header reading */
2444 }
2445 2477
2446 /* We are done reading headers, disable peer timeout */ 2478 /* We are done reading headers, disable peer timeout */
2447 alarm(0); 2479 alarm(0);
diff --git a/shell/ash.c b/shell/ash.c
index ad7b8f4dd..b82c51029 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -13747,6 +13747,10 @@ expandstr(const char *ps, int syntax_type)
13747{ 13747{
13748 union node n; 13748 union node n;
13749 int saveprompt; 13749 int saveprompt;
13750 struct parsefile *file_stop = g_parsefile;
13751 volatile int saveint;
13752 struct jmploc *volatile savehandler = exception_handler;
13753 struct jmploc jmploc;
13750 13754
13751 /* XXX Fix (char *) cast. */ 13755 /* XXX Fix (char *) cast. */
13752 setinputstring((char *)ps); 13756 setinputstring((char *)ps);
@@ -13758,29 +13762,35 @@ expandstr(const char *ps, int syntax_type)
13758 * Try a prompt with syntactically wrong command: 13762 * Try a prompt with syntactically wrong command:
13759 * PS1='$(date "+%H:%M:%S) > ' 13763 * PS1='$(date "+%H:%M:%S) > '
13760 */ 13764 */
13761 { 13765 SAVE_INT(saveint);
13762 volatile int saveint; 13766 if (setjmp(jmploc.loc) == 0) {
13763 struct jmploc *volatile savehandler = exception_handler; 13767 exception_handler = &jmploc;
13764 struct jmploc jmploc; 13768 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
13765 SAVE_INT(saveint);
13766 if (setjmp(jmploc.loc) == 0) {
13767 exception_handler = &jmploc;
13768 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
13769 }
13770 exception_handler = savehandler;
13771 RESTORE_INT(saveint);
13772 } 13769 }
13770 exception_handler = savehandler;
13771 RESTORE_INT(saveint);
13773 13772
13774 doprompt = saveprompt; 13773 doprompt = saveprompt;
13775 13774
13776 popfile(); 13775 /* Try: PS1='`xxx(`' */
13776 unwindfiles(file_stop);
13777 13777
13778 n.narg.type = NARG; 13778 n.narg.type = NARG;
13779 n.narg.next = NULL; 13779 n.narg.next = NULL;
13780 n.narg.text = wordtext; 13780 n.narg.text = wordtext;
13781 n.narg.backquote = backquotelist; 13781 n.narg.backquote = backquotelist;
13782 13782
13783 expandarg(&n, NULL, EXP_QUOTED); 13783 /* expandarg() might fail too:
13784 * PS1='$((123+))'
13785 */
13786 SAVE_INT(saveint);
13787 if (setjmp(jmploc.loc) == 0) {
13788 exception_handler = &jmploc;
13789 expandarg(&n, NULL, EXP_QUOTED);
13790 }
13791 exception_handler = savehandler;
13792 RESTORE_INT(saveint);
13793
13784 return stackblock(); 13794 return stackblock();
13785} 13795}
13786 13796
diff --git a/shell/hush.c b/shell/hush.c
index d745148f4..b3ae73b9b 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -363,9 +363,6 @@
363#ifndef F_DUPFD_CLOEXEC 363#ifndef F_DUPFD_CLOEXEC
364# define F_DUPFD_CLOEXEC F_DUPFD 364# define F_DUPFD_CLOEXEC F_DUPFD
365#endif 365#endif
366#ifndef PIPE_BUF
367# define PIPE_BUF 4096 /* amount of buffering in a pipe */
368#endif
369 366
370#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS && !(ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH) 367#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS && !(ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH)
371# include "embedded_scripts.h" 368# include "embedded_scripts.h"
diff --git a/testsuite/dc.tests b/testsuite/dc.tests
index 1708a4835..8c3af4156 100755
--- a/testsuite/dc.tests
+++ b/testsuite/dc.tests
@@ -41,6 +41,9 @@ testing "dc complex without spaces (multiple args)" \
41 "16\n" \ 41 "16\n" \
42 "" "" 42 "" ""
43 43
44optional FEATURE_DC_BIG
45# All tests below depend on FEATURE_DC_BIG
46
44testing "dc read" \ 47testing "dc read" \
45 "dc -finput" \ 48 "dc -finput" \
46 "2\n9\n1\n" \ 49 "2\n9\n1\n" \
@@ -51,9 +54,6 @@ testing "dc read string" \
51 "2\nstr\n1\n" \ 54 "2\nstr\n1\n" \
52 "1?2\nf" "[str]\n" 55 "1?2\nf" "[str]\n"
53 56
54optional FEATURE_DC_BIG
55# All tests below depend on FEATURE_DC_BIG
56
57testing "dc '>a' (conditional execute string) 1" \ 57testing "dc '>a' (conditional execute string) 1" \
58 "dc" \ 58 "dc" \
59 "1\n9\n" \ 59 "1\n9\n" \