aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2023-04-09 11:24:09 +0100
committerRon Yorston <rmy@pobox.com>2023-04-09 11:24:09 +0100
commitd9f2ea8628452f787e02dd0e496af612a2e94578 (patch)
treec12be657e31c2e832b41fbff9a77aa0f886d47f0
parentfa04f2dc766c76f2caa44a4b8429185dde6a66b0 (diff)
parenta26711a2d1464167be4ebc990fe21a3809a2da34 (diff)
downloadbusybox-w32-d9f2ea8628452f787e02dd0e496af612a2e94578.tar.gz
busybox-w32-d9f2ea8628452f787e02dd0e496af612a2e94578.tar.bz2
busybox-w32-d9f2ea8628452f787e02dd0e496af612a2e94578.zip
Merge branch 'busybox' into merge
-rw-r--r--archival/cpio.c1
-rw-r--r--archival/unzip.c22
-rw-r--r--coreutils/printf.c2
-rw-r--r--coreutils/sleep.c15
-rw-r--r--findutils/find.c39
-rw-r--r--include/libbb.h2
-rw-r--r--init/bootchartd.c2
-rw-r--r--libbb/hash_md5_sha.c28
-rw-r--r--libbb/vfork_daemon_rexec.c10
-rw-r--r--modutils/modprobe-small.c12
-rw-r--r--modutils/modutils.c12
-rw-r--r--networking/httpd.c76
-rw-r--r--procps/kill.c2
-rw-r--r--procps/top.c25
-rw-r--r--scripts/basic/fixdep.c6
-rw-r--r--shell/ash.c69
-rw-r--r--shell/ash_test/ash-signals/usage.right12
-rwxr-xr-xshell/ash_test/ash-signals/usage.tests12
-rw-r--r--shell/hush.c40
-rwxr-xr-xtestsuite/find.tests6
20 files changed, 271 insertions, 122 deletions
diff --git a/archival/cpio.c b/archival/cpio.c
index a642bbc35..388ba7c4f 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -508,7 +508,6 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
508 goto dump; 508 goto dump;
509 } 509 }
510 /* parent */ 510 /* parent */
511 USE_FOR_NOMMU(argv[-optind][0] &= 0x7f); /* undo fork_or_rexec() damage */
512 xchdir(*argv++); 511 xchdir(*argv++);
513 close(pp.wr); 512 close(pp.wr);
514 xmove_fd(pp.rd, STDIN_FILENO); 513 xmove_fd(pp.rd, STDIN_FILENO);
diff --git a/archival/unzip.c b/archival/unzip.c
index ff4f6325c..7b945c250 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -56,7 +56,7 @@
56//kbuild:lib-$(CONFIG_UNZIP) += unzip.o 56//kbuild:lib-$(CONFIG_UNZIP) += unzip.o
57 57
58//usage:#define unzip_trivial_usage 58//usage:#define unzip_trivial_usage
59//usage: "[-lnojpq] FILE[.zip] [FILE]... [-x FILE]... [-d DIR]" 59//usage: "[-lnojpqK] FILE[.zip] [FILE]... [-x FILE]... [-d DIR]"
60//usage:#define unzip_full_usage "\n\n" 60//usage:#define unzip_full_usage "\n\n"
61//usage: "Extract FILEs from ZIP archive\n" 61//usage: "Extract FILEs from ZIP archive\n"
62//usage: "\n -l List contents (with -q for short form)" 62//usage: "\n -l List contents (with -q for short form)"
@@ -66,6 +66,7 @@
66//usage: "\n -p Write to stdout" 66//usage: "\n -p Write to stdout"
67//usage: "\n -t Test" 67//usage: "\n -t Test"
68//usage: "\n -q Quiet" 68//usage: "\n -q Quiet"
69//usage: "\n -K Do not clear SUID bit"
69//usage: "\n -x FILE Exclude FILEs" 70//usage: "\n -x FILE Exclude FILEs"
70//usage: "\n -d DIR Extract into DIR" 71//usage: "\n -d DIR Extract into DIR"
71 72
@@ -497,6 +498,7 @@ int unzip_main(int argc, char **argv)
497 OPT_l = (1 << 0), 498 OPT_l = (1 << 0),
498 OPT_x = (1 << 1), 499 OPT_x = (1 << 1),
499 OPT_j = (1 << 2), 500 OPT_j = (1 << 2),
501 OPT_K = (1 << 3),
500 }; 502 };
501 unsigned opts; 503 unsigned opts;
502 smallint quiet = 0; 504 smallint quiet = 0;
@@ -560,9 +562,14 @@ int unzip_main(int argc, char **argv)
560 * 204372 1 file 562 * 204372 1 file
561 */ 563 */
562 564
565//TODO: accept and ignore these?
566// -a convert to text files with 't' label, -aa: all files
567// -b do not convert to text - bbox: we don't convert anything
568// -D skip restoration of timestamps for extracted items - bbox: we don't restore these (yet?)
569// -X restore user:group ownership
563 opts = 0; 570 opts = 0;
564 /* '-' makes getopt return 1 for non-options */ 571 /* '-' makes getopt return 1 for non-options */
565 while ((i = getopt(argc, argv, "-d:lnotpqxjv")) != -1) { 572 while ((i = getopt(argc, argv, "-d:lnotpqxjvK")) != -1) {
566 switch (i) { 573 switch (i) {
567 case 'd': /* Extract to base directory */ 574 case 'd': /* Extract to base directory */
568 base_dir = optarg; 575 base_dir = optarg;
@@ -584,6 +591,7 @@ int unzip_main(int argc, char **argv)
584 xmove_fd(xopen("/dev/null", O_WRONLY), STDOUT_FILENO); 591 xmove_fd(xopen("/dev/null", O_WRONLY), STDOUT_FILENO);
585 /*fallthrough*/ 592 /*fallthrough*/
586 593
594// NB: -c extract files to stdout/screen (unlike -p, also prints .zip and file names to stdout)
587 case 'p': /* Extract files to stdout */ 595 case 'p': /* Extract files to stdout */
588 dst_fd = STDOUT_FILENO; 596 dst_fd = STDOUT_FILENO;
589 /*fallthrough*/ 597 /*fallthrough*/
@@ -605,6 +613,10 @@ int unzip_main(int argc, char **argv)
605 opts |= OPT_j; 613 opts |= OPT_j;
606 break; 614 break;
607 615
616 case 'K':
617 opts |= OPT_K;
618 break;
619
608 case 1: 620 case 1:
609 if (!src_fn) { 621 if (!src_fn) {
610 /* The zip file */ 622 /* The zip file */
@@ -822,7 +834,10 @@ int unzip_main(int argc, char **argv)
822# endif 834# endif
823 if ((cdf.fmt.version_made_by >> 8) == 3) { 835 if ((cdf.fmt.version_made_by >> 8) == 3) {
824 /* This archive is created on Unix */ 836 /* This archive is created on Unix */
825 dir_mode = file_mode = (cdf.fmt.external_attributes >> 16); 837 file_mode = (cdf.fmt.external_attributes >> 16);
838 if (!(opts & OPT_K))
839 file_mode &= ~(mode_t)(S_ISUID | S_ISGID);
840 dir_mode = file_mode;
826 } 841 }
827 } 842 }
828#endif 843#endif
@@ -847,6 +862,7 @@ int unzip_main(int argc, char **argv)
847 unzip_skip(zip.fmt.extra_len); 862 unzip_skip(zip.fmt.extra_len);
848 863
849 /* Guard against "/abspath", "/../" and similar attacks */ 864 /* Guard against "/abspath", "/../" and similar attacks */
865// NB: UnZip 6.00 has option -: to disable this
850 overlapping_strcpy(dst_fn, strip_unsafe_prefix(dst_fn)); 866 overlapping_strcpy(dst_fn, strip_unsafe_prefix(dst_fn));
851 867
852 /* Filter zip entries */ 868 /* Filter zip entries */
diff --git a/coreutils/printf.c b/coreutils/printf.c
index da129f909..411edd5b9 100644
--- a/coreutils/printf.c
+++ b/coreutils/printf.c
@@ -493,7 +493,7 @@ int printf_main(int argc UNUSED_PARAM, char **argv)
493 if (argv[1] && argv[1][0] == '-' && argv[1][1] == '-' && !argv[1][2]) 493 if (argv[1] && argv[1][0] == '-' && argv[1][1] == '-' && !argv[1][2])
494 argv++; 494 argv++;
495 if (!argv[1]) { 495 if (!argv[1]) {
496 if (ENABLE_ASH_PRINTF 496 if ((ENABLE_ASH_PRINTF || ENABLE_HUSH_PRINTF)
497 && applet_name[0] != 'p' 497 && applet_name[0] != 'p'
498 ) { 498 ) {
499 bb_simple_error_msg("usage: printf FORMAT [ARGUMENT...]"); 499 bb_simple_error_msg("usage: printf FORMAT [ARGUMENT...]");
diff --git a/coreutils/sleep.c b/coreutils/sleep.c
index 442841210..667db558d 100644
--- a/coreutils/sleep.c
+++ b/coreutils/sleep.c
@@ -65,15 +65,28 @@ int sleep_main(int argc UNUSED_PARAM, char **argv)
65{ 65{
66 duration_t duration; 66 duration_t duration;
67 67
68 /* Note: sleep_main may be directly called from ash as a builtin.
69 * This brings some complications:
70 * + we can't use xfunc here
71 * + we can't use bb_show_usage
72 * + applet_name can be the name of the shell
73 */
68 ++argv; 74 ++argv;
69 if (!*argv) 75 if (!*argv) {
76 /* Without this, bare "sleep" in ash shows _ash_ --help */
77 if (ENABLE_ASH_SLEEP && applet_name[0] != 's') {
78 bb_simple_error_msg("sleep: missing operand");
79 return EXIT_FAILURE;
80 }
70 bb_show_usage(); 81 bb_show_usage();
82 }
71 83
72 /* GNU sleep accepts "inf", "INF", "infinity" and "INFINITY" */ 84 /* GNU sleep accepts "inf", "INF", "infinity" and "INFINITY" */
73 if (strncasecmp(argv[0], "inf", 3) == 0) 85 if (strncasecmp(argv[0], "inf", 3) == 0)
74 for (;;) 86 for (;;)
75 sleep(INT_MAX); 87 sleep(INT_MAX);
76 88
89//FIXME: in ash, "sleep 123qwerty" as a builtin aborts the shell
77#if ENABLE_FEATURE_FANCY_SLEEP 90#if ENABLE_FEATURE_FANCY_SLEEP
78 duration = 0; 91 duration = 0;
79 do { 92 do {
diff --git a/findutils/find.c b/findutils/find.c
index 2a607d180..a78dd9875 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -180,6 +180,13 @@
180//config: Without this option, -exec + is a synonym for -exec ; 180//config: Without this option, -exec + is a synonym for -exec ;
181//config: (IOW: it works correctly, but without expected speedup) 181//config: (IOW: it works correctly, but without expected speedup)
182//config: 182//config:
183//config:config FEATURE_FIND_EXEC_OK
184//config: bool "Enable -ok: execute confirmed commands"
185//config: default y
186//config: depends on FEATURE_FIND_EXEC
187//config: help
188//config: Support the 'find -ok' option which prompts before executing.
189//config:
183//config:config FEATURE_FIND_USER 190//config:config FEATURE_FIND_USER
184//config: bool "Enable -user: username/uid matching" 191//config: bool "Enable -user: username/uid matching"
185//config: default y 192//config: default y
@@ -395,6 +402,9 @@
395//usage: IF_FEATURE_FIND_EXEC_PLUS( 402//usage: IF_FEATURE_FIND_EXEC_PLUS(
396//usage: "\n -exec CMD ARG + Run CMD with {} replaced by list of file names" 403//usage: "\n -exec CMD ARG + Run CMD with {} replaced by list of file names"
397//usage: ) 404//usage: )
405//usage: IF_FEATURE_FIND_EXEC_OK(
406//usage: "\n -ok CMD ARG ; Prompt and run CMD with {} replaced"
407//usage: )
398//usage: IF_FEATURE_FIND_DELETE( 408//usage: IF_FEATURE_FIND_DELETE(
399//usage: "\n -delete Delete current file/directory. Turns on -depth option" 409//usage: "\n -delete Delete current file/directory. Turns on -depth option"
400//usage: ) 410//usage: )
@@ -467,6 +477,9 @@ IF_FEATURE_FIND_EXEC( ACTS(exec,
467 char **exec_argv; /* -exec ARGS */ 477 char **exec_argv; /* -exec ARGS */
468 unsigned *subst_count; 478 unsigned *subst_count;
469 int exec_argc; /* count of ARGS */ 479 int exec_argc; /* count of ARGS */
480 IF_FEATURE_FIND_EXEC_OK(
481 int ok; /* -ok */
482 )
470 IF_FEATURE_FIND_EXEC_PLUS( 483 IF_FEATURE_FIND_EXEC_PLUS(
471 /* 484 /*
472 * filelist is NULL if "exec ;" 485 * filelist is NULL if "exec ;"
@@ -802,10 +815,24 @@ static int do_exec(action_exec *ap, const char *fileName)
802 } 815 }
803# endif 816# endif
804 817
818# if ENABLE_FEATURE_FIND_EXEC_OK
819 if (ap->ok) {
820 for (i = 0; argv[i]; i++)
821 fprintf(stderr, "%s ", argv[i]);
822 fprintf(stderr, "?");
823 if (!bb_ask_y_confirmation()) {
824 rc = 1; /* "false" */
825 goto not_ok;
826 }
827 }
828# endif
805 rc = spawn_and_wait(argv); 829 rc = spawn_and_wait(argv);
806 if (rc < 0) 830 if (rc < 0)
807 bb_simple_perror_msg(argv[0]); 831 bb_simple_perror_msg(argv[0]);
808 832
833# if ENABLE_FEATURE_FIND_EXEC_OK
834 not_ok:
835# endif
809 i = 0; 836 i = 0;
810 while (argv[i]) 837 while (argv[i])
811 free(argv[i++]); 838 free(argv[i++]);
@@ -1120,6 +1147,7 @@ static action*** parse_params(char **argv)
1120 IF_FEATURE_FIND_DELETE( PARM_delete ,) 1147 IF_FEATURE_FIND_DELETE( PARM_delete ,)
1121 IF_FEATURE_FIND_EMPTY( PARM_empty ,) 1148 IF_FEATURE_FIND_EMPTY( PARM_empty ,)
1122 IF_FEATURE_FIND_EXEC( PARM_exec ,) 1149 IF_FEATURE_FIND_EXEC( PARM_exec ,)
1150 IF_FEATURE_FIND_EXEC_OK(PARM_ok ,)
1123 IF_FEATURE_FIND_EXECUTABLE(PARM_executable,) 1151 IF_FEATURE_FIND_EXECUTABLE(PARM_executable,)
1124 IF_FEATURE_FIND_PAREN( PARM_char_brace,) 1152 IF_FEATURE_FIND_PAREN( PARM_char_brace,)
1125 /* All options/actions starting from here require argument */ 1153 /* All options/actions starting from here require argument */
@@ -1171,6 +1199,7 @@ static action*** parse_params(char **argv)
1171 IF_FEATURE_FIND_DELETE( "-delete\0" ) 1199 IF_FEATURE_FIND_DELETE( "-delete\0" )
1172 IF_FEATURE_FIND_EMPTY( "-empty\0" ) 1200 IF_FEATURE_FIND_EMPTY( "-empty\0" )
1173 IF_FEATURE_FIND_EXEC( "-exec\0" ) 1201 IF_FEATURE_FIND_EXEC( "-exec\0" )
1202 IF_FEATURE_FIND_EXEC_OK("-ok\0" )
1174 IF_FEATURE_FIND_EXECUTABLE("-executable\0") 1203 IF_FEATURE_FIND_EXECUTABLE("-executable\0")
1175 IF_FEATURE_FIND_PAREN( "(\0" ) 1204 IF_FEATURE_FIND_PAREN( "(\0" )
1176 /* All options/actions starting from here require argument */ 1205 /* All options/actions starting from here require argument */
@@ -1351,23 +1380,27 @@ static action*** parse_params(char **argv)
1351 } 1380 }
1352#endif 1381#endif
1353#if ENABLE_FEATURE_FIND_EXEC 1382#if ENABLE_FEATURE_FIND_EXEC
1354 else if (parm == PARM_exec) { 1383 else if (parm == PARM_exec IF_FEATURE_FIND_EXEC_OK(|| parm == PARM_ok)) {
1355 int i; 1384 int i;
1356 action_exec *ap; 1385 action_exec *ap;
1357 IF_FEATURE_FIND_EXEC_PLUS(int all_subst = 0;) 1386 IF_FEATURE_FIND_EXEC_PLUS(int all_subst = 0;)
1358 dbg("%d", __LINE__); 1387 dbg("%d", __LINE__);
1359 G.need_print = 0; 1388 G.need_print = 0;
1360 ap = ALLOC_ACTION(exec); 1389 ap = ALLOC_ACTION(exec);
1390 IF_FEATURE_FIND_EXEC_OK(ap->ok = (parm == PARM_ok);)
1361 ap->exec_argv = ++argv; /* first arg after -exec */ 1391 ap->exec_argv = ++argv; /* first arg after -exec */
1362 /*ap->exec_argc = 0; - ALLOC_ACTION did it */ 1392 /*ap->exec_argc = 0; - ALLOC_ACTION did it */
1363 while (1) { 1393 while (1) {
1364 if (!*argv) /* did not see ';' or '+' until end */ 1394 if (!*argv) /* did not see ';' or '+' until end */
1365 bb_error_msg_and_die(bb_msg_requires_arg, "-exec"); 1395 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1366 // find -exec echo Foo ">{}<" ";" 1396 // find -exec echo Foo ">{}<" ";"
1367 // executes "echo Foo >FILENAME<", 1397 // executes "echo Foo >FILENAME<",
1368 // find -exec echo Foo ">{}<" "+" 1398 // find -exec echo Foo ">{}<" "+"
1369 // executes "echo Foo FILENAME1 FILENAME2 FILENAME3...". 1399 // executes "echo Foo FILENAME1 FILENAME2 FILENAME3...".
1370 if ((argv[0][0] == ';' || argv[0][0] == '+') 1400 if ((argv[0][0] == ';'
1401 || (argv[0][0] == '+' IF_FEATURE_FIND_EXEC_OK(&& parm != PARM_ok))
1402 /* -ok CMD + syntax is not accepted, only with ';' */
1403 )
1371 && argv[0][1] == '\0' 1404 && argv[0][1] == '\0'
1372 ) { 1405 ) {
1373# if ENABLE_FEATURE_FIND_EXEC_PLUS 1406# if ENABLE_FEATURE_FIND_EXEC_PLUS
diff --git a/include/libbb.h b/include/libbb.h
index 2841d7fbf..7683b3f63 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1377,7 +1377,7 @@ enum {
1377# define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus) 1377# define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus)
1378#else 1378#else
1379 extern bool re_execed; 1379 extern bool re_execed;
1380 /* Note: re_exec() and fork_or_rexec() do argv[0][0] |= 0x80 on NOMMU! 1380 /* Note: re_exec() sets argv[0][0] |= 0x80 on NOMMU!
1381 * _Parent_ needs to undo it if it doesn't want to have argv[0] mangled. 1381 * _Parent_ needs to undo it if it doesn't want to have argv[0] mangled.
1382 */ 1382 */
1383 void re_exec(char **argv) NORETURN FAST_FUNC; 1383 void re_exec(char **argv) NORETURN FAST_FUNC;
diff --git a/init/bootchartd.c b/init/bootchartd.c
index ae1ee9d9a..0929890a3 100644
--- a/init/bootchartd.c
+++ b/init/bootchartd.c
@@ -435,8 +435,6 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv)
435 435
436 /* parent */ 436 /* parent */
437 437
438 USE_FOR_NOMMU(argv[0][0] &= 0x7f); /* undo fork_or_rexec() damage */
439
440 if (DO_SIGNAL_SYNC) { 438 if (DO_SIGNAL_SYNC) {
441 /* Wait for logger child to set handlers, then unpause it. 439 /* Wait for logger child to set handlers, then unpause it.
442 * Otherwise with short-lived PROG (e.g. "bootchartd start true") 440 * Otherwise with short-lived PROG (e.g. "bootchartd start true")
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c
index 880ffab01..88baf51dc 100644
--- a/libbb/hash_md5_sha.c
+++ b/libbb/hash_md5_sha.c
@@ -23,6 +23,14 @@ static void cpuid(unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
23 ); 23 );
24} 24}
25static smallint shaNI; 25static smallint shaNI;
26static int get_shaNI(void)
27{
28 unsigned eax = 7, ebx = ebx, ecx = 0, edx = edx;
29 cpuid(&eax, &ebx, &ecx, &edx);
30 ebx = ((ebx >> 28) & 2) - 1; /* bit 29 -> 1 or -1 */
31 shaNI = (int)ebx;
32 return (int)ebx;
33}
26void FAST_FUNC sha1_process_block64_shaNI(sha1_ctx_t *ctx); 34void FAST_FUNC sha1_process_block64_shaNI(sha1_ctx_t *ctx);
27void FAST_FUNC sha256_process_block64_shaNI(sha256_ctx_t *ctx); 35void FAST_FUNC sha256_process_block64_shaNI(sha256_ctx_t *ctx);
28# if defined(__i386__) 36# if defined(__i386__)
@@ -1175,12 +1183,10 @@ void FAST_FUNC sha1_begin(sha1_ctx_t *ctx)
1175#if ENABLE_SHA1_HWACCEL 1183#if ENABLE_SHA1_HWACCEL
1176# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 1184# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
1177 { 1185 {
1178 if (!shaNI) { 1186 int ni = shaNI;
1179 unsigned eax = 7, ebx = ebx, ecx = 0, edx = edx; 1187 if (!ni)
1180 cpuid(&eax, &ebx, &ecx, &edx); 1188 ni = get_shaNI();
1181 shaNI = ((ebx >> 29) << 1) - 1; 1189 if (ni > 0)
1182 }
1183 if (shaNI > 0)
1184 ctx->process_block = sha1_process_block64_shaNI; 1190 ctx->process_block = sha1_process_block64_shaNI;
1185 } 1191 }
1186# endif 1192# endif
@@ -1229,12 +1235,10 @@ void FAST_FUNC sha256_begin(sha256_ctx_t *ctx)
1229#if ENABLE_SHA256_HWACCEL 1235#if ENABLE_SHA256_HWACCEL
1230# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 1236# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
1231 { 1237 {
1232 if (!shaNI) { 1238 int ni = shaNI;
1233 unsigned eax = 7, ebx = ebx, ecx = 0, edx = edx; 1239 if (!ni)
1234 cpuid(&eax, &ebx, &ecx, &edx); 1240 ni = get_shaNI();
1235 shaNI = ((ebx >> 29) << 1) - 1; 1241 if (ni > 0)
1236 }
1237 if (shaNI > 0)
1238 ctx->process_block = sha256_process_block64_shaNI; 1242 ctx->process_block = sha256_process_block64_shaNI;
1239 } 1243 }
1240# endif 1244# endif
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 62beb6a5d..3845c0892 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -273,10 +273,12 @@ pid_t FAST_FUNC fork_or_rexec(char **argv)
273 /* fflush_all(); ? - so far all callers had no buffered output to flush */ 273 /* fflush_all(); ? - so far all callers had no buffered output to flush */
274 274
275 pid = xvfork(); 275 pid = xvfork();
276 if (pid) /* parent */ 276 if (pid == 0) /* child - re-exec ourself */
277 return pid; 277 re_exec(argv); /* NORETURN */
278 /* child - re-exec ourself */ 278
279 re_exec(argv); 279 /* parent */
280 argv[0][0] &= 0x7f; /* undo re_rexec() damage */
281 return pid;
280} 282}
281#endif 283#endif
282 284
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c
index b61651621..77e42e3fb 100644
--- a/modutils/modprobe-small.c
+++ b/modutils/modprobe-small.c
@@ -33,6 +33,9 @@
33#define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags) 33#define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
34#ifdef __NR_finit_module 34#ifdef __NR_finit_module
35# define finit_module(fd, uargs, flags) syscall(__NR_finit_module, fd, uargs, flags) 35# define finit_module(fd, uargs, flags) syscall(__NR_finit_module, fd, uargs, flags)
36# ifndef MODULE_INIT_COMPRESSED_FILE
37# define MODULE_INIT_COMPRESSED_FILE 4
38# endif
36#endif 39#endif
37/* linux/include/linux/module.h has limit of 64 chars on module names */ 40/* linux/include/linux/module.h has limit of 64 chars on module names */
38#undef MODULE_NAME_LEN 41#undef MODULE_NAME_LEN
@@ -272,7 +275,14 @@ static int load_module(const char *fname, const char *options)
272 { 275 {
273 int fd = open(fname, O_RDONLY | O_CLOEXEC); 276 int fd = open(fname, O_RDONLY | O_CLOEXEC);
274 if (fd >= 0) { 277 if (fd >= 0) {
275 r = finit_module(fd, options, 0) != 0; 278 int flags = is_suffixed_with(fname, ".ko") ? 0 : MODULE_INIT_COMPRESSED_FILE;
279 for (;;) {
280 r = finit_module(fd, options, flags);
281 if (r == 0 || flags == 0)
282 break;
283 /* Loading non-.ko named uncompressed module? Not likely, but let's try it */
284 flags = 0;
285 }
276 close(fd); 286 close(fd);
277 } 287 }
278 } 288 }
diff --git a/modutils/modutils.c b/modutils/modutils.c
index f7ad5e805..cbff20961 100644
--- a/modutils/modutils.c
+++ b/modutils/modutils.c
@@ -12,6 +12,9 @@
12#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts) 12#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
13#if defined(__NR_finit_module) 13#if defined(__NR_finit_module)
14# define finit_module(fd, uargs, flags) syscall(__NR_finit_module, fd, uargs, flags) 14# define finit_module(fd, uargs, flags) syscall(__NR_finit_module, fd, uargs, flags)
15# ifndef MODULE_INIT_COMPRESSED_FILE
16# define MODULE_INIT_COMPRESSED_FILE 4
17# endif
15#endif 18#endif
16#define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags) 19#define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
17 20
@@ -217,7 +220,14 @@ int FAST_FUNC bb_init_module(const char *filename, const char *options)
217 { 220 {
218 int fd = open(filename, O_RDONLY | O_CLOEXEC); 221 int fd = open(filename, O_RDONLY | O_CLOEXEC);
219 if (fd >= 0) { 222 if (fd >= 0) {
220 rc = finit_module(fd, options, 0) != 0; 223 int flags = is_suffixed_with(filename, ".ko") ? 0 : MODULE_INIT_COMPRESSED_FILE;
224 for (;;) {
225 rc = finit_module(fd, options, flags);
226 if (rc == 0 || flags == 0)
227 break;
228 /* Loading non-.ko named uncompressed module? Not likely, but let's try it */
229 flags = 0;
230 }
221 close(fd); 231 close(fd);
222 if (rc == 0) 232 if (rc == 0)
223 return rc; 233 return rc;
diff --git a/networking/httpd.c b/networking/httpd.c
index b32498ddb..302d1611d 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -2475,50 +2475,52 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2475 send_headers_and_exit(HTTP_FORBIDDEN); 2475 send_headers_and_exit(HTTP_FORBIDDEN);
2476 } 2476 }
2477 cgi_type = CGI_NORMAL; 2477 cgi_type = CGI_NORMAL;
2478 } 2478 } /* why "else": do not check "cgi-bin/SCRIPT/something" for cases below: */
2479 else
2479#endif 2480#endif
2480 2481 {
2481 if (urlp[-1] == '/') { 2482 if (urlp[-1] == '/') {
2482 /* When index_page string is appended to <dir>/ URL, it overwrites 2483 /* When index_page string is appended to <dir>/ URL, it overwrites
2483 * the query string. If we fall back to call /cgi-bin/index.cgi, 2484 * the query string. If we fall back to call /cgi-bin/index.cgi,
2484 * query string would be lost and not available to the CGI. 2485 * query string would be lost and not available to the CGI.
2485 * Work around it by making a deep copy. 2486 * Work around it by making a deep copy.
2486 */ 2487 */
2487 if (ENABLE_FEATURE_HTTPD_CGI) 2488 if (ENABLE_FEATURE_HTTPD_CGI)
2488 g_query = xstrdup(g_query); /* ok for NULL too */ 2489 g_query = xstrdup(g_query); /* ok for NULL too */
2489 strcpy(urlp, index_page); 2490 strcpy(urlp, index_page);
2490 } 2491 }
2491 if (stat(tptr, &sb) == 0) { 2492 if (stat(tptr, &sb) == 0) {
2492 /* If URL is a directory with no slash, set up 2493 /* If URL is a directory with no slash, set up
2493 * "HTTP/1.1 302 Found" "Location: /dir/" reply */ 2494 * "HTTP/1.1 302 Found" "Location: /dir/" reply */
2494 if (urlp[-1] != '/' && S_ISDIR(sb.st_mode)) { 2495 if (urlp[-1] != '/' && S_ISDIR(sb.st_mode)) {
2495 found_moved_temporarily = urlcopy; 2496 found_moved_temporarily = urlcopy;
2496 } else { 2497 } else {
2497#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 2498#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
2498 char *suffix = strrchr(tptr, '.'); 2499 char *suffix = strrchr(tptr, '.');
2499 if (suffix) { 2500 if (suffix) {
2500 Htaccess *cur; 2501 Htaccess *cur;
2501 for (cur = script_i; cur; cur = cur->next) { 2502 for (cur = script_i; cur; cur = cur->next) {
2502 if (strcmp(cur->before_colon + 1, suffix) == 0) { 2503 if (strcmp(cur->before_colon + 1, suffix) == 0) {
2503 cgi_type = CGI_INTERPRETER; 2504 cgi_type = CGI_INTERPRETER;
2504 break; 2505 break;
2506 }
2505 } 2507 }
2506 } 2508 }
2507 }
2508#endif 2509#endif
2509 file_size = sb.st_size; 2510 file_size = sb.st_size;
2510 last_mod = sb.st_mtime; 2511 last_mod = sb.st_mtime;
2512 }
2511 } 2513 }
2512 }
2513#if ENABLE_FEATURE_HTTPD_CGI 2514#if ENABLE_FEATURE_HTTPD_CGI
2514 else if (urlp[-1] == '/') { 2515 else if (urlp[-1] == '/') {
2515 /* It's a dir URL and there is no index.html */ 2516 /* It's a dir URL and there is no index.html */
2516 /* Is there cgi-bin/index.cgi? */ 2517 /* Is there cgi-bin/index.cgi? */
2517 if (access("/cgi-bin/index.cgi"+1, X_OK) != 0) 2518 if (access("/cgi-bin/index.cgi"+1, X_OK) != 0)
2518 send_headers_and_exit(HTTP_NOT_FOUND); /* no */ 2519 send_headers_and_exit(HTTP_NOT_FOUND); /* no */
2519 cgi_type = CGI_INDEX; 2520 cgi_type = CGI_INDEX;
2520 } 2521 }
2521#endif 2522#endif
2523 }
2522 2524
2523#if ENABLE_FEATURE_HTTPD_BASIC_AUTH || ENABLE_FEATURE_HTTPD_CGI 2525#if ENABLE_FEATURE_HTTPD_BASIC_AUTH || ENABLE_FEATURE_HTTPD_CGI
2524 /* check_user_passwd() would be confused by added .../index.html, truncate it */ 2526 /* check_user_passwd() would be confused by added .../index.html, truncate it */
@@ -2787,8 +2789,8 @@ static void mini_httpd_nommu(int server_socket, int argc, char **argv)
2787 /* Run a copy of ourself in inetd mode */ 2789 /* Run a copy of ourself in inetd mode */
2788 re_exec(argv_copy); 2790 re_exec(argv_copy);
2789 } 2791 }
2790 argv_copy[0][0] &= 0x7f;
2791 /* parent, or vfork failed */ 2792 /* parent, or vfork failed */
2793 argv_copy[0][0] &= 0x7f; /* undo re_rexec() damage */
2792 close(n); 2794 close(n);
2793 } /* while (1) */ 2795 } /* while (1) */
2794 /* never reached */ 2796 /* never reached */
diff --git a/procps/kill.c b/procps/kill.c
index 8c2bc2b6f..583d61aaf 100644
--- a/procps/kill.c
+++ b/procps/kill.c
@@ -85,8 +85,8 @@
85 * This brings some complications: 85 * This brings some complications:
86 * 86 *
87 * + we can't use xfunc here 87 * + we can't use xfunc here
88 * + we can't use applet_name
89 * + we can't use bb_show_usage 88 * + we can't use bb_show_usage
89 * + applet_name can be the name of the shell
90 * (doesn't apply for killall[5], still should be careful b/c NOFORK) 90 * (doesn't apply for killall[5], still should be careful b/c NOFORK)
91 * 91 *
92 * kill %n gets translated into kill ' -<process group>' by shell (note space!) 92 * kill %n gets translated into kill ' -<process group>' by shell (note space!)
diff --git a/procps/top.c b/procps/top.c
index ff775422c..6d25d9633 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -619,17 +619,15 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width)
619 unsigned busy_jifs; 619 unsigned busy_jifs;
620#endif 620#endif
621 621
622 /* what info of the processes is shown */
623 printf(OPT_BATCH_MODE ? "%.*s" : ESC"[7m" "%.*s" ESC"[m", scr_width,
624 " PID PPID USER STAT VSZ %VSZ"
625 IF_FEATURE_TOP_SMP_PROCESS(" CPU")
626 IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(" %CPU")
627 " COMMAND");
628 lines_rem--;
629
630#if ENABLE_FEATURE_TOP_DECIMALS 622#if ENABLE_FEATURE_TOP_DECIMALS
631# define UPSCALE 1000 623# define UPSCALE 1000
632# define CALC_STAT(name, val) div_t name = div((val), 10) 624typedef struct { unsigned quot, rem; } bb_div_t;
625/* Used to have "div_t name = div((val), 10)" here
626 * (IOW: intended to use libc-compatible way to divide and use
627 * both result and remainder, but musl does not inline div()...)
628 * Oh well. Modern compilers detect "N/d, N%d" idiom by themselves:
629 */
630# define CALC_STAT(name, val) bb_div_t name = { (val) / 10, (val) % 10 }
633# define SHOW_STAT(name) name.quot, '0'+name.rem 631# define SHOW_STAT(name) name.quot, '0'+name.rem
634# define FMT "%3u.%c" 632# define FMT "%3u.%c"
635#else 633#else
@@ -638,6 +636,15 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width)
638# define SHOW_STAT(name) name 636# define SHOW_STAT(name) name
639# define FMT "%4u%%" 637# define FMT "%4u%%"
640#endif 638#endif
639
640 /* what info of the processes is shown */
641 printf(OPT_BATCH_MODE ? "%.*s" : ESC"[7m" "%.*s" ESC"[m", scr_width,
642 " PID PPID USER STAT VSZ %VSZ"
643 IF_FEATURE_TOP_SMP_PROCESS(" CPU")
644 IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(" %CPU")
645 " COMMAND");
646 lines_rem--;
647
641 /* 648 /*
642 * %VSZ = s->vsz/MemTotal 649 * %VSZ = s->vsz/MemTotal
643 */ 650 */
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index 64fd92f06..1ae25c919 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -394,7 +394,11 @@ void parse_dep_file(void *map, size_t len)
394 do p--; while (p != m && !isalnum((unsigned char)*p)); 394 do p--; while (p != m && !isalnum((unsigned char)*p));
395 p++; 395 p++;
396 } 396 }
397 if (p == m) break; 397 if (p < m) {
398 /* we've consumed the last filename of this list
399 already. */
400 break;
401 }
398 memcpy(s, m, p-m); s[p-m] = 0; 402 memcpy(s, m, p-m); s[p-m] = 0;
399 if (strrcmp(s, "include/autoconf.h") && 403 if (strrcmp(s, "include/autoconf.h") &&
400 strrcmp(s, "arch/um/include/uml-config.h") && 404 strrcmp(s, "arch/um/include/uml-config.h") &&
diff --git a/shell/ash.c b/shell/ash.c
index 51bf95377..0443f1a02 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -2049,16 +2049,18 @@ _STPUTC(int c, char *p)
2049/* 2049/*
2050 * prefix -- see if pfx is a prefix of string. 2050 * prefix -- see if pfx is a prefix of string.
2051 */ 2051 */
2052static char * 2052static ALWAYS_INLINE char *
2053prefix(const char *string, const char *pfx) 2053prefix(const char *string, const char *pfx)
2054{ 2054{
2055 return is_prefixed_with(string, pfx);
2056#if 0 /* dash implementation: */
2055 while (*pfx) { 2057 while (*pfx) {
2056 if (*pfx++ != *string++) 2058 if (*pfx++ != *string++)
2057 return NULL; 2059 return NULL;
2058 } 2060 }
2059 return (char *) string; 2061 return (char *) string;
2062#endif
2060} 2063}
2061
2062/* 2064/*
2063 * Check for a valid number. This should be elsewhere. 2065 * Check for a valid number. This should be elsewhere.
2064 */ 2066 */
@@ -2296,7 +2298,7 @@ struct localvar {
2296#define VNOFUNC 0x40 /* don't call the callback function */ 2298#define VNOFUNC 0x40 /* don't call the callback function */
2297#define VNOSET 0x80 /* do not set variable - just readonly test */ 2299#define VNOSET 0x80 /* do not set variable - just readonly test */
2298#define VNOSAVE 0x100 /* when text is on the heap before setvareq */ 2300#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
2299#if ENABLE_ASH_RANDOM_SUPPORT 2301#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2300# define VDYNAMIC 0x200 /* dynamic variable */ 2302# define VDYNAMIC 0x200 /* dynamic variable */
2301#else 2303#else
2302# define VDYNAMIC 0 2304# define VDYNAMIC 0
@@ -2319,10 +2321,7 @@ change_lc_ctype(const char *value)
2319} 2321}
2320#endif 2322#endif
2321#if ENABLE_ASH_MAIL 2323#if ENABLE_ASH_MAIL
2322static void chkmail(void);
2323static void changemail(const char *var_value) FAST_FUNC; 2324static void changemail(const char *var_value) FAST_FUNC;
2324#else
2325# define chkmail() ((void)0)
2326#endif 2325#endif
2327static void changepath(const char *) FAST_FUNC; 2326static void changepath(const char *) FAST_FUNC;
2328#if ENABLE_ASH_RANDOM_SUPPORT 2327#if ENABLE_ASH_RANDOM_SUPPORT
@@ -3407,7 +3406,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3407 if (!*dest) 3406 if (!*dest)
3408 dest = "."; 3407 dest = ".";
3409 path = bltinlookup("CDPATH"); 3408 path = bltinlookup("CDPATH");
3410 while (p = path, (len = padvance(&path, dest)) >= 0) { 3409 while (p = path, (len = padvance_magic(&path, dest, 0)) >= 0) {
3411 c = *p; 3410 c = *p;
3412 p = stalloc(len); 3411 p = stalloc(len);
3413 3412
@@ -4454,9 +4453,6 @@ getjob(const char *name, int getctl)
4454 unsigned num; 4453 unsigned num;
4455 int c; 4454 int c;
4456 const char *p; 4455 const char *p;
4457#if ENABLE_PLATFORM_POSIX || JOBS_WIN32
4458 char *(*match)(const char *, const char *);
4459#endif
4460 4456
4461 jp = curjob; 4457 jp = curjob;
4462 p = name; 4458 p = name;
@@ -4498,15 +4494,12 @@ getjob(const char *name, int getctl)
4498 } 4494 }
4499 4495
4500#if ENABLE_PLATFORM_POSIX || JOBS_WIN32 4496#if ENABLE_PLATFORM_POSIX || JOBS_WIN32
4501 match = prefix;
4502 if (*p == '?') {
4503 match = strstr;
4504 p++;
4505 }
4506
4507 found = NULL; 4497 found = NULL;
4508 while (jp) { 4498 while (jp) {
4509 if (match(jp->ps[0].ps_cmd, p)) { 4499 if (*p == '?'
4500 ? strstr(jp->ps[0].ps_cmd, p + 1)
4501 : prefix(jp->ps[0].ps_cmd, p)
4502 ) {
4510 if (found) 4503 if (found)
4511 goto err; 4504 goto err;
4512 found = jp; 4505 found = jp;
@@ -5802,8 +5795,7 @@ forkchild(struct job *jp, union node *n, int mode)
5802 5795
5803 closescript(); 5796 closescript();
5804 5797
5805 if (mode == FORK_NOJOB /* is it `xxx` ? */ 5798 if (n && n->type == NCMD /* is it single cmd? */
5806 && n && n->type == NCMD /* is it single cmd? */
5807 /* && n->ncmd.args->type == NARG - always true? */ 5799 /* && n->ncmd.args->type == NARG - always true? */
5808 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0 5800 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
5809 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */ 5801 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
@@ -5897,10 +5889,12 @@ forkchild(struct job *jp, union node *n, int mode)
5897 ) { 5889 ) {
5898 TRACE(("Job hack\n")); 5890 TRACE(("Job hack\n"));
5899 /* "jobs": we do not want to clear job list for it, 5891 /* "jobs": we do not want to clear job list for it,
5900 * instead we remove only _its_ own_ job from job list. 5892 * instead we remove only _its_ own_ job from job list
5893 * (if it has one).
5901 * This makes "jobs .... | cat" more useful. 5894 * This makes "jobs .... | cat" more useful.
5902 */ 5895 */
5903 freejob(curjob); 5896 if (jp)
5897 freejob(curjob);
5904 return; 5898 return;
5905 } 5899 }
5906#endif 5900#endif
@@ -7293,7 +7287,7 @@ evalbackcmd(union node *n, struct backcmd *result
7293 7287
7294 if (pipe(pip) < 0) 7288 if (pipe(pip) < 0)
7295 ash_msg_and_raise_perror("can't create pipe"); 7289 ash_msg_and_raise_perror("can't create pipe");
7296 /* process substitution uses NULL job/node, like openhere() */ 7290 /* process substitution uses NULL job, like openhere() */
7297 jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL; 7291 jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL;
7298#if ENABLE_PLATFORM_MINGW32 7292#if ENABLE_PLATFORM_MINGW32
7299 memset(&fs, 0, sizeof(fs)); 7293 memset(&fs, 0, sizeof(fs));
@@ -7302,9 +7296,9 @@ evalbackcmd(union node *n, struct backcmd *result
7302 fs.fd[0] = pip[0]; 7296 fs.fd[0] = pip[0];
7303 fs.fd[1] = pip[1]; 7297 fs.fd[1] = pip[1];
7304 fs.fd[2] = ctl; 7298 fs.fd[2] = ctl;
7305 spawn_forkshell(&fs, jp, (ctl == CTLBACKQ) ? n : NULL, FORK_NOJOB); 7299 spawn_forkshell(&fs, jp, n, FORK_NOJOB);
7306#else 7300#else
7307 if (forkshell(jp, (ctl == CTLBACKQ) ? n : NULL, FORK_NOJOB) == 0) { 7301 if (forkshell(jp, n, FORK_NOJOB) == 0) {
7308 /* child */ 7302 /* child */
7309 FORCE_INT_ON; 7303 FORCE_INT_ON;
7310 close(pip[ip]); 7304 close(pip[ip]);
@@ -9507,8 +9501,6 @@ describe_command(char *command, const char *path, int describe_command_verbose)
9507 const struct alias *ap; 9501 const struct alias *ap;
9508#endif 9502#endif
9509 9503
9510 path = path ? path : pathval();
9511
9512 if (describe_command_verbose) { 9504 if (describe_command_verbose) {
9513 out1str(command); 9505 out1str(command);
9514 } 9506 }
@@ -9533,6 +9525,7 @@ describe_command(char *command, const char *path, int describe_command_verbose)
9533 } 9525 }
9534#endif 9526#endif
9535 /* Brute force */ 9527 /* Brute force */
9528 path = path ? path : pathval();
9536 find_command(command, &entry, DO_ABS, path); 9529 find_command(command, &entry, DO_ABS, path);
9537 9530
9538 switch (entry.cmdtype) { 9531 switch (entry.cmdtype) {
@@ -12311,15 +12304,14 @@ setinputstring(char *string)
12311#if ENABLE_ASH_MAIL 12304#if ENABLE_ASH_MAIL
12312 12305
12313/* Hash of mtimes of mailboxes */ 12306/* Hash of mtimes of mailboxes */
12307/* Cleared to 0 if MAIL or MAILPATH is changed */
12314static unsigned mailtime_hash; 12308static unsigned mailtime_hash;
12315/* Set if MAIL or MAILPATH is changed. */
12316static smallint mail_var_path_changed;
12317 12309
12318/* 12310/*
12319 * Print appropriate message(s) if mail has arrived. 12311 * Print appropriate message(s) if mail has arrived.
12320 * If mail_var_path_changed is set, 12312 * If mailtime_hash is zero,
12321 * then the value of MAIL has mail_var_path_changed, 12313 * then the value of MAIL has changed,
12322 * so we just update the values. 12314 * so we just update the hash value.
12323 */ 12315 */
12324static void 12316static void
12325chkmail(void) 12317chkmail(void)
@@ -12338,10 +12330,9 @@ chkmail(void)
12338 int len; 12330 int len;
12339 12331
12340 len = padvance_magic(&mpath, nullstr, 2); 12332 len = padvance_magic(&mpath, nullstr, 2);
12341 if (!len) 12333 if (len < 0)
12342 break; 12334 break;
12343 p = stackblock(); 12335 p = stackblock();
12344 break;
12345 if (*p == '\0') 12336 if (*p == '\0')
12346 continue; 12337 continue;
12347 for (q = p; *q; q++) 12338 for (q = p; *q; q++)
@@ -12357,21 +12348,24 @@ chkmail(void)
12357 /* Very simplistic "hash": just a sum of all mtimes */ 12348 /* Very simplistic "hash": just a sum of all mtimes */
12358 new_hash += (unsigned)statb.st_mtime; 12349 new_hash += (unsigned)statb.st_mtime;
12359 } 12350 }
12360 if (!mail_var_path_changed && mailtime_hash != new_hash) { 12351 if (mailtime_hash != new_hash) {
12361 if (mailtime_hash != 0) 12352 if (mailtime_hash != 0)
12362 out2str("you have mail\n"); 12353 out2str("you have mail\n");
12363 mailtime_hash = new_hash; 12354 mailtime_hash = new_hash;
12364 } 12355 }
12365 mail_var_path_changed = 0;
12366 popstackmark(&smark); 12356 popstackmark(&smark);
12367} 12357}
12368 12358
12369static void FAST_FUNC 12359static void FAST_FUNC
12370changemail(const char *val UNUSED_PARAM) 12360changemail(const char *val UNUSED_PARAM)
12371{ 12361{
12372 mail_var_path_changed = 1; 12362 mailtime_hash = 0;
12373} 12363}
12374 12364
12365#else
12366
12367# define chkmail() ((void)0)
12368
12375#endif /* ASH_MAIL */ 12369#endif /* ASH_MAIL */
12376 12370
12377 12371
@@ -14707,7 +14701,7 @@ static char *
14707find_dot_file(char *basename) 14701find_dot_file(char *basename)
14708{ 14702{
14709 char *fullname; 14703 char *fullname;
14710 const char *path = pathval(); 14704 const char *path;
14711 struct stat statb; 14705 struct stat statb;
14712 int len; 14706 int len;
14713 14707
@@ -14715,6 +14709,7 @@ find_dot_file(char *basename)
14715 if (strchr(basename, '/') IF_PLATFORM_MINGW32(|| strchr(basename, '\\'))) 14709 if (strchr(basename, '/') IF_PLATFORM_MINGW32(|| strchr(basename, '\\')))
14716 return basename; 14710 return basename;
14717 14711
14712 path = pathval();
14718 while ((len = padvance(&path, basename)) >= 0) { 14713 while ((len = padvance(&path, basename)) >= 0) {
14719 fullname = stackblock(); 14714 fullname = stackblock();
14720 if ((!pathopt || *pathopt == 'f') 14715 if ((!pathopt || *pathopt == 'f')
diff --git a/shell/ash_test/ash-signals/usage.right b/shell/ash_test/ash-signals/usage.right
index c0dbd6c3c..df1ed2dd7 100644
--- a/shell/ash_test/ash-signals/usage.right
+++ b/shell/ash_test/ash-signals/usage.right
@@ -6,6 +6,18 @@ trap -- 'a' INT
6trap -- 'a' USR1 6trap -- 'a' USR1
7trap -- 'a' USR2 7trap -- 'a' USR2
8___ 8___
9trap -- 'a' EXIT trap -- 'a' INT trap -- 'a' USR1 trap -- 'a' USR2
10___
11trap -- 'a' EXIT
12trap -- 'a' INT
13trap -- 'a' USR1
14trap -- 'a' USR2
15___
16trap -- 'a' EXIT
17trap -- 'a' INT
18trap -- 'a' USR1
19trap -- 'a' USR2
20___
9___ 21___
10trap -- 'a' USR1 22trap -- 'a' USR1
11trap -- 'a' USR2 23trap -- 'a' USR2
diff --git a/shell/ash_test/ash-signals/usage.tests b/shell/ash_test/ash-signals/usage.tests
index d29c6e74a..34e24cceb 100755
--- a/shell/ash_test/ash-signals/usage.tests
+++ b/shell/ash_test/ash-signals/usage.tests
@@ -10,6 +10,18 @@ trap "a" EXIT INT USR1 USR2
10echo ___ 10echo ___
11trap 11trap
12 12
13# show them by command substitution
14echo ___
15echo $(trap)
16
17# show them by pipe
18echo ___
19trap | cat
20
21# show them by process substitution
22echo ___
23cat <(trap)
24
13# clear one 25# clear one
14echo ___ 26echo ___
15trap 0 INT 27trap 0 INT
diff --git a/shell/hush.c b/shell/hush.c
index e6be70078..a938cc790 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -7468,6 +7468,9 @@ static void re_execute_shell(char ***to_free, const char *s,
7468 if (!cur->flg_export || cur->flg_read_only) 7468 if (!cur->flg_export || cur->flg_read_only)
7469 cnt += 2; 7469 cnt += 2;
7470 } 7470 }
7471# if ENABLE_HUSH_LINENO_VAR
7472 cnt += 2;
7473# endif
7471# if ENABLE_HUSH_FUNCTIONS 7474# if ENABLE_HUSH_FUNCTIONS
7472 for (funcp = G.top_func; funcp; funcp = funcp->next) 7475 for (funcp = G.top_func; funcp; funcp = funcp->next)
7473 cnt += 3; 7476 cnt += 3;
@@ -7489,6 +7492,10 @@ static void re_execute_shell(char ***to_free, const char *s,
7489 *pp++ = cur->varstr; 7492 *pp++ = cur->varstr;
7490 } 7493 }
7491 } 7494 }
7495# if ENABLE_HUSH_LINENO_VAR
7496 *pp++ = (char *) "-L";
7497 *pp++ = utoa(G.execute_lineno);
7498# endif
7492# if ENABLE_HUSH_FUNCTIONS 7499# if ENABLE_HUSH_FUNCTIONS
7493 for (funcp = G.top_func; funcp; funcp = funcp->next) { 7500 for (funcp = G.top_func; funcp; funcp = funcp->next) {
7494 *pp++ = (char *) "-F"; 7501 *pp++ = (char *) "-F";
@@ -10260,6 +10267,20 @@ int hush_main(int argc, char **argv)
10260 INIT_G(); 10267 INIT_G();
10261 if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ 10268 if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */
10262 G.last_exitcode = EXIT_SUCCESS; 10269 G.last_exitcode = EXIT_SUCCESS;
10270#if !BB_MMU
10271 /* "Big heredoc" support via "sh -< STRING" invocation.
10272 * Check it first (do not bother to run the usual init code,
10273 * it is not needed for this case).
10274 */
10275 if (argv[1]
10276 && argv[1][0] == '-' && argv[1][1] == '<' /*&& !argv[1][2]*/
10277 /*&& argv[2] && !argv[3] - we don't check some conditions */
10278 ) {
10279 full_write1_str(argv[2]);
10280 _exit(0);
10281 }
10282 G.argv0_for_re_execing = argv[0];
10283#endif
10263#if ENABLE_HUSH_TRAP 10284#if ENABLE_HUSH_TRAP
10264# if ENABLE_HUSH_FUNCTIONS 10285# if ENABLE_HUSH_FUNCTIONS
10265 G.return_exitcode = -1; 10286 G.return_exitcode = -1;
@@ -10270,9 +10291,6 @@ int hush_main(int argc, char **argv)
10270#if ENABLE_HUSH_FAST 10291#if ENABLE_HUSH_FAST
10271 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ 10292 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
10272#endif 10293#endif
10273#if !BB_MMU
10274 G.argv0_for_re_execing = argv[0];
10275#endif
10276 10294
10277 cached_getpid = getpid(); /* for tcsetpgrp() during init */ 10295 cached_getpid = getpid(); /* for tcsetpgrp() during init */
10278 G.root_pid = cached_getpid; /* for $PID (NOMMU can override via -$HEXPID:HEXPPID:...) */ 10296 G.root_pid = cached_getpid; /* for $PID (NOMMU can override via -$HEXPID:HEXPPID:...) */
@@ -10388,7 +10406,10 @@ int hush_main(int argc, char **argv)
10388 int opt = getopt(argc, argv, "+" /* stop at 1st non-option */ 10406 int opt = getopt(argc, argv, "+" /* stop at 1st non-option */
10389 "cexinsl" 10407 "cexinsl"
10390#if !BB_MMU 10408#if !BB_MMU
10391 "<:$:R:V:" 10409 "$:R:V:"
10410# if ENABLE_HUSH_LINENO_VAR
10411 "L:"
10412# endif
10392# if ENABLE_HUSH_FUNCTIONS 10413# if ENABLE_HUSH_FUNCTIONS
10393 "F:" 10414 "F:"
10394# endif 10415# endif
@@ -10438,9 +10459,6 @@ int hush_main(int argc, char **argv)
10438 flags |= OPT_login; 10459 flags |= OPT_login;
10439 break; 10460 break;
10440#if !BB_MMU 10461#if !BB_MMU
10441 case '<': /* "big heredoc" support */
10442 full_write1_str(optarg);
10443 _exit(0);
10444 case '$': { 10462 case '$': {
10445 unsigned long long empty_trap_mask; 10463 unsigned long long empty_trap_mask;
10446 10464
@@ -10490,6 +10508,11 @@ int hush_main(int argc, char **argv)
10490 case 'V': 10508 case 'V':
10491 set_local_var(xstrdup(optarg), opt == 'R' ? SETFLAG_MAKE_RO : 0); 10509 set_local_var(xstrdup(optarg), opt == 'R' ? SETFLAG_MAKE_RO : 0);
10492 break; 10510 break;
10511# if ENABLE_HUSH_LINENO_VAR
10512 case 'L':
10513 G.parse_lineno = xatou(optarg);
10514 break;
10515# endif
10493# if ENABLE_HUSH_FUNCTIONS 10516# if ENABLE_HUSH_FUNCTIONS
10494 case 'F': { 10517 case 'F': {
10495 struct function *funcp = new_function(optarg); 10518 struct function *funcp = new_function(optarg);
@@ -11276,6 +11299,9 @@ static int FAST_FUNC builtin_local(char **argv)
11276 bb_error_msg("%s: not in a function", argv[0]); 11299 bb_error_msg("%s: not in a function", argv[0]);
11277 return EXIT_FAILURE; /* bash compat */ 11300 return EXIT_FAILURE; /* bash compat */
11278 } 11301 }
11302//TODO? ash and bash support "local -" special form,
11303//which saves/restores $- around function call (including async returns, such as ^C)
11304//(IOW: it makes "set +/-..." effects local)
11279 argv++; 11305 argv++;
11280 /* Since all builtins run in a nested variable level, 11306 /* Since all builtins run in a nested variable level,
11281 * need to use level - 1 here. Or else the variable will be removed at once 11307 * need to use level - 1 here. Or else the variable will be removed at once
diff --git a/testsuite/find.tests b/testsuite/find.tests
index 138236c81..d763ca6f2 100755
--- a/testsuite/find.tests
+++ b/testsuite/find.tests
@@ -28,6 +28,12 @@ testing "find -exec exitcode 2" \
28 "0\n" \ 28 "0\n" \
29 "" "" 29 "" ""
30SKIP= 30SKIP=
31optional FEATURE_FIND_EXEC_OK
32testing "find -ok" \
33 "cd find.tempdir && find testfile -ok true {} ';' 2>&1; echo \$?" \
34 "true testfile ?0\n" \
35 "" "y"
36SKIP=
31# Surprisingly, "-exec false ;" results in exitcode 0! "-exec false +" is different!!! 37# Surprisingly, "-exec false ;" results in exitcode 0! "-exec false +" is different!!!
32optional FEATURE_FIND_EXEC 38optional FEATURE_FIND_EXEC
33testing "find -exec exitcode 3" \ 39testing "find -exec exitcode 3" \