diff options
Diffstat (limited to 'shell')
-rw-r--r-- | shell/Kbuild.src | 1 | ||||
-rw-r--r-- | shell/ash.c | 2410 | ||||
-rw-r--r-- | shell/math.h | 2 | ||||
-rw-r--r-- | shell/random.c | 11 | ||||
-rw-r--r-- | shell/random.h | 3 | ||||
-rw-r--r-- | shell/shell_common.c | 78 |
6 files changed, 2469 insertions, 36 deletions
diff --git a/shell/Kbuild.src b/shell/Kbuild.src index 6bba4989f..a287fce4e 100644 --- a/shell/Kbuild.src +++ b/shell/Kbuild.src | |||
@@ -9,3 +9,4 @@ lib-y:= | |||
9 | INSERT | 9 | INSERT |
10 | 10 | ||
11 | lib-$(CONFIG_FEATURE_SH_MATH) += math.o | 11 | lib-$(CONFIG_FEATURE_SH_MATH) += math.o |
12 | lib-$(CONFIG_FEATURE_PRNG_SHELL) += random.o | ||
diff --git a/shell/ash.c b/shell/ash.c index 51b627fcc..09e8725bf 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -15,6 +15,21 @@ | |||
15 | * | 15 | * |
16 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | 16 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
17 | */ | 17 | */ |
18 | |||
19 | /* | ||
20 | * MinGW notes | ||
21 | * | ||
22 | * - Environment variables from Windows will all be turned to uppercase. | ||
23 | * - PATH accepts both ; and : as separator, but can't be mixed | ||
24 | * - command without ".exe" extension is still understood as executable | ||
25 | * - shell scripts on the path are detected by the presence of '#!' | ||
26 | * - both / and \ are supported in PATH. Usually you must use / | ||
27 | * - job control doesn't work, though the jobs builtin is available | ||
28 | * - trap doesn't work for signals, only EXIT | ||
29 | * - /dev/null is supported for redirection | ||
30 | * - fake $PPID | ||
31 | */ | ||
32 | |||
18 | //config:config SHELL_ASH | 33 | //config:config SHELL_ASH |
19 | //config: bool #hidden option | 34 | //config: bool #hidden option |
20 | //config: depends on !NOMMU | 35 | //config: depends on !NOMMU |
@@ -158,6 +173,25 @@ | |||
158 | //config: you to run the specified command or builtin, | 173 | //config: you to run the specified command or builtin, |
159 | //config: even when there is a function with the same name. | 174 | //config: even when there is a function with the same name. |
160 | //config: | 175 | //config: |
176 | //config: | ||
177 | //config:config ASH_NOCONSOLE | ||
178 | //config: bool "'noconsole' option" | ||
179 | //config: default y | ||
180 | //config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32 | ||
181 | //config: help | ||
182 | //config: Enable support for the 'noconsole' option, which attempts to | ||
183 | //config: hide the console normally associated with a command line | ||
184 | //config: application. This may be useful when running a shell script | ||
185 | //config: from a GUI application. | ||
186 | //config: | ||
187 | //config:config ASH_NOCASEGLOB | ||
188 | //config: bool "'nocaseglob' option" | ||
189 | //config: default y | ||
190 | //config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32 | ||
191 | //config: help | ||
192 | //config: Enable support for the 'nocaseglob' option, which allows | ||
193 | //config: case-insensitive filename globbing. | ||
194 | //config: | ||
161 | //config:endif # ash options | 195 | //config:endif # ash options |
162 | 196 | ||
163 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) | 197 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) |
@@ -183,7 +217,17 @@ | |||
183 | 217 | ||
184 | #define PROFILE 0 | 218 | #define PROFILE 0 |
185 | 219 | ||
220 | /* | ||
221 | * Only one of JOBS or JOBS_WIN32 is enabled at a time (or neither). | ||
222 | * JOBS_WIN32 doesn't enable job control, just some job-related features. | ||
223 | */ | ||
224 | #if ENABLE_PLATFORM_MINGW32 | ||
225 | #define JOBS_WIN32 ENABLE_ASH_JOB_CONTROL | ||
226 | #define JOBS 0 | ||
227 | #else | ||
228 | #define JOBS_WIN32 0 | ||
186 | #define JOBS ENABLE_ASH_JOB_CONTROL | 229 | #define JOBS ENABLE_ASH_JOB_CONTROL |
230 | #endif | ||
187 | 231 | ||
188 | #include <fnmatch.h> | 232 | #include <fnmatch.h> |
189 | #include <sys/times.h> | 233 | #include <sys/times.h> |
@@ -194,6 +238,9 @@ | |||
194 | #else | 238 | #else |
195 | # define NUM_SCRIPTS 0 | 239 | # define NUM_SCRIPTS 0 |
196 | #endif | 240 | #endif |
241 | #if ENABLE_PLATFORM_MINGW32 | ||
242 | # include <conio.h> | ||
243 | #endif | ||
197 | 244 | ||
198 | /* So far, all bash compat is controlled by one config option */ | 245 | /* So far, all bash compat is controlled by one config option */ |
199 | /* Separate defines document which part of code implements what */ | 246 | /* Separate defines document which part of code implements what */ |
@@ -304,10 +351,81 @@ typedef long arith_t; | |||
304 | # define unlikely(cond) (cond) | 351 | # define unlikely(cond) (cond) |
305 | #endif | 352 | #endif |
306 | 353 | ||
354 | #if !ENABLE_PLATFORM_MINGW32 | ||
355 | # define is_relative_path(path) ((path)[0] != '/') | ||
356 | #endif | ||
357 | |||
307 | #if !BB_MMU | 358 | #if !BB_MMU |
308 | # error "Do not even bother, ash will not run on NOMMU machine" | 359 | # error "Do not even bother, ash will not run on NOMMU machine" |
309 | #endif | 360 | #endif |
310 | 361 | ||
362 | #if ENABLE_PLATFORM_MINGW32 | ||
363 | # define FORKSHELL_DEBUG 0 | ||
364 | |||
365 | union node; | ||
366 | struct strlist; | ||
367 | struct job; | ||
368 | |||
369 | struct forkshell { | ||
370 | /* filled by forkshell_copy() */ | ||
371 | struct globals_var *gvp; | ||
372 | struct globals_misc *gmp; | ||
373 | struct tblentry **cmdtable; | ||
374 | #if ENABLE_ASH_ALIAS | ||
375 | struct alias **atab; | ||
376 | #endif | ||
377 | #if MAX_HISTORY | ||
378 | char **history; | ||
379 | int cnt_history; | ||
380 | #endif | ||
381 | /* struct parsefile *g_parsefile; */ | ||
382 | HANDLE hMapFile; | ||
383 | char *old_base; | ||
384 | int size; | ||
385 | # if FORKSHELL_DEBUG | ||
386 | int funcblocksize; | ||
387 | int funcstringsize; | ||
388 | # endif | ||
389 | int relocatesize; | ||
390 | |||
391 | /* type of forkshell */ | ||
392 | int fpid; | ||
393 | |||
394 | /* generic data, used by forkshell_child */ | ||
395 | int mode; | ||
396 | int nprocs; | ||
397 | |||
398 | /* optional data, used by forkshell_child */ | ||
399 | int flags; | ||
400 | int fd[3]; | ||
401 | union node *n; | ||
402 | char **argv; | ||
403 | char *path; | ||
404 | }; | ||
405 | |||
406 | enum { | ||
407 | FS_OPENHERE, | ||
408 | FS_EVALBACKCMD, | ||
409 | FS_EVALSUBSHELL, | ||
410 | FS_EVALPIPE, | ||
411 | FS_SHELLEXEC | ||
412 | }; | ||
413 | |||
414 | static struct forkshell* forkshell_prepare(struct forkshell *fs); | ||
415 | static void forkshell_init(const char *idstr); | ||
416 | static void *sticky_mem_start, *sticky_mem_end; | ||
417 | static void sticky_free(void *p); | ||
418 | # define free(p) sticky_free(p) | ||
419 | #if !JOBS && !JOBS_WIN32 | ||
420 | #define spawn_forkshell(fs, jp, n, mode) spawn_forkshell(fs, jp, mode) | ||
421 | #endif | ||
422 | static void spawn_forkshell(struct forkshell *fs, struct job *jp, | ||
423 | union node *n, int mode); | ||
424 | # if FORKSHELL_DEBUG | ||
425 | static void forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes); | ||
426 | # endif | ||
427 | #endif | ||
428 | |||
311 | /* ============ Hash table sizes. Configurable. */ | 429 | /* ============ Hash table sizes. Configurable. */ |
312 | 430 | ||
313 | #define VTABSIZE 39 | 431 | #define VTABSIZE 39 |
@@ -335,7 +453,11 @@ static const char *const optletters_optnames[] ALIGN_PTR = { | |||
335 | "m" "monitor", | 453 | "m" "monitor", |
336 | "n" "noexec", | 454 | "n" "noexec", |
337 | /* Ditto: bash has no "set -s", "set -c" */ | 455 | /* Ditto: bash has no "set -s", "set -c" */ |
456 | #if !ENABLE_PLATFORM_MINGW32 | ||
338 | "s" "", | 457 | "s" "", |
458 | #else | ||
459 | "s" "stdin", | ||
460 | #endif | ||
339 | "c" "", | 461 | "c" "", |
340 | "x" "xtrace", | 462 | "x" "xtrace", |
341 | "v" "verbose", | 463 | "v" "verbose", |
@@ -352,6 +474,15 @@ static const char *const optletters_optnames[] ALIGN_PTR = { | |||
352 | ,"\0" "nolog" | 474 | ,"\0" "nolog" |
353 | ,"\0" "debug" | 475 | ,"\0" "debug" |
354 | #endif | 476 | #endif |
477 | #if ENABLE_PLATFORM_MINGW32 | ||
478 | ,"X" "winxp" | ||
479 | #endif | ||
480 | #if ENABLE_ASH_NOCONSOLE | ||
481 | ,"\0" "noconsole" | ||
482 | #endif | ||
483 | #if ENABLE_ASH_NOCASEGLOB | ||
484 | ,"\0" "nocaseglob" | ||
485 | #endif | ||
355 | }; | 486 | }; |
356 | //bash 4.4.23 also has these opts (with these defaults): | 487 | //bash 4.4.23 also has these opts (with these defaults): |
357 | //braceexpand on | 488 | //braceexpand on |
@@ -394,28 +525,45 @@ struct jmploc { | |||
394 | struct globals_misc { | 525 | struct globals_misc { |
395 | uint8_t exitstatus; /* exit status of last command */ | 526 | uint8_t exitstatus; /* exit status of last command */ |
396 | uint8_t back_exitstatus;/* exit status of backquoted command */ | 527 | uint8_t back_exitstatus;/* exit status of backquoted command */ |
528 | #if !ENABLE_PLATFORM_MINGW32 | ||
397 | smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ | 529 | smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ |
530 | #endif | ||
398 | smallint inps4; /* Prevent PS4 nesting. */ | 531 | smallint inps4; /* Prevent PS4 nesting. */ |
399 | int savestatus; /* exit status of last command outside traps */ | 532 | int savestatus; /* exit status of last command outside traps */ |
400 | int rootpid; /* pid of main shell */ | 533 | int rootpid; /* pid of main shell */ |
401 | /* shell level: 0 for the main shell, 1 for its children, and so on */ | 534 | /* shell level: 0 for the main shell, 1 for its children, and so on */ |
402 | int shlvl; | 535 | int shlvl; |
536 | #if ENABLE_PLATFORM_MINGW32 | ||
537 | int loopnest; /* current loop nesting level */ | ||
538 | #endif | ||
403 | #define rootshell (!shlvl) | 539 | #define rootshell (!shlvl) |
404 | int errlinno; | 540 | int errlinno; |
405 | 541 | ||
406 | char *minusc; /* argument to -c option */ | 542 | char *minusc; /* argument to -c option */ |
543 | #if ENABLE_PLATFORM_MINGW32 | ||
544 | char *dirarg; /* argument to -d option */ | ||
545 | char *title; /* argument to -t option */ | ||
546 | #if ENABLE_SUW32 | ||
547 | int delayexit; /* set by -N option */ | ||
548 | # endif | ||
549 | #endif | ||
407 | 550 | ||
408 | char *curdir; // = nullstr; /* current working directory */ | 551 | char *curdir; // = nullstr; /* current working directory */ |
409 | char *physdir; // = nullstr; /* physical working directory */ | 552 | char *physdir; // = nullstr; /* physical working directory */ |
410 | 553 | ||
411 | char *arg0; /* value of $0 */ | 554 | char *arg0; /* value of $0 */ |
555 | #if ENABLE_PLATFORM_MINGW32 | ||
556 | char *commandname; | ||
557 | #endif | ||
412 | 558 | ||
413 | struct jmploc *exception_handler; | 559 | struct jmploc *exception_handler; |
414 | 560 | ||
415 | volatile int suppress_int; /* counter */ | 561 | volatile int suppress_int; /* counter */ |
416 | volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ | 562 | volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ |
563 | #if !ENABLE_PLATFORM_MINGW32 | ||
417 | volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */ | 564 | volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */ |
418 | volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */ | 565 | volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */ |
566 | #endif | ||
419 | smallint exception_type; /* kind of exception: */ | 567 | smallint exception_type; /* kind of exception: */ |
420 | #define EXINT 0 /* SIGINT received */ | 568 | #define EXINT 0 /* SIGINT received */ |
421 | #define EXERROR 1 /* a generic error */ | 569 | #define EXERROR 1 /* a generic error */ |
@@ -450,8 +598,18 @@ struct globals_misc { | |||
450 | # define nolog optlist[16 + BASH_PIPEFAIL] | 598 | # define nolog optlist[16 + BASH_PIPEFAIL] |
451 | # define debug optlist[17 + BASH_PIPEFAIL] | 599 | # define debug optlist[17 + BASH_PIPEFAIL] |
452 | #endif | 600 | #endif |
601 | #if ENABLE_PLATFORM_MINGW32 | ||
602 | # define winxp optlist[16 + BASH_PIPEFAIL + 2*(DEBUG != 0)] | ||
603 | # if ENABLE_ASH_NOCONSOLE | ||
604 | # define noconsole optlist[17 + BASH_PIPEFAIL + 2*(DEBUG != 0)] | ||
605 | # endif | ||
606 | # if ENABLE_ASH_NOCASEGLOB | ||
607 | # define nocaseglob optlist[17 + BASH_PIPEFAIL + 2*(DEBUG != 0) + ENABLE_ASH_NOCONSOLE] | ||
608 | # endif | ||
609 | #endif | ||
453 | 610 | ||
454 | /* trap handler commands */ | 611 | /* trap handler commands */ |
612 | #if !ENABLE_PLATFORM_MINGW32 | ||
455 | /* | 613 | /* |
456 | * Sigmode records the current value of the signal handlers for the various | 614 | * Sigmode records the current value of the signal handlers for the various |
457 | * modes. A value of zero means that the current handler is not known. | 615 | * modes. A value of zero means that the current handler is not known. |
@@ -465,13 +623,16 @@ struct globals_misc { | |||
465 | 623 | ||
466 | /* indicates specified signal received */ | 624 | /* indicates specified signal received */ |
467 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ | 625 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ |
626 | #endif | ||
468 | uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ | 627 | uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ |
469 | char *trap[NSIG + 1]; | 628 | char *trap[NSIG + 1]; |
470 | /* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */ | 629 | /* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */ |
471 | #define NTRAP_ERR NSIG | 630 | #define NTRAP_ERR NSIG |
472 | #define NTRAP_LAST NSIG | 631 | #define NTRAP_LAST NSIG |
473 | 632 | ||
633 | #if !ENABLE_PLATFORM_MINGW32 | ||
474 | char **trap_ptr; /* used only by "trap hack" */ | 634 | char **trap_ptr; /* used only by "trap hack" */ |
635 | #endif | ||
475 | 636 | ||
476 | /* Rarely referenced stuff */ | 637 | /* Rarely referenced stuff */ |
477 | #if ENABLE_ASH_RANDOM_SUPPORT | 638 | #if ENABLE_ASH_RANDOM_SUPPORT |
@@ -489,10 +650,21 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
489 | #define rootpid (G_misc.rootpid ) | 650 | #define rootpid (G_misc.rootpid ) |
490 | #define shlvl (G_misc.shlvl ) | 651 | #define shlvl (G_misc.shlvl ) |
491 | #define errlinno (G_misc.errlinno ) | 652 | #define errlinno (G_misc.errlinno ) |
653 | #if ENABLE_PLATFORM_MINGW32 | ||
654 | #define loopnest (G_misc.loopnest ) | ||
655 | #endif | ||
492 | #define minusc (G_misc.minusc ) | 656 | #define minusc (G_misc.minusc ) |
657 | #if ENABLE_PLATFORM_MINGW32 | ||
658 | #define dirarg (G_misc.dirarg ) | ||
659 | #define title (G_misc.title ) | ||
660 | #define delayexit (G_misc.delayexit ) | ||
661 | #endif | ||
493 | #define curdir (G_misc.curdir ) | 662 | #define curdir (G_misc.curdir ) |
494 | #define physdir (G_misc.physdir ) | 663 | #define physdir (G_misc.physdir ) |
495 | #define arg0 (G_misc.arg0 ) | 664 | #define arg0 (G_misc.arg0 ) |
665 | #if ENABLE_PLATFORM_MINGW32 | ||
666 | #define commandname (G_misc.commandname) | ||
667 | #endif | ||
496 | #define exception_handler (G_misc.exception_handler) | 668 | #define exception_handler (G_misc.exception_handler) |
497 | #define exception_type (G_misc.exception_type ) | 669 | #define exception_type (G_misc.exception_type ) |
498 | #define suppress_int (G_misc.suppress_int ) | 670 | #define suppress_int (G_misc.suppress_int ) |
@@ -508,12 +680,21 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
508 | #define trap_ptr (G_misc.trap_ptr ) | 680 | #define trap_ptr (G_misc.trap_ptr ) |
509 | #define random_gen (G_misc.random_gen ) | 681 | #define random_gen (G_misc.random_gen ) |
510 | #define backgndpid (G_misc.backgndpid ) | 682 | #define backgndpid (G_misc.backgndpid ) |
683 | |||
684 | #if ENABLE_PLATFORM_MINGW32 | ||
685 | #undef got_sigchld | ||
686 | #undef pending_sig | ||
687 | #undef trap_ptr | ||
688 | #define pending_sig (0) | ||
689 | #define trap_ptr trap | ||
690 | #endif | ||
691 | |||
511 | #define INIT_G_misc() do { \ | 692 | #define INIT_G_misc() do { \ |
512 | XZALLOC_CONST_PTR(&ash_ptr_to_globals_misc, sizeof(G_misc)); \ | 693 | XZALLOC_CONST_PTR(&ash_ptr_to_globals_misc, sizeof(G_misc)); \ |
513 | savestatus = -1; \ | 694 | savestatus = -1; \ |
514 | curdir = nullstr; \ | 695 | curdir = nullstr; \ |
515 | physdir = nullstr; \ | 696 | physdir = nullstr; \ |
516 | trap_ptr = trap; \ | 697 | IF_NOT_PLATFORM_MINGW32(trap_ptr = trap;) \ |
517 | } while (0) | 698 | } while (0) |
518 | 699 | ||
519 | 700 | ||
@@ -523,6 +704,9 @@ static void trace_printf(const char *fmt, ...); | |||
523 | static void trace_vprintf(const char *fmt, va_list va); | 704 | static void trace_vprintf(const char *fmt, va_list va); |
524 | # define TRACE(param) trace_printf param | 705 | # define TRACE(param) trace_printf param |
525 | # define TRACEV(param) trace_vprintf param | 706 | # define TRACEV(param) trace_vprintf param |
707 | # if ENABLE_PLATFORM_MINGW32 && defined(close) | ||
708 | # undef close | ||
709 | # endif | ||
526 | # define close(fd) do { \ | 710 | # define close(fd) do { \ |
527 | int dfd = (fd); \ | 711 | int dfd = (fd); \ |
528 | if (close(dfd) < 0) \ | 712 | if (close(dfd) < 0) \ |
@@ -612,11 +796,18 @@ struct parsefile { | |||
612 | 796 | ||
613 | /* Number of outstanding calls to pungetc. */ | 797 | /* Number of outstanding calls to pungetc. */ |
614 | int unget; | 798 | int unget; |
799 | |||
800 | #if ENABLE_PLATFORM_MINGW32 | ||
801 | /* True if a trailing CR from a previous read was left unprocessed. */ | ||
802 | int cr; | ||
803 | #endif | ||
615 | }; | 804 | }; |
616 | 805 | ||
617 | static struct parsefile basepf; /* top level input file */ | 806 | static struct parsefile basepf; /* top level input file */ |
618 | static struct parsefile *g_parsefile = &basepf; /* current input file */ | 807 | static struct parsefile *g_parsefile = &basepf; /* current input file */ |
808 | #if ENABLE_PLATFORM_POSIX | ||
619 | static char *commandname; /* currently executing command */ | 809 | static char *commandname; /* currently executing command */ |
810 | #endif | ||
620 | 811 | ||
621 | 812 | ||
622 | /* ============ Interrupts / exceptions */ | 813 | /* ============ Interrupts / exceptions */ |
@@ -673,21 +864,38 @@ raise_exception(int e) | |||
673 | * are held using the INT_OFF macro. (The test for iflag is just | 864 | * are held using the INT_OFF macro. (The test for iflag is just |
674 | * defensive programming.) | 865 | * defensive programming.) |
675 | */ | 866 | */ |
676 | static void raise_interrupt(void) NORETURN; | 867 | static void raise_interrupt(void) IF_NOT_PLATFORM_MINGW32(NORETURN); |
677 | static void | 868 | static void |
678 | raise_interrupt(void) | 869 | raise_interrupt(void) |
679 | { | 870 | { |
871 | #if ENABLE_PLATFORM_MINGW32 | ||
872 | /* Contrary to the comment above on Windows raise_interrupt() is | ||
873 | * called when SIGINT is trapped or ignored. We detect this here | ||
874 | * and return without doing anything. */ | ||
875 | if (trap[SIGINT]) | ||
876 | return; | ||
877 | #endif | ||
680 | pending_int = 0; | 878 | pending_int = 0; |
879 | #if !ENABLE_PLATFORM_MINGW32 | ||
681 | /* Signal is not automatically unmasked after it is raised, | 880 | /* Signal is not automatically unmasked after it is raised, |
682 | * do it ourself - unmask all signals */ | 881 | * do it ourself - unmask all signals */ |
683 | sigprocmask_allsigs(SIG_UNBLOCK); | 882 | sigprocmask_allsigs(SIG_UNBLOCK); |
883 | #endif | ||
684 | /* pending_sig = 0; - now done in signal_handler() */ | 884 | /* pending_sig = 0; - now done in signal_handler() */ |
685 | 885 | ||
686 | if (!(rootshell && iflag)) { | 886 | if (!(rootshell && iflag)) { |
887 | #if !ENABLE_PLATFORM_MINGW32 | ||
687 | /* Kill ourself with SIGINT */ | 888 | /* Kill ourself with SIGINT */ |
688 | signal(SIGINT, SIG_DFL); | 889 | signal(SIGINT, SIG_DFL); |
689 | raise(SIGINT); | 890 | raise(SIGINT); |
891 | #else | ||
892 | exit(SIGINT << 24); | ||
893 | #endif | ||
690 | } | 894 | } |
895 | #if ENABLE_PLATFORM_MINGW32 | ||
896 | if (iflag) | ||
897 | write(STDOUT_FILENO, "^C", 2); | ||
898 | #endif | ||
691 | /* bash: ^C even on empty command line sets $? */ | 899 | /* bash: ^C even on empty command line sets $? */ |
692 | exitstatus = SIGINT + 128; | 900 | exitstatus = SIGINT + 128; |
693 | raise_exception(EXINT); | 901 | raise_exception(EXINT); |
@@ -1972,6 +2180,18 @@ maybe_single_quote(const char *s) | |||
1972 | return single_quote(s); | 2180 | return single_quote(s); |
1973 | } | 2181 | } |
1974 | 2182 | ||
2183 | #if ENABLE_PLATFORM_MINGW32 | ||
2184 | /* Copy path to a string on the stack long enough to allow a file extension | ||
2185 | * to be added. */ | ||
2186 | static char * | ||
2187 | stack_add_ext_space(const char *path) | ||
2188 | { | ||
2189 | char *p = growstackto(strlen(path) + 5); | ||
2190 | strcpy(p, path); | ||
2191 | return p; | ||
2192 | } | ||
2193 | #endif | ||
2194 | |||
1975 | 2195 | ||
1976 | /* ============ nextopt */ | 2196 | /* ============ nextopt */ |
1977 | 2197 | ||
@@ -2123,6 +2343,17 @@ static void change_seconds(const char *) FAST_FUNC; | |||
2123 | static void change_realtime(const char *) FAST_FUNC; | 2343 | static void change_realtime(const char *) FAST_FUNC; |
2124 | #endif | 2344 | #endif |
2125 | 2345 | ||
2346 | #if ENABLE_PLATFORM_MINGW32 | ||
2347 | static void FAST_FUNC | ||
2348 | change_terminal_mode(const char *newval UNUSED_PARAM) | ||
2349 | { | ||
2350 | terminal_mode(TRUE); | ||
2351 | } | ||
2352 | |||
2353 | # define LINENO_INDEX (5 + 2 * ENABLE_ASH_MAIL + ENABLE_ASH_GETOPTS) | ||
2354 | # define FUNCNAME_INDEX (LINENO_INDEX + 1) | ||
2355 | #endif | ||
2356 | |||
2126 | static const struct { | 2357 | static const struct { |
2127 | int flags; | 2358 | int flags; |
2128 | const char *var_text; | 2359 | const char *var_text; |
@@ -2160,6 +2391,10 @@ static const struct { | |||
2160 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 2391 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY |
2161 | { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL }, | 2392 | { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL }, |
2162 | #endif | 2393 | #endif |
2394 | #if ENABLE_PLATFORM_MINGW32 | ||
2395 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_SKIP_ANSI_EMULATION, change_terminal_mode }, | ||
2396 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_TERMINAL_MODE, change_terminal_mode }, | ||
2397 | #endif | ||
2163 | }; | 2398 | }; |
2164 | 2399 | ||
2165 | struct redirtab; | 2400 | struct redirtab; |
@@ -2405,6 +2640,65 @@ bltinlookup(const char *name) | |||
2405 | return lookupvar(name); | 2640 | return lookupvar(name); |
2406 | } | 2641 | } |
2407 | 2642 | ||
2643 | #if ENABLE_PLATFORM_MINGW32 | ||
2644 | static char * | ||
2645 | fix_pathvar(const char *path, int len) | ||
2646 | { | ||
2647 | char *newpath = xstrdup(path); | ||
2648 | char *p; | ||
2649 | int modified = FALSE; | ||
2650 | |||
2651 | p = newpath + len; | ||
2652 | while (*p) { | ||
2653 | if (*p != ':' && *p != ';') { | ||
2654 | /* skip drive */ | ||
2655 | if (isalpha(*p) && p[1] == ':') | ||
2656 | p += 2; | ||
2657 | /* skip through path component */ | ||
2658 | for (; *p != '\0' && *p != ':' && *p != ';'; ++p) | ||
2659 | continue; | ||
2660 | } | ||
2661 | /* *p is ':', ';' or '\0' here */ | ||
2662 | if (*p == ':') { | ||
2663 | *p++ = ';'; | ||
2664 | modified = TRUE; | ||
2665 | } | ||
2666 | else if (*p == ';') { | ||
2667 | ++p; | ||
2668 | } | ||
2669 | } | ||
2670 | |||
2671 | if (!modified) { | ||
2672 | free(newpath); | ||
2673 | newpath = NULL; | ||
2674 | } | ||
2675 | return newpath; | ||
2676 | } | ||
2677 | |||
2678 | #define BB_VAR_EXACT 1 /* exact match for name */ | ||
2679 | #define BB_VAR_ASSIGN -1 /* matches name followed by '=' */ | ||
2680 | |||
2681 | /* Match variables that should be placed in the environment immediately | ||
2682 | * they're exported and removed immediately they're no longer exported */ | ||
2683 | static int | ||
2684 | is_bb_var(const char *s) | ||
2685 | { | ||
2686 | const char *p; | ||
2687 | int len; | ||
2688 | |||
2689 | for (p = bbvar; *p; p += len + 1) { | ||
2690 | len = strlen(p); | ||
2691 | if (strncmp(s, p, len) == 0) { | ||
2692 | if (s[len] == '\0') | ||
2693 | return BB_VAR_EXACT; | ||
2694 | else if (s[len] == '=') | ||
2695 | return BB_VAR_ASSIGN; | ||
2696 | } | ||
2697 | } | ||
2698 | return FALSE; | ||
2699 | } | ||
2700 | #endif | ||
2701 | |||
2408 | /* | 2702 | /* |
2409 | * Same as setvar except that the variable and value are passed in | 2703 | * Same as setvar except that the variable and value are passed in |
2410 | * the first argument as name=value. Since the first argument will | 2704 | * the first argument as name=value. Since the first argument will |
@@ -2416,6 +2710,26 @@ static struct var * | |||
2416 | setvareq(char *s, int flags) | 2710 | setvareq(char *s, int flags) |
2417 | { | 2711 | { |
2418 | struct var *vp, **vpp; | 2712 | struct var *vp, **vpp; |
2713 | #if ENABLE_PLATFORM_MINGW32 | ||
2714 | const char *paths = "PATH=\0""CDPATH=\0""MANPATH=\0"; | ||
2715 | const char *p; | ||
2716 | int len; | ||
2717 | |||
2718 | for (p = paths; *p; p += len + 1) { | ||
2719 | len = strlen(p); | ||
2720 | if (strncmp(s, p, len) == 0) { | ||
2721 | char *newpath = fix_pathvar(s, len); | ||
2722 | if (newpath) { | ||
2723 | if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE) | ||
2724 | free(s); | ||
2725 | flags |= VNOSAVE; | ||
2726 | flags &= ~(VTEXTFIXED|VSTACK); | ||
2727 | s = newpath; | ||
2728 | } | ||
2729 | break; | ||
2730 | } | ||
2731 | } | ||
2732 | #endif | ||
2419 | 2733 | ||
2420 | vpp = hashvar(s); | 2734 | vpp = hashvar(s); |
2421 | flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); | 2735 | flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); |
@@ -2441,6 +2755,11 @@ setvareq(char *s, int flags) | |||
2441 | if (!(vp->flags & (VTEXTFIXED|VSTACK))) | 2755 | if (!(vp->flags & (VTEXTFIXED|VSTACK))) |
2442 | free((char*)vp->var_text); | 2756 | free((char*)vp->var_text); |
2443 | 2757 | ||
2758 | #if ENABLE_PLATFORM_MINGW32 | ||
2759 | if ((flags & VUNSET) && (vp->flags & VEXPORT) && | ||
2760 | is_bb_var(s) == BB_VAR_EXACT) | ||
2761 | unsetenv(s); | ||
2762 | #endif | ||
2444 | if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) { | 2763 | if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) { |
2445 | *vpp = vp->next; | 2764 | *vpp = vp->next; |
2446 | free(vp); | 2765 | free(vp); |
@@ -2470,6 +2789,10 @@ setvareq(char *s, int flags) | |||
2470 | s = ckstrdup(s); | 2789 | s = ckstrdup(s); |
2471 | vp->var_text = s; | 2790 | vp->var_text = s; |
2472 | vp->flags = flags; | 2791 | vp->flags = flags; |
2792 | #if ENABLE_PLATFORM_MINGW32 | ||
2793 | if ((flags & VEXPORT) && is_bb_var(s) == BB_VAR_ASSIGN) | ||
2794 | putenv(s); | ||
2795 | #endif | ||
2473 | 2796 | ||
2474 | out: | 2797 | out: |
2475 | return vp; | 2798 | return vp; |
@@ -2634,7 +2957,7 @@ static const char *pathopt; /* set by padvance */ | |||
2634 | static int | 2957 | static int |
2635 | padvance_magic(const char **path, const char *name, int magic) | 2958 | padvance_magic(const char **path, const char *name, int magic) |
2636 | { | 2959 | { |
2637 | const char *term = "%:"; | 2960 | const char *term = "%"PATH_SEP_STR; |
2638 | const char *lpathopt; | 2961 | const char *lpathopt; |
2639 | const char *p; | 2962 | const char *p; |
2640 | char *q; | 2963 | char *q; |
@@ -2651,14 +2974,14 @@ padvance_magic(const char **path, const char *name, int magic) | |||
2651 | if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) { | 2974 | if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) { |
2652 | lpathopt = start + 1; | 2975 | lpathopt = start + 1; |
2653 | start = p; | 2976 | start = p; |
2654 | term = ":"; | 2977 | term = PATH_SEP_STR; |
2655 | } | 2978 | } |
2656 | 2979 | ||
2657 | len = strcspn(start, term); | 2980 | len = strcspn(start, term); |
2658 | p = start + len; | 2981 | p = start + len; |
2659 | 2982 | ||
2660 | if (*p == '%') { | 2983 | if (*p == '%') { |
2661 | size_t extra = strchrnul(p, ':') - p; | 2984 | size_t extra = strchrnul(p, PATH_SEP) - p; |
2662 | 2985 | ||
2663 | if (legal_pathopt(p + 1, term, magic)) | 2986 | if (legal_pathopt(p + 1, term, magic)) |
2664 | lpathopt = p + 1; | 2987 | lpathopt = p + 1; |
@@ -2669,14 +2992,18 @@ padvance_magic(const char **path, const char *name, int magic) | |||
2669 | } | 2992 | } |
2670 | 2993 | ||
2671 | pathopt = lpathopt; | 2994 | pathopt = lpathopt; |
2672 | *path = *p == ':' ? p + 1 : NULL; | 2995 | *path = *p == PATH_SEP ? p + 1 : NULL; |
2673 | 2996 | ||
2674 | /* "2" is for '/' and '\0' */ | 2997 | /* "2" is for '/' and '\0' */ |
2675 | qlen = len + strlen(name) + 2; | 2998 | /* reserve space for suffix on WIN32 */ |
2999 | qlen = len + strlen(name) + 2 IF_PLATFORM_MINGW32(+ 4); | ||
2676 | q = growstackto(qlen); | 3000 | q = growstackto(qlen); |
2677 | 3001 | ||
2678 | if (len) { | 3002 | if (len) { |
2679 | q = mempcpy(q, start, len); | 3003 | q = mempcpy(q, start, len); |
3004 | #if ENABLE_PLATFORM_MINGW32 | ||
3005 | if (q[-1] != '/' && q[-1] != '\\') | ||
3006 | #endif | ||
2680 | *q++ = '/'; | 3007 | *q++ = '/'; |
2681 | } | 3008 | } |
2682 | strcpy(q, name); | 3009 | strcpy(q, name); |
@@ -2767,6 +3094,7 @@ setprompt_if(smallint do_set, int whichprompt) | |||
2767 | 3094 | ||
2768 | #define CD_PHYSICAL 1 | 3095 | #define CD_PHYSICAL 1 |
2769 | #define CD_PRINT 2 | 3096 | #define CD_PRINT 2 |
3097 | #define CD_PRINT_ALL 4 | ||
2770 | 3098 | ||
2771 | static int | 3099 | static int |
2772 | cdopt(void) | 3100 | cdopt(void) |
@@ -2775,7 +3103,14 @@ cdopt(void) | |||
2775 | int i, j; | 3103 | int i, j; |
2776 | 3104 | ||
2777 | j = 'L'; | 3105 | j = 'L'; |
3106 | #if ENABLE_PLATFORM_MINGW32 | ||
3107 | while ((i = nextopt("LPa")) != '\0') { | ||
3108 | if (i == 'a') | ||
3109 | flags |= CD_PRINT_ALL; | ||
3110 | else | ||
3111 | #else | ||
2778 | while ((i = nextopt("LP")) != '\0') { | 3112 | while ((i = nextopt("LP")) != '\0') { |
3113 | #endif | ||
2779 | if (i != j) { | 3114 | if (i != j) { |
2780 | flags ^= CD_PHYSICAL; | 3115 | flags ^= CD_PHYSICAL; |
2781 | j = i; | 3116 | j = i; |
@@ -2792,6 +3127,129 @@ cdopt(void) | |||
2792 | static const char * | 3127 | static const char * |
2793 | updatepwd(const char *dir) | 3128 | updatepwd(const char *dir) |
2794 | { | 3129 | { |
3130 | #if ENABLE_PLATFORM_MINGW32 | ||
3131 | /* | ||
3132 | * Due to Windows drive notion, getting pwd is a completely | ||
3133 | * different thing. Handle it in a separate routine | ||
3134 | */ | ||
3135 | |||
3136 | char *new; | ||
3137 | char *p; | ||
3138 | char *cdcomppath; | ||
3139 | const char *lim; | ||
3140 | int len; | ||
3141 | char buffer[PATH_MAX]; | ||
3142 | /* | ||
3143 | * There are five cases that make some kind of sense | ||
3144 | * | ||
3145 | * Absolute paths: | ||
3146 | * c:/path | ||
3147 | * //host/share | ||
3148 | * | ||
3149 | * Relative to current working directory of other drive: | ||
3150 | * c:path | ||
3151 | * | ||
3152 | * Relative to current root (drive/share): | ||
3153 | * /path | ||
3154 | * | ||
3155 | * Relative to current working directory of current root (drive/share): | ||
3156 | * path | ||
3157 | */ | ||
3158 | enum {ABS_DRIVE, ABS_SHARE, REL_OTHER, REL_ROOT, REL_CWD} target; | ||
3159 | |||
3160 | /* skip multiple leading separators unless dir is a UNC path */ | ||
3161 | if (is_dir_sep(*dir) && unc_root_len(dir) == 0) { | ||
3162 | while (is_dir_sep(dir[1])) | ||
3163 | ++dir; | ||
3164 | } | ||
3165 | |||
3166 | len = strlen(dir); | ||
3167 | if (len >= 2 && has_dos_drive_prefix(dir)) | ||
3168 | target = len >= 3 && is_dir_sep(dir[2]) ? ABS_DRIVE : REL_OTHER; | ||
3169 | else if (unc_root_len(dir) != 0) | ||
3170 | target = ABS_SHARE; | ||
3171 | else if (is_dir_sep(*dir)) | ||
3172 | target = REL_ROOT; | ||
3173 | else | ||
3174 | target = REL_CWD; | ||
3175 | |||
3176 | cdcomppath = sstrdup(dir); | ||
3177 | STARTSTACKSTR(new); | ||
3178 | |||
3179 | switch (target) { | ||
3180 | case REL_OTHER: | ||
3181 | /* c:path */ | ||
3182 | if (get_drive_cwd(dir, buffer, PATH_MAX) == NULL) | ||
3183 | return 0; | ||
3184 | new = stack_putstr(buffer, new); | ||
3185 | len = 2; | ||
3186 | cdcomppath += len; | ||
3187 | dir += len; | ||
3188 | break; | ||
3189 | case REL_CWD: | ||
3190 | case REL_ROOT: | ||
3191 | /* path or /path */ | ||
3192 | len = root_len(curdir); | ||
3193 | if (len == 0) | ||
3194 | return 0; | ||
3195 | new = target == REL_CWD ? stack_putstr(curdir, new) : | ||
3196 | stnputs(curdir, len, new); | ||
3197 | break; | ||
3198 | default: | ||
3199 | /* //host/share or c:/path */ | ||
3200 | len = root_len(dir); | ||
3201 | if (len == 0) | ||
3202 | return 0; | ||
3203 | new = stnputs(dir, len, new); | ||
3204 | cdcomppath += len; | ||
3205 | dir += len; | ||
3206 | break; | ||
3207 | } | ||
3208 | |||
3209 | new = makestrspace(strlen(dir) + 2, new); | ||
3210 | lim = (char *)stackblock() + len + 1; | ||
3211 | |||
3212 | if (!is_dir_sep(*dir)) { | ||
3213 | if (!is_dir_sep(new[-1])) | ||
3214 | USTPUTC('/', new); | ||
3215 | if (new > lim && is_dir_sep(*lim)) | ||
3216 | lim++; | ||
3217 | } else { | ||
3218 | USTPUTC('/', new); | ||
3219 | cdcomppath++; | ||
3220 | if (is_dir_sep(dir[1]) && !is_dir_sep(dir[2])) { | ||
3221 | USTPUTC('/', new); | ||
3222 | cdcomppath++; | ||
3223 | lim++; | ||
3224 | } | ||
3225 | } | ||
3226 | p = strtok(cdcomppath, "/\\"); | ||
3227 | while (p) { | ||
3228 | switch (*p) { | ||
3229 | case '.': | ||
3230 | if (p[1] == '.' && p[2] == '\0') { | ||
3231 | while (new > lim) { | ||
3232 | STUNPUTC(new); | ||
3233 | if (is_dir_sep(new[-1])) | ||
3234 | break; | ||
3235 | } | ||
3236 | break; | ||
3237 | } | ||
3238 | if (p[1] == '\0') | ||
3239 | break; | ||
3240 | /* fall through */ | ||
3241 | default: | ||
3242 | new = stack_putstr(p, new); | ||
3243 | USTPUTC('/', new); | ||
3244 | } | ||
3245 | p = strtok(NULL, "/\\"); | ||
3246 | } | ||
3247 | if (new > lim) | ||
3248 | STUNPUTC(new); | ||
3249 | *new = 0; | ||
3250 | fix_path_case((char *)stackblock()); | ||
3251 | return bs_to_slash((char *)stackblock()); | ||
3252 | #else | ||
2795 | char *new; | 3253 | char *new; |
2796 | char *p; | 3254 | char *p; |
2797 | char *cdcomppath; | 3255 | char *cdcomppath; |
@@ -2845,6 +3303,7 @@ updatepwd(const char *dir) | |||
2845 | STUNPUTC(new); | 3303 | STUNPUTC(new); |
2846 | *new = 0; | 3304 | *new = 0; |
2847 | return stackblock(); | 3305 | return stackblock(); |
3306 | #endif | ||
2848 | } | 3307 | } |
2849 | 3308 | ||
2850 | /* | 3309 | /* |
@@ -2940,7 +3399,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2940 | } | 3399 | } |
2941 | if (!dest) | 3400 | if (!dest) |
2942 | dest = nullstr; | 3401 | dest = nullstr; |
2943 | if (*dest == '/') | 3402 | if (!is_relative_path(dest)) |
2944 | goto step6; | 3403 | goto step6; |
2945 | if (*dest == '.') { | 3404 | if (*dest == '.') { |
2946 | c = dest[1]; | 3405 | c = dest[1]; |
@@ -2963,7 +3422,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2963 | p = stalloc(len); | 3422 | p = stalloc(len); |
2964 | 3423 | ||
2965 | if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { | 3424 | if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { |
2966 | if (c && c != ':') | 3425 | if (c && c != PATH_SEP) |
2967 | flags |= CD_PRINT; | 3426 | flags |= CD_PRINT; |
2968 | docd: | 3427 | docd: |
2969 | if (!docd(p, flags)) | 3428 | if (!docd(p, flags)) |
@@ -2985,6 +3444,26 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2985 | return 0; | 3444 | return 0; |
2986 | } | 3445 | } |
2987 | 3446 | ||
3447 | #if ENABLE_PLATFORM_MINGW32 | ||
3448 | static void | ||
3449 | print_all_cwd(void) | ||
3450 | { | ||
3451 | FILE *mnt; | ||
3452 | struct mntent *entry; | ||
3453 | char buffer[PATH_MAX]; | ||
3454 | |||
3455 | mnt = setmntent(bb_path_mtab_file, "r"); | ||
3456 | if (mnt) { | ||
3457 | while ((entry=getmntent(mnt)) != NULL) { | ||
3458 | entry->mnt_dir[2] = '\0'; | ||
3459 | if (get_drive_cwd(entry->mnt_dir, buffer, PATH_MAX) != NULL) | ||
3460 | out1fmt("%s\n", buffer); | ||
3461 | } | ||
3462 | endmntent(mnt); | ||
3463 | } | ||
3464 | } | ||
3465 | #endif | ||
3466 | |||
2988 | static int FAST_FUNC | 3467 | static int FAST_FUNC |
2989 | pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 3468 | pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) |
2990 | { | 3469 | { |
@@ -2992,6 +3471,12 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2992 | const char *dir = curdir; | 3471 | const char *dir = curdir; |
2993 | 3472 | ||
2994 | flags = cdopt(); | 3473 | flags = cdopt(); |
3474 | #if ENABLE_PLATFORM_MINGW32 | ||
3475 | if (flags & CD_PRINT_ALL) { | ||
3476 | print_all_cwd(); | ||
3477 | return 0; | ||
3478 | } | ||
3479 | #endif | ||
2995 | if (flags) { | 3480 | if (flags) { |
2996 | if (physdir == nullstr) | 3481 | if (physdir == nullstr) |
2997 | setpwd(dir, 0); | 3482 | setpwd(dir, 0); |
@@ -3620,7 +4105,12 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
3620 | struct procstat { | 4105 | struct procstat { |
3621 | pid_t ps_pid; /* process id */ | 4106 | pid_t ps_pid; /* process id */ |
3622 | int ps_status; /* last process status from wait() */ | 4107 | int ps_status; /* last process status from wait() */ |
4108 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
3623 | char *ps_cmd; /* text of command being run */ | 4109 | char *ps_cmd; /* text of command being run */ |
4110 | #endif | ||
4111 | #if ENABLE_PLATFORM_MINGW32 | ||
4112 | HANDLE ps_proc; | ||
4113 | #endif | ||
3624 | }; | 4114 | }; |
3625 | 4115 | ||
3626 | struct job { | 4116 | struct job { |
@@ -3636,8 +4126,10 @@ struct job { | |||
3636 | #define JOBDONE 2 /* all procs are completed */ | 4126 | #define JOBDONE 2 /* all procs are completed */ |
3637 | unsigned | 4127 | unsigned |
3638 | state: 8, | 4128 | state: 8, |
3639 | #if JOBS | 4129 | #if JOBS || ENABLE_PLATFORM_MINGW32 |
3640 | sigint: 1, /* job was killed by SIGINT */ | 4130 | sigint: 1, /* job was killed by SIGINT */ |
4131 | #endif | ||
4132 | #if JOBS | ||
3641 | jobctl: 1, /* job running under job control */ | 4133 | jobctl: 1, /* job running under job control */ |
3642 | #endif | 4134 | #endif |
3643 | waited: 1, /* true if this entry has been waited for */ | 4135 | waited: 1, /* true if this entry has been waited for */ |
@@ -3647,17 +4139,23 @@ struct job { | |||
3647 | }; | 4139 | }; |
3648 | 4140 | ||
3649 | static struct job *makejob(/*union node *,*/ int); | 4141 | static struct job *makejob(/*union node *,*/ int); |
4142 | #if !ENABLE_PLATFORM_MINGW32 | ||
3650 | static int forkshell(struct job *, union node *, int); | 4143 | static int forkshell(struct job *, union node *, int); |
4144 | #endif | ||
3651 | static int waitforjob(struct job *); | 4145 | static int waitforjob(struct job *); |
3652 | 4146 | ||
3653 | #if !JOBS | 4147 | #if !JOBS && !JOBS_WIN32 |
3654 | enum { doing_jobctl = 0 }; | 4148 | enum { doing_jobctl = 0 }; |
3655 | #define setjobctl(on) do {} while (0) | 4149 | #define setjobctl(on) do {} while (0) |
3656 | #else | 4150 | #elif JOBS_WIN32 |
4151 | static smallint doing_jobctl; //references:8 | ||
4152 | #define setjobctl(on) do { if (rootshell) doing_jobctl = on; } while (0) | ||
4153 | #else /* JOBS */ | ||
3657 | static smallint doing_jobctl; //references:8 | 4154 | static smallint doing_jobctl; //references:8 |
3658 | static void setjobctl(int); | 4155 | static void setjobctl(int); |
3659 | #endif | 4156 | #endif |
3660 | 4157 | ||
4158 | #if !ENABLE_PLATFORM_MINGW32 | ||
3661 | /* | 4159 | /* |
3662 | * Ignore a signal. | 4160 | * Ignore a signal. |
3663 | */ | 4161 | */ |
@@ -3806,6 +4304,10 @@ setsignal(int signo) | |||
3806 | 4304 | ||
3807 | sigaction_set(signo, &act); | 4305 | sigaction_set(signo, &act); |
3808 | } | 4306 | } |
4307 | #else | ||
4308 | #define setsignal(s) | ||
4309 | #define ignoresig(s) | ||
4310 | #endif | ||
3809 | 4311 | ||
3810 | /* mode flags for set_curjob */ | 4312 | /* mode flags for set_curjob */ |
3811 | #define CUR_DELETE 2 | 4313 | #define CUR_DELETE 2 |
@@ -3939,7 +4441,7 @@ set_curjob(struct job *jp, unsigned mode) | |||
3939 | } | 4441 | } |
3940 | } | 4442 | } |
3941 | 4443 | ||
3942 | #if JOBS || DEBUG | 4444 | #if JOBS || ENABLE_PLATFORM_MINGW32 || DEBUG |
3943 | static int | 4445 | static int |
3944 | jobno(const struct job *jp) | 4446 | jobno(const struct job *jp) |
3945 | { | 4447 | { |
@@ -3957,7 +4459,9 @@ static struct job * | |||
3957 | getjob(const char *name, int getctl) | 4459 | getjob(const char *name, int getctl) |
3958 | { | 4460 | { |
3959 | struct job *jp; | 4461 | struct job *jp; |
4462 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
3960 | struct job *found; | 4463 | struct job *found; |
4464 | #endif | ||
3961 | const char *err_msg = "%s: no such job"; | 4465 | const char *err_msg = "%s: no such job"; |
3962 | unsigned num; | 4466 | unsigned num; |
3963 | int c; | 4467 | int c; |
@@ -4002,6 +4506,7 @@ getjob(const char *name, int getctl) | |||
4002 | } | 4506 | } |
4003 | } | 4507 | } |
4004 | 4508 | ||
4509 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
4005 | found = NULL; | 4510 | found = NULL; |
4006 | while (jp) { | 4511 | while (jp) { |
4007 | if (*p == '?' | 4512 | if (*p == '?' |
@@ -4018,6 +4523,9 @@ getjob(const char *name, int getctl) | |||
4018 | if (!found) | 4523 | if (!found) |
4019 | goto err; | 4524 | goto err; |
4020 | jp = found; | 4525 | jp = found; |
4526 | #else | ||
4527 | goto err; | ||
4528 | #endif | ||
4021 | 4529 | ||
4022 | gotit: | 4530 | gotit: |
4023 | #if JOBS | 4531 | #if JOBS |
@@ -4036,14 +4544,18 @@ getjob(const char *name, int getctl) | |||
4036 | static void | 4544 | static void |
4037 | freejob(struct job *jp) | 4545 | freejob(struct job *jp) |
4038 | { | 4546 | { |
4547 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
4039 | struct procstat *ps; | 4548 | struct procstat *ps; |
4040 | int i; | 4549 | int i; |
4550 | #endif | ||
4041 | 4551 | ||
4042 | INT_OFF; | 4552 | INT_OFF; |
4553 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
4043 | for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { | 4554 | for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { |
4044 | if (ps->ps_cmd != nullstr) | 4555 | if (ps->ps_cmd != nullstr) |
4045 | free(ps->ps_cmd); | 4556 | free(ps->ps_cmd); |
4046 | } | 4557 | } |
4558 | #endif | ||
4047 | if (jp->ps != &jp->ps0) | 4559 | if (jp->ps != &jp->ps0) |
4048 | free(jp->ps); | 4560 | free(jp->ps); |
4049 | jp->used = 0; | 4561 | jp->used = 0; |
@@ -4136,7 +4648,9 @@ setjobctl(int on) | |||
4136 | ttyfd = fd; | 4648 | ttyfd = fd; |
4137 | doing_jobctl = on; | 4649 | doing_jobctl = on; |
4138 | } | 4650 | } |
4651 | #endif | ||
4139 | 4652 | ||
4653 | #if JOBS || JOBS_WIN32 | ||
4140 | static int FAST_FUNC | 4654 | static int FAST_FUNC |
4141 | killcmd(int argc, char **argv) | 4655 | killcmd(int argc, char **argv) |
4142 | { | 4656 | { |
@@ -4166,8 +4680,10 @@ killcmd(int argc, char **argv) | |||
4166 | * sh -c 'true|sleep 1 & sleep 2; kill %1' | 4680 | * sh -c 'true|sleep 1 & sleep 2; kill %1' |
4167 | */ | 4681 | */ |
4168 | n = jp->nprocs; /* can't be 0 (I hope) */ | 4682 | n = jp->nprocs; /* can't be 0 (I hope) */ |
4683 | #if !ENABLE_PLATFORM_MINGW32 | ||
4169 | if (jp->jobctl) | 4684 | if (jp->jobctl) |
4170 | n = 1; | 4685 | n = 1; |
4686 | #endif | ||
4171 | dst = alloca(n * sizeof(int)*4); | 4687 | dst = alloca(n * sizeof(int)*4); |
4172 | argv[i] = dst; | 4688 | argv[i] = dst; |
4173 | for (j = 0; j < n; j++) { | 4689 | for (j = 0; j < n; j++) { |
@@ -4182,7 +4698,11 @@ killcmd(int argc, char **argv) | |||
4182 | * leading space. Needed to not confuse | 4698 | * leading space. Needed to not confuse |
4183 | * negative pids with "kill -SIGNAL_NO" syntax | 4699 | * negative pids with "kill -SIGNAL_NO" syntax |
4184 | */ | 4700 | */ |
4701 | #if !ENABLE_PLATFORM_MINGW32 | ||
4185 | dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); | 4702 | dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); |
4703 | #else | ||
4704 | dst += sprintf(dst, " -%u", (int)ps->ps_pid); | ||
4705 | #endif | ||
4186 | } | 4706 | } |
4187 | *dst = '\0'; | 4707 | *dst = '\0'; |
4188 | } | 4708 | } |
@@ -4190,7 +4710,9 @@ killcmd(int argc, char **argv) | |||
4190 | } | 4710 | } |
4191 | return kill_main(argc, argv); | 4711 | return kill_main(argc, argv); |
4192 | } | 4712 | } |
4713 | #endif | ||
4193 | 4714 | ||
4715 | #if JOBS | ||
4194 | static void | 4716 | static void |
4195 | showpipe(struct job *jp /*, FILE *out*/) | 4717 | showpipe(struct job *jp /*, FILE *out*/) |
4196 | { | 4718 | { |
@@ -4295,6 +4817,89 @@ sprint_status48(char *os, int status, int sigonly) | |||
4295 | return s - os; | 4817 | return s - os; |
4296 | } | 4818 | } |
4297 | 4819 | ||
4820 | #if ENABLE_PLATFORM_MINGW32 | ||
4821 | static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) | ||
4822 | { | ||
4823 | if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { | ||
4824 | # if ENABLE_FEATURE_EDITING | ||
4825 | bb_got_signal = SIGINT; /* for read_line_input: "we got a signal" */ | ||
4826 | # endif | ||
4827 | if (!suppress_int && !(rootshell && iflag)) | ||
4828 | raise_interrupt(); | ||
4829 | pending_int = 1; | ||
4830 | return TRUE; | ||
4831 | } | ||
4832 | return FALSE; | ||
4833 | } | ||
4834 | |||
4835 | /* | ||
4836 | * Windows does not know about parent-child relationship | ||
4837 | * They don't support waitpid(-1) | ||
4838 | */ | ||
4839 | static pid_t | ||
4840 | waitpid_child(int *status, int wait_flags) | ||
4841 | { | ||
4842 | struct job *jb; | ||
4843 | struct procstat *ps; | ||
4844 | int pid_nr = 0; | ||
4845 | pid_t *pidlist; | ||
4846 | HANDLE *proclist; | ||
4847 | pid_t pid = -1; | ||
4848 | DWORD win_status, idx; | ||
4849 | int i, sig; | ||
4850 | |||
4851 | for (jb = curjob; jb; jb = jb->prev_job) { | ||
4852 | if (jb->state != JOBDONE) | ||
4853 | pid_nr += jb->nprocs; | ||
4854 | } | ||
4855 | if (pid_nr == 0) | ||
4856 | return -1; | ||
4857 | |||
4858 | pidlist = ckmalloc(sizeof(*pidlist)*pid_nr); | ||
4859 | proclist = ckmalloc(sizeof(*proclist)*pid_nr); | ||
4860 | |||
4861 | pid_nr = 0; | ||
4862 | for (jb = curjob; jb; jb = jb->prev_job) { | ||
4863 | if (jb->state == JOBDONE) | ||
4864 | continue; | ||
4865 | ps = jb->ps; | ||
4866 | for (i = 0; i < jb->nprocs; ++i) { | ||
4867 | if (ps[i].ps_proc) { | ||
4868 | pidlist[pid_nr] = ps[i].ps_pid; | ||
4869 | proclist[pid_nr++] = ps[i].ps_proc; | ||
4870 | } | ||
4871 | } | ||
4872 | } | ||
4873 | |||
4874 | if (pid_nr == 0) | ||
4875 | goto done; | ||
4876 | |||
4877 | idx = WaitForMultipleObjects(pid_nr, proclist, FALSE, | ||
4878 | wait_flags&WNOHANG ? 1 : INFINITE); | ||
4879 | if (idx < pid_nr) { | ||
4880 | GetExitCodeProcess(proclist[idx], &win_status); | ||
4881 | if (win_status == 0xc0000005) | ||
4882 | win_status = SIGSEGV << 24; | ||
4883 | else if (win_status == 0xc000013a) | ||
4884 | win_status = SIGINT << 24; | ||
4885 | |||
4886 | // When a process is terminated as if by a signal the exit | ||
4887 | // code is zero apart from the signal in its topmost byte. | ||
4888 | sig = win_status >> 24; | ||
4889 | if (sig != 0 && win_status == sig << 24 && is_valid_signal(sig)) | ||
4890 | *status = sig; | ||
4891 | else | ||
4892 | *status = (int)win_status << 8; | ||
4893 | pid = pidlist[idx]; | ||
4894 | } | ||
4895 | done: | ||
4896 | free(pidlist); | ||
4897 | free(proclist); | ||
4898 | return pid; | ||
4899 | } | ||
4900 | #define waitpid(p, s, f) waitpid_child(s, f) | ||
4901 | #endif | ||
4902 | |||
4298 | #define DOWAIT_NONBLOCK 0 | 4903 | #define DOWAIT_NONBLOCK 0 |
4299 | #define DOWAIT_BLOCK 1 | 4904 | #define DOWAIT_BLOCK 1 |
4300 | #define DOWAIT_BLOCK_OR_SIG 2 | 4905 | #define DOWAIT_BLOCK_OR_SIG 2 |
@@ -4305,6 +4910,7 @@ sprint_status48(char *os, int status, int sigonly) | |||
4305 | static int | 4910 | static int |
4306 | waitproc(int block, int *status) | 4911 | waitproc(int block, int *status) |
4307 | { | 4912 | { |
4913 | #if !ENABLE_PLATFORM_MINGW32 | ||
4308 | sigset_t oldmask; | 4914 | sigset_t oldmask; |
4309 | int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; | 4915 | int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; |
4310 | int err; | 4916 | int err; |
@@ -4335,6 +4941,11 @@ waitproc(int block, int *status) | |||
4335 | } while (got_sigchld); | 4941 | } while (got_sigchld); |
4336 | 4942 | ||
4337 | return err; | 4943 | return err; |
4944 | #else | ||
4945 | int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; | ||
4946 | *status = 0; | ||
4947 | return waitpid(-1, status, flags); | ||
4948 | #endif | ||
4338 | } | 4949 | } |
4339 | 4950 | ||
4340 | static int | 4951 | static int |
@@ -4391,6 +5002,11 @@ waitone(int block, struct job *job) | |||
4391 | jobno(jp), pid, ps->ps_status, status)); | 5002 | jobno(jp), pid, ps->ps_status, status)); |
4392 | ps->ps_status = status; | 5003 | ps->ps_status = status; |
4393 | thisjob = jp; | 5004 | thisjob = jp; |
5005 | #if ENABLE_PLATFORM_MINGW32 | ||
5006 | ps->ps_pid = -1; | ||
5007 | CloseHandle(ps->ps_proc); | ||
5008 | ps->ps_proc = NULL; | ||
5009 | #endif | ||
4394 | } | 5010 | } |
4395 | if (ps->ps_status == -1) | 5011 | if (ps->ps_status == -1) |
4396 | jobstate = JOBRUNNING; | 5012 | jobstate = JOBRUNNING; |
@@ -4453,6 +5069,7 @@ waitone(int block, struct job *job) | |||
4453 | static int | 5069 | static int |
4454 | dowait(int block, struct job *jp) | 5070 | dowait(int block, struct job *jp) |
4455 | { | 5071 | { |
5072 | #if !ENABLE_PLATFORM_MINGW32 | ||
4456 | smallint gotchld = *(volatile smallint *)&got_sigchld; | 5073 | smallint gotchld = *(volatile smallint *)&got_sigchld; |
4457 | int rpid; | 5074 | int rpid; |
4458 | int pid; | 5075 | int pid; |
@@ -4474,9 +5091,17 @@ dowait(int block, struct job *jp) | |||
4474 | } while (pid >= 0); | 5091 | } while (pid >= 0); |
4475 | 5092 | ||
4476 | return rpid; | 5093 | return rpid; |
5094 | #else | ||
5095 | int pid = 1; | ||
5096 | |||
5097 | while (jp ? jp->state == JOBRUNNING : pid > 0) | ||
5098 | pid = waitone(block, jp); | ||
5099 | |||
5100 | return pid; | ||
5101 | #endif | ||
4477 | } | 5102 | } |
4478 | 5103 | ||
4479 | #if JOBS | 5104 | #if JOBS || JOBS_WIN32 |
4480 | static void | 5105 | static void |
4481 | showjob(struct job *jp, int mode) | 5106 | showjob(struct job *jp, int mode) |
4482 | { | 5107 | { |
@@ -4491,7 +5116,7 @@ showjob(struct job *jp, int mode) | |||
4491 | 5116 | ||
4492 | if (mode & SHOW_ONLY_PGID) { /* jobs -p */ | 5117 | if (mode & SHOW_ONLY_PGID) { /* jobs -p */ |
4493 | /* just output process (group) id of pipeline */ | 5118 | /* just output process (group) id of pipeline */ |
4494 | fprintf(out, "%d\n", ps->ps_pid); | 5119 | fprintf(out, "%"PID_FMT"d\n", ps->ps_pid); |
4495 | return; | 5120 | return; |
4496 | } | 5121 | } |
4497 | 5122 | ||
@@ -4504,7 +5129,7 @@ showjob(struct job *jp, int mode) | |||
4504 | s[col - 3] = '-'; | 5129 | s[col - 3] = '-'; |
4505 | 5130 | ||
4506 | if (mode & SHOW_PIDS) | 5131 | if (mode & SHOW_PIDS) |
4507 | col += fmtstr(s + col, 16, "%d ", ps->ps_pid); | 5132 | col += fmtstr(s + col, 16, "%"PID_FMT"d ", ps->ps_pid); |
4508 | 5133 | ||
4509 | psend = ps + jp->nprocs; | 5134 | psend = ps + jp->nprocs; |
4510 | 5135 | ||
@@ -4513,8 +5138,10 @@ showjob(struct job *jp, int mode) | |||
4513 | col += sizeof("Running") - 1; | 5138 | col += sizeof("Running") - 1; |
4514 | } else { | 5139 | } else { |
4515 | int status = psend[-1].ps_status; | 5140 | int status = psend[-1].ps_status; |
5141 | #if !ENABLE_PLATFORM_MINGW32 | ||
4516 | if (jp->state == JOBSTOPPED) | 5142 | if (jp->state == JOBSTOPPED) |
4517 | status = jp->stopstatus; | 5143 | status = jp->stopstatus; |
5144 | #endif | ||
4518 | col += sprint_status48(s + col, status, 0); | 5145 | col += sprint_status48(s + col, status, 0); |
4519 | } | 5146 | } |
4520 | /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ | 5147 | /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ |
@@ -4533,14 +5160,18 @@ showjob(struct job *jp, int mode) | |||
4533 | s[0] = '\0'; | 5160 | s[0] = '\0'; |
4534 | col = 33; | 5161 | col = 33; |
4535 | if (mode & SHOW_PIDS) | 5162 | if (mode & SHOW_PIDS) |
4536 | col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1; | 5163 | col = fmtstr(s, 48, "\n%*c%"PID_FMT"d ", indent_col, ' ', ps->ps_pid) - 1; |
4537 | start: | 5164 | start: |
5165 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
4538 | fprintf(out, "%s%*c%s%s", | 5166 | fprintf(out, "%s%*c%s%s", |
4539 | s, | 5167 | s, |
4540 | 33 - col >= 0 ? 33 - col : 0, ' ', | 5168 | 33 - col >= 0 ? 33 - col : 0, ' ', |
4541 | ps == jp->ps ? "" : "| ", | 5169 | ps == jp->ps ? "" : "| ", |
4542 | ps->ps_cmd | 5170 | ps->ps_cmd |
4543 | ); | 5171 | ); |
5172 | #else | ||
5173 | fprintf(out, "%s", s); | ||
5174 | #endif | ||
4544 | } while (++ps != psend); | 5175 | } while (++ps != psend); |
4545 | newline_and_flush(out); | 5176 | newline_and_flush(out); |
4546 | 5177 | ||
@@ -4625,7 +5256,7 @@ getstatus(struct job *job) | |||
4625 | { | 5256 | { |
4626 | /* XXX: limits number of signals */ | 5257 | /* XXX: limits number of signals */ |
4627 | retval = WTERMSIG(status); | 5258 | retval = WTERMSIG(status); |
4628 | #if JOBS | 5259 | #if JOBS || ENABLE_PLATFORM_MINGW32 |
4629 | if (retval == SIGINT) | 5260 | if (retval == SIGINT) |
4630 | job->sigint = 1; | 5261 | job->sigint = 1; |
4631 | #endif | 5262 | #endif |
@@ -4797,7 +5428,7 @@ makejob(/*union node *node,*/ int nprocs) | |||
4797 | break; | 5428 | break; |
4798 | if (jp->state != JOBDONE || !jp->waited) | 5429 | if (jp->state != JOBDONE || !jp->waited) |
4799 | continue; | 5430 | continue; |
4800 | #if JOBS | 5431 | #if JOBS || JOBS_WIN32 |
4801 | if (doing_jobctl) | 5432 | if (doing_jobctl) |
4802 | continue; | 5433 | continue; |
4803 | #endif | 5434 | #endif |
@@ -4823,7 +5454,7 @@ makejob(/*union node *node,*/ int nprocs) | |||
4823 | return jp; | 5454 | return jp; |
4824 | } | 5455 | } |
4825 | 5456 | ||
4826 | #if JOBS | 5457 | #if JOBS || JOBS_WIN32 |
4827 | /* | 5458 | /* |
4828 | * Return a string identifying a command (to be printed by the | 5459 | * Return a string identifying a command (to be printed by the |
4829 | * jobs command). | 5460 | * jobs command). |
@@ -5142,6 +5773,7 @@ commandtext(union node *n) | |||
5142 | * | 5773 | * |
5143 | * Called with interrupts off. | 5774 | * Called with interrupts off. |
5144 | */ | 5775 | */ |
5776 | #if !ENABLE_PLATFORM_MINGW32 | ||
5145 | /* | 5777 | /* |
5146 | * Clear traps on a fork. | 5778 | * Clear traps on a fork. |
5147 | */ | 5779 | */ |
@@ -5291,14 +5923,22 @@ forkchild(struct job *jp, union node *n, int mode) | |||
5291 | for (jp = curjob; jp; jp = jp->prev_job) | 5923 | for (jp = curjob; jp; jp = jp->prev_job) |
5292 | freejob(jp); | 5924 | freejob(jp); |
5293 | } | 5925 | } |
5926 | #endif | ||
5294 | 5927 | ||
5295 | /* Called after fork(), in parent */ | 5928 | /* Called after fork(), in parent */ |
5296 | #if !JOBS | 5929 | #if !JOBS && !JOBS_WIN32 |
5297 | #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) | 5930 | #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) |
5298 | #endif | 5931 | #endif |
5299 | static void | 5932 | static void |
5933 | #if !ENABLE_PLATFORM_MINGW32 | ||
5300 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 5934 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
5935 | #else | ||
5936 | forkparent(struct job *jp, union node *n, int mode, HANDLE proc) | ||
5937 | #endif | ||
5301 | { | 5938 | { |
5939 | #if ENABLE_PLATFORM_MINGW32 | ||
5940 | pid_t pid = GetProcessId(proc); | ||
5941 | #endif | ||
5302 | TRACE(("In parent shell: child = %d\n", pid)); | 5942 | TRACE(("In parent shell: child = %d\n", pid)); |
5303 | if (!jp) /* jp is NULL when called by openhere() for heredoc support */ | 5943 | if (!jp) /* jp is NULL when called by openhere() for heredoc support */ |
5304 | return; | 5944 | return; |
@@ -5317,19 +5957,29 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) | |||
5317 | if (mode == FORK_BG) { | 5957 | if (mode == FORK_BG) { |
5318 | backgndpid = pid; /* set $! */ | 5958 | backgndpid = pid; /* set $! */ |
5319 | set_curjob(jp, CUR_RUNNING); | 5959 | set_curjob(jp, CUR_RUNNING); |
5960 | #if ENABLE_PLATFORM_MINGW32 | ||
5961 | if (iflag && jp && jp->nprocs == 0) | ||
5962 | fprintf(stderr, "[%d] %"PID_FMT"d\n", jobno(jp), pid); | ||
5963 | #endif | ||
5320 | } | 5964 | } |
5321 | if (jp) { | 5965 | if (jp) { |
5322 | struct procstat *ps = &jp->ps[jp->nprocs++]; | 5966 | struct procstat *ps = &jp->ps[jp->nprocs++]; |
5323 | ps->ps_pid = pid; | 5967 | ps->ps_pid = pid; |
5324 | ps->ps_status = -1; | 5968 | ps->ps_status = -1; |
5969 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
5325 | ps->ps_cmd = nullstr; | 5970 | ps->ps_cmd = nullstr; |
5326 | #if JOBS | 5971 | #endif |
5972 | #if ENABLE_PLATFORM_MINGW32 | ||
5973 | ps->ps_proc = proc; | ||
5974 | #endif | ||
5975 | #if JOBS || JOBS_WIN32 | ||
5327 | if (doing_jobctl && n) | 5976 | if (doing_jobctl && n) |
5328 | ps->ps_cmd = commandtext(n); | 5977 | ps->ps_cmd = commandtext(n); |
5329 | #endif | 5978 | #endif |
5330 | } | 5979 | } |
5331 | } | 5980 | } |
5332 | 5981 | ||
5982 | #if !ENABLE_PLATFORM_MINGW32 | ||
5333 | /* jp and n are NULL when called by openhere() for heredoc support */ | 5983 | /* jp and n are NULL when called by openhere() for heredoc support */ |
5334 | static int | 5984 | static int |
5335 | forkshell(struct job *jp, union node *n, int mode) | 5985 | forkshell(struct job *jp, union node *n, int mode) |
@@ -5352,6 +6002,7 @@ forkshell(struct job *jp, union node *n, int mode) | |||
5352 | } | 6002 | } |
5353 | return pid; | 6003 | return pid; |
5354 | } | 6004 | } |
6005 | #endif | ||
5355 | 6006 | ||
5356 | /* | 6007 | /* |
5357 | * Wait for job to finish. | 6008 | * Wait for job to finish. |
@@ -5415,6 +6066,10 @@ waitforjob(struct job *jp) | |||
5415 | return exitstatus; | 6066 | return exitstatus; |
5416 | 6067 | ||
5417 | st = getstatus(jp); | 6068 | st = getstatus(jp); |
6069 | #if ENABLE_PLATFORM_MINGW32 | ||
6070 | if (!jp->sigint && iflag && rootshell) | ||
6071 | pending_int = 0; | ||
6072 | #endif | ||
5418 | #if JOBS | 6073 | #if JOBS |
5419 | if (jp->jobctl) { | 6074 | if (jp->jobctl) { |
5420 | xtcsetpgrp(ttyfd, rootpid); | 6075 | xtcsetpgrp(ttyfd, rootpid); |
@@ -5440,6 +6095,7 @@ waitforjob(struct job *jp) | |||
5440 | /* | 6095 | /* |
5441 | * return 1 if there are stopped jobs, otherwise 0 | 6096 | * return 1 if there are stopped jobs, otherwise 0 |
5442 | */ | 6097 | */ |
6098 | #if !ENABLE_PLATFORM_MINGW32 | ||
5443 | static int | 6099 | static int |
5444 | stoppedjobs(void) | 6100 | stoppedjobs(void) |
5445 | { | 6101 | { |
@@ -5458,6 +6114,17 @@ stoppedjobs(void) | |||
5458 | out: | 6114 | out: |
5459 | return retval; | 6115 | return retval; |
5460 | } | 6116 | } |
6117 | #else | ||
6118 | static int | ||
6119 | stoppedjobs(void) | ||
6120 | { | ||
6121 | if (iflag && curjob) { | ||
6122 | out2str("You have background jobs.\n"); | ||
6123 | return 1; | ||
6124 | } | ||
6125 | return 0; | ||
6126 | } | ||
6127 | #endif | ||
5461 | 6128 | ||
5462 | 6129 | ||
5463 | /* | 6130 | /* |
@@ -5482,6 +6149,7 @@ openhere(union node *redir) | |||
5482 | char *p; | 6149 | char *p; |
5483 | int pip[2]; | 6150 | int pip[2]; |
5484 | size_t len = 0; | 6151 | size_t len = 0; |
6152 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5485 | 6153 | ||
5486 | if (pipe(pip) < 0) | 6154 | if (pipe(pip) < 0) |
5487 | ash_msg_and_raise_perror("can't create pipe"); | 6155 | ash_msg_and_raise_perror("can't create pipe"); |
@@ -5498,6 +6166,14 @@ openhere(union node *redir) | |||
5498 | goto out; | 6166 | goto out; |
5499 | } | 6167 | } |
5500 | 6168 | ||
6169 | #if ENABLE_PLATFORM_MINGW32 | ||
6170 | memset(&fs, 0, sizeof(fs)); | ||
6171 | fs.fpid = FS_OPENHERE; | ||
6172 | fs.fd[0] = pip[0]; | ||
6173 | fs.fd[1] = pip[1]; | ||
6174 | fs.path = p; | ||
6175 | spawn_forkshell(&fs, NULL, NULL, FORK_NOJOB); | ||
6176 | #else | ||
5501 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | 6177 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { |
5502 | /* child */ | 6178 | /* child */ |
5503 | close(pip[0]); | 6179 | close(pip[0]); |
@@ -5509,6 +6185,7 @@ openhere(union node *redir) | |||
5509 | xwrite(pip[1], p, len); | 6185 | xwrite(pip[1], p, len); |
5510 | _exit_SUCCESS(); | 6186 | _exit_SUCCESS(); |
5511 | } | 6187 | } |
6188 | #endif | ||
5512 | out: | 6189 | out: |
5513 | close(pip[1]); | 6190 | close(pip[1]); |
5514 | return pip[0]; | 6191 | return pip[0]; |
@@ -5586,6 +6263,9 @@ openredirect(union node *redir) | |||
5586 | f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); | 6263 | f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); |
5587 | if (f < 0) | 6264 | if (f < 0) |
5588 | goto ecreate; | 6265 | goto ecreate; |
6266 | #if ENABLE_PLATFORM_MINGW32 | ||
6267 | lseek(f, 0, SEEK_END); | ||
6268 | #endif | ||
5589 | break; | 6269 | break; |
5590 | } | 6270 | } |
5591 | 6271 | ||
@@ -6137,6 +6817,9 @@ ifsbreakup(char *string, struct arglist *arglist) | |||
6137 | const char *ifs, *realifs; | 6817 | const char *ifs, *realifs; |
6138 | int ifsspc; | 6818 | int ifsspc; |
6139 | int nulonly; | 6819 | int nulonly; |
6820 | #if ENABLE_PLATFORM_MINGW32 | ||
6821 | int lshift = 0; | ||
6822 | #endif | ||
6140 | 6823 | ||
6141 | start = string; | 6824 | start = string; |
6142 | if (ifslastp != NULL) { | 6825 | if (ifslastp != NULL) { |
@@ -6147,7 +6830,33 @@ ifsbreakup(char *string, struct arglist *arglist) | |||
6147 | do { | 6830 | do { |
6148 | int afternul; | 6831 | int afternul; |
6149 | 6832 | ||
6833 | #if ENABLE_PLATFORM_MINGW32 | ||
6834 | /* Adjust region offsets for left-shifted string. */ | ||
6835 | ifsp->begoff -= lshift; | ||
6836 | ifsp->endoff -= lshift; | ||
6837 | #endif | ||
6150 | p = string + ifsp->begoff; | 6838 | p = string + ifsp->begoff; |
6839 | #if ENABLE_PLATFORM_MINGW32 | ||
6840 | if (ifsp->endoff > ifsp->begoff + 1) { | ||
6841 | /* Transform CRLF to LF. Skip regions having zero or | ||
6842 | * one characters: they can't contain CRLF. If the | ||
6843 | * region shrinks shift the rest of the string left. */ | ||
6844 | int oldlen = ifsp->endoff - ifsp->begoff; | ||
6845 | int newlen = remove_cr(p, oldlen); | ||
6846 | int delta = oldlen - newlen; | ||
6847 | |||
6848 | if (delta > 0) { | ||
6849 | char *t = string + ifsp->endoff; | ||
6850 | char *s = string + ifsp->endoff - delta; | ||
6851 | |||
6852 | while (*t) | ||
6853 | *s++ = *t++; | ||
6854 | *s = '\0'; | ||
6855 | lshift += delta; | ||
6856 | ifsp->endoff -= delta; | ||
6857 | } | ||
6858 | } | ||
6859 | #endif | ||
6151 | afternul = nulonly; | 6860 | afternul = nulonly; |
6152 | nulonly = ifsp->nulonly; | 6861 | nulonly = ifsp->nulonly; |
6153 | ifs = nulonly ? nullstr : realifs; | 6862 | ifs = nulonly ? nullstr : realifs; |
@@ -6592,6 +7301,7 @@ evalbackcmd(union node *n, struct backcmd *result | |||
6592 | const int ip = 0; | 7301 | const int ip = 0; |
6593 | const int ic = 1; | 7302 | const int ic = 1; |
6594 | #endif | 7303 | #endif |
7304 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
6595 | 7305 | ||
6596 | result->fd = -1; | 7306 | result->fd = -1; |
6597 | result->buf = NULL; | 7307 | result->buf = NULL; |
@@ -6605,6 +7315,15 @@ evalbackcmd(union node *n, struct backcmd *result | |||
6605 | ash_msg_and_raise_perror("can't create pipe"); | 7315 | ash_msg_and_raise_perror("can't create pipe"); |
6606 | /* process substitution uses NULL job, like openhere() */ | 7316 | /* process substitution uses NULL job, like openhere() */ |
6607 | jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL; | 7317 | jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL; |
7318 | #if ENABLE_PLATFORM_MINGW32 | ||
7319 | memset(&fs, 0, sizeof(fs)); | ||
7320 | fs.fpid = FS_EVALBACKCMD; | ||
7321 | fs.n = n; | ||
7322 | fs.fd[0] = pip[0]; | ||
7323 | fs.fd[1] = pip[1]; | ||
7324 | fs.fd[2] = ctl; | ||
7325 | spawn_forkshell(&fs, jp, n, FORK_NOJOB); | ||
7326 | #else | ||
6608 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 7327 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
6609 | /* child */ | 7328 | /* child */ |
6610 | FORCE_INT_ON; | 7329 | FORCE_INT_ON; |
@@ -6628,6 +7347,7 @@ evalbackcmd(union node *n, struct backcmd *result | |||
6628 | evaltreenr(n, EV_EXIT); | 7347 | evaltreenr(n, EV_EXIT); |
6629 | /* NOTREACHED */ | 7348 | /* NOTREACHED */ |
6630 | } | 7349 | } |
7350 | #endif | ||
6631 | /* parent */ | 7351 | /* parent */ |
6632 | #if BASH_PROCESS_SUBST | 7352 | #if BASH_PROCESS_SUBST |
6633 | if (ctl != CTLBACKQ) { | 7353 | if (ctl != CTLBACKQ) { |
@@ -6706,8 +7426,14 @@ expbackq(union node *cmd, int flag IF_BASH_PROCESS_SUBST(, int ctl)) | |||
6706 | 7426 | ||
6707 | /* Eat all trailing newlines */ | 7427 | /* Eat all trailing newlines */ |
6708 | dest = expdest; | 7428 | dest = expdest; |
6709 | for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';) | 7429 | for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';) { |
6710 | STUNPUTC(dest); | 7430 | STUNPUTC(dest); |
7431 | #if ENABLE_PLATFORM_MINGW32 | ||
7432 | if (dest > ((char *)stackblock() + startloc) && dest[-1] == '\r') { | ||
7433 | STUNPUTC(dest); | ||
7434 | } | ||
7435 | #endif | ||
7436 | } | ||
6711 | expdest = dest; | 7437 | expdest = dest; |
6712 | 7438 | ||
6713 | if (!(flag & EXP_QUOTED)) | 7439 | if (!(flag & EXP_QUOTED)) |
@@ -7876,6 +8602,10 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
7876 | 8602 | ||
7877 | metaflag = 0; | 8603 | metaflag = 0; |
7878 | start = name; | 8604 | start = name; |
8605 | #if ENABLE_PLATFORM_MINGW32 | ||
8606 | if (expdir_len == 0 && has_dos_drive_prefix(start) && start[2] != '/') | ||
8607 | start += 2; | ||
8608 | #endif | ||
7879 | for (p = name; esc = 0, *p; p += esc + 1) { | 8609 | for (p = name; esc = 0, *p; p += esc + 1) { |
7880 | if (*p == '*' || *p == '?') | 8610 | if (*p == '*' || *p == '?') |
7881 | metaflag = 1; | 8611 | metaflag = 1; |
@@ -7950,6 +8680,10 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
7950 | while (!pending_int && (dp = readdir(dirp)) != NULL) { | 8680 | while (!pending_int && (dp = readdir(dirp)) != NULL) { |
7951 | if (dp->d_name[0] == '.' && !matchdot) | 8681 | if (dp->d_name[0] == '.' && !matchdot) |
7952 | continue; | 8682 | continue; |
8683 | #if ENABLE_ASH_NOCASEGLOB | ||
8684 | # undef pmatch | ||
8685 | # define pmatch(a, b) !fnmatch((a), (b), nocaseglob ? FNM_CASEFOLD : 0) | ||
8686 | #endif | ||
7953 | if (pmatch(start, dp->d_name)) { | 8687 | if (pmatch(start, dp->d_name)) { |
7954 | if (atend) { | 8688 | if (atend) { |
7955 | strcpy(enddir, dp->d_name); | 8689 | strcpy(enddir, dp->d_name); |
@@ -7979,6 +8713,10 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
7979 | endname[-esc - 1] = esc ? '\\' : '/'; | 8713 | endname[-esc - 1] = esc ? '\\' : '/'; |
7980 | #undef expdir | 8714 | #undef expdir |
7981 | #undef expdir_max | 8715 | #undef expdir_max |
8716 | #if ENABLE_ASH_NOCASEGLOB | ||
8717 | # undef pmatch | ||
8718 | # define pmatch(a, b) !fnmatch((a), (b), 0) | ||
8719 | #endif | ||
7982 | } | 8720 | } |
7983 | 8721 | ||
7984 | static struct strlist * | 8722 | static struct strlist * |
@@ -8255,10 +8993,34 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
8255 | { | 8993 | { |
8256 | #if ENABLE_FEATURE_SH_STANDALONE | 8994 | #if ENABLE_FEATURE_SH_STANDALONE |
8257 | if (applet_no >= 0) { | 8995 | if (applet_no >= 0) { |
8996 | # if ENABLE_PLATFORM_MINGW32 | ||
8997 | /* Treat all applets as NOEXEC, including the shell itself if | ||
8998 | * this is a FS_SHELLEXEC shell. */ | ||
8999 | struct forkshell *fs = (struct forkshell *)sticky_mem_start; | ||
9000 | if (applet_main[applet_no] != ash_main || | ||
9001 | (fs && fs->fpid == FS_SHELLEXEC)) { | ||
9002 | /* mingw-w64's getopt() uses __argv[0] as the program name */ | ||
9003 | __argv[0] = (char *)cmd; | ||
9004 | /* 'which' wants to know if it was invoked from a standalone | ||
9005 | * shell. Use the spare element of argv to add a flag, but | ||
9006 | * not if the first argument is '--help', that's a special | ||
9007 | * case. */ | ||
9008 | if (strcmp(argv[0], "which") == 0 && | ||
9009 | (argv[1] == NULL || strcmp(argv[1], "--help") != 0)) { | ||
9010 | --argv; | ||
9011 | argv[0] = argv[1]; | ||
9012 | argv[1] = (char *)"-s"; | ||
9013 | } | ||
9014 | # else | ||
8258 | if (APPLET_IS_NOEXEC(applet_no)) { | 9015 | if (APPLET_IS_NOEXEC(applet_no)) { |
9016 | # endif | ||
9017 | #if ENABLE_PLATFORM_MINGW32 && !defined(_UCRT) | ||
9018 | /* If building for UCRT move this up into shellexec() to | ||
9019 | * work around a bug. */ | ||
8259 | clearenv(); | 9020 | clearenv(); |
8260 | while (*envp) | 9021 | while (*envp) |
8261 | putenv(*envp++); | 9022 | putenv(*envp++); |
9023 | #endif | ||
8262 | popredir(/*drop:*/ 1); | 9024 | popredir(/*drop:*/ 1); |
8263 | run_noexec_applet_and_exit(applet_no, cmd, argv); | 9025 | run_noexec_applet_and_exit(applet_no, cmd, argv); |
8264 | } | 9026 | } |
@@ -8269,6 +9031,12 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
8269 | } | 9031 | } |
8270 | #endif | 9032 | #endif |
8271 | 9033 | ||
9034 | #if ENABLE_PLATFORM_MINGW32 | ||
9035 | /* cmd was allocated on the stack with room for an extension */ | ||
9036 | add_win32_extension((char *)cmd); | ||
9037 | execve(cmd, argv, envp); | ||
9038 | /* skip POSIX-mandated retry on ENOEXEC */ | ||
9039 | #else /* !ENABLE_PLATFORM_MINGW32 */ | ||
8272 | repeat: | 9040 | repeat: |
8273 | #ifdef SYSV | 9041 | #ifdef SYSV |
8274 | do { | 9042 | do { |
@@ -8304,6 +9072,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
8304 | argv[0] = (char*) "ash"; | 9072 | argv[0] = (char*) "ash"; |
8305 | goto repeat; | 9073 | goto repeat; |
8306 | } | 9074 | } |
9075 | #endif /* !ENABLE_PLATFORM_MINGW32 */ | ||
8307 | } | 9076 | } |
8308 | 9077 | ||
8309 | /* | 9078 | /* |
@@ -8311,6 +9080,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
8311 | * have to change the find_command routine as well. | 9080 | * have to change the find_command routine as well. |
8312 | * argv[-1] must exist and be writable! See tryexec() for why. | 9081 | * argv[-1] must exist and be writable! See tryexec() for why. |
8313 | */ | 9082 | */ |
9083 | static struct builtincmd *find_builtin(const char *name); | ||
8314 | static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN; | 9084 | static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN; |
8315 | static void shellexec(char *prog, char **argv, const char *path, int idx) | 9085 | static void shellexec(char *prog, char **argv, const char *path, int idx) |
8316 | { | 9086 | { |
@@ -8321,12 +9091,29 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
8321 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ | 9091 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ |
8322 | 9092 | ||
8323 | envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); | 9093 | envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); |
9094 | #if ENABLE_PLATFORM_MINGW32 && defined(_UCRT) | ||
9095 | /* Avoid UCRT bug by updating parent's environment and passing a | ||
9096 | * NULL environment pointer to execve(). */ | ||
9097 | clearenv(); | ||
9098 | while (*envp) | ||
9099 | putenv(*envp++); | ||
9100 | envp = NULL; | ||
9101 | #endif | ||
9102 | #if !ENABLE_PLATFORM_MINGW32 | ||
8324 | if (strchr(prog, '/') != NULL | 9103 | if (strchr(prog, '/') != NULL |
9104 | #else | ||
9105 | if (has_path(prog) | ||
9106 | #endif | ||
8325 | #if ENABLE_FEATURE_SH_STANDALONE | 9107 | #if ENABLE_FEATURE_SH_STANDALONE |
8326 | || (applet_no = find_applet_by_name(prog)) >= 0 | 9108 | || (applet_no = find_applet_by_name(prog)) >= 0 |
8327 | #endif | 9109 | #endif |
8328 | ) { | 9110 | ) { |
9111 | #if ENABLE_PLATFORM_MINGW32 | ||
9112 | char *progext = stack_add_ext_space(prog); | ||
9113 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) progext, argv, envp); | ||
9114 | #else | ||
8329 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); | 9115 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); |
9116 | #endif | ||
8330 | if (applet_no >= 0) { | 9117 | if (applet_no >= 0) { |
8331 | /* We tried execing ourself, but it didn't work. | 9118 | /* We tried execing ourself, but it didn't work. |
8332 | * Maybe /proc/self/exe doesn't exist? | 9119 | * Maybe /proc/self/exe doesn't exist? |
@@ -8335,6 +9122,21 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
8335 | goto try_PATH; | 9122 | goto try_PATH; |
8336 | } | 9123 | } |
8337 | e = errno; | 9124 | e = errno; |
9125 | #if ENABLE_PLATFORM_MINGW32 | ||
9126 | if (unix_path(prog)) { | ||
9127 | const char *name = bb_basename(prog); | ||
9128 | # if ENABLE_FEATURE_SH_STANDALONE | ||
9129 | if ((applet_no = find_applet_by_name(name)) >= 0) { | ||
9130 | tryexec(applet_no, name, argv, envp); | ||
9131 | e = errno; | ||
9132 | } | ||
9133 | # endif | ||
9134 | if (!find_builtin(name)) { | ||
9135 | argv[0] = (char *)name; | ||
9136 | goto try_PATH; | ||
9137 | } | ||
9138 | } | ||
9139 | #endif | ||
8338 | } else { | 9140 | } else { |
8339 | try_PATH: | 9141 | try_PATH: |
8340 | e = ENOENT; | 9142 | e = ENOENT; |
@@ -8380,6 +9182,9 @@ printentry(struct tblentry *cmdp) | |||
8380 | padvance(&path, cmdp->cmdname); | 9182 | padvance(&path, cmdp->cmdname); |
8381 | } while (--idx >= 0); | 9183 | } while (--idx >= 0); |
8382 | name = stackblock(); | 9184 | name = stackblock(); |
9185 | #if ENABLE_PLATFORM_MINGW32 | ||
9186 | add_win32_extension(name); | ||
9187 | #endif | ||
8383 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); | 9188 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); |
8384 | } | 9189 | } |
8385 | 9190 | ||
@@ -8580,7 +9385,7 @@ changepath(const char *newval) | |||
8580 | bltin = idx; | 9385 | bltin = idx; |
8581 | break; | 9386 | break; |
8582 | } | 9387 | } |
8583 | new = strchr(new, ':'); | 9388 | new = strchr(new, PATH_SEP); |
8584 | if (!new) | 9389 | if (!new) |
8585 | break; | 9390 | break; |
8586 | idx++; | 9391 | idx++; |
@@ -8757,14 +9562,37 @@ describe_command(char *command, const char *path, int describe_command_verbose) | |||
8757 | case CMDNORMAL: { | 9562 | case CMDNORMAL: { |
8758 | int j = entry.u.index; | 9563 | int j = entry.u.index; |
8759 | char *p; | 9564 | char *p; |
9565 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
9566 | if (j < -1) { | ||
9567 | p = (char *)bb_basename(command); | ||
9568 | if (describe_command_verbose) { | ||
9569 | out1fmt(" is a builtin applet"); | ||
9570 | } else { | ||
9571 | out1str(applet_to_exe(p)); | ||
9572 | } | ||
9573 | break; | ||
9574 | } | ||
9575 | #endif | ||
8760 | if (j < 0) { | 9576 | if (j < 0) { |
9577 | #if ENABLE_PLATFORM_MINGW32 | ||
9578 | p = stack_add_ext_space(command); | ||
9579 | #else | ||
8761 | p = command; | 9580 | p = command; |
9581 | #endif | ||
8762 | } else { | 9582 | } else { |
9583 | #if ENABLE_PLATFORM_MINGW32 | ||
9584 | if (unix_path(command)) | ||
9585 | command = (char *)bb_basename(command); | ||
9586 | #endif | ||
8763 | do { | 9587 | do { |
8764 | padvance(&path, command); | 9588 | padvance(&path, command); |
8765 | } while (--j >= 0); | 9589 | } while (--j >= 0); |
8766 | p = stackblock(); | 9590 | p = stackblock(); |
8767 | } | 9591 | } |
9592 | #if ENABLE_PLATFORM_MINGW32 | ||
9593 | add_win32_extension(p); | ||
9594 | bs_to_slash(p); | ||
9595 | #endif | ||
8768 | if (describe_command_verbose) { | 9596 | if (describe_command_verbose) { |
8769 | out1fmt(" is %s", p); | 9597 | out1fmt(" is %s", p); |
8770 | } else { | 9598 | } else { |
@@ -8920,6 +9748,13 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
8920 | /*static int funcstringsize; // size of strings in node */ | 9748 | /*static int funcstringsize; // size of strings in node */ |
8921 | static void *funcblock; /* block to allocate function from */ | 9749 | static void *funcblock; /* block to allocate function from */ |
8922 | static char *funcstring_end; /* end of block to allocate strings from */ | 9750 | static char *funcstring_end; /* end of block to allocate strings from */ |
9751 | #if ENABLE_PLATFORM_MINGW32 | ||
9752 | static int fs_size; | ||
9753 | # if FORKSHELL_DEBUG | ||
9754 | static void *fs_start; | ||
9755 | static const char **annot; | ||
9756 | # endif | ||
9757 | #endif | ||
8923 | 9758 | ||
8924 | static const uint8_t nodesize[N_NUMBER] ALIGN1 = { | 9759 | static const uint8_t nodesize[N_NUMBER] ALIGN1 = { |
8925 | [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), | 9760 | [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), |
@@ -9052,14 +9887,60 @@ calcsize(int funcblocksize, union node *n) | |||
9052 | } | 9887 | } |
9053 | 9888 | ||
9054 | static char * | 9889 | static char * |
9055 | nodeckstrdup(char *s) | 9890 | nodeckstrdup(const char *s) |
9056 | { | 9891 | { |
9892 | #if ENABLE_PLATFORM_MINGW32 | ||
9893 | if(!s) | ||
9894 | return NULL; | ||
9895 | #endif | ||
9057 | funcstring_end -= SHELL_ALIGN(strlen(s) + 1); | 9896 | funcstring_end -= SHELL_ALIGN(strlen(s) + 1); |
9058 | return strcpy(funcstring_end, s); | 9897 | return strcpy(funcstring_end, s); |
9059 | } | 9898 | } |
9060 | 9899 | ||
9061 | static union node *copynode(union node *); | 9900 | static union node *copynode(union node *); |
9062 | 9901 | ||
9902 | #if ENABLE_PLATFORM_MINGW32 | ||
9903 | # if FORKSHELL_DEBUG | ||
9904 | # define FREE 1 | ||
9905 | # define NO_FREE 2 | ||
9906 | # define ANNOT(dst,note) { \ | ||
9907 | if (annot) \ | ||
9908 | annot[(char *)&dst - (char *)fs_start] = note; \ | ||
9909 | } | ||
9910 | # else | ||
9911 | # define FREE 1 | ||
9912 | # define NO_FREE 1 | ||
9913 | # define ANNOT(dst,note) | ||
9914 | # endif | ||
9915 | |||
9916 | /* The relocation map is offset from the start of the forkshell data | ||
9917 | * block by 'fs_size' bytes. The flag relating to a particular destination | ||
9918 | * pointer is thus at (dst+fs_size). */ | ||
9919 | # define MARK_PTR(dst,flag) {*((char *)&dst + fs_size) = flag;} | ||
9920 | |||
9921 | # define SAVE_PTR(dst,note,flag) { \ | ||
9922 | if (fs_size) { \ | ||
9923 | MARK_PTR(dst,flag); ANNOT(dst,note); \ | ||
9924 | } \ | ||
9925 | } | ||
9926 | # define SAVE_PTR2(dst1,note1,flag1,dst2,note2,flag2) { \ | ||
9927 | if (fs_size) { \ | ||
9928 | MARK_PTR(dst1,flag1); MARK_PTR(dst2,flag2); \ | ||
9929 | ANNOT(dst1,note1); ANNOT(dst2,note2); \ | ||
9930 | } \ | ||
9931 | } | ||
9932 | # define SAVE_PTR3(dst1,note1,flag1,dst2,note2,flag2,dst3,note3,flag3) { \ | ||
9933 | if (fs_size) { \ | ||
9934 | MARK_PTR(dst1,flag1); MARK_PTR(dst2,flag2); MARK_PTR(dst3,flag3); \ | ||
9935 | ANNOT(dst1,note1); ANNOT(dst2,note2); ANNOT(dst3,note3); \ | ||
9936 | } \ | ||
9937 | } | ||
9938 | #else | ||
9939 | # define SAVE_PTR(dst,note,flag) | ||
9940 | # define SAVE_PTR2(dst1,note1,flag1,dst2,note2,flag2) | ||
9941 | # define SAVE_PTR3(dst1,note1,flag1,dst2,note2,flag2,dst3,note3,flag3) | ||
9942 | #endif | ||
9943 | |||
9063 | static struct nodelist * | 9944 | static struct nodelist * |
9064 | copynodelist(struct nodelist *lp) | 9945 | copynodelist(struct nodelist *lp) |
9065 | { | 9946 | { |
@@ -9071,6 +9952,8 @@ copynodelist(struct nodelist *lp) | |||
9071 | *lpp = funcblock; | 9952 | *lpp = funcblock; |
9072 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); | 9953 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); |
9073 | (*lpp)->n = copynode(lp->n); | 9954 | (*lpp)->n = copynode(lp->n); |
9955 | SAVE_PTR2((*lpp)->n, "(*lpp)->next", NO_FREE, | ||
9956 | (*lpp)->next, "(*lpp)->next", NO_FREE); | ||
9074 | lp = lp->next; | 9957 | lp = lp->next; |
9075 | lpp = &(*lpp)->next; | 9958 | lpp = &(*lpp)->next; |
9076 | } | 9959 | } |
@@ -9094,10 +9977,14 @@ copynode(union node *n) | |||
9094 | new->ncmd.args = copynode(n->ncmd.args); | 9977 | new->ncmd.args = copynode(n->ncmd.args); |
9095 | new->ncmd.assign = copynode(n->ncmd.assign); | 9978 | new->ncmd.assign = copynode(n->ncmd.assign); |
9096 | new->ncmd.linno = n->ncmd.linno; | 9979 | new->ncmd.linno = n->ncmd.linno; |
9980 | SAVE_PTR3(new->ncmd.redirect, "ncmd.redirect", NO_FREE, | ||
9981 | new->ncmd.args, "ncmd.args", NO_FREE, | ||
9982 | new->ncmd.assign, "ncmd.assign", NO_FREE); | ||
9097 | break; | 9983 | break; |
9098 | case NPIPE: | 9984 | case NPIPE: |
9099 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | 9985 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); |
9100 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; | 9986 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; |
9987 | SAVE_PTR(new->npipe.cmdlist, "npipe.cmdlist", NO_FREE); | ||
9101 | break; | 9988 | break; |
9102 | case NREDIR: | 9989 | case NREDIR: |
9103 | case NBACKGND: | 9990 | case NBACKGND: |
@@ -9105,6 +9992,8 @@ copynode(union node *n) | |||
9105 | new->nredir.redirect = copynode(n->nredir.redirect); | 9992 | new->nredir.redirect = copynode(n->nredir.redirect); |
9106 | new->nredir.n = copynode(n->nredir.n); | 9993 | new->nredir.n = copynode(n->nredir.n); |
9107 | new->nredir.linno = n->nredir.linno; | 9994 | new->nredir.linno = n->nredir.linno; |
9995 | SAVE_PTR2(new->nredir.redirect, "nredir.redirect", NO_FREE, | ||
9996 | new->nredir.n, "nredir.n", NO_FREE); | ||
9108 | break; | 9997 | break; |
9109 | case NAND: | 9998 | case NAND: |
9110 | case NOR: | 9999 | case NOR: |
@@ -9113,37 +10002,58 @@ copynode(union node *n) | |||
9113 | case NUNTIL: | 10002 | case NUNTIL: |
9114 | new->nbinary.ch2 = copynode(n->nbinary.ch2); | 10003 | new->nbinary.ch2 = copynode(n->nbinary.ch2); |
9115 | new->nbinary.ch1 = copynode(n->nbinary.ch1); | 10004 | new->nbinary.ch1 = copynode(n->nbinary.ch1); |
10005 | SAVE_PTR2(new->nbinary.ch1, "nbinary.ch1", NO_FREE, | ||
10006 | new->nbinary.ch2, "nbinary.ch2", NO_FREE); | ||
9116 | break; | 10007 | break; |
9117 | case NIF: | 10008 | case NIF: |
9118 | new->nif.elsepart = copynode(n->nif.elsepart); | 10009 | new->nif.elsepart = copynode(n->nif.elsepart); |
9119 | new->nif.ifpart = copynode(n->nif.ifpart); | 10010 | new->nif.ifpart = copynode(n->nif.ifpart); |
9120 | new->nif.test = copynode(n->nif.test); | 10011 | new->nif.test = copynode(n->nif.test); |
10012 | SAVE_PTR3(new->nif.elsepart, "nif.elsepart", NO_FREE, | ||
10013 | new->nif.ifpart, "nif.ifpart", NO_FREE, | ||
10014 | new->nif.test, "nif.test", NO_FREE); | ||
9121 | break; | 10015 | break; |
9122 | case NFOR: | 10016 | case NFOR: |
9123 | new->nfor.var = nodeckstrdup(n->nfor.var); | 10017 | new->nfor.var = nodeckstrdup(n->nfor.var); |
9124 | new->nfor.body = copynode(n->nfor.body); | 10018 | new->nfor.body = copynode(n->nfor.body); |
9125 | new->nfor.args = copynode(n->nfor.args); | 10019 | new->nfor.args = copynode(n->nfor.args); |
9126 | new->nfor.linno = n->nfor.linno; | 10020 | new->nfor.linno = n->nfor.linno; |
10021 | SAVE_PTR3(new->nfor.var, | ||
10022 | xasprintf("nfor.var '%s'", n->nfor.var ?: "NULL"), FREE, | ||
10023 | new->nfor.body, "nfor.body", NO_FREE, | ||
10024 | new->nfor.args, "nfor.args", NO_FREE); | ||
9127 | break; | 10025 | break; |
9128 | case NCASE: | 10026 | case NCASE: |
9129 | new->ncase.cases = copynode(n->ncase.cases); | 10027 | new->ncase.cases = copynode(n->ncase.cases); |
9130 | new->ncase.expr = copynode(n->ncase.expr); | 10028 | new->ncase.expr = copynode(n->ncase.expr); |
9131 | new->ncase.linno = n->ncase.linno; | 10029 | new->ncase.linno = n->ncase.linno; |
10030 | SAVE_PTR2(new->ncase.cases, "ncase.cases", NO_FREE, | ||
10031 | new->ncase.expr, "ncase.expr", NO_FREE); | ||
9132 | break; | 10032 | break; |
9133 | case NCLIST: | 10033 | case NCLIST: |
9134 | new->nclist.body = copynode(n->nclist.body); | 10034 | new->nclist.body = copynode(n->nclist.body); |
9135 | new->nclist.pattern = copynode(n->nclist.pattern); | 10035 | new->nclist.pattern = copynode(n->nclist.pattern); |
9136 | new->nclist.next = copynode(n->nclist.next); | 10036 | new->nclist.next = copynode(n->nclist.next); |
10037 | SAVE_PTR3(new->nclist.body, "nclist.body", NO_FREE, | ||
10038 | new->nclist.pattern, "nclist.pattern", NO_FREE, | ||
10039 | new->nclist.next, "nclist.next", NO_FREE); | ||
9137 | break; | 10040 | break; |
9138 | case NDEFUN: | 10041 | case NDEFUN: |
9139 | new->ndefun.body = copynode(n->ndefun.body); | 10042 | new->ndefun.body = copynode(n->ndefun.body); |
9140 | new->ndefun.text = nodeckstrdup(n->ndefun.text); | 10043 | new->ndefun.text = nodeckstrdup(n->ndefun.text); |
9141 | new->ndefun.linno = n->ndefun.linno; | 10044 | new->ndefun.linno = n->ndefun.linno; |
10045 | SAVE_PTR2(new->ndefun.body, "ndefun.body", NO_FREE, | ||
10046 | new->ndefun.text, | ||
10047 | xasprintf("ndefun.text '%s'", n->ndefun.text ?: "NULL"), FREE); | ||
9142 | break; | 10048 | break; |
9143 | case NARG: | 10049 | case NARG: |
9144 | new->narg.backquote = copynodelist(n->narg.backquote); | 10050 | new->narg.backquote = copynodelist(n->narg.backquote); |
9145 | new->narg.text = nodeckstrdup(n->narg.text); | 10051 | new->narg.text = nodeckstrdup(n->narg.text); |
9146 | new->narg.next = copynode(n->narg.next); | 10052 | new->narg.next = copynode(n->narg.next); |
10053 | SAVE_PTR3(new->narg.backquote, "narg.backquote", NO_FREE, | ||
10054 | new->narg.text, | ||
10055 | xasprintf("narg.text '%s'", n->narg.text ?: "NULL"), FREE, | ||
10056 | new->narg.next, "narg.next", NO_FREE); | ||
9147 | break; | 10057 | break; |
9148 | case NTO: | 10058 | case NTO: |
9149 | #if BASH_REDIR_OUTPUT | 10059 | #if BASH_REDIR_OUTPUT |
@@ -9156,6 +10066,8 @@ copynode(union node *n) | |||
9156 | new->nfile.fname = copynode(n->nfile.fname); | 10066 | new->nfile.fname = copynode(n->nfile.fname); |
9157 | new->nfile.fd = n->nfile.fd; | 10067 | new->nfile.fd = n->nfile.fd; |
9158 | new->nfile.next = copynode(n->nfile.next); | 10068 | new->nfile.next = copynode(n->nfile.next); |
10069 | SAVE_PTR2(new->nfile.fname, "nfile.fname", NO_FREE, | ||
10070 | new->nfile.next, "nfile.next", NO_FREE); | ||
9159 | break; | 10071 | break; |
9160 | case NTOFD: | 10072 | case NTOFD: |
9161 | case NFROMFD: | 10073 | case NFROMFD: |
@@ -9163,15 +10075,20 @@ copynode(union node *n) | |||
9163 | new->ndup.dupfd = n->ndup.dupfd; | 10075 | new->ndup.dupfd = n->ndup.dupfd; |
9164 | new->ndup.fd = n->ndup.fd; | 10076 | new->ndup.fd = n->ndup.fd; |
9165 | new->ndup.next = copynode(n->ndup.next); | 10077 | new->ndup.next = copynode(n->ndup.next); |
10078 | SAVE_PTR2(new->ndup.vname, "ndup.vname", NO_FREE, | ||
10079 | new->ndup.next, "ndup.next", NO_FREE); | ||
9166 | break; | 10080 | break; |
9167 | case NHERE: | 10081 | case NHERE: |
9168 | case NXHERE: | 10082 | case NXHERE: |
9169 | new->nhere.doc = copynode(n->nhere.doc); | 10083 | new->nhere.doc = copynode(n->nhere.doc); |
9170 | new->nhere.fd = n->nhere.fd; | 10084 | new->nhere.fd = n->nhere.fd; |
9171 | new->nhere.next = copynode(n->nhere.next); | 10085 | new->nhere.next = copynode(n->nhere.next); |
10086 | SAVE_PTR2(new->nhere.doc, "nhere.doc", NO_FREE, | ||
10087 | new->nhere.next, "nhere.next", NO_FREE); | ||
9172 | break; | 10088 | break; |
9173 | case NNOT: | 10089 | case NNOT: |
9174 | new->nnot.com = copynode(n->nnot.com); | 10090 | new->nnot.com = copynode(n->nnot.com); |
10091 | SAVE_PTR(new->nnot.com, "nnot.com", NO_FREE); | ||
9175 | break; | 10092 | break; |
9176 | }; | 10093 | }; |
9177 | new->type = n->type; | 10094 | new->type = n->type; |
@@ -9192,6 +10109,7 @@ copyfunc(union node *n) | |||
9192 | f = ckzalloc(blocksize /* + funcstringsize */); | 10109 | f = ckzalloc(blocksize /* + funcstringsize */); |
9193 | funcblock = (char *) f + offsetof(struct funcnode, n); | 10110 | funcblock = (char *) f + offsetof(struct funcnode, n); |
9194 | funcstring_end = (char *) f + blocksize; | 10111 | funcstring_end = (char *) f + blocksize; |
10112 | IF_PLATFORM_MINGW32(fs_size = 0); | ||
9195 | copynode(n); | 10113 | copynode(n); |
9196 | /* f->count = 0; - ckzalloc did it */ | 10114 | /* f->count = 0; - ckzalloc did it */ |
9197 | return f; | 10115 | return f; |
@@ -9219,12 +10137,15 @@ defun(union node *func) | |||
9219 | #define SKIPFUNCDEF (1 << 3) | 10137 | #define SKIPFUNCDEF (1 << 3) |
9220 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ | 10138 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ |
9221 | static int skipcount; /* number of levels to skip */ | 10139 | static int skipcount; /* number of levels to skip */ |
10140 | #if ENABLE_PLATFORM_POSIX | ||
9222 | static int loopnest; /* current loop nesting level */ | 10141 | static int loopnest; /* current loop nesting level */ |
10142 | #endif | ||
9223 | static int funcline; /* starting line number of current function, or 0 if not in a function */ | 10143 | static int funcline; /* starting line number of current function, or 0 if not in a function */ |
9224 | 10144 | ||
9225 | /* Forward decl way out to parsing code - dotrap needs it */ | 10145 | /* Forward decl way out to parsing code - dotrap needs it */ |
9226 | static int evalstring(char *s, int flags); | 10146 | static int evalstring(char *s, int flags); |
9227 | 10147 | ||
10148 | #if !ENABLE_PLATFORM_MINGW32 | ||
9228 | /* Called to execute a trap. | 10149 | /* Called to execute a trap. |
9229 | * Single callsite - at the end of evaltree(). | 10150 | * Single callsite - at the end of evaltree(). |
9230 | * If we return non-zero, evaltree raises EXEXIT exception. | 10151 | * If we return non-zero, evaltree raises EXEXIT exception. |
@@ -9283,6 +10204,45 @@ dotrap(void) | |||
9283 | savestatus = last_status; | 10204 | savestatus = last_status; |
9284 | TRACE(("dotrap returns\n")); | 10205 | TRACE(("dotrap returns\n")); |
9285 | } | 10206 | } |
10207 | #else | ||
10208 | static void | ||
10209 | dotrap(void) | ||
10210 | { | ||
10211 | int status, last_status; | ||
10212 | char *p; | ||
10213 | |||
10214 | if (!pending_int) | ||
10215 | return; | ||
10216 | |||
10217 | status = savestatus; | ||
10218 | last_status = status; | ||
10219 | if (status < 0) { | ||
10220 | status = exitstatus; | ||
10221 | savestatus = status; | ||
10222 | } | ||
10223 | pending_int = 0; | ||
10224 | barrier(); | ||
10225 | |||
10226 | TRACE(("dotrap entered\n")); | ||
10227 | if (evalskip) { | ||
10228 | pending_int = 1; | ||
10229 | return; | ||
10230 | } | ||
10231 | |||
10232 | p = trap[SIGINT]; | ||
10233 | if (p) { | ||
10234 | TRACE(("sig %d is active, will run handler '%s'\n", SIGINT, p)); | ||
10235 | trap_depth++; | ||
10236 | evalstring(p, 0); | ||
10237 | trap_depth--; | ||
10238 | if (evalskip != SKIPFUNC) | ||
10239 | exitstatus = status; | ||
10240 | } | ||
10241 | |||
10242 | savestatus = last_status; | ||
10243 | TRACE(("dotrap returns\n")); | ||
10244 | } | ||
10245 | #endif | ||
9286 | 10246 | ||
9287 | /* forward declarations - evaluation is fairly recursive business... */ | 10247 | /* forward declarations - evaluation is fairly recursive business... */ |
9288 | static int evalloop(union node *, int); | 10248 | static int evalloop(union node *, int); |
@@ -9568,19 +10528,36 @@ evalcase(union node *n, int flags) | |||
9568 | static int | 10528 | static int |
9569 | evalsubshell(union node *n, int flags) | 10529 | evalsubshell(union node *n, int flags) |
9570 | { | 10530 | { |
10531 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
9571 | struct job *jp; | 10532 | struct job *jp; |
9572 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ | 10533 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ |
9573 | int status; | 10534 | int status; |
9574 | 10535 | ||
9575 | errlinno = lineno = n->nredir.linno; | 10536 | errlinno = lineno = n->nredir.linno; |
9576 | 10537 | ||
10538 | #if ENABLE_PLATFORM_MINGW32 | ||
10539 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) { | ||
10540 | expredir(n->nredir.redirect); | ||
10541 | redirect(n->nredir.redirect, 0); | ||
10542 | evaltreenr(n->nredir.n, flags); | ||
10543 | /* never returns */ | ||
10544 | } | ||
10545 | #else | ||
9577 | expredir(n->nredir.redirect); | 10546 | expredir(n->nredir.redirect); |
9578 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) | 10547 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) |
9579 | goto nofork; | 10548 | goto nofork; |
10549 | #endif | ||
9580 | INT_OFF; | 10550 | INT_OFF; |
9581 | if (backgnd == FORK_FG) | 10551 | if (backgnd == FORK_FG) |
9582 | get_tty_state(); | 10552 | get_tty_state(); |
9583 | jp = makejob(/*n,*/ 1); | 10553 | jp = makejob(/*n,*/ 1); |
10554 | #if ENABLE_PLATFORM_MINGW32 | ||
10555 | memset(&fs, 0, sizeof(fs)); | ||
10556 | fs.fpid = FS_EVALSUBSHELL; | ||
10557 | fs.n = n; | ||
10558 | fs.flags = flags; | ||
10559 | spawn_forkshell(&fs, jp, n, backgnd); | ||
10560 | #else | ||
9584 | if (forkshell(jp, n, backgnd) == 0) { | 10561 | if (forkshell(jp, n, backgnd) == 0) { |
9585 | /* child */ | 10562 | /* child */ |
9586 | INT_ON; | 10563 | INT_ON; |
@@ -9592,6 +10569,7 @@ evalsubshell(union node *n, int flags) | |||
9592 | evaltreenr(n->nredir.n, flags); | 10569 | evaltreenr(n->nredir.n, flags); |
9593 | /* never returns */ | 10570 | /* never returns */ |
9594 | } | 10571 | } |
10572 | #endif | ||
9595 | /* parent */ | 10573 | /* parent */ |
9596 | status = 0; | 10574 | status = 0; |
9597 | if (backgnd == FORK_FG) | 10575 | if (backgnd == FORK_FG) |
@@ -9672,6 +10650,7 @@ expredir(union node *n) | |||
9672 | static int | 10650 | static int |
9673 | evalpipe(union node *n, int flags) | 10651 | evalpipe(union node *n, int flags) |
9674 | { | 10652 | { |
10653 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
9675 | struct job *jp; | 10654 | struct job *jp; |
9676 | struct nodelist *lp; | 10655 | struct nodelist *lp; |
9677 | int pipelen; | 10656 | int pipelen; |
@@ -9698,6 +10677,16 @@ evalpipe(union node *n, int flags) | |||
9698 | ash_msg_and_raise_perror("can't create pipe"); | 10677 | ash_msg_and_raise_perror("can't create pipe"); |
9699 | } | 10678 | } |
9700 | } | 10679 | } |
10680 | #if ENABLE_PLATFORM_MINGW32 | ||
10681 | memset(&fs, 0, sizeof(fs)); | ||
10682 | fs.fpid = FS_EVALPIPE; | ||
10683 | fs.flags = flags; | ||
10684 | fs.n = lp->n; | ||
10685 | fs.fd[0] = pip[0]; | ||
10686 | fs.fd[1] = pip[1]; | ||
10687 | fs.fd[2] = prevfd; | ||
10688 | spawn_forkshell(&fs, jp, lp->n, n->npipe.pipe_backgnd); | ||
10689 | #else | ||
9701 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { | 10690 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { |
9702 | /* child */ | 10691 | /* child */ |
9703 | INT_ON; | 10692 | INT_ON; |
@@ -9715,6 +10704,7 @@ evalpipe(union node *n, int flags) | |||
9715 | evaltreenr(lp->n, flags); | 10704 | evaltreenr(lp->n, flags); |
9716 | /* never returns */ | 10705 | /* never returns */ |
9717 | } | 10706 | } |
10707 | #endif | ||
9718 | /* parent */ | 10708 | /* parent */ |
9719 | if (prevfd >= 0) | 10709 | if (prevfd >= 0) |
9720 | close(prevfd); | 10710 | close(prevfd); |
@@ -9860,6 +10850,10 @@ poplocalvars(int keep) | |||
9860 | free((char*)vp->var_text); | 10850 | free((char*)vp->var_text); |
9861 | vp->flags = lvp->flags; | 10851 | vp->flags = lvp->flags; |
9862 | vp->var_text = lvp->text; | 10852 | vp->var_text = lvp->text; |
10853 | #if ENABLE_PLATFORM_MINGW32 | ||
10854 | if (is_bb_var(lvp->text) == BB_VAR_ASSIGN) | ||
10855 | putenv(lvp->text); | ||
10856 | #endif | ||
9863 | } | 10857 | } |
9864 | free(lvp); | 10858 | free(lvp); |
9865 | } | 10859 | } |
@@ -10209,7 +11203,7 @@ static const struct builtincmd builtintab[] = { | |||
10209 | #if MAX_HISTORY | 11203 | #if MAX_HISTORY |
10210 | { BUILTIN_NOSPEC "history" , historycmd }, | 11204 | { BUILTIN_NOSPEC "history" , historycmd }, |
10211 | #endif | 11205 | #endif |
10212 | #if JOBS | 11206 | #if JOBS || JOBS_WIN32 |
10213 | { BUILTIN_REGULAR "jobs" , jobscmd }, | 11207 | { BUILTIN_REGULAR "jobs" , jobscmd }, |
10214 | { BUILTIN_REGULAR "kill" , killcmd }, | 11208 | { BUILTIN_REGULAR "kill" , killcmd }, |
10215 | #endif | 11209 | #endif |
@@ -10254,7 +11248,7 @@ static const struct builtincmd builtintab[] = { | |||
10254 | /* [ */ 1 * ENABLE_ASH_TEST + \ | 11248 | /* [ */ 1 * ENABLE_ASH_TEST + \ |
10255 | /* [[ */ 1 * BASH_TEST2 + \ | 11249 | /* [[ */ 1 * BASH_TEST2 + \ |
10256 | /* alias */ 1 * ENABLE_ASH_ALIAS + \ | 11250 | /* alias */ 1 * ENABLE_ASH_ALIAS + \ |
10257 | /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \ | 11251 | /* bg */ 1 * JOBS + \ |
10258 | /* break cd cddir */ 3) | 11252 | /* break cd cddir */ 3) |
10259 | #define EVALCMD (COMMANDCMD + \ | 11253 | #define EVALCMD (COMMANDCMD + \ |
10260 | /* command */ 1 * ENABLE_ASH_CMDCMD + \ | 11254 | /* command */ 1 * ENABLE_ASH_CMDCMD + \ |
@@ -10335,6 +11329,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
10335 | * as POSIX mandates */ | 11329 | * as POSIX mandates */ |
10336 | return back_exitstatus; | 11330 | return back_exitstatus; |
10337 | } | 11331 | } |
11332 | |||
10338 | static int | 11333 | static int |
10339 | evalcommand(union node *cmd, int flags) | 11334 | evalcommand(union node *cmd, int flags) |
10340 | { | 11335 | { |
@@ -10588,6 +11583,22 @@ evalcommand(union node *cmd, int flags) | |||
10588 | * in a script or a subshell does not need forking, | 11583 | * in a script or a subshell does not need forking, |
10589 | * we can just exec it. | 11584 | * we can just exec it. |
10590 | */ | 11585 | */ |
11586 | #if ENABLE_PLATFORM_MINGW32 | ||
11587 | if (!(flags & EV_EXIT) || may_have_traps IF_SUW32(|| delayexit)) { | ||
11588 | /* No, forking off a child is necessary */ | ||
11589 | struct forkshell fs; | ||
11590 | |||
11591 | INT_OFF; | ||
11592 | memset(&fs, 0, sizeof(fs)); | ||
11593 | fs.fpid = FS_SHELLEXEC; | ||
11594 | fs.argv = argv; | ||
11595 | fs.path = (char*)path; | ||
11596 | fs.fd[0] = cmdentry.u.index; | ||
11597 | jp = makejob(/*cmd,*/ 1); | ||
11598 | spawn_forkshell(&fs, jp, cmd, FORK_FG); | ||
11599 | break; | ||
11600 | } | ||
11601 | #else | ||
10591 | if (!(flags & EV_EXIT) || may_have_traps) { | 11602 | if (!(flags & EV_EXIT) || may_have_traps) { |
10592 | /* No, forking off a child is necessary */ | 11603 | /* No, forking off a child is necessary */ |
10593 | INT_OFF; | 11604 | INT_OFF; |
@@ -10601,6 +11612,7 @@ evalcommand(union node *cmd, int flags) | |||
10601 | FORCE_INT_ON; | 11612 | FORCE_INT_ON; |
10602 | /* fall through to exec'ing external program */ | 11613 | /* fall through to exec'ing external program */ |
10603 | } | 11614 | } |
11615 | #endif | ||
10604 | shellexec(argv[0], argv, path, cmdentry.u.index); | 11616 | shellexec(argv[0], argv, path, cmdentry.u.index); |
10605 | /* NOTREACHED */ | 11617 | /* NOTREACHED */ |
10606 | } /* default */ | 11618 | } /* default */ |
@@ -10813,6 +11825,54 @@ static void popstring(void) | |||
10813 | INT_ON; | 11825 | INT_ON; |
10814 | } | 11826 | } |
10815 | 11827 | ||
11828 | #if ENABLE_PLATFORM_MINGW32 | ||
11829 | /* | ||
11830 | * Wrapper around nonblock_immune_read() to remove CRs, but only from | ||
11831 | * CRLF pairs. The tricky part is handling a CR at the end of the buffer. | ||
11832 | */ | ||
11833 | static inline ssize_t | ||
11834 | nonblock_immune_wrapper(struct parsefile *pf, char *buffer, size_t count) | ||
11835 | { | ||
11836 | int nr, injected_cr; | ||
11837 | |||
11838 | // Inject unprocessed CR from previous read into the buffer. | ||
11839 | if (pf->cr) | ||
11840 | *buffer = '\r'; | ||
11841 | retry: | ||
11842 | nr = nonblock_immune_read(pf->pf_fd, buffer + pf->cr, count - pf->cr); | ||
11843 | if (nr < 0) | ||
11844 | return nr; | ||
11845 | |||
11846 | injected_cr = pf->cr; | ||
11847 | nr += pf->cr; | ||
11848 | pf->cr = 0; | ||
11849 | |||
11850 | if (nr > 0) { | ||
11851 | nr = remove_cr(buffer, nr); | ||
11852 | // remove_cr() won't reduce size to zero, so [nr - 1] is OK. | ||
11853 | if (buffer[nr - 1] == '\r') { | ||
11854 | if (nr > 1) { | ||
11855 | // Ignore trailing CR for now: we'll deal with it later. | ||
11856 | pf->cr = 1; | ||
11857 | --nr; | ||
11858 | } else if (injected_cr) { // nr == 1 | ||
11859 | // Buffer only contains an injected CR. This means the | ||
11860 | // read returned EOF. Return the buffer as-is. The | ||
11861 | // next call will detect EOF. | ||
11862 | } else { | ||
11863 | // Buffer only contains a CR from the most recent read. | ||
11864 | // Try another read, treating the CR as injected. We'll | ||
11865 | // either get more characters or EOF. Either way we | ||
11866 | // won't end up here again. | ||
11867 | pf->cr = 1; | ||
11868 | goto retry; | ||
11869 | } | ||
11870 | } | ||
11871 | } | ||
11872 | return nr; | ||
11873 | } | ||
11874 | #endif | ||
11875 | |||
10816 | static int | 11876 | static int |
10817 | preadfd(void) | 11877 | preadfd(void) |
10818 | { | 11878 | { |
@@ -10823,7 +11883,11 @@ preadfd(void) | |||
10823 | #if ENABLE_FEATURE_EDITING | 11883 | #if ENABLE_FEATURE_EDITING |
10824 | /* retry: */ | 11884 | /* retry: */ |
10825 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) | 11885 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) |
11886 | #if ENABLE_PLATFORM_MINGW32 | ||
11887 | nr = nonblock_immune_wrapper(g_parsefile, buf, IBUFSIZ - 1); | ||
11888 | #else | ||
10826 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); | 11889 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
11890 | #endif | ||
10827 | else { | 11891 | else { |
10828 | # if ENABLE_ASH_IDLE_TIMEOUT | 11892 | # if ENABLE_ASH_IDLE_TIMEOUT |
10829 | int timeout = -1; | 11893 | int timeout = -1; |
@@ -10862,12 +11926,21 @@ preadfd(void) | |||
10862 | INT_ON; /* here non-blocked SIGINT will longjmp */ | 11926 | INT_ON; /* here non-blocked SIGINT will longjmp */ |
10863 | if (nr == 0) { | 11927 | if (nr == 0) { |
10864 | /* ^C pressed, "convert" to SIGINT */ | 11928 | /* ^C pressed, "convert" to SIGINT */ |
11929 | # if !ENABLE_PLATFORM_MINGW32 | ||
10865 | write(STDOUT_FILENO, "^C\n", 3); | 11930 | write(STDOUT_FILENO, "^C\n", 3); |
10866 | raise(SIGINT); /* here non-blocked SIGINT will longjmp */ | 11931 | raise(SIGINT); /* here non-blocked SIGINT will longjmp */ |
10867 | /* raise(SIGINT) did not work! (e.g. if SIGINT | 11932 | /* raise(SIGINT) did not work! (e.g. if SIGINT |
10868 | * is SIG_IGNed on startup, it stays SIG_IGNed) | 11933 | * is SIG_IGNed on startup, it stays SIG_IGNed) |
10869 | */ | 11934 | */ |
11935 | # else | ||
11936 | raise_interrupt(); | ||
11937 | write(STDOUT_FILENO, "^C\n", 3); | ||
11938 | # endif | ||
10870 | if (trap[SIGINT]) { | 11939 | if (trap[SIGINT]) { |
11940 | # if ENABLE_PLATFORM_MINGW32 | ||
11941 | pending_int = 1; | ||
11942 | dotrap(); | ||
11943 | # endif | ||
10871 | empty_line_input: | 11944 | empty_line_input: |
10872 | buf[0] = '\n'; | 11945 | buf[0] = '\n'; |
10873 | buf[1] = '\0'; | 11946 | buf[1] = '\0'; |
@@ -10896,7 +11969,11 @@ preadfd(void) | |||
10896 | } | 11969 | } |
10897 | } | 11970 | } |
10898 | #else | 11971 | #else |
11972 | # if ENABLE_PLATFORM_MINGW32 | ||
11973 | nr = nonblock_immune_wrapper(g_parsefile, buf, IBUFSIZ - 1); | ||
11974 | # else | ||
10899 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); | 11975 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
11976 | # endif | ||
10900 | #endif | 11977 | #endif |
10901 | 11978 | ||
10902 | #if 0 /* disabled: nonblock_immune_read() handles this problem */ | 11979 | #if 0 /* disabled: nonblock_immune_read() handles this problem */ |
@@ -11195,6 +12272,7 @@ popallfiles(void) | |||
11195 | unwindfiles(&basepf); | 12272 | unwindfiles(&basepf); |
11196 | } | 12273 | } |
11197 | 12274 | ||
12275 | #if !ENABLE_PLATFORM_MINGW32 | ||
11198 | /* | 12276 | /* |
11199 | * Close the file(s) that the shell is reading commands from. Called | 12277 | * Close the file(s) that the shell is reading commands from. Called |
11200 | * after a fork is done. | 12278 | * after a fork is done. |
@@ -11208,6 +12286,7 @@ closescript(void) | |||
11208 | g_parsefile->pf_fd = 0; | 12286 | g_parsefile->pf_fd = 0; |
11209 | } | 12287 | } |
11210 | } | 12288 | } |
12289 | #endif | ||
11211 | 12290 | ||
11212 | /* | 12291 | /* |
11213 | * Like setinputfile, but takes an open file descriptor. Call this with | 12292 | * Like setinputfile, but takes an open file descriptor. Call this with |
@@ -11444,8 +12523,16 @@ options(int *login_sh) | |||
11444 | int val; | 12523 | int val; |
11445 | int c; | 12524 | int c; |
11446 | 12525 | ||
11447 | if (login_sh != NULL) /* if we came from startup code */ | 12526 | if (login_sh != NULL) { /* if we came from startup code */ |
11448 | minusc = NULL; | 12527 | minusc = NULL; |
12528 | #if ENABLE_PLATFORM_MINGW32 | ||
12529 | dirarg = NULL; | ||
12530 | title = NULL; | ||
12531 | # if ENABLE_SUW32 | ||
12532 | delayexit = 0; | ||
12533 | # endif | ||
12534 | #endif | ||
12535 | } | ||
11449 | while ((p = *argptr) != NULL) { | 12536 | while ((p = *argptr) != NULL) { |
11450 | c = *p++; | 12537 | c = *p++; |
11451 | if (c != '-' && c != '+') | 12538 | if (c != '-' && c != '+') |
@@ -11475,6 +12562,31 @@ options(int *login_sh) | |||
11475 | cflag = 1; | 12562 | cflag = 1; |
11476 | continue; | 12563 | continue; |
11477 | } | 12564 | } |
12565 | #if ENABLE_PLATFORM_MINGW32 | ||
12566 | /* Undocumented flags; | ||
12567 | * -d force current directory | ||
12568 | * -t title to display in console window | ||
12569 | * -N prompt user before exit | ||
12570 | * Must appear before -s or -c. */ | ||
12571 | if (c == 'd' && val == 1) { | ||
12572 | if (*argptr == NULL) | ||
12573 | ash_msg_and_raise_error(bb_msg_requires_arg, "-d"); | ||
12574 | dirarg = *argptr++; | ||
12575 | continue; | ||
12576 | } | ||
12577 | if (c == 't' && val == 1) { | ||
12578 | if (*argptr == NULL) | ||
12579 | ash_msg_and_raise_error(bb_msg_requires_arg, "-t"); | ||
12580 | title = *argptr++; | ||
12581 | continue; | ||
12582 | } | ||
12583 | # if ENABLE_SUW32 | ||
12584 | if (c == 'N' && val == 1) { | ||
12585 | delayexit = 1; | ||
12586 | continue; | ||
12587 | } | ||
12588 | # endif | ||
12589 | #endif | ||
11478 | if (c == 's') { /* -s, +s */ | 12590 | if (c == 's') { /* -s, +s */ |
11479 | sflag = 1; | 12591 | sflag = 1; |
11480 | continue; | 12592 | continue; |
@@ -13501,6 +14613,9 @@ evalstring(char *s, int flags) | |||
13501 | int status; | 14613 | int status; |
13502 | 14614 | ||
13503 | s = sstrdup(s); | 14615 | s = sstrdup(s); |
14616 | #if ENABLE_PLATFORM_MINGW32 | ||
14617 | remove_cr(s, strlen(s)+1); | ||
14618 | #endif | ||
13504 | setinputstring(s); | 14619 | setinputstring(s); |
13505 | setstackmark(&smark); | 14620 | setstackmark(&smark); |
13506 | 14621 | ||
@@ -13588,7 +14703,7 @@ cmdloop(int top) | |||
13588 | int skip; | 14703 | int skip; |
13589 | 14704 | ||
13590 | setstackmark(&smark); | 14705 | setstackmark(&smark); |
13591 | #if JOBS | 14706 | #if JOBS || JOBS_WIN32 |
13592 | if (doing_jobctl) | 14707 | if (doing_jobctl) |
13593 | showjobs(SHOW_CHANGED|SHOW_STDERR); | 14708 | showjobs(SHOW_CHANGED|SHOW_STDERR); |
13594 | #endif | 14709 | #endif |
@@ -13596,6 +14711,9 @@ cmdloop(int top) | |||
13596 | if (iflag && top) { | 14711 | if (iflag && top) { |
13597 | inter++; | 14712 | inter++; |
13598 | chkmail(); | 14713 | chkmail(); |
14714 | #if ENABLE_PLATFORM_MINGW32 | ||
14715 | terminal_mode(TRUE); | ||
14716 | #endif | ||
13599 | } | 14717 | } |
13600 | n = parsecmd(inter); | 14718 | n = parsecmd(inter); |
13601 | #if DEBUG | 14719 | #if DEBUG |
@@ -13619,8 +14737,10 @@ cmdloop(int top) | |||
13619 | } else { | 14737 | } else { |
13620 | int i; | 14738 | int i; |
13621 | 14739 | ||
14740 | #if !ENABLE_PLATFORM_MINGW32 | ||
13622 | /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */ | 14741 | /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */ |
13623 | job_warning >>= 1; | 14742 | job_warning >>= 1; |
14743 | #endif | ||
13624 | numeof = 0; | 14744 | numeof = 0; |
13625 | i = evaltree(n, 0); | 14745 | i = evaltree(n, 0); |
13626 | if (n) | 14746 | if (n) |
@@ -13650,7 +14770,7 @@ find_dot_file(char *basename) | |||
13650 | int len; | 14770 | int len; |
13651 | 14771 | ||
13652 | /* don't try this for absolute or relative paths */ | 14772 | /* don't try this for absolute or relative paths */ |
13653 | if (strchr(basename, '/')) | 14773 | if (strchr(basename, '/') IF_PLATFORM_MINGW32(|| strchr(basename, '\\'))) |
13654 | return basename; | 14774 | return basename; |
13655 | 14775 | ||
13656 | path = pathval(); | 14776 | path = pathval(); |
@@ -13779,6 +14899,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13779 | struct builtincmd *bcmd; | 14899 | struct builtincmd *bcmd; |
13780 | int len; | 14900 | int len; |
13781 | 14901 | ||
14902 | #if !ENABLE_PLATFORM_MINGW32 | ||
13782 | /* If name contains a slash, don't use PATH or hash table */ | 14903 | /* If name contains a slash, don't use PATH or hash table */ |
13783 | if (strchr(name, '/') != NULL) { | 14904 | if (strchr(name, '/') != NULL) { |
13784 | entry->u.index = -1; | 14905 | entry->u.index = -1; |
@@ -13795,6 +14916,35 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13795 | entry->cmdtype = CMDNORMAL; | 14916 | entry->cmdtype = CMDNORMAL; |
13796 | return; | 14917 | return; |
13797 | } | 14918 | } |
14919 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
14920 | /* If name contains a slash or drive prefix, don't use PATH or hash table */ | ||
14921 | if (has_path(name)) { | ||
14922 | entry->u.index = -1; | ||
14923 | entry->cmdtype = CMDNORMAL; | ||
14924 | fullname = stack_add_ext_space(name); | ||
14925 | if (add_win32_extension(fullname) || file_is_executable(fullname)) { | ||
14926 | return; | ||
14927 | } else if (unix_path(name)) { | ||
14928 | name = (char *)bb_basename(name); | ||
14929 | if ( | ||
14930 | # if ENABLE_FEATURE_SH_STANDALONE | ||
14931 | find_applet_by_name(name) >= 0 || | ||
14932 | # endif | ||
14933 | !find_builtin(bb_basename(name)) | ||
14934 | ) { | ||
14935 | act |= DO_NOFUNC; | ||
14936 | } else if (act & DO_ABS) { | ||
14937 | entry->cmdtype = CMDUNKNOWN; | ||
14938 | return; | ||
14939 | } | ||
14940 | } else if (act & DO_ABS) { | ||
14941 | entry->cmdtype = CMDUNKNOWN; | ||
14942 | return; | ||
14943 | } else { | ||
14944 | return; | ||
14945 | } | ||
14946 | } | ||
14947 | #endif /* ENABLE_PLATFORM_MINGW32 */ | ||
13798 | 14948 | ||
13799 | /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ | 14949 | /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ |
13800 | 14950 | ||
@@ -13888,12 +15038,15 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13888 | } | 15038 | } |
13889 | } | 15039 | } |
13890 | /* if rehash, don't redo absolute path names */ | 15040 | /* if rehash, don't redo absolute path names */ |
13891 | if (fullname[0] == '/' && idx <= prev) { | 15041 | if (!is_relative_path(fullname) && idx <= prev) { |
13892 | if (idx < prev) | 15042 | if (idx < prev) |
13893 | continue; | 15043 | continue; |
13894 | TRACE(("searchexec \"%s\": no change\n", name)); | 15044 | TRACE(("searchexec \"%s\": no change\n", name)); |
13895 | goto success; | 15045 | goto success; |
13896 | } | 15046 | } |
15047 | #if ENABLE_PLATFORM_MINGW32 | ||
15048 | add_win32_extension(fullname); | ||
15049 | #endif | ||
13897 | while (stat(fullname, &statb) < 0) { | 15050 | while (stat(fullname, &statb) < 0) { |
13898 | #ifdef SYSV | 15051 | #ifdef SYSV |
13899 | if (errno == EINTR) | 15052 | if (errno == EINTR) |
@@ -14032,19 +15185,41 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14032 | if (LONE_DASH(action)) | 15185 | if (LONE_DASH(action)) |
14033 | action = NULL; | 15186 | action = NULL; |
14034 | else { | 15187 | else { |
15188 | #if !ENABLE_PLATFORM_MINGW32 | ||
14035 | if (action[0]) /* not NULL and not "" and not "-" */ | 15189 | if (action[0]) /* not NULL and not "" and not "-" */ |
14036 | may_have_traps = 1; | 15190 | may_have_traps = 1; |
15191 | #endif | ||
14037 | action = ckstrdup(action); | 15192 | action = ckstrdup(action); |
14038 | } | 15193 | } |
14039 | } | 15194 | } |
14040 | free(trap[signo]); | 15195 | free(trap[signo]); |
14041 | trap[signo] = action; | 15196 | trap[signo] = action; |
15197 | #if ENABLE_PLATFORM_MINGW32 | ||
15198 | if (signo == SIGINT) { | ||
15199 | // trap '' INT disables Ctrl-C, anything else enables it | ||
15200 | if (action && action[0] == '\0') { | ||
15201 | SetConsoleCtrlHandler(NULL, TRUE); | ||
15202 | if (line_input_state) { | ||
15203 | line_input_state->flags |= IGNORE_CTRL_C; | ||
15204 | } | ||
15205 | } else { | ||
15206 | SetConsoleCtrlHandler(NULL, FALSE); | ||
15207 | if (line_input_state) { | ||
15208 | line_input_state->flags &= ~IGNORE_CTRL_C; | ||
15209 | } | ||
15210 | } | ||
15211 | } | ||
15212 | #else | ||
14042 | if (signo != 0 && signo < NSIG) | 15213 | if (signo != 0 && signo < NSIG) |
14043 | setsignal(signo); | 15214 | setsignal(signo); |
15215 | #endif | ||
14044 | INT_ON; | 15216 | INT_ON; |
14045 | next: | 15217 | next: |
14046 | ap++; | 15218 | ap++; |
14047 | } | 15219 | } |
15220 | #if ENABLE_PLATFORM_MINGW32 | ||
15221 | may_have_traps = trap[SIGINT] && trap[SIGINT][0] != '\0'; | ||
15222 | #endif | ||
14048 | return exitcode; | 15223 | return exitcode; |
14049 | } | 15224 | } |
14050 | 15225 | ||
@@ -14073,10 +15248,12 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14073 | { | 15248 | { |
14074 | const char *a = applet_names; | 15249 | const char *a = applet_names; |
14075 | while (*a) { | 15250 | while (*a) { |
14076 | col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a); | 15251 | if (is_applet_preferred(a)) { |
14077 | if (col > 60) { | 15252 | col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a); |
14078 | out1fmt("\n"); | 15253 | if (col > 60) { |
14079 | col = 0; | 15254 | out1fmt("\n"); |
15255 | col = 0; | ||
15256 | } | ||
14080 | } | 15257 | } |
14081 | while (*a++ != '\0') | 15258 | while (*a++ != '\0') |
14082 | continue; | 15259 | continue; |
@@ -14138,6 +15315,14 @@ exportcmd(int argc UNUSED_PARAM, char **argv) | |||
14138 | } else { | 15315 | } else { |
14139 | vp = *findvar(hashvar(name), name); | 15316 | vp = *findvar(hashvar(name), name); |
14140 | if (vp) { | 15317 | if (vp) { |
15318 | #if ENABLE_PLATFORM_MINGW32 | ||
15319 | if (is_bb_var(name) == BB_VAR_EXACT) { | ||
15320 | if (flag_off == ~VEXPORT) | ||
15321 | unsetenv(name); | ||
15322 | else if (flag == VEXPORT && !(vp->flags & VUNSET)) | ||
15323 | putenv(vp->var_text); | ||
15324 | } | ||
15325 | #endif | ||
14141 | vp->flags = ((vp->flags | flag) & flag_off); | 15326 | vp->flags = ((vp->flags | flag) & flag_off); |
14142 | continue; | 15327 | continue; |
14143 | } | 15328 | } |
@@ -14329,6 +15514,27 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14329 | goto again; | 15514 | goto again; |
14330 | } | 15515 | } |
14331 | 15516 | ||
15517 | #if ENABLE_PLATFORM_MINGW32 | ||
15518 | if ((uintptr_t)r == 2) { | ||
15519 | /* ^C pressed, propagate event */ | ||
15520 | if (trap[SIGINT]) { | ||
15521 | write(STDOUT_FILENO, "^C", 2); | ||
15522 | pending_int = 1; | ||
15523 | dotrap(); | ||
15524 | if (!(rootshell && iflag)) | ||
15525 | return (uintptr_t)0; | ||
15526 | else | ||
15527 | goto again; | ||
15528 | } else if (iflag) { | ||
15529 | raise_interrupt(); | ||
15530 | } else { | ||
15531 | GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); | ||
15532 | exitshell(); | ||
15533 | } | ||
15534 | return (uintptr_t)r; | ||
15535 | } | ||
15536 | #endif | ||
15537 | |||
14332 | if ((uintptr_t)r > 1) | 15538 | if ((uintptr_t)r > 1) |
14333 | ash_msg_and_raise_error(r); | 15539 | ash_msg_and_raise_error(r); |
14334 | 15540 | ||
@@ -14389,6 +15595,9 @@ umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14389 | if (!isdigit(modestr[0])) | 15595 | if (!isdigit(modestr[0])) |
14390 | mask ^= 0777; | 15596 | mask ^= 0777; |
14391 | umask(mask); | 15597 | umask(mask); |
15598 | #if ENABLE_PLATFORM_MINGW32 | ||
15599 | setvareq(xasprintf("BB_UMASK=0%o", mask), VEXPORT|VNOSAVE); | ||
15600 | #endif | ||
14392 | } | 15601 | } |
14393 | return 0; | 15602 | return 0; |
14394 | } | 15603 | } |
@@ -14472,6 +15681,13 @@ exitshell(void) | |||
14472 | /*free(p); - we'll exit soon */ | 15681 | /*free(p); - we'll exit soon */ |
14473 | } | 15682 | } |
14474 | out: | 15683 | out: |
15684 | #if ENABLE_SUW32 | ||
15685 | if (delayexit) { | ||
15686 | freopen("CONOUT$", "w", stdout); | ||
15687 | fputs_stdout("Press any key to exit..."); | ||
15688 | _getch(); | ||
15689 | } | ||
15690 | #endif | ||
14475 | exitreset(); | 15691 | exitreset(); |
14476 | /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". | 15692 | /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". |
14477 | * our setjobctl(0) does not panic if tcsetpgrp fails inside it. | 15693 | * our setjobctl(0) does not panic if tcsetpgrp fails inside it. |
@@ -14482,22 +15698,113 @@ exitshell(void) | |||
14482 | /* NOTREACHED */ | 15698 | /* NOTREACHED */ |
14483 | } | 15699 | } |
14484 | 15700 | ||
15701 | #if ENABLE_PLATFORM_MINGW32 | ||
15702 | /* We need to see if HOME is *really* unset */ | ||
15703 | # undef getenv | ||
15704 | static void xsetenv_if_unset(const char *key, const char *value) | ||
15705 | { | ||
15706 | if (!getenv(key) || getuid() == 0) | ||
15707 | xsetenv(key, value); | ||
15708 | } | ||
15709 | #endif | ||
15710 | |||
14485 | /* Don't inline: conserve stack of caller from having our locals too */ | 15711 | /* Don't inline: conserve stack of caller from having our locals too */ |
14486 | static NOINLINE void | 15712 | static NOINLINE void |
14487 | init(void) | 15713 | init(void) |
14488 | { | 15714 | { |
15715 | #if !ENABLE_PLATFORM_MINGW32 | ||
14489 | /* we will never free this */ | 15716 | /* we will never free this */ |
14490 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); | 15717 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); |
14491 | basepf.linno = 1; | 15718 | basepf.linno = 1; |
14492 | 15719 | ||
14493 | sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ | 15720 | sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ |
14494 | setsignal(SIGCHLD); | 15721 | setsignal(SIGCHLD); |
15722 | #endif | ||
14495 | 15723 | ||
14496 | { | 15724 | { |
14497 | char **envp; | 15725 | char **envp; |
14498 | const char *p; | 15726 | const char *p; |
14499 | 15727 | ||
14500 | initvar(); | 15728 | initvar(); |
15729 | |||
15730 | #if ENABLE_PLATFORM_MINGW32 | ||
15731 | /* | ||
15732 | * case insensitive env names from Windows world | ||
15733 | * | ||
15734 | * Some standard env names such as PATH is named Path and so on | ||
15735 | * ash itself is case sensitive, so "Path" will confuse it, as | ||
15736 | * MSVC getenv() is case insensitive. | ||
15737 | * | ||
15738 | * We may end up having both Path and PATH. Then Path will be chosen | ||
15739 | * because it appears first. | ||
15740 | */ | ||
15741 | for (envp = environ; envp && *envp; envp++) { | ||
15742 | if (is_prefixed_with_case(*envp, "PATH=") && | ||
15743 | !is_prefixed_with(*envp, "PATH=")) { | ||
15744 | break; | ||
15745 | } | ||
15746 | } | ||
15747 | |||
15748 | if (envp && *envp) { | ||
15749 | /* | ||
15750 | * If we get here it's because the environment contains a path | ||
15751 | * variable called something other than PATH. This suggests we | ||
15752 | * haven't been invoked from an earlier instance of BusyBox. | ||
15753 | */ | ||
15754 | char *start, *end; | ||
15755 | struct passwd *pw; | ||
15756 | |||
15757 | for (envp = environ; envp && *envp; envp++) { | ||
15758 | if (!(end=strchr(*envp, '='))) | ||
15759 | continue; | ||
15760 | |||
15761 | /* make all variable names uppercase */ | ||
15762 | for (start = *envp;start < end;start++) | ||
15763 | *start = toupper(*start); | ||
15764 | |||
15765 | /* Convert backslashes to forward slashes in value but | ||
15766 | * not if we're on Windows XP or for variables known to | ||
15767 | * cause problems */ | ||
15768 | if (!winxp && !is_prefixed_with(*envp, "SYSTEMROOT=") && | ||
15769 | !is_prefixed_with(*envp, "COMSPEC=")) { | ||
15770 | bs_to_slash(end+1); | ||
15771 | } | ||
15772 | |||
15773 | /* check for invalid characters in name */ | ||
15774 | for (start = *envp;start < end;start++) { | ||
15775 | if (!isdigit(*start) && !isalpha(*start) && *start != '_') { | ||
15776 | break; | ||
15777 | } | ||
15778 | } | ||
15779 | |||
15780 | if (start != end) { | ||
15781 | /* | ||
15782 | * Make a copy of the variable, replacing invalid | ||
15783 | * characters in the name with underscores. | ||
15784 | */ | ||
15785 | char *var = xstrdup(*envp); | ||
15786 | |||
15787 | for (start = var;*start != '=';start++) { | ||
15788 | if (!isdigit(*start) && !isalpha(*start)) { | ||
15789 | *start = '_'; | ||
15790 | } | ||
15791 | } | ||
15792 | setvareq(var, VEXPORT|VNOSAVE); | ||
15793 | } | ||
15794 | } | ||
15795 | |||
15796 | /* Initialise some variables normally set at login, but | ||
15797 | * only if someone hasn't already set them or we're root. */ | ||
15798 | pw = getpwuid(getuid()); | ||
15799 | if (pw) { | ||
15800 | xsetenv_if_unset("USER", pw->pw_name); | ||
15801 | xsetenv_if_unset("USERNAME", pw->pw_name); | ||
15802 | xsetenv_if_unset("LOGNAME", pw->pw_name); | ||
15803 | xsetenv_if_unset("HOME", pw->pw_dir); | ||
15804 | } | ||
15805 | xsetenv_if_unset("SHELL", DEFAULT_SHELL); | ||
15806 | } | ||
15807 | #endif | ||
14501 | for (envp = environ; envp && *envp; envp++) { | 15808 | for (envp = environ; envp && *envp; envp++) { |
14502 | /* Used to have | 15809 | /* Used to have |
14503 | * p = endofname(*envp); | 15810 | * p = endofname(*envp); |
@@ -14511,7 +15818,11 @@ init(void) | |||
14511 | * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this | 15818 | * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this |
14512 | */ | 15819 | */ |
14513 | if (strchr(*envp, '=')) { | 15820 | if (strchr(*envp, '=')) { |
15821 | #if !ENABLE_PLATFORM_MINGW32 | ||
14514 | setvareq(*envp, VEXPORT|VTEXTFIXED); | 15822 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
15823 | #else | ||
15824 | setvareq(*envp, VEXPORT); | ||
15825 | #endif | ||
14515 | } | 15826 | } |
14516 | } | 15827 | } |
14517 | 15828 | ||
@@ -14586,7 +15897,9 @@ procargs(char **argv) | |||
14586 | } | 15897 | } |
14587 | if (iflag == 2 /* no explicit -i given */ | 15898 | if (iflag == 2 /* no explicit -i given */ |
14588 | && sflag == 1 /* -s given (or implied) */ | 15899 | && sflag == 1 /* -s given (or implied) */ |
15900 | #if !ENABLE_PLATFORM_MINGW32 | ||
14589 | && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */ | 15901 | && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */ |
15902 | #endif | ||
14590 | && isatty(0) && isatty(1) /* we are on tty */ | 15903 | && isatty(0) && isatty(1) /* we are on tty */ |
14591 | ) { | 15904 | ) { |
14592 | iflag = 1; | 15905 | iflag = 1; |
@@ -14606,6 +15919,9 @@ procargs(char **argv) | |||
14606 | goto setarg0; | 15919 | goto setarg0; |
14607 | } else if (!sflag) { | 15920 | } else if (!sflag) { |
14608 | setinputfile(*xargv, 0); | 15921 | setinputfile(*xargv, 0); |
15922 | #if ENABLE_PLATFORM_MINGW32 | ||
15923 | bs_to_slash(*xargv); | ||
15924 | #endif | ||
14609 | setarg0: | 15925 | setarg0: |
14610 | arg0 = *xargv++; | 15926 | arg0 = *xargv++; |
14611 | commandname = arg0; | 15927 | commandname = arg0; |
@@ -14629,8 +15945,10 @@ procargs(char **argv) | |||
14629 | * NB: must do it before setting up signals (in optschanged()) | 15945 | * NB: must do it before setting up signals (in optschanged()) |
14630 | * and reading .profile etc (after we return from here): | 15946 | * and reading .profile etc (after we return from here): |
14631 | */ | 15947 | */ |
15948 | #if !ENABLE_PLATFORM_MINGW32 | ||
14632 | if (iflag) | 15949 | if (iflag) |
14633 | signal(SIGHUP, SIG_DFL); | 15950 | signal(SIGHUP, SIG_DFL); |
15951 | #endif | ||
14634 | 15952 | ||
14635 | optschanged(); | 15953 | optschanged(); |
14636 | 15954 | ||
@@ -14675,9 +15993,25 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14675 | struct stackmark smark; | 15993 | struct stackmark smark; |
14676 | int login_sh; | 15994 | int login_sh; |
14677 | 15995 | ||
15996 | #if ENABLE_PLATFORM_MINGW32 | ||
15997 | INIT_G_memstack(); | ||
15998 | |||
15999 | /* from init() */ | ||
16000 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); | ||
16001 | basepf.linno = 1; | ||
16002 | |||
16003 | if (argc == 3 && !strcmp(argv[1], "--fs")) { | ||
16004 | forkshell_init(argv[2]); | ||
16005 | /* only reached in case of error */ | ||
16006 | bb_error_msg_and_die("forkshell failed"); | ||
16007 | } | ||
16008 | #endif | ||
16009 | |||
14678 | /* Initialize global data */ | 16010 | /* Initialize global data */ |
14679 | INIT_G_misc(); | 16011 | INIT_G_misc(); |
16012 | #if !ENABLE_PLATFORM_MINGW32 | ||
14680 | INIT_G_memstack(); | 16013 | INIT_G_memstack(); |
16014 | #endif | ||
14681 | INIT_G_var(); | 16015 | INIT_G_var(); |
14682 | #if ENABLE_ASH_ALIAS | 16016 | #if ENABLE_ASH_ALIAS |
14683 | INIT_G_alias(); | 16017 | INIT_G_alias(); |
@@ -14720,9 +16054,16 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14720 | exception_handler = &jmploc; | 16054 | exception_handler = &jmploc; |
14721 | rootpid = getpid(); | 16055 | rootpid = getpid(); |
14722 | 16056 | ||
16057 | #if ENABLE_PLATFORM_MINGW32 | ||
16058 | winxp = (argv[1] != NULL && strcmp(argv[1], "-X") == 0); | ||
16059 | #endif | ||
14723 | init(); | 16060 | init(); |
14724 | setstackmark(&smark); | 16061 | setstackmark(&smark); |
14725 | 16062 | ||
16063 | #if ENABLE_PLATFORM_MINGW32 | ||
16064 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
16065 | #endif | ||
16066 | |||
14726 | #if NUM_SCRIPTS > 0 | 16067 | #if NUM_SCRIPTS > 0 |
14727 | if (argc < 0) | 16068 | if (argc < 0) |
14728 | /* Non-NULL minusc tells procargs that an embedded script is being run */ | 16069 | /* Non-NULL minusc tells procargs that an embedded script is being run */ |
@@ -14734,11 +16075,50 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14734 | trace_puts_args(argv); | 16075 | trace_puts_args(argv); |
14735 | #endif | 16076 | #endif |
14736 | 16077 | ||
16078 | #if ENABLE_ASH_NOCONSOLE | ||
16079 | if (noconsole) | ||
16080 | hide_console(); | ||
16081 | #endif | ||
16082 | |||
16083 | #if ENABLE_PLATFORM_MINGW32 | ||
16084 | if (dirarg) { | ||
16085 | chdir(dirarg); | ||
16086 | setpwd(NULL, 0); | ||
16087 | } | ||
16088 | else if (!login_sh && iflag) { | ||
16089 | char *cwd = getcwd(NULL, 0); | ||
16090 | if (cwd) { | ||
16091 | chdir(cwd); | ||
16092 | setpwd(NULL, 0); | ||
16093 | free(cwd); | ||
16094 | } | ||
16095 | } | ||
16096 | |||
16097 | if (title) | ||
16098 | set_title(title); | ||
16099 | #endif | ||
16100 | |||
14737 | if (login_sh) { | 16101 | if (login_sh) { |
14738 | const char *hp; | 16102 | const char *hp; |
14739 | 16103 | ||
16104 | #if ENABLE_PLATFORM_MINGW32 | ||
16105 | if (!dirarg) { | ||
16106 | hp = lookupvar("HOME"); | ||
16107 | if (hp == NULL || *hp == '\0') | ||
16108 | hp = xgetpwuid(getuid())->pw_dir; | ||
16109 | chdir(hp); | ||
16110 | setpwd(NULL, 0); | ||
16111 | } | ||
16112 | #endif | ||
16113 | |||
14740 | state = 1; | 16114 | state = 1; |
16115 | #if ENABLE_PLATFORM_MINGW32 | ||
16116 | hp = xasprintf("%s/etc/profile", get_system_drive() ?: ""); | ||
16117 | read_profile(hp); | ||
16118 | free((void *)hp); | ||
16119 | #else | ||
14741 | read_profile("/etc/profile"); | 16120 | read_profile("/etc/profile"); |
16121 | #endif | ||
14742 | state1: | 16122 | state1: |
14743 | state = 2; | 16123 | state = 2; |
14744 | hp = lookupvar("HOME"); | 16124 | hp = lookupvar("HOME"); |
@@ -14748,9 +16128,11 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14748 | state2: | 16128 | state2: |
14749 | state = 3; | 16129 | state = 3; |
14750 | if (iflag | 16130 | if (iflag |
16131 | #if ENABLE_PLATFORM_POSIX | ||
14751 | #ifndef linux | 16132 | #ifndef linux |
14752 | && getuid() == geteuid() && getgid() == getegid() | 16133 | && getuid() == geteuid() && getgid() == getegid() |
14753 | #endif | 16134 | #endif |
16135 | #endif | ||
14754 | ) { | 16136 | ) { |
14755 | const char *shinit = lookupvar("ENV"); | 16137 | const char *shinit = lookupvar("ENV"); |
14756 | if (shinit != NULL && *shinit != '\0') | 16138 | if (shinit != NULL && *shinit != '\0') |
@@ -14775,7 +16157,11 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14775 | // ash -sc 'echo $-' | 16157 | // ash -sc 'echo $-' |
14776 | // continue reading input from stdin after running 'echo'. | 16158 | // continue reading input from stdin after running 'echo'. |
14777 | // bash does not do this: it prints "hBcs" and exits. | 16159 | // bash does not do this: it prints "hBcs" and exits. |
16160 | #if !ENABLE_PLATFORM_MINGW32 | ||
14778 | evalstring(minusc, EV_EXIT); | 16161 | evalstring(minusc, EV_EXIT); |
16162 | #else | ||
16163 | evalstring(minusc, sflag ? 0 : EV_EXIT); | ||
16164 | #endif | ||
14779 | } | 16165 | } |
14780 | 16166 | ||
14781 | if (sflag || minusc == NULL) { | 16167 | if (sflag || minusc == NULL) { |
@@ -14818,6 +16204,960 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14818 | /* NOTREACHED */ | 16204 | /* NOTREACHED */ |
14819 | } | 16205 | } |
14820 | 16206 | ||
16207 | #if ENABLE_PLATFORM_MINGW32 | ||
16208 | static void | ||
16209 | forkshell_openhere(struct forkshell *fs) | ||
16210 | { | ||
16211 | const char *p = fs->path; | ||
16212 | size_t len = strlen(p); | ||
16213 | int pip[2]; | ||
16214 | |||
16215 | pip[0] = fs->fd[0]; | ||
16216 | pip[1] = fs->fd[1]; | ||
16217 | |||
16218 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
16219 | |||
16220 | close(pip[0]); | ||
16221 | ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); | ||
16222 | ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); | ||
16223 | ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); | ||
16224 | ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); | ||
16225 | signal(SIGPIPE, SIG_DFL); | ||
16226 | xwrite(pip[1], p, len); | ||
16227 | _exit_SUCCESS(); | ||
16228 | } | ||
16229 | |||
16230 | static void | ||
16231 | forkshell_evalbackcmd(struct forkshell *fs) | ||
16232 | { | ||
16233 | #if BASH_PROCESS_SUBST | ||
16234 | /* determine end of pipe used by parent (ip) and child (ic) */ | ||
16235 | const int ctl = fs->fd[2]; | ||
16236 | const int ip = (ctl == CTLTOPROC); | ||
16237 | const int ic = !(ctl == CTLTOPROC); | ||
16238 | #else | ||
16239 | const int ip = 0; | ||
16240 | const int ic = 1; | ||
16241 | #endif | ||
16242 | union node *n = fs->n; | ||
16243 | int pip[2]; | ||
16244 | |||
16245 | pip[ip] = fs->fd[ip]; | ||
16246 | pip[ic] = fs->fd[ic]; | ||
16247 | |||
16248 | FORCE_INT_ON; | ||
16249 | close(pip[ip]); | ||
16250 | if (pip[ic] != ic) { | ||
16251 | /*close(ic);*/ | ||
16252 | dup2_or_raise(pip[ic], ic); | ||
16253 | close(pip[ic]); | ||
16254 | } | ||
16255 | eflag = 0; | ||
16256 | ifsfree(); | ||
16257 | evaltreenr(n, EV_EXIT); | ||
16258 | /* NOTREACHED */ | ||
16259 | } | ||
16260 | |||
16261 | static void | ||
16262 | forkshell_evalsubshell(struct forkshell *fs) | ||
16263 | { | ||
16264 | union node *n = fs->n; | ||
16265 | int flags = fs->flags; | ||
16266 | |||
16267 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
16268 | INT_ON; | ||
16269 | flags |= EV_EXIT; | ||
16270 | if (fs->mode) | ||
16271 | flags &= ~EV_TESTED; | ||
16272 | expredir(n->nredir.redirect); | ||
16273 | redirect(n->nredir.redirect, 0); | ||
16274 | evaltreenr(n->nredir.n, flags); | ||
16275 | /* never returns */ | ||
16276 | } | ||
16277 | |||
16278 | static void | ||
16279 | forkshell_evalpipe(struct forkshell *fs) | ||
16280 | { | ||
16281 | union node *n = fs->n; | ||
16282 | int flags = fs->flags; | ||
16283 | int prevfd = fs->fd[2]; | ||
16284 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
16285 | |||
16286 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
16287 | INT_ON; | ||
16288 | if (pip[1] >= 0) { | ||
16289 | close(pip[0]); | ||
16290 | } | ||
16291 | if (prevfd > 0) { | ||
16292 | dup2(prevfd, 0); | ||
16293 | close(prevfd); | ||
16294 | } | ||
16295 | if (pip[1] > 1) { | ||
16296 | dup2(pip[1], 1); | ||
16297 | close(pip[1]); | ||
16298 | } | ||
16299 | evaltreenr(n, flags); | ||
16300 | } | ||
16301 | |||
16302 | static void | ||
16303 | forkshell_shellexec(struct forkshell *fs) | ||
16304 | { | ||
16305 | int idx = fs->fd[0]; | ||
16306 | char **argv = fs->argv; | ||
16307 | char *path = fs->path; | ||
16308 | |||
16309 | FORCE_INT_ON; | ||
16310 | shellexec(argv[0], argv, path, idx); | ||
16311 | } | ||
16312 | |||
16313 | static void | ||
16314 | forkshell_child(struct forkshell *fs) | ||
16315 | { | ||
16316 | switch ( fs->fpid ) { | ||
16317 | case FS_OPENHERE: | ||
16318 | forkshell_openhere(fs); | ||
16319 | break; | ||
16320 | case FS_EVALBACKCMD: | ||
16321 | forkshell_evalbackcmd(fs); | ||
16322 | break; | ||
16323 | case FS_EVALSUBSHELL: | ||
16324 | forkshell_evalsubshell(fs); | ||
16325 | break; | ||
16326 | case FS_EVALPIPE: | ||
16327 | forkshell_evalpipe(fs); | ||
16328 | break; | ||
16329 | case FS_SHELLEXEC: | ||
16330 | forkshell_shellexec(fs); | ||
16331 | break; | ||
16332 | } | ||
16333 | } | ||
16334 | |||
16335 | /* | ||
16336 | * Reinitialise the builtin environment variables in varinit. Their | ||
16337 | * current settings have been copied from the parent in vartab. Look | ||
16338 | * these up using the names from varinit_data, copy the details from | ||
16339 | * vartab to varinit and replace the old copy in vartab with the new | ||
16340 | * one in varinit. | ||
16341 | * | ||
16342 | * Also reinitialise the function pointers and line number variable. | ||
16343 | */ | ||
16344 | static void | ||
16345 | reinitvar(void) | ||
16346 | { | ||
16347 | int i; | ||
16348 | const char *name; | ||
16349 | struct var **vpp, **old; | ||
16350 | |||
16351 | for (i=0; i<ARRAY_SIZE(varinit); ++i) { | ||
16352 | if (i == LINENO_INDEX) | ||
16353 | name = "LINENO="; | ||
16354 | else if (i == FUNCNAME_INDEX) | ||
16355 | name = "FUNCNAME="; | ||
16356 | else | ||
16357 | name = varinit_data[i].var_text; | ||
16358 | vpp = hashvar(name); | ||
16359 | if ( (old=findvar(vpp, name)) != NULL ) { | ||
16360 | varinit[i] = **old; | ||
16361 | *old = varinit+i; | ||
16362 | } | ||
16363 | varinit[i].var_func = varinit_data[i].var_func; | ||
16364 | } | ||
16365 | vlineno.var_text = linenovar; | ||
16366 | vfuncname.var_text = funcnamevar; | ||
16367 | } | ||
16368 | |||
16369 | static void | ||
16370 | spawn_forkshell(struct forkshell *fs, struct job *jp, union node *n, int mode) | ||
16371 | { | ||
16372 | struct forkshell *new; | ||
16373 | char buf[32]; | ||
16374 | const char *argv[] = { "sh", "--fs", NULL, NULL }; | ||
16375 | intptr_t ret; | ||
16376 | |||
16377 | new = forkshell_prepare(fs); | ||
16378 | if (new == NULL) | ||
16379 | goto fail; | ||
16380 | |||
16381 | new->mode = mode; | ||
16382 | new->nprocs = jp == NULL ? 0 : jp->nprocs; | ||
16383 | sprintf(buf, "%p", new->hMapFile); | ||
16384 | argv[2] = buf; | ||
16385 | ret = spawnve(P_NOWAIT, bb_busybox_exec_path, (char *const *)argv, NULL); | ||
16386 | CloseHandle(new->hMapFile); | ||
16387 | UnmapViewOfFile(new); | ||
16388 | if (ret == -1) { | ||
16389 | fail: | ||
16390 | if (jp) | ||
16391 | freejob(jp); | ||
16392 | ash_msg_and_raise_error("unable to spawn shell"); | ||
16393 | } | ||
16394 | forkparent(jp, n, mode, (HANDLE)ret); | ||
16395 | } | ||
16396 | |||
16397 | /* | ||
16398 | * forkshell_prepare() and friends | ||
16399 | * | ||
16400 | * The sequence is as follows: | ||
16401 | * - funcblocksize is initialized | ||
16402 | * - forkshell_size(fs) is called to calculate the exact memory needed | ||
16403 | * - a new struct is allocated | ||
16404 | * - funcblock, funcstring, relocate are initialized from the new block | ||
16405 | * - forkshell_copy(fs) is called to copy recursively everything over | ||
16406 | * it will record all relocations along the way | ||
16407 | * | ||
16408 | * When this memory is mapped elsewhere, pointer fixup will be needed | ||
16409 | */ | ||
16410 | |||
16411 | /* redefine without test that fs_size is nonzero */ | ||
16412 | #undef SAVE_PTR | ||
16413 | #undef SAVE_PTR2 | ||
16414 | #undef SAVE_PTR3 | ||
16415 | #define SAVE_PTR(dst,note,flag) {MARK_PTR(dst,flag); ANNOT(dst,note);} | ||
16416 | |||
16417 | static int align_len(const char *s) | ||
16418 | { | ||
16419 | return s ? SHELL_ALIGN(strlen(s)+1) : 0; | ||
16420 | } | ||
16421 | |||
16422 | struct datasize { | ||
16423 | int funcblocksize; | ||
16424 | int funcstringsize; | ||
16425 | }; | ||
16426 | |||
16427 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
16428 | static struct datasize \ | ||
16429 | name(struct datasize ds, type *p) \ | ||
16430 | { \ | ||
16431 | while (p) { \ | ||
16432 | ds.funcblocksize += sizeof(type); | ||
16433 | /* do something here with p */ | ||
16434 | #define SLIST_SIZE_END() \ | ||
16435 | p = p->next; \ | ||
16436 | } \ | ||
16437 | return ds; \ | ||
16438 | } | ||
16439 | |||
16440 | #define SLIST_COPY_BEGIN(name,type) \ | ||
16441 | static type * \ | ||
16442 | name(type *vp) \ | ||
16443 | { \ | ||
16444 | type *start; \ | ||
16445 | type **vpp; \ | ||
16446 | vpp = &start; \ | ||
16447 | while (vp) { \ | ||
16448 | *vpp = funcblock; \ | ||
16449 | funcblock = (char *) funcblock + sizeof(type); | ||
16450 | /* do something here with vpp and vp */ | ||
16451 | #define SLIST_COPY_END() \ | ||
16452 | SAVE_PTR((*vpp)->next, "(*vpp)->next", NO_FREE); \ | ||
16453 | vp = vp->next; \ | ||
16454 | vpp = &(*vpp)->next; \ | ||
16455 | } \ | ||
16456 | *vpp = NULL; \ | ||
16457 | return start; \ | ||
16458 | } | ||
16459 | |||
16460 | /* | ||
16461 | * struct var | ||
16462 | */ | ||
16463 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
16464 | ds.funcstringsize += align_len(p->var_text); | ||
16465 | SLIST_SIZE_END() | ||
16466 | |||
16467 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
16468 | (*vpp)->var_text = nodeckstrdup(vp->var_text); | ||
16469 | (*vpp)->flags = vp->flags; | ||
16470 | (*vpp)->var_func = NULL; | ||
16471 | SAVE_PTR((*vpp)->var_text, xasprintf("(*vpp)->var_text '%s'", vp->var_text ?: "NULL"), FREE); | ||
16472 | SLIST_COPY_END() | ||
16473 | |||
16474 | /* | ||
16475 | * struct tblentry | ||
16476 | */ | ||
16477 | static struct datasize | ||
16478 | tblentry_size(struct datasize ds, struct tblentry *tep) | ||
16479 | { | ||
16480 | while (tep) { | ||
16481 | ds.funcblocksize += sizeof(struct tblentry) + align_len(tep->cmdname); | ||
16482 | /* CMDBUILTIN, e->param.cmd needs no pointer relocation */ | ||
16483 | if (tep->cmdtype == CMDFUNCTION) { | ||
16484 | ds.funcblocksize += offsetof(struct funcnode, n); | ||
16485 | ds.funcblocksize = calcsize(ds.funcblocksize, &tep->param.func->n); | ||
16486 | } | ||
16487 | tep = tep->next; | ||
16488 | } | ||
16489 | return ds; | ||
16490 | } | ||
16491 | |||
16492 | static struct tblentry * | ||
16493 | tblentry_copy(struct tblentry *tep) | ||
16494 | { | ||
16495 | struct tblentry *start; | ||
16496 | struct tblentry **newp; | ||
16497 | int size; | ||
16498 | |||
16499 | newp = &start; | ||
16500 | while (tep) { | ||
16501 | *newp = funcblock; | ||
16502 | size = sizeof(struct tblentry) + align_len(tep->cmdname); | ||
16503 | |||
16504 | funcblock = (char *) funcblock + size; | ||
16505 | memcpy(*newp, tep, sizeof(struct tblentry)+strlen(tep->cmdname)); | ||
16506 | switch (tep->cmdtype) { | ||
16507 | case CMDBUILTIN: | ||
16508 | /* Save index of builtin, not pointer; fixed by forkshell_init() */ | ||
16509 | (*newp)->param.index = tep->param.cmd - builtintab; | ||
16510 | break; | ||
16511 | case CMDFUNCTION: | ||
16512 | (*newp)->param.func = funcblock; | ||
16513 | funcblock = (char *) funcblock + offsetof(struct funcnode, n); | ||
16514 | copynode(&tep->param.func->n); | ||
16515 | SAVE_PTR((*newp)->param.func, "param.func", NO_FREE); | ||
16516 | break; | ||
16517 | default: | ||
16518 | break; | ||
16519 | } | ||
16520 | SAVE_PTR((*newp)->next, xasprintf("cmdname '%s'", tep->cmdname), FREE); | ||
16521 | tep = tep->next; | ||
16522 | newp = &(*newp)->next; | ||
16523 | } | ||
16524 | *newp = NULL; | ||
16525 | return start; | ||
16526 | } | ||
16527 | |||
16528 | static struct datasize | ||
16529 | cmdtable_size(struct datasize ds) | ||
16530 | { | ||
16531 | int i; | ||
16532 | ds.funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE; | ||
16533 | for (i = 0; i < CMDTABLESIZE; i++) | ||
16534 | ds = tblentry_size(ds, cmdtable[i]); | ||
16535 | return ds; | ||
16536 | } | ||
16537 | |||
16538 | static struct tblentry ** | ||
16539 | cmdtable_copy(void) | ||
16540 | { | ||
16541 | struct tblentry **new = funcblock; | ||
16542 | int i; | ||
16543 | |||
16544 | funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE; | ||
16545 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
16546 | new[i] = tblentry_copy(cmdtable[i]); | ||
16547 | SAVE_PTR(new[i], xasprintf("cmdtable[%d]", i), FREE); | ||
16548 | } | ||
16549 | return new; | ||
16550 | } | ||
16551 | |||
16552 | #if ENABLE_ASH_ALIAS | ||
16553 | /* | ||
16554 | * struct alias | ||
16555 | */ | ||
16556 | SLIST_SIZE_BEGIN(alias_size,struct alias) | ||
16557 | ds.funcstringsize += align_len(p->name); | ||
16558 | ds.funcstringsize += align_len(p->val); | ||
16559 | SLIST_SIZE_END() | ||
16560 | |||
16561 | SLIST_COPY_BEGIN(alias_copy,struct alias) | ||
16562 | (*vpp)->name = nodeckstrdup(vp->name); | ||
16563 | (*vpp)->val = nodeckstrdup(vp->val); | ||
16564 | (*vpp)->flag = vp->flag; | ||
16565 | SAVE_PTR((*vpp)->name, xasprintf("(*vpp)->name '%s'", vp->name ?: "NULL"), FREE); | ||
16566 | SAVE_PTR((*vpp)->val, xasprintf("(*vpp)->val '%s'", vp->val ?: "NULL"), FREE); | ||
16567 | SLIST_COPY_END() | ||
16568 | |||
16569 | static struct datasize | ||
16570 | atab_size(struct datasize ds) | ||
16571 | { | ||
16572 | int i; | ||
16573 | ds.funcblocksize += sizeof(struct alias *)*ATABSIZE; | ||
16574 | for (i = 0; i < ATABSIZE; i++) | ||
16575 | ds = alias_size(ds, atab[i]); | ||
16576 | return ds; | ||
16577 | } | ||
16578 | |||
16579 | static struct alias ** | ||
16580 | atab_copy(void) | ||
16581 | { | ||
16582 | struct alias **new = funcblock; | ||
16583 | int i; | ||
16584 | |||
16585 | funcblock = (char *) funcblock + sizeof(struct alias *)*ATABSIZE; | ||
16586 | for (i = 0; i < ATABSIZE; i++) { | ||
16587 | new[i] = alias_copy(atab[i]); | ||
16588 | SAVE_PTR(new[i], xasprintf("atab[%d]", i), FREE); | ||
16589 | } | ||
16590 | return new; | ||
16591 | } | ||
16592 | #endif | ||
16593 | |||
16594 | /* | ||
16595 | * char ** | ||
16596 | */ | ||
16597 | static struct datasize | ||
16598 | argv_size(struct datasize ds, char **p) | ||
16599 | { | ||
16600 | if (p) { | ||
16601 | while (*p) { | ||
16602 | ds.funcblocksize += sizeof(char *); | ||
16603 | ds.funcstringsize += align_len(*p); | ||
16604 | p++; | ||
16605 | } | ||
16606 | ds.funcblocksize += sizeof(char *); | ||
16607 | } | ||
16608 | return ds; | ||
16609 | } | ||
16610 | |||
16611 | static char ** | ||
16612 | argv_copy(char **p) | ||
16613 | { | ||
16614 | char **new, **start = funcblock; | ||
16615 | #if FORKSHELL_DEBUG | ||
16616 | int i = 0; | ||
16617 | #endif | ||
16618 | |||
16619 | if (p) { | ||
16620 | while (*p) { | ||
16621 | new = funcblock; | ||
16622 | funcblock = (char *) funcblock + sizeof(char *); | ||
16623 | *new = nodeckstrdup(*p); | ||
16624 | SAVE_PTR(*new, xasprintf("argv[%d] '%s'", i++, *p), FREE); | ||
16625 | p++; | ||
16626 | } | ||
16627 | new = funcblock; | ||
16628 | funcblock = (char *) funcblock + sizeof(char *); | ||
16629 | *new = NULL; | ||
16630 | return start; | ||
16631 | } | ||
16632 | return NULL; | ||
16633 | } | ||
16634 | |||
16635 | #if MAX_HISTORY | ||
16636 | static struct datasize | ||
16637 | history_size(struct datasize ds) | ||
16638 | { | ||
16639 | int i; | ||
16640 | line_input_t *st = line_input_state; | ||
16641 | |||
16642 | ds.funcblocksize += sizeof(char *) * st->cnt_history; | ||
16643 | for (i = 0; i < st->cnt_history; i++) { | ||
16644 | ds.funcstringsize += align_len(st->history[i]); | ||
16645 | } | ||
16646 | return ds; | ||
16647 | } | ||
16648 | |||
16649 | static char ** | ||
16650 | history_copy(void) | ||
16651 | { | ||
16652 | line_input_t *st = line_input_state; | ||
16653 | char **new = funcblock; | ||
16654 | int i; | ||
16655 | |||
16656 | funcblock = (char *)funcblock + sizeof(char *) * st->cnt_history; | ||
16657 | for (i = 0; i < st->cnt_history; i++) { | ||
16658 | new[i] = nodeckstrdup(st->history[i]); | ||
16659 | SAVE_PTR(new[i], | ||
16660 | xasprintf("history[%d] '%s'", i, st->history[i]), FREE); | ||
16661 | } | ||
16662 | return new; | ||
16663 | } | ||
16664 | #endif | ||
16665 | |||
16666 | /* | ||
16667 | * struct redirtab | ||
16668 | */ | ||
16669 | static int | ||
16670 | redirtab_size(int funcblocksize, struct redirtab *rdtp) | ||
16671 | { | ||
16672 | while (rdtp) { | ||
16673 | funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
16674 | rdtp = rdtp->next; | ||
16675 | } | ||
16676 | return funcblocksize; | ||
16677 | } | ||
16678 | |||
16679 | static struct redirtab * | ||
16680 | redirtab_copy(struct redirtab *rdtp) | ||
16681 | { | ||
16682 | struct redirtab *start; | ||
16683 | struct redirtab **vpp; | ||
16684 | |||
16685 | vpp = &start; | ||
16686 | while (rdtp) { | ||
16687 | int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
16688 | *vpp = funcblock; | ||
16689 | funcblock = (char *) funcblock + size; | ||
16690 | memcpy(*vpp, rdtp, size); | ||
16691 | SAVE_PTR((*vpp)->next, "(*vpp)->next", NO_FREE); | ||
16692 | rdtp = rdtp->next; | ||
16693 | vpp = &(*vpp)->next; | ||
16694 | } | ||
16695 | *vpp = NULL; | ||
16696 | return start; | ||
16697 | } | ||
16698 | |||
16699 | static struct datasize | ||
16700 | globals_var_size(struct datasize ds) | ||
16701 | { | ||
16702 | int i; | ||
16703 | |||
16704 | ds.funcblocksize += sizeof(struct globals_var); | ||
16705 | ds.funcstringsize += align_len(funcname); | ||
16706 | ds = argv_size(ds, shellparam.p); | ||
16707 | ds.funcblocksize = redirtab_size(ds.funcblocksize, redirlist); | ||
16708 | for (i = 0; i < VTABSIZE; i++) | ||
16709 | ds = var_size(ds, vartab[i]); | ||
16710 | return ds; | ||
16711 | } | ||
16712 | |||
16713 | #undef funcname | ||
16714 | #undef shellparam | ||
16715 | #undef redirlist | ||
16716 | #undef vartab | ||
16717 | static struct globals_var * | ||
16718 | globals_var_copy(void) | ||
16719 | { | ||
16720 | int i; | ||
16721 | struct globals_var *gvp, *new; | ||
16722 | |||
16723 | gvp = ash_ptr_to_globals_var; | ||
16724 | new = funcblock; | ||
16725 | funcblock = (char *) funcblock + sizeof(struct globals_var); | ||
16726 | memcpy(new, gvp, sizeof(struct globals_var)); | ||
16727 | |||
16728 | new->funcname = nodeckstrdup(gvp->funcname); | ||
16729 | SAVE_PTR(new->funcname, xasprintf("funcname '%s'", gvp->funcname ?: "NULL"), FREE); | ||
16730 | |||
16731 | /* shparam */ | ||
16732 | new->shellparam.malloced = 0; | ||
16733 | new->shellparam.p = argv_copy(gvp->shellparam.p); | ||
16734 | SAVE_PTR(new->shellparam.p, "shellparam.p", NO_FREE); | ||
16735 | |||
16736 | new->redirlist = redirtab_copy(gvp->redirlist); | ||
16737 | SAVE_PTR(new->redirlist, "redirlist", NO_FREE); | ||
16738 | |||
16739 | for (i = 0; i < VTABSIZE; i++) { | ||
16740 | new->vartab[i] = var_copy(gvp->vartab[i]); | ||
16741 | SAVE_PTR(new->vartab[i], xasprintf("vartab[%d]", i), FREE); | ||
16742 | } | ||
16743 | |||
16744 | return new; | ||
16745 | } | ||
16746 | |||
16747 | static struct datasize | ||
16748 | globals_misc_size(struct datasize ds) | ||
16749 | { | ||
16750 | ds.funcblocksize += sizeof(struct globals_misc); | ||
16751 | ds.funcstringsize += align_len(minusc); | ||
16752 | if (curdir != nullstr) | ||
16753 | ds.funcstringsize += align_len(curdir); | ||
16754 | if (physdir != nullstr) | ||
16755 | ds.funcstringsize += align_len(physdir); | ||
16756 | ds.funcstringsize += align_len(arg0); | ||
16757 | ds.funcstringsize += align_len(commandname); | ||
16758 | return ds; | ||
16759 | } | ||
16760 | |||
16761 | #undef minusc | ||
16762 | #undef curdir | ||
16763 | #undef physdir | ||
16764 | #undef arg0 | ||
16765 | #undef commandname | ||
16766 | #undef nullstr | ||
16767 | static struct globals_misc * | ||
16768 | globals_misc_copy(void) | ||
16769 | { | ||
16770 | struct globals_misc *p = ash_ptr_to_globals_misc; | ||
16771 | struct globals_misc *new = funcblock; | ||
16772 | |||
16773 | funcblock = (char *) funcblock + sizeof(struct globals_misc); | ||
16774 | memcpy(new, p, sizeof(struct globals_misc)); | ||
16775 | |||
16776 | new->minusc = nodeckstrdup(p->minusc); | ||
16777 | new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr; | ||
16778 | new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr; | ||
16779 | new->arg0 = nodeckstrdup(p->arg0); | ||
16780 | new->commandname = nodeckstrdup(p->commandname); | ||
16781 | SAVE_PTR(new->minusc, xasprintf("minusc '%s'", p->minusc ?: "NULL"), FREE); | ||
16782 | SAVE_PTR(new->curdir, | ||
16783 | xasprintf("curdir '%s'", new->curdir ?: "NULL"), FREE); | ||
16784 | SAVE_PTR(new->physdir, | ||
16785 | xasprintf("physdir '%s'", new->physdir ?: "NULL"), FREE); | ||
16786 | SAVE_PTR(new->arg0, xasprintf("arg0 '%s'", p->arg0 ?: "NULL"), FREE); | ||
16787 | SAVE_PTR(new->commandname, | ||
16788 | xasprintf("commandname '%s'", p->commandname ?: "NULL"), FREE); | ||
16789 | return new; | ||
16790 | } | ||
16791 | |||
16792 | static struct datasize | ||
16793 | forkshell_size(struct forkshell *fs) | ||
16794 | { | ||
16795 | struct datasize ds = {0, 0}; | ||
16796 | |||
16797 | ds.funcstringsize += align_len(fs->path); | ||
16798 | if (fs->fpid == FS_OPENHERE) | ||
16799 | return ds; | ||
16800 | |||
16801 | ds = globals_var_size(ds); | ||
16802 | ds = globals_misc_size(ds); | ||
16803 | ds = cmdtable_size(ds); | ||
16804 | |||
16805 | ds.funcblocksize = calcsize(ds.funcblocksize, fs->n); | ||
16806 | ds = argv_size(ds, fs->argv); | ||
16807 | |||
16808 | if ((ENABLE_ASH_ALIAS || MAX_HISTORY) && fs->fpid != FS_SHELLEXEC) { | ||
16809 | #if ENABLE_ASH_ALIAS | ||
16810 | ds = atab_size(ds); | ||
16811 | #endif | ||
16812 | #if MAX_HISTORY | ||
16813 | if (line_input_state) | ||
16814 | ds = history_size(ds); | ||
16815 | #endif | ||
16816 | } | ||
16817 | return ds; | ||
16818 | } | ||
16819 | |||
16820 | static void | ||
16821 | forkshell_copy(struct forkshell *fs, struct forkshell *new) | ||
16822 | { | ||
16823 | memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */ | ||
16824 | |||
16825 | new->path = nodeckstrdup(fs->path); | ||
16826 | SAVE_PTR(new->path, xasprintf("path '%s'", fs->path ?: "NULL"), FREE); | ||
16827 | if (fs->fpid == FS_OPENHERE) | ||
16828 | return; | ||
16829 | |||
16830 | new->gvp = globals_var_copy(); | ||
16831 | new->gmp = globals_misc_copy(); | ||
16832 | new->cmdtable = cmdtable_copy(); | ||
16833 | SAVE_PTR(new->gvp, "gvp", NO_FREE); | ||
16834 | SAVE_PTR(new->gmp, "gmp", NO_FREE); | ||
16835 | SAVE_PTR(new->cmdtable, "cmdtable", NO_FREE); | ||
16836 | |||
16837 | new->n = copynode(fs->n); | ||
16838 | new->argv = argv_copy(fs->argv); | ||
16839 | SAVE_PTR(new->n, "n", NO_FREE); | ||
16840 | SAVE_PTR(new->argv, "argv", NO_FREE); | ||
16841 | |||
16842 | if ((ENABLE_ASH_ALIAS || MAX_HISTORY) && fs->fpid != FS_SHELLEXEC) { | ||
16843 | #if ENABLE_ASH_ALIAS | ||
16844 | new->atab = atab_copy(); | ||
16845 | SAVE_PTR(new->atab, "atab", NO_FREE); | ||
16846 | #endif | ||
16847 | #if MAX_HISTORY | ||
16848 | if (line_input_state) { | ||
16849 | new->history = history_copy(); | ||
16850 | SAVE_PTR(new->history, "history", NO_FREE); | ||
16851 | new->cnt_history = line_input_state->cnt_history; | ||
16852 | } | ||
16853 | #endif | ||
16854 | } | ||
16855 | } | ||
16856 | |||
16857 | #if FORKSHELL_DEBUG | ||
16858 | /* fp and notes can each be NULL */ | ||
16859 | #define NUM_BLOCKS 7 | ||
16860 | static void | ||
16861 | forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes) | ||
16862 | { | ||
16863 | FILE *fp; | ||
16864 | void *lfuncblock; | ||
16865 | char *lfuncstring; | ||
16866 | char *lrelocate; | ||
16867 | char *s; | ||
16868 | int count, i, total; | ||
16869 | int size[NUM_BLOCKS]; | ||
16870 | char *lptr[NUM_BLOCKS+1]; | ||
16871 | enum {GVP, GMP, CMDTABLE, NODE, ARGV, ATAB, HISTORY, FUNCSTRING}; | ||
16872 | const char *fsname[] = { | ||
16873 | "FS_OPENHERE", | ||
16874 | "FS_EVALBACKCMD", | ||
16875 | "FS_EVALSUBSHELL", | ||
16876 | "FS_EVALPIPE", | ||
16877 | "FS_SHELLEXEC" | ||
16878 | }; | ||
16879 | |||
16880 | if (fp0 != NULL) { | ||
16881 | fp = fp0; | ||
16882 | } | ||
16883 | else { | ||
16884 | char name[64]; | ||
16885 | static int num = 0; | ||
16886 | |||
16887 | sprintf(name, "fs_%d_%03d.out", getpid(), ++num % 100); | ||
16888 | if ((fp=fopen(name, "w")) == NULL) | ||
16889 | return; | ||
16890 | } | ||
16891 | |||
16892 | total = sizeof(struct forkshell) + fs->funcblocksize + | ||
16893 | fs->funcstringsize + fs->relocatesize; | ||
16894 | fprintf(fp, "total size %6d = %d + %d + %d + %d = %d\n", | ||
16895 | fs->size + fs->relocatesize, | ||
16896 | (int)sizeof(struct forkshell), fs->funcblocksize, | ||
16897 | fs->funcstringsize, fs->relocatesize, total); | ||
16898 | |||
16899 | lfuncblock = (char *)(fs + 1); | ||
16900 | lfuncstring = (char *)lfuncblock + fs->funcblocksize; | ||
16901 | lrelocate = (char *)lfuncstring + fs->funcstringsize; | ||
16902 | |||
16903 | /* funcblocksize is zero for FS_OPENHERE */ | ||
16904 | if (fs->funcblocksize != 0) { | ||
16905 | /* Depending on the configuration and the type of forkshell | ||
16906 | * some items may not be present. */ | ||
16907 | lptr[FUNCSTRING] = lfuncstring; | ||
16908 | #if MAX_HISTORY | ||
16909 | lptr[HISTORY] = fs->history ? (char *)fs->history : lptr[FUNCSTRING]; | ||
16910 | #else | ||
16911 | lptr[HISTORY] = lptr[FUNCSTRING]; | ||
16912 | #endif | ||
16913 | lptr[ATAB] = IF_ASH_ALIAS(fs->atab ? (char *)fs->atab :) lptr[HISTORY]; | ||
16914 | lptr[ARGV] = fs->argv ? (char *)fs->argv : lptr[ATAB]; | ||
16915 | lptr[NODE] = fs->n ? (char *)fs->n : lptr[ARGV]; | ||
16916 | lptr[CMDTABLE] = (char *)fs->cmdtable; | ||
16917 | lptr[GMP] = (char *)fs->gmp; | ||
16918 | lptr[GVP] = (char *)fs->gvp; | ||
16919 | |||
16920 | fprintf(fp, "funcblocksize %6d = ", fs->funcblocksize); | ||
16921 | total = 0; | ||
16922 | for (i=0; i<NUM_BLOCKS; ++i) { | ||
16923 | size[i] = (int)(lptr[i+1] - lptr[i]); | ||
16924 | total += size[i]; | ||
16925 | fprintf(fp, "%d %c ", size[i], i == NUM_BLOCKS - 1 ? '=' : '+'); | ||
16926 | } | ||
16927 | fprintf(fp, "%d\n\n", total); | ||
16928 | } | ||
16929 | else { | ||
16930 | fprintf(fp, "\n"); | ||
16931 | } | ||
16932 | |||
16933 | fprintf(fp, "%s\n\n", fsname[fs->fpid]); | ||
16934 | fprintf(fp, "--- relocate ---\n"); | ||
16935 | count = 0; | ||
16936 | for (i = 0; i < fs->relocatesize; ++i) { | ||
16937 | if (lrelocate[i]) { | ||
16938 | char **ptr = (char **)((char *)fs + i); | ||
16939 | fprintf(fp, "%p %p %s\n", ptr, *ptr, | ||
16940 | notes && notes[i] ? notes[i] : ""); | ||
16941 | ++count; | ||
16942 | } | ||
16943 | } | ||
16944 | fprintf(fp, "--- %d relocations ---\n\n", count); | ||
16945 | |||
16946 | fprintf(fp, "--- funcstring ---\n"); | ||
16947 | count = 0; | ||
16948 | s = lfuncstring; | ||
16949 | while (s-lfuncstring < fs->funcstringsize) { | ||
16950 | if (!*s) { | ||
16951 | ++s; | ||
16952 | continue; | ||
16953 | } | ||
16954 | fprintf(fp, "%p '%s'\n", s, s); | ||
16955 | s += strlen(s)+1; | ||
16956 | ++count; | ||
16957 | } | ||
16958 | fprintf(fp, "--- %d strings ---\n", count); | ||
16959 | |||
16960 | if (fp0 == NULL) | ||
16961 | fclose(fp); | ||
16962 | } | ||
16963 | #endif | ||
16964 | |||
16965 | static struct forkshell * | ||
16966 | forkshell_prepare(struct forkshell *fs) | ||
16967 | { | ||
16968 | struct forkshell *new; | ||
16969 | struct datasize ds; | ||
16970 | int size, relocatesize; | ||
16971 | HANDLE h; | ||
16972 | SECURITY_ATTRIBUTES sa; | ||
16973 | #if FORKSHELL_DEBUG | ||
16974 | char *relocate; | ||
16975 | char name[64]; | ||
16976 | FILE *fp; | ||
16977 | static int num = 0; | ||
16978 | #endif | ||
16979 | |||
16980 | /* calculate size of structure, funcblock and funcstring */ | ||
16981 | ds = forkshell_size(fs); | ||
16982 | size = sizeof(struct forkshell) + ds.funcblocksize + ds.funcstringsize; | ||
16983 | relocatesize = sizeof(struct forkshell) + ds.funcblocksize; | ||
16984 | |||
16985 | /* Allocate shared memory region */ | ||
16986 | memset(&sa, 0, sizeof(sa)); | ||
16987 | sa.nLength = sizeof(sa); | ||
16988 | sa.lpSecurityDescriptor = NULL; | ||
16989 | sa.bInheritHandle = TRUE; | ||
16990 | h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, | ||
16991 | size+relocatesize, NULL); | ||
16992 | |||
16993 | /* Initialise pointers */ | ||
16994 | new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
16995 | if (new == NULL) | ||
16996 | return NULL; | ||
16997 | fs_size = size; | ||
16998 | funcblock = (char *)(new + 1); | ||
16999 | funcstring_end = (char *)new + size; | ||
17000 | #if FORKSHELL_DEBUG | ||
17001 | fs_start = new; | ||
17002 | relocate = (char *)new + size; | ||
17003 | annot = (const char **)xzalloc(sizeof(char *)*relocatesize); | ||
17004 | #endif | ||
17005 | |||
17006 | /* Now pack them all */ | ||
17007 | forkshell_copy(fs, new); | ||
17008 | |||
17009 | /* Finish it up */ | ||
17010 | new->size = size; | ||
17011 | new->relocatesize = relocatesize; | ||
17012 | new->old_base = (char *)new; | ||
17013 | new->hMapFile = h; | ||
17014 | #if FORKSHELL_DEBUG | ||
17015 | sprintf(name, "fs_%d_%03d.out", getpid(), ++num % 100); | ||
17016 | if ((fp=fopen(name, "w")) != NULL) { | ||
17017 | int i; | ||
17018 | |||
17019 | new->funcblocksize = (char *)funcblock - (char *)(new + 1); | ||
17020 | new->funcstringsize = (char *)new + size - funcstring_end; | ||
17021 | |||
17022 | /* perform some sanity checks on pointers */ | ||
17023 | fprintf(fp, "forkshell %p %6d\n", new, (int)sizeof(*new)); | ||
17024 | fprintf(fp, "funcblock %p %6d\n", new+1, new->funcblocksize); | ||
17025 | fprintf(fp, "funcstring %p %6d\n", funcstring_end, | ||
17026 | new->funcstringsize); | ||
17027 | if ((char *)funcblock != funcstring_end) | ||
17028 | fprintf(fp, " funcstring != end funcblock + 1 %p\n", funcblock); | ||
17029 | fprintf(fp, "relocate %p %6d\n\n", relocate, new->relocatesize); | ||
17030 | |||
17031 | forkshell_print(fp, new, annot); | ||
17032 | |||
17033 | for (i = 0; i < relocatesize; ++i) { | ||
17034 | /* check relocations are only present for structure and funcblock */ | ||
17035 | if (i >= sizeof(*new)+new->funcblocksize && annot[i] != NULL) { | ||
17036 | fprintf(fp, "\nnon-NULL annotation at offset %d (> %d) %s\n", | ||
17037 | i, (int)sizeof(*new)+new->funcblocksize, annot[i]); | ||
17038 | break; | ||
17039 | } | ||
17040 | if (relocate[i] == FREE) { | ||
17041 | free((void *)annot[i]); | ||
17042 | } | ||
17043 | } | ||
17044 | free(annot); | ||
17045 | annot = NULL; | ||
17046 | fclose(fp); | ||
17047 | } | ||
17048 | #endif | ||
17049 | return new; | ||
17050 | } | ||
17051 | |||
17052 | #undef trap | ||
17053 | #undef trap_ptr | ||
17054 | static void | ||
17055 | forkshell_init(const char *idstr) | ||
17056 | { | ||
17057 | struct forkshell *fs; | ||
17058 | void *map_handle; | ||
17059 | HANDLE h; | ||
17060 | struct globals_var **gvpp; | ||
17061 | struct globals_misc **gmpp; | ||
17062 | int i; | ||
17063 | char **ptr; | ||
17064 | char *lrelocate; | ||
17065 | struct jmploc jmploc; | ||
17066 | |||
17067 | if (sscanf(idstr, "%p", &map_handle) != 1) | ||
17068 | return; | ||
17069 | |||
17070 | h = (HANDLE)map_handle; | ||
17071 | fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
17072 | if (!fs) | ||
17073 | return; | ||
17074 | |||
17075 | /* this memory can't be freed */ | ||
17076 | sticky_mem_start = fs; | ||
17077 | sticky_mem_end = (char *) fs + fs->size; | ||
17078 | |||
17079 | /* pointer fixup */ | ||
17080 | lrelocate = (char *)fs + fs->size; | ||
17081 | for (i = 0; i < fs->relocatesize; i++) { | ||
17082 | if (lrelocate[i]) { | ||
17083 | ptr = (char **)((char *)fs + i); | ||
17084 | if (*ptr) | ||
17085 | *ptr = (char *)fs + (*ptr - fs->old_base); | ||
17086 | } | ||
17087 | } | ||
17088 | |||
17089 | if (fs->fpid == FS_OPENHERE) | ||
17090 | goto end; | ||
17091 | |||
17092 | /* Now fix up stuff that can't be transferred */ | ||
17093 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
17094 | struct tblentry *e = fs->cmdtable[i]; | ||
17095 | while (e) { | ||
17096 | if (e->cmdtype == CMDBUILTIN) | ||
17097 | e->param.cmd = builtintab + e->param.index; | ||
17098 | e = e->next; | ||
17099 | } | ||
17100 | } | ||
17101 | memset(fs->gmp->trap, 0, sizeof(fs->gmp->trap[0])*NSIG); | ||
17102 | /* fs->gmp->trap_ptr = fs->gmp->trap; */ | ||
17103 | |||
17104 | /* Set global variables */ | ||
17105 | gvpp = (struct globals_var **)&ash_ptr_to_globals_var; | ||
17106 | *gvpp = fs->gvp; | ||
17107 | gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc; | ||
17108 | *gmpp = fs->gmp; | ||
17109 | cmdtable = fs->cmdtable; | ||
17110 | #if ENABLE_ASH_ALIAS | ||
17111 | atab = fs->atab; /* will be NULL for FS_SHELLEXEC */ | ||
17112 | #endif | ||
17113 | #if MAX_HISTORY | ||
17114 | if (fs->cnt_history) { | ||
17115 | line_input_state = new_line_input_t(FOR_SHELL); | ||
17116 | line_input_state->cnt_history = fs->cnt_history; | ||
17117 | for (i = 0; i < line_input_state->cnt_history; i++) | ||
17118 | line_input_state->history[i] = fs->history[i]; | ||
17119 | } | ||
17120 | #endif | ||
17121 | |||
17122 | CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */ | ||
17123 | |||
17124 | reinitvar(); | ||
17125 | |||
17126 | if (setjmp(jmploc.loc)) { | ||
17127 | exitreset(); | ||
17128 | exitshell(); | ||
17129 | } | ||
17130 | exception_handler = &jmploc; | ||
17131 | |||
17132 | shlvl++; | ||
17133 | if (fs->mode == FORK_BG) { | ||
17134 | SetConsoleCtrlHandler(NULL, TRUE); | ||
17135 | if (fs->nprocs == 0) { | ||
17136 | close(0); | ||
17137 | if (open(bb_dev_null, O_RDONLY) != 0) | ||
17138 | ash_msg_and_raise_perror("can't open '%s'", bb_dev_null); | ||
17139 | } | ||
17140 | } | ||
17141 | else { | ||
17142 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
17143 | } | ||
17144 | #if JOBS_WIN32 | ||
17145 | /* do job control only in root shell */ | ||
17146 | doing_jobctl = 0; | ||
17147 | #endif | ||
17148 | end: | ||
17149 | forkshell_child(fs); | ||
17150 | } | ||
17151 | |||
17152 | #undef free | ||
17153 | static void | ||
17154 | sticky_free(void *base) | ||
17155 | { | ||
17156 | if (base >= sticky_mem_start && base < sticky_mem_end) | ||
17157 | return; | ||
17158 | free(base); | ||
17159 | } | ||
17160 | #endif | ||
14821 | 17161 | ||
14822 | /*- | 17162 | /*- |
14823 | * Copyright (c) 1989, 1991, 1993, 1994 | 17163 | * Copyright (c) 1989, 1991, 1993, 1994 |
diff --git a/shell/math.h b/shell/math.h index 41ef6e8df..a3fe51b6b 100644 --- a/shell/math.h +++ b/shell/math.h | |||
@@ -65,7 +65,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN | |||
65 | 65 | ||
66 | #if ENABLE_FEATURE_SH_MATH_64 | 66 | #if ENABLE_FEATURE_SH_MATH_64 |
67 | typedef long long arith_t; | 67 | typedef long long arith_t; |
68 | # define ARITH_FMT "%lld" | 68 | #define ARITH_FMT "%"LL_FMT"d" |
69 | #else | 69 | #else |
70 | typedef long arith_t; | 70 | typedef long arith_t; |
71 | # define ARITH_FMT "%ld" | 71 | # define ARITH_FMT "%ld" |
diff --git a/shell/random.c b/shell/random.c index 56c7c5a3c..ffe0cc937 100644 --- a/shell/random.c +++ b/shell/random.c | |||
@@ -19,6 +19,17 @@ | |||
19 | # include "random.h" | 19 | # include "random.h" |
20 | # define RAND_BASH_MASK 0x7fff | 20 | # define RAND_BASH_MASK 0x7fff |
21 | 21 | ||
22 | # if ENABLE_FEATURE_PRNG_SHELL | ||
23 | uint32_t FAST_FUNC | ||
24 | next_random(random_t *rnd) | ||
25 | { | ||
26 | return full_random(rnd) & RAND_BASH_MASK; | ||
27 | } | ||
28 | # undef RAND_BASH_MASK | ||
29 | # define RAND_BASH_MASK 0xffffffff | ||
30 | # define next_random full_random | ||
31 | # endif | ||
32 | |||
22 | #else | 33 | #else |
23 | # include <stdint.h> | 34 | # include <stdint.h> |
24 | # include <unistd.h> | 35 | # include <unistd.h> |
diff --git a/shell/random.h b/shell/random.h index c4eb44c13..75fe0f69f 100644 --- a/shell/random.h +++ b/shell/random.h | |||
@@ -35,6 +35,9 @@ typedef struct random_t { | |||
35 | ((rnd)->galois_LFSR = 0) | 35 | ((rnd)->galois_LFSR = 0) |
36 | 36 | ||
37 | uint32_t next_random(random_t *rnd) FAST_FUNC; | 37 | uint32_t next_random(random_t *rnd) FAST_FUNC; |
38 | #if ENABLE_FEATURE_PRNG_SHELL | ||
39 | uint32_t full_random(random_t *rnd) FAST_FUNC; | ||
40 | #endif | ||
38 | 41 | ||
39 | POP_SAVED_FUNCTION_VISIBILITY | 42 | POP_SAVED_FUNCTION_VISIBILITY |
40 | 43 | ||
diff --git a/shell/shell_common.c b/shell/shell_common.c index 13163acdf..716d3aebb 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c | |||
@@ -43,7 +43,9 @@ shell_builtin_read(struct builtin_read_params *params) | |||
43 | char **pp; | 43 | char **pp; |
44 | char *buffer; | 44 | char *buffer; |
45 | char delim; | 45 | char delim; |
46 | #if !ENABLE_PLATFORM_MINGW32 | ||
46 | struct termios tty, old_tty; | 47 | struct termios tty, old_tty; |
48 | #endif | ||
47 | const char *retval; | 49 | const char *retval; |
48 | int bufpos; /* need to be able to hold -1 */ | 50 | int bufpos; /* need to be able to hold -1 */ |
49 | int startword; | 51 | int startword; |
@@ -139,6 +141,7 @@ shell_builtin_read(struct builtin_read_params *params) | |||
139 | ifs = defifs; | 141 | ifs = defifs; |
140 | 142 | ||
141 | read_flags = params->read_flags; | 143 | read_flags = params->read_flags; |
144 | #if !ENABLE_PLATFORM_MINGW32 | ||
142 | if (nchars || (read_flags & BUILTIN_READ_SILENT)) { | 145 | if (nchars || (read_flags & BUILTIN_READ_SILENT)) { |
143 | tcgetattr(fd, &tty); | 146 | tcgetattr(fd, &tty); |
144 | old_tty = tty; | 147 | old_tty = tty; |
@@ -161,6 +164,7 @@ shell_builtin_read(struct builtin_read_params *params) | |||
161 | * Ignoring, it's harmless. */ | 164 | * Ignoring, it's harmless. */ |
162 | tcsetattr(fd, TCSANOW, &tty); | 165 | tcsetattr(fd, TCSANOW, &tty); |
163 | } | 166 | } |
167 | #endif | ||
164 | 168 | ||
165 | retval = (const char *)(uintptr_t)0; | 169 | retval = (const char *)(uintptr_t)0; |
166 | startword = 1; | 170 | startword = 1; |
@@ -177,6 +181,7 @@ shell_builtin_read(struct builtin_read_params *params) | |||
177 | if ((bufpos & 0xff) == 0) | 181 | if ((bufpos & 0xff) == 0) |
178 | buffer = xrealloc(buffer, bufpos + 0x101); | 182 | buffer = xrealloc(buffer, bufpos + 0x101); |
179 | 183 | ||
184 | IF_PLATFORM_MINGW32(loop:) | ||
180 | timeout = -1; | 185 | timeout = -1; |
181 | if (params->opt_t) { | 186 | if (params->opt_t) { |
182 | timeout = end_ms - (unsigned)monotonic_ms(); | 187 | timeout = end_ms - (unsigned)monotonic_ms(); |
@@ -190,6 +195,7 @@ shell_builtin_read(struct builtin_read_params *params) | |||
190 | } | 195 | } |
191 | } | 196 | } |
192 | 197 | ||
198 | #if !ENABLE_PLATFORM_MINGW32 | ||
193 | /* We must poll even if timeout is -1: | 199 | /* We must poll even if timeout is -1: |
194 | * we want to be interrupted if signal arrives, | 200 | * we want to be interrupted if signal arrives, |
195 | * regardless of SA_RESTART-ness of that signal! | 201 | * regardless of SA_RESTART-ness of that signal! |
@@ -208,10 +214,73 @@ shell_builtin_read(struct builtin_read_params *params) | |||
208 | retval = (const char *)(uintptr_t)1; | 214 | retval = (const char *)(uintptr_t)1; |
209 | break; | 215 | break; |
210 | } | 216 | } |
217 | #else | ||
218 | errno = 0; | ||
219 | if (isatty(fd)) { | ||
220 | int64_t key; | ||
221 | |||
222 | key = windows_read_key(fd, NULL, timeout); | ||
223 | if (key == 0x03) { | ||
224 | /* ^C pressed */ | ||
225 | retval = (const char *)(uintptr_t)2; | ||
226 | goto ret; | ||
227 | } | ||
228 | else if (key == -1 || (key == 0x1a && bufpos == 0)) { | ||
229 | /* timeout or ^Z at start of buffer */ | ||
230 | retval = (const char *)(uintptr_t)1; | ||
231 | goto ret; | ||
232 | } | ||
233 | else if (key == '\b') { | ||
234 | if (bufpos > 0) { | ||
235 | --bufpos; | ||
236 | ++nchars; | ||
237 | if (!(read_flags & BUILTIN_READ_SILENT)) { | ||
238 | printf("\b \b"); | ||
239 | } | ||
240 | } | ||
241 | goto loop; | ||
242 | } | ||
243 | buffer[bufpos] = key == '\r' ? '\n' : key; | ||
244 | if (!(read_flags & BUILTIN_READ_SILENT)) { | ||
245 | /* echo input if not in silent mode */ | ||
246 | putchar(buffer[bufpos]); | ||
247 | } | ||
248 | } | ||
249 | else { | ||
250 | if (read(fd, &buffer[bufpos], 1) != 1) { | ||
251 | err = errno; | ||
252 | retval = (const char *)(uintptr_t)1; | ||
253 | break; | ||
254 | } | ||
255 | } | ||
256 | #endif | ||
211 | 257 | ||
212 | c = buffer[bufpos]; | 258 | c = buffer[bufpos]; |
259 | #if ENABLE_PLATFORM_MINGW32 | ||
260 | if (c == '\n') { | ||
261 | if (backslash == 2 || (bufpos > 0 && buffer[bufpos - 1] == '\r')) { | ||
262 | /* We saw either: | ||
263 | * - BS CR LF: remove CR, fall through to ignore escaped LF | ||
264 | * and exit BS context. | ||
265 | * - CR LF not in BS context: replace CR with LF */ | ||
266 | buffer[--bufpos] = c; | ||
267 | ++nchars; | ||
268 | } | ||
269 | } else if (backslash == 2) { | ||
270 | /* We saw BS CR ??, keep escaped CR, exit BS context, | ||
271 | * process ?? */ | ||
272 | backslash = 0; | ||
273 | } | ||
274 | #endif | ||
213 | if (!(read_flags & BUILTIN_READ_RAW)) { | 275 | if (!(read_flags & BUILTIN_READ_RAW)) { |
214 | if (backslash) { | 276 | if (backslash) { |
277 | #if ENABLE_PLATFORM_MINGW32 | ||
278 | if (c == '\r') { | ||
279 | /* We have BS CR, keep CR for now, might see LF next */ | ||
280 | backslash = 2; | ||
281 | goto put; | ||
282 | } | ||
283 | #endif | ||
215 | backslash = 0; | 284 | backslash = 0; |
216 | if (c != '\n') | 285 | if (c != '\n') |
217 | goto put; | 286 | goto put; |
@@ -310,8 +379,10 @@ shell_builtin_read(struct builtin_read_params *params) | |||
310 | 379 | ||
311 | ret: | 380 | ret: |
312 | free(buffer); | 381 | free(buffer); |
382 | #if !ENABLE_PLATFORM_MINGW32 | ||
313 | if (read_flags & BUILTIN_READ_SILENT) | 383 | if (read_flags & BUILTIN_READ_SILENT) |
314 | tcsetattr(fd, TCSANOW, &old_tty); | 384 | tcsetattr(fd, TCSANOW, &old_tty); |
385 | #endif | ||
315 | 386 | ||
316 | errno = err; | 387 | errno = err; |
317 | return retval; | 388 | return retval; |
@@ -320,6 +391,7 @@ shell_builtin_read(struct builtin_read_params *params) | |||
320 | 391 | ||
321 | /* ulimit builtin */ | 392 | /* ulimit builtin */ |
322 | 393 | ||
394 | #if !ENABLE_PLATFORM_MINGW32 | ||
323 | struct limits { | 395 | struct limits { |
324 | uint8_t cmd; /* RLIMIT_xxx fit into it */ | 396 | uint8_t cmd; /* RLIMIT_xxx fit into it */ |
325 | uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ | 397 | uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ |
@@ -688,3 +760,9 @@ shell_builtin_ulimit(char **argv) | |||
688 | 760 | ||
689 | return EXIT_SUCCESS; | 761 | return EXIT_SUCCESS; |
690 | } | 762 | } |
763 | #else | ||
764 | int FAST_FUNC shell_builtin_ulimit(char **argv UNUSED_PARAM) | ||
765 | { | ||
766 | return 1; | ||
767 | } | ||
768 | #endif | ||