diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 2789 |
1 files changed, 2748 insertions, 41 deletions
diff --git a/shell/ash.c b/shell/ash.c index 9173b8608..3919118f0 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -15,6 +15,20 @@ | |||
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 | */ | ||
31 | |||
18 | //config:config SHELL_ASH | 32 | //config:config SHELL_ASH |
19 | //config: bool #hidden option | 33 | //config: bool #hidden option |
20 | //config: depends on !NOMMU | 34 | //config: depends on !NOMMU |
@@ -170,11 +184,36 @@ | |||
170 | //config: you to run the specified command or builtin, | 184 | //config: you to run the specified command or builtin, |
171 | //config: even when there is a function with the same name. | 185 | //config: even when there is a function with the same name. |
172 | //config: | 186 | //config: |
187 | //config: | ||
188 | //config:config ASH_NOCONSOLE | ||
189 | //config: bool "'noconsole' option" | ||
190 | //config: default y | ||
191 | //config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32 | ||
192 | //config: help | ||
193 | //config: Enable support for the 'noconsole' option, which attempts to | ||
194 | //config: conceal the console normally associated with a command line | ||
195 | //config: application. This may be useful when running a shell script | ||
196 | //config: from a GUI application. Also the 'noiconify' option, which | ||
197 | //config: controls whether the console is iconified or hidden. | ||
198 | //config: | ||
199 | //config:config ASH_GLOB_OPTIONS | ||
200 | //config: bool "Globbing options" | ||
201 | //config: default y | ||
202 | //config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32 | ||
203 | //config: help | ||
204 | //config: Enable support for options to control globbing: | ||
205 | //config: - 'nocaseglob' allows case-insensitive filename globbing | ||
206 | //config: - 'nohiddenglob' allows hidden files to be omitted from globbing | ||
207 | //config: - 'nohidsysglob' allows hidden system files to be omitted | ||
208 | //config: | ||
173 | //config:endif # ash options | 209 | //config:endif # ash options |
174 | 210 | ||
175 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) | 211 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) |
176 | // APPLET_ODDNAME:name main location suid_type help | 212 | // APPLET_ODDNAME:name main location suid_type help |
177 | //applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) | 213 | //applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) |
214 | //applet:IF_PLATFORM_MINGW32( | ||
215 | //applet:IF_SH_IS_ASH( APPLET_ODDNAME(lash, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) | ||
216 | //applet:) | ||
178 | //applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) | 217 | //applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) |
179 | 218 | ||
180 | //kbuild:lib-$(CONFIG_SHELL_ASH) += ash.o ash_ptr_hack.o shell_common.o | 219 | //kbuild:lib-$(CONFIG_SHELL_ASH) += ash.o ash_ptr_hack.o shell_common.o |
@@ -195,7 +234,17 @@ | |||
195 | 234 | ||
196 | #define PROFILE 0 | 235 | #define PROFILE 0 |
197 | 236 | ||
237 | /* | ||
238 | * Only one of JOBS or JOBS_WIN32 is enabled at a time (or neither). | ||
239 | * JOBS_WIN32 doesn't enable job control, just some job-related features. | ||
240 | */ | ||
241 | #if ENABLE_PLATFORM_MINGW32 | ||
242 | #define JOBS_WIN32 ENABLE_ASH_JOB_CONTROL | ||
243 | #define JOBS 0 | ||
244 | #else | ||
245 | #define JOBS_WIN32 0 | ||
198 | #define JOBS ENABLE_ASH_JOB_CONTROL | 246 | #define JOBS ENABLE_ASH_JOB_CONTROL |
247 | #endif | ||
199 | 248 | ||
200 | #include <fnmatch.h> | 249 | #include <fnmatch.h> |
201 | #include <sys/times.h> | 250 | #include <sys/times.h> |
@@ -206,6 +255,10 @@ | |||
206 | #else | 255 | #else |
207 | # define NUM_SCRIPTS 0 | 256 | # define NUM_SCRIPTS 0 |
208 | #endif | 257 | #endif |
258 | #if ENABLE_PLATFORM_MINGW32 | ||
259 | # include <conio.h> | ||
260 | # include "lazyload.h" | ||
261 | #endif | ||
209 | 262 | ||
210 | /* So far, all bash compat is controlled by one config option */ | 263 | /* So far, all bash compat is controlled by one config option */ |
211 | /* Separate defines document which part of code implements what */ | 264 | /* Separate defines document which part of code implements what */ |
@@ -316,10 +369,89 @@ typedef long arith_t; | |||
316 | # define unlikely(cond) (cond) | 369 | # define unlikely(cond) (cond) |
317 | #endif | 370 | #endif |
318 | 371 | ||
372 | #if !ENABLE_PLATFORM_MINGW32 | ||
373 | # define is_relative_path(path) ((path)[0] != '/') | ||
374 | #endif | ||
375 | |||
319 | #if !BB_MMU | 376 | #if !BB_MMU |
320 | # error "Do not even bother, ash will not run on NOMMU machine" | 377 | # error "Do not even bother, ash will not run on NOMMU machine" |
321 | #endif | 378 | #endif |
322 | 379 | ||
380 | #if ENABLE_PLATFORM_MINGW32 | ||
381 | # define FORKSHELL_DEBUG 0 | ||
382 | |||
383 | union node; | ||
384 | struct strlist; | ||
385 | struct job; | ||
386 | |||
387 | struct forkshell { | ||
388 | /* filled by forkshell_copy() */ | ||
389 | struct globals_var *gvp; | ||
390 | struct globals_misc *gmp; | ||
391 | struct tblentry **cmdtable; | ||
392 | #if ENABLE_ASH_ALIAS | ||
393 | struct alias **atab; | ||
394 | #endif | ||
395 | #if MAX_HISTORY | ||
396 | char **history; | ||
397 | int cnt_history; | ||
398 | #endif | ||
399 | #if JOBS_WIN32 | ||
400 | struct job *jobtab; | ||
401 | unsigned njobs; | ||
402 | struct job *curjob; | ||
403 | #endif | ||
404 | /* struct parsefile *g_parsefile; */ | ||
405 | HANDLE hMapFile; | ||
406 | char *old_base; | ||
407 | int size; | ||
408 | # if FORKSHELL_DEBUG | ||
409 | int funcblocksize; | ||
410 | int funcstringsize; | ||
411 | # endif | ||
412 | int relocatesize; | ||
413 | |||
414 | /* type of forkshell */ | ||
415 | int fpid; | ||
416 | |||
417 | /* generic data, used by forkshell_child */ | ||
418 | int mode; | ||
419 | int nprocs; | ||
420 | #if JOBS_WIN32 | ||
421 | int jpnull; | ||
422 | #endif | ||
423 | |||
424 | /* optional data, used by forkshell_child */ | ||
425 | int flags; | ||
426 | int fd[3]; | ||
427 | union node *n; | ||
428 | char **argv; | ||
429 | char *path; | ||
430 | }; | ||
431 | |||
432 | enum { | ||
433 | FS_OPENHERE, | ||
434 | FS_EVALBACKCMD, | ||
435 | FS_EVALSUBSHELL, | ||
436 | FS_EVALPIPE, | ||
437 | FS_SHELLEXEC | ||
438 | }; | ||
439 | |||
440 | static struct forkshell* forkshell_prepare(struct forkshell *fs); | ||
441 | static void forkshell_init(const char *idstr); | ||
442 | static void *sticky_mem_start, *sticky_mem_end; | ||
443 | static void sticky_free(void *p); | ||
444 | # define free(p) sticky_free(p) | ||
445 | #if !JOBS && !JOBS_WIN32 | ||
446 | #define spawn_forkshell(fs, jp, n, mode) spawn_forkshell(fs, jp, mode) | ||
447 | #endif | ||
448 | static void spawn_forkshell(struct forkshell *fs, struct job *jp, | ||
449 | union node *n, int mode); | ||
450 | # if FORKSHELL_DEBUG | ||
451 | static void forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes); | ||
452 | # endif | ||
453 | #endif | ||
454 | |||
323 | /* ============ Hash table sizes. Configurable. */ | 455 | /* ============ Hash table sizes. Configurable. */ |
324 | 456 | ||
325 | #define VTABSIZE 39 | 457 | #define VTABSIZE 39 |
@@ -347,7 +479,11 @@ static const char *const optletters_optnames[] ALIGN_PTR = { | |||
347 | "m" "monitor", | 479 | "m" "monitor", |
348 | "n" "noexec", | 480 | "n" "noexec", |
349 | /* Ditto: bash has no "set -s", "set -c" */ | 481 | /* Ditto: bash has no "set -s", "set -c" */ |
482 | #if !ENABLE_PLATFORM_MINGW32 | ||
350 | "s" "", | 483 | "s" "", |
484 | #else | ||
485 | "s" "stdin", | ||
486 | #endif | ||
351 | "c" "", | 487 | "c" "", |
352 | "x" "xtrace", | 488 | "x" "xtrace", |
353 | "v" "verbose", | 489 | "v" "verbose", |
@@ -364,6 +500,18 @@ static const char *const optletters_optnames[] ALIGN_PTR = { | |||
364 | ,"\0" "nolog" | 500 | ,"\0" "nolog" |
365 | ,"\0" "debug" | 501 | ,"\0" "debug" |
366 | #endif | 502 | #endif |
503 | #if ENABLE_PLATFORM_MINGW32 | ||
504 | ,"X" "winxp" | ||
505 | #endif | ||
506 | #if ENABLE_ASH_NOCONSOLE | ||
507 | ,"\0" "noconsole" | ||
508 | ,"\0" "noiconify" | ||
509 | #endif | ||
510 | #if ENABLE_ASH_GLOB_OPTIONS | ||
511 | ,"\0" "nocaseglob" | ||
512 | ,"\0" "nohiddenglob" | ||
513 | ,"\0" "nohidsysglob" | ||
514 | #endif | ||
367 | }; | 515 | }; |
368 | //bash 4.4.23 also has these opts (with these defaults): | 516 | //bash 4.4.23 also has these opts (with these defaults): |
369 | //braceexpand on | 517 | //braceexpand on |
@@ -406,21 +554,36 @@ struct jmploc { | |||
406 | struct globals_misc { | 554 | struct globals_misc { |
407 | uint8_t exitstatus; /* exit status of last command */ | 555 | uint8_t exitstatus; /* exit status of last command */ |
408 | uint8_t back_exitstatus;/* exit status of backquoted command */ | 556 | uint8_t back_exitstatus;/* exit status of backquoted command */ |
557 | #if !ENABLE_PLATFORM_MINGW32 | ||
409 | smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ | 558 | smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ |
559 | #endif | ||
410 | smallint inps4; /* Prevent PS4 nesting. */ | 560 | smallint inps4; /* Prevent PS4 nesting. */ |
411 | int savestatus; /* exit status of last command outside traps */ | 561 | int savestatus; /* exit status of last command outside traps */ |
412 | int rootpid; /* pid of main shell */ | 562 | int rootpid; /* pid of main shell */ |
413 | /* shell level: 0 for the main shell, 1 for its children, and so on */ | 563 | /* shell level: 0 for the main shell, 1 for its children, and so on */ |
414 | int shlvl; | 564 | int shlvl; |
565 | #if ENABLE_PLATFORM_MINGW32 | ||
566 | int loopnest; /* current loop nesting level */ | ||
567 | #endif | ||
415 | #define rootshell (!shlvl) | 568 | #define rootshell (!shlvl) |
416 | int errlinno; | 569 | int errlinno; |
417 | 570 | ||
418 | char *minusc; /* argument to -c option */ | 571 | char *minusc; /* argument to -c option */ |
572 | #if ENABLE_PLATFORM_MINGW32 | ||
573 | char *dirarg; /* argument to -d option */ | ||
574 | char *title; /* argument to -t option */ | ||
575 | #if ENABLE_SUW32 | ||
576 | int delayexit; /* set by -N option */ | ||
577 | # endif | ||
578 | #endif | ||
419 | 579 | ||
420 | char *curdir; // = nullstr; /* current working directory */ | 580 | char *curdir; // = nullstr; /* current working directory */ |
421 | char *physdir; // = nullstr; /* physical working directory */ | 581 | char *physdir; // = nullstr; /* physical working directory */ |
422 | 582 | ||
423 | char *arg0; /* value of $0 */ | 583 | char *arg0; /* value of $0 */ |
584 | #if ENABLE_PLATFORM_MINGW32 | ||
585 | char *commandname; | ||
586 | #endif | ||
424 | 587 | ||
425 | struct jmploc *exception_handler; | 588 | struct jmploc *exception_handler; |
426 | 589 | ||
@@ -431,8 +594,10 @@ struct globals_misc { | |||
431 | * but we do read it async. | 594 | * but we do read it async. |
432 | */ | 595 | */ |
433 | volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ | 596 | volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ |
597 | #if !ENABLE_PLATFORM_MINGW32 | ||
434 | volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */ | 598 | volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */ |
435 | volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */ | 599 | volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */ |
600 | #endif | ||
436 | smallint exception_type; /* kind of exception: */ | 601 | smallint exception_type; /* kind of exception: */ |
437 | #define EXINT 0 /* SIGINT received */ | 602 | #define EXINT 0 /* SIGINT received */ |
438 | #define EXERROR 1 /* a generic error */ | 603 | #define EXERROR 1 /* a generic error */ |
@@ -467,8 +632,21 @@ struct globals_misc { | |||
467 | # define nolog optlist[16 + BASH_PIPEFAIL] | 632 | # define nolog optlist[16 + BASH_PIPEFAIL] |
468 | # define debug optlist[17 + BASH_PIPEFAIL] | 633 | # define debug optlist[17 + BASH_PIPEFAIL] |
469 | #endif | 634 | #endif |
635 | #if ENABLE_PLATFORM_MINGW32 | ||
636 | # define winxp optlist[16 + BASH_PIPEFAIL + 2*(DEBUG != 0)] | ||
637 | # if ENABLE_ASH_NOCONSOLE | ||
638 | # define noconsole optlist[17 + BASH_PIPEFAIL + 2*(DEBUG != 0)] | ||
639 | # define noiconify optlist[18 + BASH_PIPEFAIL + 2*(DEBUG != 0)] | ||
640 | # endif | ||
641 | # if ENABLE_ASH_GLOB_OPTIONS | ||
642 | # define nocaseglob optlist[17 + BASH_PIPEFAIL + 2*(DEBUG != 0) + 2*ENABLE_ASH_NOCONSOLE] | ||
643 | # define nohiddenglob optlist[18 + BASH_PIPEFAIL + 2*(DEBUG != 0) + 2*ENABLE_ASH_NOCONSOLE] | ||
644 | # define nohidsysglob optlist[19 + BASH_PIPEFAIL + 2*(DEBUG != 0) + 2*ENABLE_ASH_NOCONSOLE] | ||
645 | # endif | ||
646 | #endif | ||
470 | 647 | ||
471 | /* trap handler commands */ | 648 | /* trap handler commands */ |
649 | #if !ENABLE_PLATFORM_MINGW32 | ||
472 | /* | 650 | /* |
473 | * Sigmode records the current value of the signal handlers for the various | 651 | * Sigmode records the current value of the signal handlers for the various |
474 | * modes. A value of zero means that the current handler is not known. | 652 | * modes. A value of zero means that the current handler is not known. |
@@ -482,6 +660,7 @@ struct globals_misc { | |||
482 | 660 | ||
483 | /* indicates specified signal received */ | 661 | /* indicates specified signal received */ |
484 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ | 662 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ |
663 | #endif | ||
485 | uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ | 664 | uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ |
486 | char *trap[NSIG + 1]; | 665 | char *trap[NSIG + 1]; |
487 | /* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */ | 666 | /* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */ |
@@ -510,10 +689,21 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
510 | #define rootpid (G_misc.rootpid ) | 689 | #define rootpid (G_misc.rootpid ) |
511 | #define shlvl (G_misc.shlvl ) | 690 | #define shlvl (G_misc.shlvl ) |
512 | #define errlinno (G_misc.errlinno ) | 691 | #define errlinno (G_misc.errlinno ) |
692 | #if ENABLE_PLATFORM_MINGW32 | ||
693 | #define loopnest (G_misc.loopnest ) | ||
694 | #endif | ||
513 | #define minusc (G_misc.minusc ) | 695 | #define minusc (G_misc.minusc ) |
696 | #if ENABLE_PLATFORM_MINGW32 | ||
697 | #define dirarg (G_misc.dirarg ) | ||
698 | #define title (G_misc.title ) | ||
699 | #define delayexit (G_misc.delayexit ) | ||
700 | #endif | ||
514 | #define curdir (G_misc.curdir ) | 701 | #define curdir (G_misc.curdir ) |
515 | #define physdir (G_misc.physdir ) | 702 | #define physdir (G_misc.physdir ) |
516 | #define arg0 (G_misc.arg0 ) | 703 | #define arg0 (G_misc.arg0 ) |
704 | #if ENABLE_PLATFORM_MINGW32 | ||
705 | #define commandname (G_misc.commandname) | ||
706 | #endif | ||
517 | #define exception_handler (G_misc.exception_handler) | 707 | #define exception_handler (G_misc.exception_handler) |
518 | #define exception_type (G_misc.exception_type ) | 708 | #define exception_type (G_misc.exception_type ) |
519 | #define suppress_int (G_misc.suppress_int ) | 709 | #define suppress_int (G_misc.suppress_int ) |
@@ -530,6 +720,13 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
530 | #define groupinfo (G_misc.groupinfo ) | 720 | #define groupinfo (G_misc.groupinfo ) |
531 | #define random_gen (G_misc.random_gen ) | 721 | #define random_gen (G_misc.random_gen ) |
532 | #define backgndpid (G_misc.backgndpid ) | 722 | #define backgndpid (G_misc.backgndpid ) |
723 | |||
724 | #if ENABLE_PLATFORM_MINGW32 | ||
725 | #undef got_sigchld | ||
726 | #undef pending_sig | ||
727 | #define pending_sig (0) | ||
728 | #endif | ||
729 | |||
533 | #define INIT_G_misc() do { \ | 730 | #define INIT_G_misc() do { \ |
534 | XZALLOC_CONST_PTR(&ash_ptr_to_globals_misc, sizeof(G_misc)); \ | 731 | XZALLOC_CONST_PTR(&ash_ptr_to_globals_misc, sizeof(G_misc)); \ |
535 | savestatus = -1; \ | 732 | savestatus = -1; \ |
@@ -547,6 +744,9 @@ static void trace_printf(const char *fmt, ...); | |||
547 | static void trace_vprintf(const char *fmt, va_list va); | 744 | static void trace_vprintf(const char *fmt, va_list va); |
548 | # define TRACE(param) trace_printf param | 745 | # define TRACE(param) trace_printf param |
549 | # define TRACEV(param) trace_vprintf param | 746 | # define TRACEV(param) trace_vprintf param |
747 | # if ENABLE_PLATFORM_MINGW32 && defined(close) | ||
748 | # undef close | ||
749 | # endif | ||
550 | # define close(fd) do { \ | 750 | # define close(fd) do { \ |
551 | int dfd = (fd); \ | 751 | int dfd = (fd); \ |
552 | if (close(dfd) < 0) \ | 752 | if (close(dfd) < 0) \ |
@@ -635,11 +835,18 @@ struct parsefile { | |||
635 | 835 | ||
636 | /* Number of outstanding calls to pungetc. */ | 836 | /* Number of outstanding calls to pungetc. */ |
637 | int unget; | 837 | int unget; |
838 | |||
839 | #if ENABLE_PLATFORM_MINGW32 | ||
840 | /* True if a trailing CR from a previous read was left unprocessed. */ | ||
841 | int cr; | ||
842 | #endif | ||
638 | }; | 843 | }; |
639 | 844 | ||
640 | static struct parsefile basepf; /* top level input file */ | 845 | static struct parsefile basepf; /* top level input file */ |
641 | static struct parsefile *g_parsefile = &basepf; /* current input file */ | 846 | static struct parsefile *g_parsefile = &basepf; /* current input file */ |
847 | #if ENABLE_PLATFORM_POSIX | ||
642 | static char *commandname; /* currently executing command */ | 848 | static char *commandname; /* currently executing command */ |
849 | #endif | ||
643 | 850 | ||
644 | 851 | ||
645 | /* ============ Interrupts / exceptions */ | 852 | /* ============ Interrupts / exceptions */ |
@@ -696,21 +903,39 @@ raise_exception(int e) | |||
696 | * are held using the INT_OFF macro. (The test for iflag is just | 903 | * are held using the INT_OFF macro. (The test for iflag is just |
697 | * defensive programming.) | 904 | * defensive programming.) |
698 | */ | 905 | */ |
699 | static void raise_interrupt(void) NORETURN; | 906 | static void raise_interrupt(void) IF_NOT_PLATFORM_MINGW32(NORETURN); |
700 | static void | 907 | static void |
701 | raise_interrupt(void) | 908 | raise_interrupt(void) |
702 | { | 909 | { |
910 | #if ENABLE_PLATFORM_MINGW32 | ||
911 | /* Contrary to the comment above on Windows raise_interrupt() is | ||
912 | * called when SIGINT is trapped or ignored. We detect this here | ||
913 | * and return without doing anything. */ | ||
914 | if (trap[SIGINT]) | ||
915 | return; | ||
916 | #endif | ||
703 | pending_int = 0; | 917 | pending_int = 0; |
918 | #if !ENABLE_PLATFORM_MINGW32 | ||
704 | /* Signal is not automatically unmasked after it is raised, | 919 | /* Signal is not automatically unmasked after it is raised, |
705 | * do it ourself - unmask all signals */ | 920 | * do it ourself - unmask all signals */ |
706 | sigprocmask_allsigs(SIG_UNBLOCK); | 921 | sigprocmask_allsigs(SIG_UNBLOCK); |
922 | #endif | ||
707 | /* pending_sig = 0; - now done in signal_handler() */ | 923 | /* pending_sig = 0; - now done in signal_handler() */ |
708 | 924 | ||
709 | if (!(rootshell && iflag)) { | 925 | if (!(rootshell && iflag)) { |
926 | #if !ENABLE_PLATFORM_MINGW32 | ||
710 | /* Kill ourself with SIGINT */ | 927 | /* Kill ourself with SIGINT */ |
711 | signal(SIGINT, SIG_DFL); | 928 | signal(SIGINT, SIG_DFL); |
712 | raise(SIGINT); | 929 | raise(SIGINT); |
930 | #else | ||
931 | fflush_all(); | ||
932 | _exit(SIGINT << 24); | ||
933 | #endif | ||
713 | } | 934 | } |
935 | #if ENABLE_PLATFORM_MINGW32 | ||
936 | if (iflag) | ||
937 | write(STDOUT_FILENO, "^C", 2); | ||
938 | #endif | ||
714 | /* bash: ^C even on empty command line sets $? */ | 939 | /* bash: ^C even on empty command line sets $? */ |
715 | exitstatus = SIGINT + 128; | 940 | exitstatus = SIGINT + 128; |
716 | raise_exception(EXINT); | 941 | raise_exception(EXINT); |
@@ -1998,6 +2223,18 @@ maybe_single_quote(const char *s) | |||
1998 | return single_quote(s); | 2223 | return single_quote(s); |
1999 | } | 2224 | } |
2000 | 2225 | ||
2226 | #if ENABLE_PLATFORM_MINGW32 | ||
2227 | /* Copy path to a string on the stack long enough to allow a file extension | ||
2228 | * to be added. */ | ||
2229 | static char * | ||
2230 | stack_add_ext_space(const char *path) | ||
2231 | { | ||
2232 | char *p = growstackto(strlen(path) + 5); | ||
2233 | strcpy(p, path); | ||
2234 | return p; | ||
2235 | } | ||
2236 | #endif | ||
2237 | |||
2001 | 2238 | ||
2002 | /* ============ nextopt */ | 2239 | /* ============ nextopt */ |
2003 | 2240 | ||
@@ -2120,6 +2357,9 @@ struct localvar { | |||
2120 | #else | 2357 | #else |
2121 | # define VDYNAMIC 0 | 2358 | # define VDYNAMIC 0 |
2122 | #endif | 2359 | #endif |
2360 | #if ENABLE_PLATFORM_MINGW32 | ||
2361 | # define VIMPORT 0x400 /* variable was imported from environment */ | ||
2362 | #endif | ||
2123 | 2363 | ||
2124 | 2364 | ||
2125 | /* Need to be before varinit_data[] */ | 2365 | /* Need to be before varinit_data[] */ |
@@ -2149,6 +2389,24 @@ static void change_seconds(const char *) FAST_FUNC; | |||
2149 | static void change_realtime(const char *) FAST_FUNC; | 2389 | static void change_realtime(const char *) FAST_FUNC; |
2150 | #endif | 2390 | #endif |
2151 | 2391 | ||
2392 | #if ENABLE_PLATFORM_MINGW32 | ||
2393 | static void FAST_FUNC | ||
2394 | change_terminal_mode(const char *newval UNUSED_PARAM) | ||
2395 | { | ||
2396 | terminal_mode(TRUE); | ||
2397 | } | ||
2398 | |||
2399 | static void clearcmdentry(void); | ||
2400 | static void FAST_FUNC | ||
2401 | change_override_applets(const char *newval UNUSED_PARAM) | ||
2402 | { | ||
2403 | clearcmdentry(); | ||
2404 | } | ||
2405 | |||
2406 | # define LINENO_INDEX (5 + 2 * ENABLE_ASH_MAIL + ENABLE_ASH_GETOPTS) | ||
2407 | # define FUNCNAME_INDEX (LINENO_INDEX + 1) | ||
2408 | #endif | ||
2409 | |||
2152 | static const struct { | 2410 | static const struct { |
2153 | int flags; | 2411 | int flags; |
2154 | const char *var_text; | 2412 | const char *var_text; |
@@ -2186,6 +2444,12 @@ static const struct { | |||
2186 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 2444 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY |
2187 | { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL }, | 2445 | { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL }, |
2188 | #endif | 2446 | #endif |
2447 | #if ENABLE_PLATFORM_MINGW32 | ||
2448 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_SKIP_ANSI_EMULATION, change_terminal_mode }, | ||
2449 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_TERMINAL_MODE, change_terminal_mode }, | ||
2450 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_OVERRIDE_APPLETS, change_override_applets }, | ||
2451 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_CRITICAL_ERROR_DIALOGS, change_critical_error_dialogs }, | ||
2452 | #endif | ||
2189 | }; | 2453 | }; |
2190 | 2454 | ||
2191 | struct redirtab; | 2455 | struct redirtab; |
@@ -2409,6 +2673,65 @@ bltinlookup(const char *name) | |||
2409 | return lookupvar(name); | 2673 | return lookupvar(name); |
2410 | } | 2674 | } |
2411 | 2675 | ||
2676 | #if ENABLE_PLATFORM_MINGW32 | ||
2677 | static char * | ||
2678 | fix_pathvar(const char *path, int len) | ||
2679 | { | ||
2680 | char *newpath = xstrdup(path); | ||
2681 | char *p; | ||
2682 | int modified = FALSE; | ||
2683 | |||
2684 | p = newpath + len; | ||
2685 | while (*p) { | ||
2686 | if (*p != ':' && *p != ';') { | ||
2687 | /* skip drive */ | ||
2688 | if (isalpha(*p) && p[1] == ':') | ||
2689 | p += 2; | ||
2690 | /* skip through path component */ | ||
2691 | for (; *p != '\0' && *p != ':' && *p != ';'; ++p) | ||
2692 | continue; | ||
2693 | } | ||
2694 | /* *p is ':', ';' or '\0' here */ | ||
2695 | if (*p == ':') { | ||
2696 | *p++ = ';'; | ||
2697 | modified = TRUE; | ||
2698 | } | ||
2699 | else if (*p == ';') { | ||
2700 | ++p; | ||
2701 | } | ||
2702 | } | ||
2703 | |||
2704 | if (!modified) { | ||
2705 | free(newpath); | ||
2706 | newpath = NULL; | ||
2707 | } | ||
2708 | return newpath; | ||
2709 | } | ||
2710 | |||
2711 | #define BB_VAR_EXACT 1 /* exact match for name */ | ||
2712 | #define BB_VAR_ASSIGN -1 /* matches name followed by '=' */ | ||
2713 | |||
2714 | /* Match variables that should be placed in the environment immediately | ||
2715 | * they're exported and removed immediately they're no longer exported */ | ||
2716 | static int | ||
2717 | is_bb_var(const char *s) | ||
2718 | { | ||
2719 | const char *p; | ||
2720 | int len; | ||
2721 | |||
2722 | for (p = bbvar; *p; p += len + 1) { | ||
2723 | len = strlen(p); | ||
2724 | if (strncmp(s, p, len) == 0) { | ||
2725 | if (s[len] == '\0') | ||
2726 | return BB_VAR_EXACT; | ||
2727 | else if (s[len] == '=') | ||
2728 | return BB_VAR_ASSIGN; | ||
2729 | } | ||
2730 | } | ||
2731 | return FALSE; | ||
2732 | } | ||
2733 | #endif | ||
2734 | |||
2412 | /* | 2735 | /* |
2413 | * Same as setvar except that the variable and value are passed in | 2736 | * Same as setvar except that the variable and value are passed in |
2414 | * the first argument as name=value. Since the first argument will | 2737 | * the first argument as name=value. Since the first argument will |
@@ -2420,6 +2743,26 @@ static struct var * | |||
2420 | setvareq(char *s, int flags) | 2743 | setvareq(char *s, int flags) |
2421 | { | 2744 | { |
2422 | struct var *vp, **vpp; | 2745 | struct var *vp, **vpp; |
2746 | #if ENABLE_PLATFORM_MINGW32 | ||
2747 | const char *paths = "PATH=\0""CDPATH=\0""MANPATH=\0"; | ||
2748 | const char *p; | ||
2749 | int len; | ||
2750 | |||
2751 | for (p = paths; *p; p += len + 1) { | ||
2752 | len = strlen(p); | ||
2753 | if (strncmp(s, p, len) == 0) { | ||
2754 | char *newpath = fix_pathvar(s, len); | ||
2755 | if (newpath) { | ||
2756 | if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE) | ||
2757 | free(s); | ||
2758 | flags |= VNOSAVE; | ||
2759 | flags &= ~(VTEXTFIXED|VSTACK); | ||
2760 | s = newpath; | ||
2761 | } | ||
2762 | break; | ||
2763 | } | ||
2764 | } | ||
2765 | #endif | ||
2423 | 2766 | ||
2424 | flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); | 2767 | flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); |
2425 | vpp = findvar(s); | 2768 | vpp = findvar(s); |
@@ -2444,6 +2787,11 @@ setvareq(char *s, int flags) | |||
2444 | if (!(vp->flags & (VTEXTFIXED|VSTACK))) | 2787 | if (!(vp->flags & (VTEXTFIXED|VSTACK))) |
2445 | free((char*)vp->var_text); | 2788 | free((char*)vp->var_text); |
2446 | 2789 | ||
2790 | #if ENABLE_PLATFORM_MINGW32 | ||
2791 | if ((flags & VUNSET) && (vp->flags & VEXPORT) && | ||
2792 | is_bb_var(s) == BB_VAR_EXACT) | ||
2793 | unsetenv(s); | ||
2794 | #endif | ||
2447 | if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) { | 2795 | if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) { |
2448 | *vpp = vp->next; | 2796 | *vpp = vp->next; |
2449 | free(vp); | 2797 | free(vp); |
@@ -2473,6 +2821,10 @@ setvareq(char *s, int flags) | |||
2473 | s = ckstrdup(s); | 2821 | s = ckstrdup(s); |
2474 | vp->var_text = s; | 2822 | vp->var_text = s; |
2475 | vp->flags = flags; | 2823 | vp->flags = flags; |
2824 | #if ENABLE_PLATFORM_MINGW32 | ||
2825 | if ((flags & VEXPORT) && is_bb_var(s) == BB_VAR_ASSIGN) | ||
2826 | putenv(s); | ||
2827 | #endif | ||
2476 | 2828 | ||
2477 | out: | 2829 | out: |
2478 | return vp; | 2830 | return vp; |
@@ -2594,6 +2946,65 @@ listvars(int on, int off, struct strlist *lp, char ***end) | |||
2594 | return grabstackstr(ep); | 2946 | return grabstackstr(ep); |
2595 | } | 2947 | } |
2596 | 2948 | ||
2949 | #if ENABLE_PLATFORM_MINGW32 | ||
2950 | /* Adjust directory separator in variables imported from the environment */ | ||
2951 | static void | ||
2952 | setwinxp(int on) | ||
2953 | { | ||
2954 | static smallint is_winxp = 1; | ||
2955 | struct var **vpp; | ||
2956 | struct var *vp; | ||
2957 | |||
2958 | if (on == is_winxp) | ||
2959 | return; | ||
2960 | is_winxp = on; | ||
2961 | |||
2962 | for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) { | ||
2963 | for (vp = *vpp; vp; vp = vp->next) { | ||
2964 | if ((vp->flags & VIMPORT)) { | ||
2965 | char *end = strchr(vp->var_text, '='); | ||
2966 | if (!end || is_prefixed_with(vp->var_text, "COMSPEC=") || | ||
2967 | is_prefixed_with(vp->var_text, "SYSTEMROOT=")) | ||
2968 | continue; | ||
2969 | if (!on) | ||
2970 | bs_to_slash(end + 1); | ||
2971 | else | ||
2972 | slash_to_bs(end + 1); | ||
2973 | } | ||
2974 | } | ||
2975 | } | ||
2976 | } | ||
2977 | |||
2978 | # if ENABLE_ASH_NOCONSOLE | ||
2979 | /* | ||
2980 | * Console state is either: | ||
2981 | * 0 normal | ||
2982 | * 1 iconified/hidden | ||
2983 | * 2 unknown | ||
2984 | */ | ||
2985 | static int console_state(void) | ||
2986 | { | ||
2987 | DECLARE_PROC_ADDR(BOOL, ShowWindow, HWND, int); | ||
2988 | |||
2989 | if (INIT_PROC_ADDR(user32.dll, ShowWindow)) { | ||
2990 | BOOL visible = IsWindowVisible(GetConsoleWindow()); | ||
2991 | BOOL iconified = IsIconic(GetConsoleWindow()); | ||
2992 | |||
2993 | return !visible || iconified; | ||
2994 | } | ||
2995 | return 2; | ||
2996 | } | ||
2997 | |||
2998 | static void hide_console(int hide) | ||
2999 | { | ||
3000 | // Switch console state if it's known and isn't the required state | ||
3001 | if (console_state() == !hide) | ||
3002 | ShowWindow(GetConsoleWindow(), hide ? | ||
3003 | (noiconify ? SW_HIDE : SW_MINIMIZE) : SW_NORMAL); | ||
3004 | } | ||
3005 | # endif | ||
3006 | #endif | ||
3007 | |||
2597 | 3008 | ||
2598 | /* ============ Path search helper */ | 3009 | /* ============ Path search helper */ |
2599 | static const char * | 3010 | static const char * |
@@ -2637,7 +3048,7 @@ static const char *pathopt; /* set by padvance */ | |||
2637 | static int | 3048 | static int |
2638 | padvance_magic(const char **path, const char *name, int magic) | 3049 | padvance_magic(const char **path, const char *name, int magic) |
2639 | { | 3050 | { |
2640 | const char *term = "%:"; | 3051 | const char *term = "%"PATH_SEP_STR; |
2641 | const char *lpathopt; | 3052 | const char *lpathopt; |
2642 | const char *p; | 3053 | const char *p; |
2643 | char *q; | 3054 | char *q; |
@@ -2654,14 +3065,14 @@ padvance_magic(const char **path, const char *name, int magic) | |||
2654 | if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) { | 3065 | if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) { |
2655 | lpathopt = start + 1; | 3066 | lpathopt = start + 1; |
2656 | start = p; | 3067 | start = p; |
2657 | term = ":"; | 3068 | term = PATH_SEP_STR; |
2658 | } | 3069 | } |
2659 | 3070 | ||
2660 | len = strcspn(start, term); | 3071 | len = strcspn(start, term); |
2661 | p = start + len; | 3072 | p = start + len; |
2662 | 3073 | ||
2663 | if (*p == '%') { | 3074 | if (*p == '%') { |
2664 | size_t extra = strchrnul(p, ':') - p; | 3075 | size_t extra = strchrnul(p, PATH_SEP) - p; |
2665 | 3076 | ||
2666 | if (legal_pathopt(p + 1, term, magic)) | 3077 | if (legal_pathopt(p + 1, term, magic)) |
2667 | lpathopt = p + 1; | 3078 | lpathopt = p + 1; |
@@ -2672,14 +3083,18 @@ padvance_magic(const char **path, const char *name, int magic) | |||
2672 | } | 3083 | } |
2673 | 3084 | ||
2674 | pathopt = lpathopt; | 3085 | pathopt = lpathopt; |
2675 | *path = *p == ':' ? p + 1 : NULL; | 3086 | *path = *p == PATH_SEP ? p + 1 : NULL; |
2676 | 3087 | ||
2677 | /* "2" is for '/' and '\0' */ | 3088 | /* "2" is for '/' and '\0' */ |
2678 | qlen = len + strlen(name) + 2; | 3089 | /* reserve space for suffix on WIN32 */ |
3090 | qlen = len + strlen(name) + 2 IF_PLATFORM_MINGW32(+ 4); | ||
2679 | q = growstackto(qlen); | 3091 | q = growstackto(qlen); |
2680 | 3092 | ||
2681 | if (len) { | 3093 | if (len) { |
2682 | q = mempcpy(q, start, len); | 3094 | q = mempcpy(q, start, len); |
3095 | #if ENABLE_PLATFORM_MINGW32 | ||
3096 | if (q[-1] != '/' && q[-1] != '\\') | ||
3097 | #endif | ||
2683 | *q++ = '/'; | 3098 | *q++ = '/'; |
2684 | } | 3099 | } |
2685 | strcpy(q, name); | 3100 | strcpy(q, name); |
@@ -2770,6 +3185,7 @@ setprompt_if(smallint do_set, int whichprompt) | |||
2770 | 3185 | ||
2771 | #define CD_PHYSICAL 1 | 3186 | #define CD_PHYSICAL 1 |
2772 | #define CD_PRINT 2 | 3187 | #define CD_PRINT 2 |
3188 | #define CD_PRINT_ALL 4 | ||
2773 | 3189 | ||
2774 | static int | 3190 | static int |
2775 | cdopt(void) | 3191 | cdopt(void) |
@@ -2778,7 +3194,14 @@ cdopt(void) | |||
2778 | int i, j; | 3194 | int i, j; |
2779 | 3195 | ||
2780 | j = 'L'; | 3196 | j = 'L'; |
3197 | #if ENABLE_PLATFORM_MINGW32 | ||
3198 | while ((i = nextopt("LPa")) != '\0') { | ||
3199 | if (i == 'a') | ||
3200 | flags |= CD_PRINT_ALL; | ||
3201 | else | ||
3202 | #else | ||
2781 | while ((i = nextopt("LP")) != '\0') { | 3203 | while ((i = nextopt("LP")) != '\0') { |
3204 | #endif | ||
2782 | if (i != j) { | 3205 | if (i != j) { |
2783 | flags ^= CD_PHYSICAL; | 3206 | flags ^= CD_PHYSICAL; |
2784 | j = i; | 3207 | j = i; |
@@ -2795,6 +3218,130 @@ cdopt(void) | |||
2795 | static const char * | 3218 | static const char * |
2796 | updatepwd(const char *dir) | 3219 | updatepwd(const char *dir) |
2797 | { | 3220 | { |
3221 | #if ENABLE_PLATFORM_MINGW32 | ||
3222 | /* | ||
3223 | * Due to Windows drive notion, getting pwd is a completely | ||
3224 | * different thing. Handle it in a separate routine | ||
3225 | */ | ||
3226 | |||
3227 | char *new; | ||
3228 | char *p; | ||
3229 | char *cdcomppath; | ||
3230 | const char *lim; | ||
3231 | int len; | ||
3232 | char buffer[PATH_MAX]; | ||
3233 | /* | ||
3234 | * There are five cases that make some kind of sense | ||
3235 | * | ||
3236 | * Absolute paths: | ||
3237 | * c:/path | ||
3238 | * //host/share | ||
3239 | * | ||
3240 | * Relative to current working directory of other drive: | ||
3241 | * c:path | ||
3242 | * | ||
3243 | * Relative to current root (drive/share): | ||
3244 | * /path | ||
3245 | * | ||
3246 | * Relative to current working directory of current root (drive/share): | ||
3247 | * path | ||
3248 | */ | ||
3249 | enum {ABS_DRIVE, ABS_SHARE, REL_OTHER, REL_ROOT, REL_CWD} target; | ||
3250 | |||
3251 | /* skip multiple leading separators unless dir is a UNC path */ | ||
3252 | if (is_dir_sep(*dir) && unc_root_len(dir) == 0) { | ||
3253 | while (is_dir_sep(dir[1])) | ||
3254 | ++dir; | ||
3255 | } | ||
3256 | |||
3257 | len = strlen(dir); | ||
3258 | if (len >= 2 && has_dos_drive_prefix(dir)) | ||
3259 | target = len >= 3 && is_dir_sep(dir[2]) ? ABS_DRIVE : REL_OTHER; | ||
3260 | else if (unc_root_len(dir) != 0) | ||
3261 | target = ABS_SHARE; | ||
3262 | else if (is_dir_sep(*dir)) | ||
3263 | target = REL_ROOT; | ||
3264 | else | ||
3265 | target = REL_CWD; | ||
3266 | |||
3267 | cdcomppath = sstrdup(dir); | ||
3268 | STARTSTACKSTR(new); | ||
3269 | |||
3270 | switch (target) { | ||
3271 | case REL_OTHER: | ||
3272 | /* c:path */ | ||
3273 | if (get_drive_cwd(dir, buffer, PATH_MAX) == NULL) | ||
3274 | return 0; | ||
3275 | new = stack_putstr(buffer, new); | ||
3276 | len = 2; | ||
3277 | cdcomppath += len; | ||
3278 | dir += len; | ||
3279 | break; | ||
3280 | case REL_CWD: | ||
3281 | case REL_ROOT: | ||
3282 | /* path or /path */ | ||
3283 | len = root_len(curdir); | ||
3284 | if (len == 0) | ||
3285 | return 0; | ||
3286 | new = target == REL_CWD ? stack_putstr(curdir, new) : | ||
3287 | stnputs(curdir, len, new); | ||
3288 | break; | ||
3289 | default: | ||
3290 | /* //host/share or c:/path */ | ||
3291 | len = root_len(dir); | ||
3292 | if (len == 0) | ||
3293 | return 0; | ||
3294 | new = stnputs(dir, len, new); | ||
3295 | cdcomppath += len; | ||
3296 | dir += len; | ||
3297 | break; | ||
3298 | } | ||
3299 | |||
3300 | new = makestrspace(strlen(dir) + 2, new); | ||
3301 | lim = (char *)stackblock() + len + 1; | ||
3302 | |||
3303 | if (!is_dir_sep(*dir)) { | ||
3304 | if (!is_dir_sep(new[-1])) | ||
3305 | USTPUTC('/', new); | ||
3306 | if (new > lim && is_dir_sep(*lim)) | ||
3307 | lim++; | ||
3308 | } else { | ||
3309 | USTPUTC('/', new); | ||
3310 | cdcomppath++; | ||
3311 | if (is_dir_sep(dir[1]) && !is_dir_sep(dir[2])) { | ||
3312 | USTPUTC('/', new); | ||
3313 | cdcomppath++; | ||
3314 | lim++; | ||
3315 | } | ||
3316 | } | ||
3317 | p = strtok(cdcomppath, "/\\"); | ||
3318 | while (p) { | ||
3319 | switch (*p) { | ||
3320 | case '.': | ||
3321 | if (p[1] == '.' && p[2] == '\0') { | ||
3322 | while (new > lim) { | ||
3323 | STUNPUTC(new); | ||
3324 | if (is_dir_sep(new[-1])) | ||
3325 | break; | ||
3326 | } | ||
3327 | break; | ||
3328 | } | ||
3329 | if (p[1] == '\0') | ||
3330 | break; | ||
3331 | /* fall through */ | ||
3332 | default: | ||
3333 | new = stack_putstr(p, new); | ||
3334 | USTPUTC('/', new); | ||
3335 | } | ||
3336 | p = strtok(NULL, "/\\"); | ||
3337 | } | ||
3338 | if (new > lim) | ||
3339 | STUNPUTC(new); | ||
3340 | *new = 0; | ||
3341 | strip_dot_space((char *)stackblock()); | ||
3342 | fix_path_case((char *)stackblock()); | ||
3343 | return bs_to_slash((char *)stackblock()); | ||
3344 | #else | ||
2798 | char *new; | 3345 | char *new; |
2799 | char *p; | 3346 | char *p; |
2800 | char *cdcomppath; | 3347 | char *cdcomppath; |
@@ -2848,6 +3395,7 @@ updatepwd(const char *dir) | |||
2848 | STUNPUTC(new); | 3395 | STUNPUTC(new); |
2849 | *new = 0; | 3396 | *new = 0; |
2850 | return stackblock(); | 3397 | return stackblock(); |
3398 | #endif | ||
2851 | } | 3399 | } |
2852 | 3400 | ||
2853 | /* | 3401 | /* |
@@ -2943,7 +3491,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2943 | } | 3491 | } |
2944 | if (!dest) | 3492 | if (!dest) |
2945 | dest = nullstr; | 3493 | dest = nullstr; |
2946 | if (*dest == '/') | 3494 | if (!is_relative_path(dest)) |
2947 | goto step6; | 3495 | goto step6; |
2948 | if (*dest == '.') { | 3496 | if (*dest == '.') { |
2949 | c = dest[1]; | 3497 | c = dest[1]; |
@@ -2966,7 +3514,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2966 | p = stalloc(len); | 3514 | p = stalloc(len); |
2967 | 3515 | ||
2968 | if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { | 3516 | if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { |
2969 | if (c && c != ':') | 3517 | if (c && c != PATH_SEP) |
2970 | flags |= CD_PRINT; | 3518 | flags |= CD_PRINT; |
2971 | docd: | 3519 | docd: |
2972 | if (!docd(p, flags)) | 3520 | if (!docd(p, flags)) |
@@ -2988,6 +3536,26 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2988 | return 0; | 3536 | return 0; |
2989 | } | 3537 | } |
2990 | 3538 | ||
3539 | #if ENABLE_PLATFORM_MINGW32 | ||
3540 | static void | ||
3541 | print_all_cwd(void) | ||
3542 | { | ||
3543 | FILE *mnt; | ||
3544 | struct mntent *entry; | ||
3545 | char buffer[PATH_MAX]; | ||
3546 | |||
3547 | mnt = setmntent(bb_path_mtab_file, "r"); | ||
3548 | if (mnt) { | ||
3549 | while ((entry=getmntent(mnt)) != NULL) { | ||
3550 | entry->mnt_dir[2] = '\0'; | ||
3551 | if (get_drive_cwd(entry->mnt_dir, buffer, PATH_MAX) != NULL) | ||
3552 | out1fmt("%s\n", buffer); | ||
3553 | } | ||
3554 | endmntent(mnt); | ||
3555 | } | ||
3556 | } | ||
3557 | #endif | ||
3558 | |||
2991 | static int FAST_FUNC | 3559 | static int FAST_FUNC |
2992 | pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 3560 | pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) |
2993 | { | 3561 | { |
@@ -2995,6 +3563,12 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2995 | const char *dir = curdir; | 3563 | const char *dir = curdir; |
2996 | 3564 | ||
2997 | flags = cdopt(); | 3565 | flags = cdopt(); |
3566 | #if ENABLE_PLATFORM_MINGW32 | ||
3567 | if (flags & CD_PRINT_ALL) { | ||
3568 | print_all_cwd(); | ||
3569 | return 0; | ||
3570 | } | ||
3571 | #endif | ||
2998 | if (flags) { | 3572 | if (flags) { |
2999 | if (physdir == nullstr) | 3573 | if (physdir == nullstr) |
3000 | setpwd(dir, 0); | 3574 | setpwd(dir, 0); |
@@ -3623,7 +4197,12 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
3623 | struct procstat { | 4197 | struct procstat { |
3624 | pid_t ps_pid; /* process id */ | 4198 | pid_t ps_pid; /* process id */ |
3625 | int ps_status; /* last process status from wait() */ | 4199 | int ps_status; /* last process status from wait() */ |
4200 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
3626 | char *ps_cmd; /* text of command being run */ | 4201 | char *ps_cmd; /* text of command being run */ |
4202 | #endif | ||
4203 | #if ENABLE_PLATFORM_MINGW32 | ||
4204 | HANDLE ps_proc; | ||
4205 | #endif | ||
3627 | }; | 4206 | }; |
3628 | 4207 | ||
3629 | struct job { | 4208 | struct job { |
@@ -3639,8 +4218,10 @@ struct job { | |||
3639 | #define JOBDONE 2 /* all procs are completed */ | 4218 | #define JOBDONE 2 /* all procs are completed */ |
3640 | unsigned | 4219 | unsigned |
3641 | state: 8, | 4220 | state: 8, |
3642 | #if JOBS | 4221 | #if JOBS || ENABLE_PLATFORM_MINGW32 |
3643 | sigint: 1, /* job was killed by SIGINT */ | 4222 | sigint: 1, /* job was killed by SIGINT */ |
4223 | #endif | ||
4224 | #if JOBS | ||
3644 | jobctl: 1, /* job running under job control */ | 4225 | jobctl: 1, /* job running under job control */ |
3645 | #endif | 4226 | #endif |
3646 | waited: 1, /* true if this entry has been waited for */ | 4227 | waited: 1, /* true if this entry has been waited for */ |
@@ -3650,17 +4231,23 @@ struct job { | |||
3650 | }; | 4231 | }; |
3651 | 4232 | ||
3652 | static struct job *makejob(/*union node *,*/ int); | 4233 | static struct job *makejob(/*union node *,*/ int); |
4234 | #if !ENABLE_PLATFORM_MINGW32 | ||
3653 | static int forkshell(struct job *, union node *, int); | 4235 | static int forkshell(struct job *, union node *, int); |
4236 | #endif | ||
3654 | static int waitforjob(struct job *); | 4237 | static int waitforjob(struct job *); |
3655 | 4238 | ||
3656 | #if !JOBS | 4239 | #if !JOBS && !JOBS_WIN32 |
3657 | enum { doing_jobctl = 0 }; | 4240 | enum { doing_jobctl = 0 }; |
3658 | #define setjobctl(on) do {} while (0) | 4241 | #define setjobctl(on) do {} while (0) |
3659 | #else | 4242 | #elif JOBS_WIN32 |
4243 | static smallint doing_jobctl; //references:8 | ||
4244 | #define setjobctl(on) do { if (rootshell) doing_jobctl = on; } while (0) | ||
4245 | #else /* JOBS */ | ||
3660 | static smallint doing_jobctl; //references:8 | 4246 | static smallint doing_jobctl; //references:8 |
3661 | static void setjobctl(int); | 4247 | static void setjobctl(int); |
3662 | #endif | 4248 | #endif |
3663 | 4249 | ||
4250 | #if !ENABLE_PLATFORM_MINGW32 | ||
3664 | /* | 4251 | /* |
3665 | * Ignore a signal. | 4252 | * Ignore a signal. |
3666 | */ | 4253 | */ |
@@ -3809,6 +4396,10 @@ setsignal(int signo) | |||
3809 | 4396 | ||
3810 | sigaction_set(signo, &act); | 4397 | sigaction_set(signo, &act); |
3811 | } | 4398 | } |
4399 | #else | ||
4400 | #define setsignal(s) | ||
4401 | #define ignoresig(s) | ||
4402 | #endif | ||
3812 | 4403 | ||
3813 | /* mode flags for set_curjob */ | 4404 | /* mode flags for set_curjob */ |
3814 | #define CUR_DELETE 2 | 4405 | #define CUR_DELETE 2 |
@@ -3942,7 +4533,7 @@ set_curjob(struct job *jp, unsigned mode) | |||
3942 | } | 4533 | } |
3943 | } | 4534 | } |
3944 | 4535 | ||
3945 | #if JOBS || DEBUG | 4536 | #if JOBS || ENABLE_PLATFORM_MINGW32 || DEBUG |
3946 | static int | 4537 | static int |
3947 | jobno(const struct job *jp) | 4538 | jobno(const struct job *jp) |
3948 | { | 4539 | { |
@@ -3960,7 +4551,9 @@ static struct job * | |||
3960 | getjob(const char *name, int getctl) | 4551 | getjob(const char *name, int getctl) |
3961 | { | 4552 | { |
3962 | struct job *jp; | 4553 | struct job *jp; |
4554 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
3963 | struct job *found; | 4555 | struct job *found; |
4556 | #endif | ||
3964 | const char *err_msg = "%s: no such job"; | 4557 | const char *err_msg = "%s: no such job"; |
3965 | unsigned num; | 4558 | unsigned num; |
3966 | int c; | 4559 | int c; |
@@ -4005,6 +4598,7 @@ getjob(const char *name, int getctl) | |||
4005 | } | 4598 | } |
4006 | } | 4599 | } |
4007 | 4600 | ||
4601 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
4008 | found = NULL; | 4602 | found = NULL; |
4009 | while (jp) { | 4603 | while (jp) { |
4010 | if (*p == '?' | 4604 | if (*p == '?' |
@@ -4021,6 +4615,9 @@ getjob(const char *name, int getctl) | |||
4021 | if (!found) | 4615 | if (!found) |
4022 | goto err; | 4616 | goto err; |
4023 | jp = found; | 4617 | jp = found; |
4618 | #else | ||
4619 | goto err; | ||
4620 | #endif | ||
4024 | 4621 | ||
4025 | gotit: | 4622 | gotit: |
4026 | #if JOBS | 4623 | #if JOBS |
@@ -4039,14 +4636,18 @@ getjob(const char *name, int getctl) | |||
4039 | static void | 4636 | static void |
4040 | freejob(struct job *jp) | 4637 | freejob(struct job *jp) |
4041 | { | 4638 | { |
4639 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
4042 | struct procstat *ps; | 4640 | struct procstat *ps; |
4043 | int i; | 4641 | int i; |
4642 | #endif | ||
4044 | 4643 | ||
4045 | INT_OFF; | 4644 | INT_OFF; |
4645 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
4046 | for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { | 4646 | for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { |
4047 | if (ps->ps_cmd != nullstr) | 4647 | if (ps->ps_cmd != nullstr) |
4048 | free(ps->ps_cmd); | 4648 | free(ps->ps_cmd); |
4049 | } | 4649 | } |
4650 | #endif | ||
4050 | if (jp->ps != &jp->ps0) | 4651 | if (jp->ps != &jp->ps0) |
4051 | free(jp->ps); | 4652 | free(jp->ps); |
4052 | jp->used = 0; | 4653 | jp->used = 0; |
@@ -4139,7 +4740,9 @@ setjobctl(int on) | |||
4139 | ttyfd = fd; | 4740 | ttyfd = fd; |
4140 | doing_jobctl = on; | 4741 | doing_jobctl = on; |
4141 | } | 4742 | } |
4743 | #endif | ||
4142 | 4744 | ||
4745 | #if JOBS || JOBS_WIN32 | ||
4143 | static int FAST_FUNC | 4746 | static int FAST_FUNC |
4144 | killcmd(int argc, char **argv) | 4747 | killcmd(int argc, char **argv) |
4145 | { | 4748 | { |
@@ -4169,8 +4772,10 @@ killcmd(int argc, char **argv) | |||
4169 | * sh -c 'true|sleep 1 & sleep 2; kill %1' | 4772 | * sh -c 'true|sleep 1 & sleep 2; kill %1' |
4170 | */ | 4773 | */ |
4171 | n = jp->nprocs; /* can't be 0 (I hope) */ | 4774 | n = jp->nprocs; /* can't be 0 (I hope) */ |
4775 | #if !ENABLE_PLATFORM_MINGW32 | ||
4172 | if (jp->jobctl) | 4776 | if (jp->jobctl) |
4173 | n = 1; | 4777 | n = 1; |
4778 | #endif | ||
4174 | dst = alloca(n * sizeof(int)*4); | 4779 | dst = alloca(n * sizeof(int)*4); |
4175 | argv[i] = dst; | 4780 | argv[i] = dst; |
4176 | for (j = 0; j < n; j++) { | 4781 | for (j = 0; j < n; j++) { |
@@ -4185,7 +4790,11 @@ killcmd(int argc, char **argv) | |||
4185 | * leading space. Needed to not confuse | 4790 | * leading space. Needed to not confuse |
4186 | * negative pids with "kill -SIGNAL_NO" syntax | 4791 | * negative pids with "kill -SIGNAL_NO" syntax |
4187 | */ | 4792 | */ |
4793 | #if !ENABLE_PLATFORM_MINGW32 | ||
4188 | dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); | 4794 | dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); |
4795 | #else | ||
4796 | dst += sprintf(dst, " -%u", (int)ps->ps_pid); | ||
4797 | #endif | ||
4189 | } | 4798 | } |
4190 | *dst = '\0'; | 4799 | *dst = '\0'; |
4191 | } | 4800 | } |
@@ -4193,7 +4802,9 @@ killcmd(int argc, char **argv) | |||
4193 | } | 4802 | } |
4194 | return kill_main(argc, argv); | 4803 | return kill_main(argc, argv); |
4195 | } | 4804 | } |
4805 | #endif | ||
4196 | 4806 | ||
4807 | #if JOBS | ||
4197 | static void | 4808 | static void |
4198 | showpipe(struct job *jp /*, FILE *out*/) | 4809 | showpipe(struct job *jp /*, FILE *out*/) |
4199 | { | 4810 | { |
@@ -4298,6 +4909,65 @@ sprint_status48(char *os, int status, int sigonly) | |||
4298 | return s - os; | 4909 | return s - os; |
4299 | } | 4910 | } |
4300 | 4911 | ||
4912 | #if ENABLE_PLATFORM_MINGW32 | ||
4913 | static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) | ||
4914 | { | ||
4915 | if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { | ||
4916 | # if ENABLE_FEATURE_EDITING | ||
4917 | bb_got_signal = SIGINT; /* for read_line_input: "we got a signal" */ | ||
4918 | # endif | ||
4919 | if (!suppress_int && !(rootshell && iflag)) | ||
4920 | raise_interrupt(); | ||
4921 | pending_int = 1; | ||
4922 | return TRUE; | ||
4923 | } | ||
4924 | return FALSE; | ||
4925 | } | ||
4926 | |||
4927 | /* | ||
4928 | * Windows does not know about parent-child relationship | ||
4929 | * They don't support waitpid(-1) | ||
4930 | */ | ||
4931 | static pid_t | ||
4932 | waitpid_child(int *status, int wait_flags) | ||
4933 | { | ||
4934 | struct job *jb; | ||
4935 | int pid_nr = 0; | ||
4936 | static HANDLE *proclist = NULL; | ||
4937 | static int pid_max = 0; | ||
4938 | pid_t pid = -1; | ||
4939 | DWORD win_status, idx; | ||
4940 | int i; | ||
4941 | |||
4942 | for (jb = curjob; jb; jb = jb->prev_job) { | ||
4943 | if (jb->state != JOBDONE) { | ||
4944 | if (pid_nr + jb->nprocs > pid_max) { | ||
4945 | pid_max = pid_nr + jb->nprocs; | ||
4946 | proclist = ckrealloc(proclist, sizeof(*proclist) * pid_max); | ||
4947 | } | ||
4948 | |||
4949 | for (i = 0; i < jb->nprocs; ++i) { | ||
4950 | if (jb->ps[i].ps_proc) { | ||
4951 | proclist[pid_nr++] = jb->ps[i].ps_proc; | ||
4952 | } | ||
4953 | } | ||
4954 | } | ||
4955 | } | ||
4956 | |||
4957 | if (pid_nr) { | ||
4958 | idx = WaitForMultipleObjects(pid_nr, proclist, FALSE, | ||
4959 | wait_flags & WNOHANG ? 0 : INFINITE); | ||
4960 | if (idx < pid_nr) { | ||
4961 | GetExitCodeProcess(proclist[idx], &win_status); | ||
4962 | *status = exit_code_to_wait_status(win_status); | ||
4963 | pid = GetProcessId(proclist[idx]); | ||
4964 | } | ||
4965 | } | ||
4966 | return pid; | ||
4967 | } | ||
4968 | #define waitpid(p, s, f) waitpid_child(s, f) | ||
4969 | #endif | ||
4970 | |||
4301 | #define DOWAIT_NONBLOCK 0 | 4971 | #define DOWAIT_NONBLOCK 0 |
4302 | #define DOWAIT_BLOCK 1 | 4972 | #define DOWAIT_BLOCK 1 |
4303 | #define DOWAIT_BLOCK_OR_SIG 2 | 4973 | #define DOWAIT_BLOCK_OR_SIG 2 |
@@ -4308,6 +4978,7 @@ sprint_status48(char *os, int status, int sigonly) | |||
4308 | static int | 4978 | static int |
4309 | waitproc(int block, int *status) | 4979 | waitproc(int block, int *status) |
4310 | { | 4980 | { |
4981 | #if !ENABLE_PLATFORM_MINGW32 | ||
4311 | sigset_t oldmask; | 4982 | sigset_t oldmask; |
4312 | int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; | 4983 | int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; |
4313 | int err; | 4984 | int err; |
@@ -4338,6 +5009,11 @@ waitproc(int block, int *status) | |||
4338 | } while (got_sigchld); | 5009 | } while (got_sigchld); |
4339 | 5010 | ||
4340 | return err; | 5011 | return err; |
5012 | #else | ||
5013 | int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; | ||
5014 | *status = 0; | ||
5015 | return waitpid(-1, status, flags); | ||
5016 | #endif | ||
4341 | } | 5017 | } |
4342 | 5018 | ||
4343 | static int | 5019 | static int |
@@ -4394,6 +5070,10 @@ waitone(int block, struct job *job) | |||
4394 | jobno(jp), pid, ps->ps_status, status)); | 5070 | jobno(jp), pid, ps->ps_status, status)); |
4395 | ps->ps_status = status; | 5071 | ps->ps_status = status; |
4396 | thisjob = jp; | 5072 | thisjob = jp; |
5073 | #if ENABLE_PLATFORM_MINGW32 | ||
5074 | CloseHandle(ps->ps_proc); | ||
5075 | ps->ps_proc = NULL; | ||
5076 | #endif | ||
4397 | } | 5077 | } |
4398 | if (ps->ps_status == -1) | 5078 | if (ps->ps_status == -1) |
4399 | jobstate = JOBRUNNING; | 5079 | jobstate = JOBRUNNING; |
@@ -4456,6 +5136,7 @@ waitone(int block, struct job *job) | |||
4456 | static int | 5136 | static int |
4457 | dowait(int block, struct job *jp) | 5137 | dowait(int block, struct job *jp) |
4458 | { | 5138 | { |
5139 | #if !ENABLE_PLATFORM_MINGW32 | ||
4459 | smallint gotchld = *(volatile smallint *)&got_sigchld; | 5140 | smallint gotchld = *(volatile smallint *)&got_sigchld; |
4460 | int rpid; | 5141 | int rpid; |
4461 | int pid; | 5142 | int pid; |
@@ -4477,9 +5158,17 @@ dowait(int block, struct job *jp) | |||
4477 | } while (pid >= 0); | 5158 | } while (pid >= 0); |
4478 | 5159 | ||
4479 | return rpid; | 5160 | return rpid; |
5161 | #else | ||
5162 | int pid = 1; | ||
5163 | |||
5164 | while (jp ? jp->state == JOBRUNNING : pid > 0) | ||
5165 | pid = waitone(block, jp); | ||
5166 | |||
5167 | return pid; | ||
5168 | #endif | ||
4480 | } | 5169 | } |
4481 | 5170 | ||
4482 | #if JOBS | 5171 | #if JOBS || JOBS_WIN32 |
4483 | static void | 5172 | static void |
4484 | showjob(struct job *jp, int mode) | 5173 | showjob(struct job *jp, int mode) |
4485 | { | 5174 | { |
@@ -4494,7 +5183,7 @@ showjob(struct job *jp, int mode) | |||
4494 | 5183 | ||
4495 | if (mode & SHOW_ONLY_PGID) { /* jobs -p */ | 5184 | if (mode & SHOW_ONLY_PGID) { /* jobs -p */ |
4496 | /* just output process (group) id of pipeline */ | 5185 | /* just output process (group) id of pipeline */ |
4497 | fprintf(out, "%d\n", ps->ps_pid); | 5186 | fprintf(out, "%"PID_FMT"d\n", ps->ps_pid); |
4498 | return; | 5187 | return; |
4499 | } | 5188 | } |
4500 | 5189 | ||
@@ -4507,7 +5196,7 @@ showjob(struct job *jp, int mode) | |||
4507 | s[col - 3] = '-'; | 5196 | s[col - 3] = '-'; |
4508 | 5197 | ||
4509 | if (mode & SHOW_PIDS) | 5198 | if (mode & SHOW_PIDS) |
4510 | col += fmtstr(s + col, 16, "%d ", ps->ps_pid); | 5199 | col += fmtstr(s + col, 16, "%"PID_FMT"d ", ps->ps_pid); |
4511 | 5200 | ||
4512 | psend = ps + jp->nprocs; | 5201 | psend = ps + jp->nprocs; |
4513 | 5202 | ||
@@ -4516,8 +5205,10 @@ showjob(struct job *jp, int mode) | |||
4516 | col += sizeof("Running") - 1; | 5205 | col += sizeof("Running") - 1; |
4517 | } else { | 5206 | } else { |
4518 | int status = psend[-1].ps_status; | 5207 | int status = psend[-1].ps_status; |
5208 | #if !ENABLE_PLATFORM_MINGW32 | ||
4519 | if (jp->state == JOBSTOPPED) | 5209 | if (jp->state == JOBSTOPPED) |
4520 | status = jp->stopstatus; | 5210 | status = jp->stopstatus; |
5211 | #endif | ||
4521 | col += sprint_status48(s + col, status, 0); | 5212 | col += sprint_status48(s + col, status, 0); |
4522 | } | 5213 | } |
4523 | /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ | 5214 | /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ |
@@ -4536,14 +5227,18 @@ showjob(struct job *jp, int mode) | |||
4536 | s[0] = '\0'; | 5227 | s[0] = '\0'; |
4537 | col = 33; | 5228 | col = 33; |
4538 | if (mode & SHOW_PIDS) | 5229 | if (mode & SHOW_PIDS) |
4539 | col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1; | 5230 | col = fmtstr(s, 48, "\n%*c%"PID_FMT"d ", indent_col, ' ', ps->ps_pid) - 1; |
4540 | start: | 5231 | start: |
5232 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
4541 | fprintf(out, "%s%*c%s%s", | 5233 | fprintf(out, "%s%*c%s%s", |
4542 | s, | 5234 | s, |
4543 | 33 - col >= 0 ? 33 - col : 0, ' ', | 5235 | 33 - col >= 0 ? 33 - col : 0, ' ', |
4544 | ps == jp->ps ? "" : "| ", | 5236 | ps == jp->ps ? "" : "| ", |
4545 | ps->ps_cmd | 5237 | ps->ps_cmd |
4546 | ); | 5238 | ); |
5239 | #else | ||
5240 | fprintf(out, "%s", s); | ||
5241 | #endif | ||
4547 | } while (++ps != psend); | 5242 | } while (++ps != psend); |
4548 | newline_and_flush(out); | 5243 | newline_and_flush(out); |
4549 | 5244 | ||
@@ -4628,7 +5323,7 @@ getstatus(struct job *job) | |||
4628 | { | 5323 | { |
4629 | /* XXX: limits number of signals */ | 5324 | /* XXX: limits number of signals */ |
4630 | retval = WTERMSIG(status); | 5325 | retval = WTERMSIG(status); |
4631 | #if JOBS | 5326 | #if JOBS || ENABLE_PLATFORM_MINGW32 |
4632 | if (retval == SIGINT) | 5327 | if (retval == SIGINT) |
4633 | job->sigint = 1; | 5328 | job->sigint = 1; |
4634 | #endif | 5329 | #endif |
@@ -4800,7 +5495,7 @@ makejob(/*union node *node,*/ int nprocs) | |||
4800 | break; | 5495 | break; |
4801 | if (jp->state != JOBDONE || !jp->waited) | 5496 | if (jp->state != JOBDONE || !jp->waited) |
4802 | continue; | 5497 | continue; |
4803 | #if JOBS | 5498 | #if JOBS || JOBS_WIN32 |
4804 | if (doing_jobctl) | 5499 | if (doing_jobctl) |
4805 | continue; | 5500 | continue; |
4806 | #endif | 5501 | #endif |
@@ -4826,7 +5521,7 @@ makejob(/*union node *node,*/ int nprocs) | |||
4826 | return jp; | 5521 | return jp; |
4827 | } | 5522 | } |
4828 | 5523 | ||
4829 | #if JOBS | 5524 | #if JOBS || JOBS_WIN32 |
4830 | /* | 5525 | /* |
4831 | * Return a string identifying a command (to be printed by the | 5526 | * Return a string identifying a command (to be printed by the |
4832 | * jobs command). | 5527 | * jobs command). |
@@ -5168,6 +5863,7 @@ clear_traps(void) | |||
5168 | INT_ON; | 5863 | INT_ON; |
5169 | } | 5864 | } |
5170 | 5865 | ||
5866 | #if !ENABLE_PLATFORM_MINGW32 | ||
5171 | /* Lives far away from here, needed for forkchild */ | 5867 | /* Lives far away from here, needed for forkchild */ |
5172 | static void closescript(void); | 5868 | static void closescript(void); |
5173 | 5869 | ||
@@ -5294,14 +5990,22 @@ forkchild(struct job *jp, union node *n, int mode) | |||
5294 | for (jp = curjob; jp; jp = jp->prev_job) | 5990 | for (jp = curjob; jp; jp = jp->prev_job) |
5295 | freejob(jp); | 5991 | freejob(jp); |
5296 | } | 5992 | } |
5993 | #endif | ||
5297 | 5994 | ||
5298 | /* Called after fork(), in parent */ | 5995 | /* Called after fork(), in parent */ |
5299 | #if !JOBS | 5996 | #if !JOBS && !JOBS_WIN32 |
5300 | #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) | 5997 | #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) |
5301 | #endif | 5998 | #endif |
5302 | static void | 5999 | static void |
6000 | #if !ENABLE_PLATFORM_MINGW32 | ||
5303 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 6001 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
6002 | #else | ||
6003 | forkparent(struct job *jp, union node *n, int mode, HANDLE proc) | ||
6004 | #endif | ||
5304 | { | 6005 | { |
6006 | #if ENABLE_PLATFORM_MINGW32 | ||
6007 | pid_t pid = GetProcessId(proc); | ||
6008 | #endif | ||
5305 | TRACE(("In parent shell: child = %d\n", pid)); | 6009 | TRACE(("In parent shell: child = %d\n", pid)); |
5306 | if (!jp) /* jp is NULL when called by openhere() for heredoc support */ | 6010 | if (!jp) /* jp is NULL when called by openhere() for heredoc support */ |
5307 | return; | 6011 | return; |
@@ -5320,19 +6024,29 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) | |||
5320 | if (mode == FORK_BG) { | 6024 | if (mode == FORK_BG) { |
5321 | backgndpid = pid; /* set $! */ | 6025 | backgndpid = pid; /* set $! */ |
5322 | set_curjob(jp, CUR_RUNNING); | 6026 | set_curjob(jp, CUR_RUNNING); |
6027 | #if ENABLE_PLATFORM_MINGW32 | ||
6028 | if (iflag && jp && jp->nprocs == 0) | ||
6029 | fprintf(stderr, "[%d] %"PID_FMT"d\n", jobno(jp), pid); | ||
6030 | #endif | ||
5323 | } | 6031 | } |
5324 | if (jp) { | 6032 | if (jp) { |
5325 | struct procstat *ps = &jp->ps[jp->nprocs++]; | 6033 | struct procstat *ps = &jp->ps[jp->nprocs++]; |
5326 | ps->ps_pid = pid; | 6034 | ps->ps_pid = pid; |
5327 | ps->ps_status = -1; | 6035 | ps->ps_status = -1; |
6036 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
5328 | ps->ps_cmd = nullstr; | 6037 | ps->ps_cmd = nullstr; |
5329 | #if JOBS | 6038 | #endif |
6039 | #if ENABLE_PLATFORM_MINGW32 | ||
6040 | ps->ps_proc = proc; | ||
6041 | #endif | ||
6042 | #if JOBS || JOBS_WIN32 | ||
5330 | if (doing_jobctl && n) | 6043 | if (doing_jobctl && n) |
5331 | ps->ps_cmd = commandtext(n); | 6044 | ps->ps_cmd = commandtext(n); |
5332 | #endif | 6045 | #endif |
5333 | } | 6046 | } |
5334 | } | 6047 | } |
5335 | 6048 | ||
6049 | #if !ENABLE_PLATFORM_MINGW32 | ||
5336 | /* jp and n are NULL when called by openhere() for heredoc support */ | 6050 | /* jp and n are NULL when called by openhere() for heredoc support */ |
5337 | static int | 6051 | static int |
5338 | forkshell(struct job *jp, union node *n, int mode) | 6052 | forkshell(struct job *jp, union node *n, int mode) |
@@ -5355,6 +6069,7 @@ forkshell(struct job *jp, union node *n, int mode) | |||
5355 | } | 6069 | } |
5356 | return pid; | 6070 | return pid; |
5357 | } | 6071 | } |
6072 | #endif | ||
5358 | 6073 | ||
5359 | /* | 6074 | /* |
5360 | * Wait for job to finish. | 6075 | * Wait for job to finish. |
@@ -5418,6 +6133,10 @@ waitforjob(struct job *jp) | |||
5418 | return exitstatus; | 6133 | return exitstatus; |
5419 | 6134 | ||
5420 | st = getstatus(jp); | 6135 | st = getstatus(jp); |
6136 | #if ENABLE_PLATFORM_MINGW32 | ||
6137 | if (!jp->sigint && iflag && rootshell) | ||
6138 | pending_int = 0; | ||
6139 | #endif | ||
5421 | #if JOBS | 6140 | #if JOBS |
5422 | if (jp->jobctl) { | 6141 | if (jp->jobctl) { |
5423 | xtcsetpgrp(ttyfd, rootpid); | 6142 | xtcsetpgrp(ttyfd, rootpid); |
@@ -5443,6 +6162,7 @@ waitforjob(struct job *jp) | |||
5443 | /* | 6162 | /* |
5444 | * return 1 if there are stopped jobs, otherwise 0 | 6163 | * return 1 if there are stopped jobs, otherwise 0 |
5445 | */ | 6164 | */ |
6165 | #if !ENABLE_PLATFORM_MINGW32 | ||
5446 | static int | 6166 | static int |
5447 | stoppedjobs(void) | 6167 | stoppedjobs(void) |
5448 | { | 6168 | { |
@@ -5461,6 +6181,17 @@ stoppedjobs(void) | |||
5461 | out: | 6181 | out: |
5462 | return retval; | 6182 | return retval; |
5463 | } | 6183 | } |
6184 | #else | ||
6185 | static int | ||
6186 | stoppedjobs(void) | ||
6187 | { | ||
6188 | if (iflag && curjob) { | ||
6189 | out2str("You have background jobs.\n"); | ||
6190 | return 1; | ||
6191 | } | ||
6192 | return 0; | ||
6193 | } | ||
6194 | #endif | ||
5464 | 6195 | ||
5465 | 6196 | ||
5466 | /* | 6197 | /* |
@@ -5485,6 +6216,7 @@ openhere(union node *redir) | |||
5485 | char *p; | 6216 | char *p; |
5486 | int pip[2]; | 6217 | int pip[2]; |
5487 | size_t len = 0; | 6218 | size_t len = 0; |
6219 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5488 | 6220 | ||
5489 | if (pipe(pip) < 0) | 6221 | if (pipe(pip) < 0) |
5490 | ash_msg_and_raise_perror("can't create pipe"); | 6222 | ash_msg_and_raise_perror("can't create pipe"); |
@@ -5501,6 +6233,14 @@ openhere(union node *redir) | |||
5501 | goto out; | 6233 | goto out; |
5502 | } | 6234 | } |
5503 | 6235 | ||
6236 | #if ENABLE_PLATFORM_MINGW32 | ||
6237 | memset(&fs, 0, sizeof(fs)); | ||
6238 | fs.fpid = FS_OPENHERE; | ||
6239 | fs.fd[0] = pip[0]; | ||
6240 | fs.fd[1] = pip[1]; | ||
6241 | fs.path = p; | ||
6242 | spawn_forkshell(&fs, NULL, NULL, FORK_NOJOB); | ||
6243 | #else | ||
5504 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | 6244 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { |
5505 | /* child */ | 6245 | /* child */ |
5506 | close(pip[0]); | 6246 | close(pip[0]); |
@@ -5512,6 +6252,7 @@ openhere(union node *redir) | |||
5512 | xwrite(pip[1], p, len); | 6252 | xwrite(pip[1], p, len); |
5513 | _exit_SUCCESS(); | 6253 | _exit_SUCCESS(); |
5514 | } | 6254 | } |
6255 | #endif | ||
5515 | out: | 6256 | out: |
5516 | close(pip[1]); | 6257 | close(pip[1]); |
5517 | return pip[0]; | 6258 | return pip[0]; |
@@ -5589,6 +6330,9 @@ openredirect(union node *redir) | |||
5589 | f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); | 6330 | f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); |
5590 | if (f < 0) | 6331 | if (f < 0) |
5591 | goto ecreate; | 6332 | goto ecreate; |
6333 | #if ENABLE_PLATFORM_MINGW32 | ||
6334 | lseek(f, 0, SEEK_END); | ||
6335 | #endif | ||
5592 | break; | 6336 | break; |
5593 | } | 6337 | } |
5594 | 6338 | ||
@@ -5799,6 +6543,12 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq) | |||
5799 | if (fd == preverrout_fd) | 6543 | if (fd == preverrout_fd) |
5800 | preverrout_fd = new_fd; | 6544 | preverrout_fd = new_fd; |
5801 | 6545 | ||
6546 | #if ENABLE_PLATFORM_MINGW32 && !defined(_UCRT) | ||
6547 | // Workaround for problems with stderr in MSVCRT | ||
6548 | if (fd == fileno(stderr)) | ||
6549 | setvbuf(stderr, NULL, _IONBF, 0); | ||
6550 | #endif | ||
6551 | |||
5802 | return 0; /* "we did not close fd" */ | 6552 | return 0; /* "we did not close fd" */ |
5803 | } | 6553 | } |
5804 | 6554 | ||
@@ -6152,6 +6902,9 @@ ifsbreakup(char *string, struct arglist *arglist) | |||
6152 | const char *ifs, *realifs; | 6902 | const char *ifs, *realifs; |
6153 | int ifsspc; | 6903 | int ifsspc; |
6154 | int nulonly; | 6904 | int nulonly; |
6905 | #if ENABLE_PLATFORM_MINGW32 | ||
6906 | int lshift = 0; | ||
6907 | #endif | ||
6155 | 6908 | ||
6156 | start = string; | 6909 | start = string; |
6157 | if (ifslastp != NULL) { | 6910 | if (ifslastp != NULL) { |
@@ -6162,7 +6915,33 @@ ifsbreakup(char *string, struct arglist *arglist) | |||
6162 | do { | 6915 | do { |
6163 | int afternul; | 6916 | int afternul; |
6164 | 6917 | ||
6918 | #if ENABLE_PLATFORM_MINGW32 | ||
6919 | /* Adjust region offsets for left-shifted string. */ | ||
6920 | ifsp->begoff -= lshift; | ||
6921 | ifsp->endoff -= lshift; | ||
6922 | #endif | ||
6165 | p = string + ifsp->begoff; | 6923 | p = string + ifsp->begoff; |
6924 | #if ENABLE_PLATFORM_MINGW32 | ||
6925 | if (ifsp->endoff > ifsp->begoff + 1) { | ||
6926 | /* Transform CRLF to LF. Skip regions having zero or | ||
6927 | * one characters: they can't contain CRLF. If the | ||
6928 | * region shrinks shift the rest of the string left. */ | ||
6929 | int oldlen = ifsp->endoff - ifsp->begoff; | ||
6930 | int newlen = remove_cr(p, oldlen); | ||
6931 | int delta = oldlen - newlen; | ||
6932 | |||
6933 | if (delta > 0) { | ||
6934 | char *t = string + ifsp->endoff; | ||
6935 | char *s = string + ifsp->endoff - delta; | ||
6936 | |||
6937 | while (*t) | ||
6938 | *s++ = *t++; | ||
6939 | *s = '\0'; | ||
6940 | lshift += delta; | ||
6941 | ifsp->endoff -= delta; | ||
6942 | } | ||
6943 | } | ||
6944 | #endif | ||
6166 | afternul = nulonly; | 6945 | afternul = nulonly; |
6167 | nulonly = ifsp->nulonly; | 6946 | nulonly = ifsp->nulonly; |
6168 | ifs = nulonly ? nullstr : realifs; | 6947 | ifs = nulonly ? nullstr : realifs; |
@@ -6607,6 +7386,7 @@ evalbackcmd(union node *n, struct backcmd *result | |||
6607 | const int ip = 0; | 7386 | const int ip = 0; |
6608 | const int ic = 1; | 7387 | const int ic = 1; |
6609 | #endif | 7388 | #endif |
7389 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
6610 | 7390 | ||
6611 | result->fd = -1; | 7391 | result->fd = -1; |
6612 | result->buf = NULL; | 7392 | result->buf = NULL; |
@@ -6620,6 +7400,15 @@ evalbackcmd(union node *n, struct backcmd *result | |||
6620 | ash_msg_and_raise_perror("can't create pipe"); | 7400 | ash_msg_and_raise_perror("can't create pipe"); |
6621 | /* process substitution uses NULL job, like openhere() */ | 7401 | /* process substitution uses NULL job, like openhere() */ |
6622 | jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL; | 7402 | jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL; |
7403 | #if ENABLE_PLATFORM_MINGW32 | ||
7404 | memset(&fs, 0, sizeof(fs)); | ||
7405 | fs.fpid = FS_EVALBACKCMD; | ||
7406 | fs.n = n; | ||
7407 | fs.fd[0] = pip[0]; | ||
7408 | fs.fd[1] = pip[1]; | ||
7409 | fs.fd[2] = ctl; | ||
7410 | spawn_forkshell(&fs, jp, n, FORK_NOJOB); | ||
7411 | #else | ||
6623 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 7412 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
6624 | /* child */ | 7413 | /* child */ |
6625 | FORCE_INT_ON; | 7414 | FORCE_INT_ON; |
@@ -6643,6 +7432,7 @@ evalbackcmd(union node *n, struct backcmd *result | |||
6643 | evaltreenr(n, EV_EXIT); | 7432 | evaltreenr(n, EV_EXIT); |
6644 | /* NOTREACHED */ | 7433 | /* NOTREACHED */ |
6645 | } | 7434 | } |
7435 | #endif | ||
6646 | /* parent */ | 7436 | /* parent */ |
6647 | #if BASH_PROCESS_SUBST | 7437 | #if BASH_PROCESS_SUBST |
6648 | if (ctl != CTLBACKQ) { | 7438 | if (ctl != CTLBACKQ) { |
@@ -6721,8 +7511,14 @@ expbackq(union node *cmd, int flag IF_BASH_PROCESS_SUBST(, int ctl)) | |||
6721 | 7511 | ||
6722 | /* Eat all trailing newlines */ | 7512 | /* Eat all trailing newlines */ |
6723 | dest = expdest; | 7513 | dest = expdest; |
6724 | for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';) | 7514 | for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';) { |
6725 | STUNPUTC(dest); | 7515 | STUNPUTC(dest); |
7516 | #if ENABLE_PLATFORM_MINGW32 | ||
7517 | if (dest > ((char *)stackblock() + startloc) && dest[-1] == '\r') { | ||
7518 | STUNPUTC(dest); | ||
7519 | } | ||
7520 | #endif | ||
7521 | } | ||
6726 | expdest = dest; | 7522 | expdest = dest; |
6727 | 7523 | ||
6728 | if (!(flag & EXP_QUOTED)) | 7524 | if (!(flag & EXP_QUOTED)) |
@@ -7869,6 +8665,26 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
7869 | #else | 8665 | #else |
7870 | /* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */ | 8666 | /* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */ |
7871 | 8667 | ||
8668 | #if ENABLE_ASH_GLOB_OPTIONS | ||
8669 | static int FAST_FUNC | ||
8670 | ash_accept_glob(const char *name) | ||
8671 | { | ||
8672 | struct stat st; | ||
8673 | |||
8674 | if (nohiddenglob || nohidsysglob) { | ||
8675 | if (!lstat(name, &st)) { | ||
8676 | if ((st.st_attr & FILE_ATTRIBUTE_HIDDEN)) { | ||
8677 | if (nohiddenglob || | ||
8678 | (st.st_attr & FILE_ATTRIBUTE_SYSTEM)) { | ||
8679 | return FALSE; | ||
8680 | } | ||
8681 | } | ||
8682 | } | ||
8683 | } | ||
8684 | return TRUE; | ||
8685 | } | ||
8686 | #endif | ||
8687 | |||
7872 | /* | 8688 | /* |
7873 | * Do metacharacter (i.e. *, ?, [...]) expansion. | 8689 | * Do metacharacter (i.e. *, ?, [...]) expansion. |
7874 | */ | 8690 | */ |
@@ -7896,6 +8712,10 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
7896 | 8712 | ||
7897 | metaflag = 0; | 8713 | metaflag = 0; |
7898 | start = name; | 8714 | start = name; |
8715 | #if ENABLE_PLATFORM_MINGW32 | ||
8716 | if (expdir_len == 0 && has_dos_drive_prefix(start) && start[2] != '/') | ||
8717 | start += 2; | ||
8718 | #endif | ||
7899 | for (p = name; esc = 0, *p; p += esc + 1) { | 8719 | for (p = name; esc = 0, *p; p += esc + 1) { |
7900 | if (*p == '*' || *p == '?') | 8720 | if (*p == '*' || *p == '?') |
7901 | metaflag = 1; | 8721 | metaflag = 1; |
@@ -7970,8 +8790,16 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
7970 | while (!pending_int && (dp = readdir(dirp)) != NULL) { | 8790 | while (!pending_int && (dp = readdir(dirp)) != NULL) { |
7971 | if (dp->d_name[0] == '.' && !matchdot) | 8791 | if (dp->d_name[0] == '.' && !matchdot) |
7972 | continue; | 8792 | continue; |
8793 | #if ENABLE_ASH_GLOB_OPTIONS | ||
8794 | # undef pmatch | ||
8795 | # define pmatch(a, b) !fnmatch((a), (b), nocaseglob ? FNM_CASEFOLD : 0) | ||
8796 | #endif | ||
7973 | if (pmatch(start, dp->d_name)) { | 8797 | if (pmatch(start, dp->d_name)) { |
7974 | if (atend) { | 8798 | if (atend) { |
8799 | #if ENABLE_ASH_GLOB_OPTIONS | ||
8800 | if (!ash_accept_glob(dp->d_name)) | ||
8801 | continue; | ||
8802 | #endif | ||
7975 | strcpy(enddir, dp->d_name); | 8803 | strcpy(enddir, dp->d_name); |
7976 | addfname(expdir); | 8804 | addfname(expdir); |
7977 | } else { | 8805 | } else { |
@@ -7999,6 +8827,10 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
7999 | endname[-esc - 1] = esc ? '\\' : '/'; | 8827 | endname[-esc - 1] = esc ? '\\' : '/'; |
8000 | #undef expdir | 8828 | #undef expdir |
8001 | #undef expdir_max | 8829 | #undef expdir_max |
8830 | #if ENABLE_ASH_GLOB_OPTIONS | ||
8831 | # undef pmatch | ||
8832 | # define pmatch(a, b) !fnmatch((a), (b), 0) | ||
8833 | #endif | ||
8002 | } | 8834 | } |
8003 | 8835 | ||
8004 | static struct strlist * | 8836 | static struct strlist * |
@@ -8271,14 +9103,40 @@ static int builtinloc = -1; /* index in path of %builtin, or -1 */ | |||
8271 | 9103 | ||
8272 | 9104 | ||
8273 | static void | 9105 | static void |
9106 | #if ENABLE_PLATFORM_MINGW32 | ||
9107 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no, const char *path, int noexec,) | ||
9108 | const char *cmd, char **argv, char **envp) | ||
9109 | #else | ||
8274 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp) | 9110 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp) |
9111 | #endif | ||
8275 | { | 9112 | { |
9113 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
9114 | interp_t interp; | ||
9115 | #endif | ||
8276 | #if ENABLE_FEATURE_SH_STANDALONE | 9116 | #if ENABLE_FEATURE_SH_STANDALONE |
8277 | if (applet_no >= 0) { | 9117 | if (applet_no >= 0) { |
9118 | # if ENABLE_PLATFORM_MINGW32 | ||
9119 | /* Treat all applets as NOEXEC, including the shell itself | ||
9120 | * if we were called from forkshell_shellexec(). */ | ||
9121 | run_noexec: | ||
9122 | if (applet_main[applet_no] != ash_main || noexec) { | ||
9123 | /* mingw-w64's getopt() uses __argv[0] as the program name */ | ||
9124 | __argv[0] = (char *)cmd; | ||
9125 | /* 'which' wants to know if it was invoked from a standalone | ||
9126 | * shell. 'Which' in argv[0] indicates this. */ | ||
9127 | if (strcmp(argv[0], "which") == 0) { | ||
9128 | argv[0] = (char *)"Which"; | ||
9129 | } | ||
9130 | # else | ||
8278 | if (APPLET_IS_NOEXEC(applet_no)) { | 9131 | if (APPLET_IS_NOEXEC(applet_no)) { |
9132 | # endif | ||
9133 | #if !ENABLE_PLATFORM_MINGW32 || !defined(_UCRT) | ||
9134 | /* If building for UCRT move this up into shellexec() to | ||
9135 | * work around a bug. */ | ||
8279 | clearenv(); | 9136 | clearenv(); |
8280 | while (*envp) | 9137 | while (*envp) |
8281 | putenv(*envp++); | 9138 | putenv(*envp++); |
9139 | #endif | ||
8282 | popredir(/*drop:*/ 1); | 9140 | popredir(/*drop:*/ 1); |
8283 | run_noexec_applet_and_exit(applet_no, cmd, argv); | 9141 | run_noexec_applet_and_exit(applet_no, cmd, argv); |
8284 | } | 9142 | } |
@@ -8289,6 +9147,44 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
8289 | } | 9147 | } |
8290 | #endif | 9148 | #endif |
8291 | 9149 | ||
9150 | #if ENABLE_PLATFORM_MINGW32 | ||
9151 | /* Workaround for libtool, which assumes the host is an MSYS2 | ||
9152 | * environment and requires special-case escaping for cmd.exe. | ||
9153 | * https://github.com/skeeto/w64devkit/issues/50 */ | ||
9154 | if (string_array_len(argv) >= 3 && | ||
9155 | strcmp(argv[0], "cmd") == 0 && | ||
9156 | strcmp(argv[1], "//c") == 0 && | ||
9157 | strcmp(argv[2], "echo") == 0) { | ||
9158 | argv[1]++; /* drop extra slash */ | ||
9159 | } | ||
9160 | |||
9161 | /* cmd was allocated on the stack with room for an extension */ | ||
9162 | add_win32_extension((char *)cmd); | ||
9163 | |||
9164 | # if ENABLE_FEATURE_SH_STANDALONE | ||
9165 | /* If the command is a script with an interpreter which is an | ||
9166 | * applet, we can run it as if it were a noexec applet. */ | ||
9167 | if (parse_interpreter(cmd, &interp)) { | ||
9168 | applet_no = find_applet_by_name_for_sh(interp.name, path); | ||
9169 | if (applet_no >= 0) { | ||
9170 | argv[0] = (char *)cmd; | ||
9171 | /* evalcommand()/spawn_forkshell() add two elements before argv */ | ||
9172 | if (interp.opts) { | ||
9173 | argv--; | ||
9174 | argv[0] = (char *)interp.opts; | ||
9175 | } | ||
9176 | argv--; | ||
9177 | cmd = argv[0] = (char *)interp.name; | ||
9178 | /* Identify the index of the script file in argv */ | ||
9179 | set_interp(1 + (interp.opts != NULL)); | ||
9180 | goto run_noexec; | ||
9181 | } | ||
9182 | } | ||
9183 | # endif | ||
9184 | |||
9185 | execve(cmd, argv, envp); | ||
9186 | /* skip POSIX-mandated retry on ENOEXEC */ | ||
9187 | #else /* !ENABLE_PLATFORM_MINGW32 */ | ||
8292 | repeat: | 9188 | repeat: |
8293 | #ifdef SYSV | 9189 | #ifdef SYSV |
8294 | do { | 9190 | do { |
@@ -8324,15 +9220,23 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
8324 | argv[0] = (char*) "ash"; | 9220 | argv[0] = (char*) "ash"; |
8325 | goto repeat; | 9221 | goto repeat; |
8326 | } | 9222 | } |
9223 | #endif /* !ENABLE_PLATFORM_MINGW32 */ | ||
8327 | } | 9224 | } |
8328 | 9225 | ||
9226 | #if !ENABLE_PLATFORM_MINGW32 || !ENABLE_FEATURE_SH_STANDALONE | ||
9227 | # define shellexec(prg, a, pth, i, n) shellexec(prg, a, pth, i) | ||
9228 | #endif | ||
9229 | |||
8329 | /* | 9230 | /* |
8330 | * Exec a program. Never returns. If you change this routine, you may | 9231 | * Exec a program. Never returns. If you change this routine, you may |
8331 | * have to change the find_command routine as well. | 9232 | * have to change the find_command routine as well. |
8332 | * argv[-1] must exist and be writable! See tryexec() for why. | 9233 | * argv[-1] must exist and be writable! See tryexec() for why. |
8333 | */ | 9234 | */ |
8334 | static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN; | 9235 | static struct builtincmd *find_builtin(const char *name); |
8335 | static void shellexec(char *prog, char **argv, const char *path, int idx) | 9236 | static void shellexec(char *prog, char **argv, const char *path, int idx, |
9237 | int noexec) NORETURN; | ||
9238 | static void shellexec(char *prog, char **argv, const char *path, int idx, | ||
9239 | int noexec) | ||
8336 | { | 9240 | { |
8337 | char *cmdname; | 9241 | char *cmdname; |
8338 | int e; | 9242 | int e; |
@@ -8341,12 +9245,30 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
8341 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ | 9245 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ |
8342 | 9246 | ||
8343 | envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); | 9247 | envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); |
9248 | #if ENABLE_FEATURE_SH_STANDALONE && ENABLE_PLATFORM_MINGW32 && defined(_UCRT) | ||
9249 | /* Avoid UCRT bug by updating parent's environment and passing a | ||
9250 | * NULL environment pointer to execve(). */ | ||
9251 | clearenv(); | ||
9252 | while (*envp) | ||
9253 | putenv(*envp++); | ||
9254 | envp = NULL; | ||
9255 | #endif | ||
9256 | #if !ENABLE_PLATFORM_MINGW32 | ||
8344 | if (strchr(prog, '/') != NULL | 9257 | if (strchr(prog, '/') != NULL |
9258 | #else | ||
9259 | if (has_path(prog) | ||
9260 | #endif | ||
8345 | #if ENABLE_FEATURE_SH_STANDALONE | 9261 | #if ENABLE_FEATURE_SH_STANDALONE |
8346 | || (applet_no = find_applet_by_name(prog)) >= 0 | 9262 | || (applet_no = find_applet_by_name_for_sh(prog, path)) >= 0 |
8347 | #endif | 9263 | #endif |
8348 | ) { | 9264 | ) { |
9265 | #if ENABLE_PLATFORM_MINGW32 | ||
9266 | char *progext = stack_add_ext_space(prog); | ||
9267 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no, path, noexec,) | ||
9268 | progext, argv, envp); | ||
9269 | #else | ||
8349 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); | 9270 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); |
9271 | #endif | ||
8350 | if (applet_no >= 0) { | 9272 | if (applet_no >= 0) { |
8351 | /* We tried execing ourself, but it didn't work. | 9273 | /* We tried execing ourself, but it didn't work. |
8352 | * Maybe /proc/self/exe doesn't exist? | 9274 | * Maybe /proc/self/exe doesn't exist? |
@@ -8355,13 +9277,33 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
8355 | goto try_PATH; | 9277 | goto try_PATH; |
8356 | } | 9278 | } |
8357 | e = errno; | 9279 | e = errno; |
9280 | #if ENABLE_PLATFORM_MINGW32 | ||
9281 | if (unix_path(prog)) { | ||
9282 | const char *name = bb_basename(prog); | ||
9283 | # if ENABLE_FEATURE_SH_STANDALONE | ||
9284 | if ((applet_no = find_applet_by_name_for_sh(name, path)) >= 0) { | ||
9285 | tryexec(applet_no, path, noexec, name, argv, envp); | ||
9286 | e = errno; | ||
9287 | } | ||
9288 | # endif | ||
9289 | if (!find_builtin(name)) { | ||
9290 | argv[0] = (char *)name; | ||
9291 | goto try_PATH; | ||
9292 | } | ||
9293 | } | ||
9294 | #endif | ||
8358 | } else { | 9295 | } else { |
8359 | try_PATH: | 9296 | try_PATH: |
8360 | e = ENOENT; | 9297 | e = ENOENT; |
8361 | while (padvance(&path, argv[0]) >= 0) { | 9298 | while (padvance(&path, argv[0]) >= 0) { |
8362 | cmdname = stackblock(); | 9299 | cmdname = stackblock(); |
8363 | if (--idx < 0 && pathopt == NULL) { | 9300 | if (--idx < 0 && pathopt == NULL) { |
9301 | #if ENABLE_PLATFORM_MINGW32 | ||
9302 | tryexec(IF_FEATURE_SH_STANDALONE(-1, path, noexec,) | ||
9303 | cmdname, argv, envp); | ||
9304 | #else | ||
8364 | tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp); | 9305 | tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp); |
9306 | #endif | ||
8365 | if (errno != ENOENT && errno != ENOTDIR) | 9307 | if (errno != ENOENT && errno != ENOTDIR) |
8366 | e = errno; | 9308 | e = errno; |
8367 | } | 9309 | } |
@@ -8400,6 +9342,9 @@ printentry(struct tblentry *cmdp) | |||
8400 | padvance(&path, cmdp->cmdname); | 9342 | padvance(&path, cmdp->cmdname); |
8401 | } while (--idx >= 0); | 9343 | } while (--idx >= 0); |
8402 | name = stackblock(); | 9344 | name = stackblock(); |
9345 | #if ENABLE_PLATFORM_MINGW32 | ||
9346 | add_win32_extension(name); | ||
9347 | #endif | ||
8403 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); | 9348 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); |
8404 | } | 9349 | } |
8405 | 9350 | ||
@@ -8600,7 +9545,7 @@ changepath(const char *newval) | |||
8600 | bltin = idx; | 9545 | bltin = idx; |
8601 | break; | 9546 | break; |
8602 | } | 9547 | } |
8603 | new = strchr(new, ':'); | 9548 | new = strchr(new, PATH_SEP); |
8604 | if (!new) | 9549 | if (!new) |
8605 | break; | 9550 | break; |
8606 | idx++; | 9551 | idx++; |
@@ -8777,14 +9722,37 @@ describe_command(char *command, const char *path, int describe_command_verbose) | |||
8777 | case CMDNORMAL: { | 9722 | case CMDNORMAL: { |
8778 | int j = entry.u.index; | 9723 | int j = entry.u.index; |
8779 | char *p; | 9724 | char *p; |
9725 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
9726 | if (j < -1) { | ||
9727 | p = (char *)bb_basename(command); | ||
9728 | if (describe_command_verbose) { | ||
9729 | out1fmt(" is a builtin applet"); | ||
9730 | } else { | ||
9731 | out1str(applet_to_exe(p)); | ||
9732 | } | ||
9733 | break; | ||
9734 | } | ||
9735 | #endif | ||
8780 | if (j < 0) { | 9736 | if (j < 0) { |
9737 | #if ENABLE_PLATFORM_MINGW32 | ||
9738 | p = stack_add_ext_space(command); | ||
9739 | #else | ||
8781 | p = command; | 9740 | p = command; |
9741 | #endif | ||
8782 | } else { | 9742 | } else { |
9743 | #if ENABLE_PLATFORM_MINGW32 | ||
9744 | if (unix_path(command)) | ||
9745 | command = (char *)bb_basename(command); | ||
9746 | #endif | ||
8783 | do { | 9747 | do { |
8784 | padvance(&path, command); | 9748 | padvance(&path, command); |
8785 | } while (--j >= 0); | 9749 | } while (--j >= 0); |
8786 | p = stackblock(); | 9750 | p = stackblock(); |
8787 | } | 9751 | } |
9752 | #if ENABLE_PLATFORM_MINGW32 | ||
9753 | add_win32_extension(p); | ||
9754 | bs_to_slash(p); | ||
9755 | #endif | ||
8788 | if (describe_command_verbose) { | 9756 | if (describe_command_verbose) { |
8789 | out1fmt(" is %s", p); | 9757 | out1fmt(" is %s", p); |
8790 | } else { | 9758 | } else { |
@@ -8940,6 +9908,15 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
8940 | /*static int funcstringsize; // size of strings in node */ | 9908 | /*static int funcstringsize; // size of strings in node */ |
8941 | static void *funcblock; /* block to allocate function from */ | 9909 | static void *funcblock; /* block to allocate function from */ |
8942 | static char *funcstring_end; /* end of block to allocate strings from */ | 9910 | static char *funcstring_end; /* end of block to allocate strings from */ |
9911 | #if ENABLE_PLATFORM_MINGW32 | ||
9912 | static int fs_size; | ||
9913 | static void *fs_start; | ||
9914 | # if FORKSHELL_DEBUG | ||
9915 | static void *fs_funcstring; | ||
9916 | static const char **annot; | ||
9917 | static char *annot_free; | ||
9918 | # endif | ||
9919 | #endif | ||
8943 | 9920 | ||
8944 | static const uint8_t nodesize[N_NUMBER] ALIGN1 = { | 9921 | static const uint8_t nodesize[N_NUMBER] ALIGN1 = { |
8945 | [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), | 9922 | [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), |
@@ -9072,14 +10049,79 @@ calcsize(int funcblocksize, union node *n) | |||
9072 | } | 10049 | } |
9073 | 10050 | ||
9074 | static char * | 10051 | static char * |
9075 | nodeckstrdup(char *s) | 10052 | nodeckstrdup(const char *s) |
9076 | { | 10053 | { |
10054 | #if ENABLE_PLATFORM_MINGW32 | ||
10055 | if(!s) | ||
10056 | return NULL; | ||
10057 | #endif | ||
9077 | funcstring_end -= SHELL_ALIGN(strlen(s) + 1); | 10058 | funcstring_end -= SHELL_ALIGN(strlen(s) + 1); |
9078 | return strcpy(funcstring_end, s); | 10059 | return strcpy(funcstring_end, s); |
9079 | } | 10060 | } |
9080 | 10061 | ||
9081 | static union node *copynode(union node *); | 10062 | static union node *copynode(union node *); |
9082 | 10063 | ||
10064 | #if ENABLE_PLATFORM_MINGW32 | ||
10065 | # if FORKSHELL_DEBUG | ||
10066 | # define MARK_PTR(dst,note,flag) forkshell_mark_ptr((void *)&dst, note, flag) | ||
10067 | # else | ||
10068 | # define MARK_PTR(dst,note,flag) forkshell_mark_ptr((void *)&dst) | ||
10069 | # endif | ||
10070 | |||
10071 | #define NO_FREE 0 | ||
10072 | #define FREE 1 | ||
10073 | |||
10074 | #if FORKSHELL_DEBUG | ||
10075 | static void forkshell_mark_ptr(void *dst, const char *note, int flag) | ||
10076 | #else | ||
10077 | static void forkshell_mark_ptr(void *dst) | ||
10078 | #endif | ||
10079 | { | ||
10080 | char *lrelocate = (char *)fs_start + fs_size; | ||
10081 | int index = ((char *)dst - (char *)fs_start)/sizeof(char *); | ||
10082 | |||
10083 | lrelocate[index/8] |= 1 << (index % 8); | ||
10084 | |||
10085 | #if FORKSHELL_DEBUG | ||
10086 | if (dst < fs_start || dst >= fs_funcstring) { | ||
10087 | fprintf(stderr, "dst (%p) out of range (%p %p)\n", | ||
10088 | dst, fs_start, fs_funcstring); | ||
10089 | } | ||
10090 | if (annot) { | ||
10091 | if (annot[index]) { | ||
10092 | fprintf(stderr, "duplicate annotation: %s %s\n", | ||
10093 | annot[index], note); | ||
10094 | } | ||
10095 | annot[index] = note; | ||
10096 | annot_free[index] = flag; | ||
10097 | } | ||
10098 | #endif | ||
10099 | } | ||
10100 | |||
10101 | # define SAVE_PTR(dst,note,flag) { \ | ||
10102 | if (fs_size) { \ | ||
10103 | MARK_PTR(dst,note,flag); \ | ||
10104 | } \ | ||
10105 | } | ||
10106 | # define SAVE_PTR2(dst1,note1,flag1,dst2,note2,flag2) { \ | ||
10107 | if (fs_size) { \ | ||
10108 | MARK_PTR(dst1,note1,flag1); \ | ||
10109 | MARK_PTR(dst2,note2,flag2); \ | ||
10110 | } \ | ||
10111 | } | ||
10112 | # define SAVE_PTR3(dst1,note1,flag1,dst2,note2,flag2,dst3,note3,flag3) { \ | ||
10113 | if (fs_size) { \ | ||
10114 | MARK_PTR(dst1,note1,flag1); \ | ||
10115 | MARK_PTR(dst2,note2,flag2); \ | ||
10116 | MARK_PTR(dst3,note3,flag3); \ | ||
10117 | } \ | ||
10118 | } | ||
10119 | #else | ||
10120 | # define SAVE_PTR(dst,note,flag) | ||
10121 | # define SAVE_PTR2(dst1,note1,flag1,dst2,note2,flag2) | ||
10122 | # define SAVE_PTR3(dst1,note1,flag1,dst2,note2,flag2,dst3,note3,flag3) | ||
10123 | #endif | ||
10124 | |||
9083 | static struct nodelist * | 10125 | static struct nodelist * |
9084 | copynodelist(struct nodelist *lp) | 10126 | copynodelist(struct nodelist *lp) |
9085 | { | 10127 | { |
@@ -9091,6 +10133,8 @@ copynodelist(struct nodelist *lp) | |||
9091 | *lpp = funcblock; | 10133 | *lpp = funcblock; |
9092 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); | 10134 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); |
9093 | (*lpp)->n = copynode(lp->n); | 10135 | (*lpp)->n = copynode(lp->n); |
10136 | SAVE_PTR2((*lpp)->n, "(*lpp)->next", NO_FREE, | ||
10137 | (*lpp)->next, "(*lpp)->next", NO_FREE); | ||
9094 | lp = lp->next; | 10138 | lp = lp->next; |
9095 | lpp = &(*lpp)->next; | 10139 | lpp = &(*lpp)->next; |
9096 | } | 10140 | } |
@@ -9114,10 +10158,14 @@ copynode(union node *n) | |||
9114 | new->ncmd.args = copynode(n->ncmd.args); | 10158 | new->ncmd.args = copynode(n->ncmd.args); |
9115 | new->ncmd.assign = copynode(n->ncmd.assign); | 10159 | new->ncmd.assign = copynode(n->ncmd.assign); |
9116 | new->ncmd.linno = n->ncmd.linno; | 10160 | new->ncmd.linno = n->ncmd.linno; |
10161 | SAVE_PTR3(new->ncmd.redirect, "ncmd.redirect", NO_FREE, | ||
10162 | new->ncmd.args, "ncmd.args", NO_FREE, | ||
10163 | new->ncmd.assign, "ncmd.assign", NO_FREE); | ||
9117 | break; | 10164 | break; |
9118 | case NPIPE: | 10165 | case NPIPE: |
9119 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | 10166 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); |
9120 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; | 10167 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; |
10168 | SAVE_PTR(new->npipe.cmdlist, "npipe.cmdlist", NO_FREE); | ||
9121 | break; | 10169 | break; |
9122 | case NREDIR: | 10170 | case NREDIR: |
9123 | case NBACKGND: | 10171 | case NBACKGND: |
@@ -9125,6 +10173,8 @@ copynode(union node *n) | |||
9125 | new->nredir.redirect = copynode(n->nredir.redirect); | 10173 | new->nredir.redirect = copynode(n->nredir.redirect); |
9126 | new->nredir.n = copynode(n->nredir.n); | 10174 | new->nredir.n = copynode(n->nredir.n); |
9127 | new->nredir.linno = n->nredir.linno; | 10175 | new->nredir.linno = n->nredir.linno; |
10176 | SAVE_PTR2(new->nredir.redirect, "nredir.redirect", NO_FREE, | ||
10177 | new->nredir.n, "nredir.n", NO_FREE); | ||
9128 | break; | 10178 | break; |
9129 | case NAND: | 10179 | case NAND: |
9130 | case NOR: | 10180 | case NOR: |
@@ -9133,37 +10183,58 @@ copynode(union node *n) | |||
9133 | case NUNTIL: | 10183 | case NUNTIL: |
9134 | new->nbinary.ch2 = copynode(n->nbinary.ch2); | 10184 | new->nbinary.ch2 = copynode(n->nbinary.ch2); |
9135 | new->nbinary.ch1 = copynode(n->nbinary.ch1); | 10185 | new->nbinary.ch1 = copynode(n->nbinary.ch1); |
10186 | SAVE_PTR2(new->nbinary.ch1, "nbinary.ch1", NO_FREE, | ||
10187 | new->nbinary.ch2, "nbinary.ch2", NO_FREE); | ||
9136 | break; | 10188 | break; |
9137 | case NIF: | 10189 | case NIF: |
9138 | new->nif.elsepart = copynode(n->nif.elsepart); | 10190 | new->nif.elsepart = copynode(n->nif.elsepart); |
9139 | new->nif.ifpart = copynode(n->nif.ifpart); | 10191 | new->nif.ifpart = copynode(n->nif.ifpart); |
9140 | new->nif.test = copynode(n->nif.test); | 10192 | new->nif.test = copynode(n->nif.test); |
10193 | SAVE_PTR3(new->nif.elsepart, "nif.elsepart", NO_FREE, | ||
10194 | new->nif.ifpart, "nif.ifpart", NO_FREE, | ||
10195 | new->nif.test, "nif.test", NO_FREE); | ||
9141 | break; | 10196 | break; |
9142 | case NFOR: | 10197 | case NFOR: |
9143 | new->nfor.var = nodeckstrdup(n->nfor.var); | 10198 | new->nfor.var = nodeckstrdup(n->nfor.var); |
9144 | new->nfor.body = copynode(n->nfor.body); | 10199 | new->nfor.body = copynode(n->nfor.body); |
9145 | new->nfor.args = copynode(n->nfor.args); | 10200 | new->nfor.args = copynode(n->nfor.args); |
9146 | new->nfor.linno = n->nfor.linno; | 10201 | new->nfor.linno = n->nfor.linno; |
10202 | SAVE_PTR3(new->nfor.var, | ||
10203 | xasprintf("nfor.var '%s'", n->nfor.var ?: "NULL"), FREE, | ||
10204 | new->nfor.body, "nfor.body", NO_FREE, | ||
10205 | new->nfor.args, "nfor.args", NO_FREE); | ||
9147 | break; | 10206 | break; |
9148 | case NCASE: | 10207 | case NCASE: |
9149 | new->ncase.cases = copynode(n->ncase.cases); | 10208 | new->ncase.cases = copynode(n->ncase.cases); |
9150 | new->ncase.expr = copynode(n->ncase.expr); | 10209 | new->ncase.expr = copynode(n->ncase.expr); |
9151 | new->ncase.linno = n->ncase.linno; | 10210 | new->ncase.linno = n->ncase.linno; |
10211 | SAVE_PTR2(new->ncase.cases, "ncase.cases", NO_FREE, | ||
10212 | new->ncase.expr, "ncase.expr", NO_FREE); | ||
9152 | break; | 10213 | break; |
9153 | case NCLIST: | 10214 | case NCLIST: |
9154 | new->nclist.body = copynode(n->nclist.body); | 10215 | new->nclist.body = copynode(n->nclist.body); |
9155 | new->nclist.pattern = copynode(n->nclist.pattern); | 10216 | new->nclist.pattern = copynode(n->nclist.pattern); |
9156 | new->nclist.next = copynode(n->nclist.next); | 10217 | new->nclist.next = copynode(n->nclist.next); |
10218 | SAVE_PTR3(new->nclist.body, "nclist.body", NO_FREE, | ||
10219 | new->nclist.pattern, "nclist.pattern", NO_FREE, | ||
10220 | new->nclist.next, "nclist.next", NO_FREE); | ||
9157 | break; | 10221 | break; |
9158 | case NDEFUN: | 10222 | case NDEFUN: |
9159 | new->ndefun.body = copynode(n->ndefun.body); | 10223 | new->ndefun.body = copynode(n->ndefun.body); |
9160 | new->ndefun.text = nodeckstrdup(n->ndefun.text); | 10224 | new->ndefun.text = nodeckstrdup(n->ndefun.text); |
9161 | new->ndefun.linno = n->ndefun.linno; | 10225 | new->ndefun.linno = n->ndefun.linno; |
10226 | SAVE_PTR2(new->ndefun.body, "ndefun.body", NO_FREE, | ||
10227 | new->ndefun.text, | ||
10228 | xasprintf("ndefun.text '%s'", n->ndefun.text ?: "NULL"), FREE); | ||
9162 | break; | 10229 | break; |
9163 | case NARG: | 10230 | case NARG: |
9164 | new->narg.backquote = copynodelist(n->narg.backquote); | 10231 | new->narg.backquote = copynodelist(n->narg.backquote); |
9165 | new->narg.text = nodeckstrdup(n->narg.text); | 10232 | new->narg.text = nodeckstrdup(n->narg.text); |
9166 | new->narg.next = copynode(n->narg.next); | 10233 | new->narg.next = copynode(n->narg.next); |
10234 | SAVE_PTR3(new->narg.backquote, "narg.backquote", NO_FREE, | ||
10235 | new->narg.text, | ||
10236 | xasprintf("narg.text '%s'", n->narg.text ?: "NULL"), FREE, | ||
10237 | new->narg.next, "narg.next", NO_FREE); | ||
9167 | break; | 10238 | break; |
9168 | case NTO: | 10239 | case NTO: |
9169 | #if BASH_REDIR_OUTPUT | 10240 | #if BASH_REDIR_OUTPUT |
@@ -9176,6 +10247,8 @@ copynode(union node *n) | |||
9176 | new->nfile.fname = copynode(n->nfile.fname); | 10247 | new->nfile.fname = copynode(n->nfile.fname); |
9177 | new->nfile.fd = n->nfile.fd; | 10248 | new->nfile.fd = n->nfile.fd; |
9178 | new->nfile.next = copynode(n->nfile.next); | 10249 | new->nfile.next = copynode(n->nfile.next); |
10250 | SAVE_PTR2(new->nfile.fname, "nfile.fname", NO_FREE, | ||
10251 | new->nfile.next, "nfile.next", NO_FREE); | ||
9179 | break; | 10252 | break; |
9180 | case NTOFD: | 10253 | case NTOFD: |
9181 | case NFROMFD: | 10254 | case NFROMFD: |
@@ -9183,15 +10256,20 @@ copynode(union node *n) | |||
9183 | new->ndup.dupfd = n->ndup.dupfd; | 10256 | new->ndup.dupfd = n->ndup.dupfd; |
9184 | new->ndup.fd = n->ndup.fd; | 10257 | new->ndup.fd = n->ndup.fd; |
9185 | new->ndup.next = copynode(n->ndup.next); | 10258 | new->ndup.next = copynode(n->ndup.next); |
10259 | SAVE_PTR2(new->ndup.vname, "ndup.vname", NO_FREE, | ||
10260 | new->ndup.next, "ndup.next", NO_FREE); | ||
9186 | break; | 10261 | break; |
9187 | case NHERE: | 10262 | case NHERE: |
9188 | case NXHERE: | 10263 | case NXHERE: |
9189 | new->nhere.doc = copynode(n->nhere.doc); | 10264 | new->nhere.doc = copynode(n->nhere.doc); |
9190 | new->nhere.fd = n->nhere.fd; | 10265 | new->nhere.fd = n->nhere.fd; |
9191 | new->nhere.next = copynode(n->nhere.next); | 10266 | new->nhere.next = copynode(n->nhere.next); |
10267 | SAVE_PTR2(new->nhere.doc, "nhere.doc", NO_FREE, | ||
10268 | new->nhere.next, "nhere.next", NO_FREE); | ||
9192 | break; | 10269 | break; |
9193 | case NNOT: | 10270 | case NNOT: |
9194 | new->nnot.com = copynode(n->nnot.com); | 10271 | new->nnot.com = copynode(n->nnot.com); |
10272 | SAVE_PTR(new->nnot.com, "nnot.com", NO_FREE); | ||
9195 | break; | 10273 | break; |
9196 | }; | 10274 | }; |
9197 | new->type = n->type; | 10275 | new->type = n->type; |
@@ -9212,6 +10290,7 @@ copyfunc(union node *n) | |||
9212 | f = ckzalloc(blocksize /* + funcstringsize */); | 10290 | f = ckzalloc(blocksize /* + funcstringsize */); |
9213 | funcblock = (char *) f + offsetof(struct funcnode, n); | 10291 | funcblock = (char *) f + offsetof(struct funcnode, n); |
9214 | funcstring_end = (char *) f + blocksize; | 10292 | funcstring_end = (char *) f + blocksize; |
10293 | IF_PLATFORM_MINGW32(fs_size = 0); | ||
9215 | copynode(n); | 10294 | copynode(n); |
9216 | /* f->count = 0; - ckzalloc did it */ | 10295 | /* f->count = 0; - ckzalloc did it */ |
9217 | return f; | 10296 | return f; |
@@ -9239,12 +10318,15 @@ defun(union node *func) | |||
9239 | #define SKIPFUNCDEF (1 << 3) | 10318 | #define SKIPFUNCDEF (1 << 3) |
9240 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ | 10319 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ |
9241 | static int skipcount; /* number of levels to skip */ | 10320 | static int skipcount; /* number of levels to skip */ |
10321 | #if ENABLE_PLATFORM_POSIX | ||
9242 | static int loopnest; /* current loop nesting level */ | 10322 | static int loopnest; /* current loop nesting level */ |
10323 | #endif | ||
9243 | static int funcline; /* starting line number of current function, or 0 if not in a function */ | 10324 | static int funcline; /* starting line number of current function, or 0 if not in a function */ |
9244 | 10325 | ||
9245 | /* Forward decl way out to parsing code - dotrap needs it */ | 10326 | /* Forward decl way out to parsing code - dotrap needs it */ |
9246 | static int evalstring(char *s, int flags); | 10327 | static int evalstring(char *s, int flags); |
9247 | 10328 | ||
10329 | #if !ENABLE_PLATFORM_MINGW32 | ||
9248 | /* Called to execute a trap. | 10330 | /* Called to execute a trap. |
9249 | * Single callsite - at the end of evaltree(). | 10331 | * Single callsite - at the end of evaltree(). |
9250 | * If we return non-zero, evaltree raises EXEXIT exception. | 10332 | * If we return non-zero, evaltree raises EXEXIT exception. |
@@ -9303,6 +10385,45 @@ dotrap(void) | |||
9303 | savestatus = last_status; | 10385 | savestatus = last_status; |
9304 | TRACE(("dotrap returns\n")); | 10386 | TRACE(("dotrap returns\n")); |
9305 | } | 10387 | } |
10388 | #else | ||
10389 | static void | ||
10390 | dotrap(void) | ||
10391 | { | ||
10392 | int status, last_status; | ||
10393 | char *p; | ||
10394 | |||
10395 | if (!pending_int) | ||
10396 | return; | ||
10397 | |||
10398 | status = savestatus; | ||
10399 | last_status = status; | ||
10400 | if (status < 0) { | ||
10401 | status = exitstatus; | ||
10402 | savestatus = status; | ||
10403 | } | ||
10404 | pending_int = 0; | ||
10405 | barrier(); | ||
10406 | |||
10407 | TRACE(("dotrap entered\n")); | ||
10408 | if (evalskip) { | ||
10409 | pending_int = 1; | ||
10410 | return; | ||
10411 | } | ||
10412 | |||
10413 | p = trap[SIGINT]; | ||
10414 | if (p) { | ||
10415 | TRACE(("sig %d is active, will run handler '%s'\n", SIGINT, p)); | ||
10416 | trap_depth++; | ||
10417 | evalstring(p, 0); | ||
10418 | trap_depth--; | ||
10419 | if (evalskip != SKIPFUNC) | ||
10420 | exitstatus = status; | ||
10421 | } | ||
10422 | |||
10423 | savestatus = last_status; | ||
10424 | TRACE(("dotrap returns\n")); | ||
10425 | } | ||
10426 | #endif | ||
9306 | 10427 | ||
9307 | /* forward declarations - evaluation is fairly recursive business... */ | 10428 | /* forward declarations - evaluation is fairly recursive business... */ |
9308 | static int evalloop(union node *, int); | 10429 | static int evalloop(union node *, int); |
@@ -9588,19 +10709,36 @@ evalcase(union node *n, int flags) | |||
9588 | static int | 10709 | static int |
9589 | evalsubshell(union node *n, int flags) | 10710 | evalsubshell(union node *n, int flags) |
9590 | { | 10711 | { |
10712 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
9591 | struct job *jp; | 10713 | struct job *jp; |
9592 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ | 10714 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ |
9593 | int status; | 10715 | int status; |
9594 | 10716 | ||
9595 | errlinno = lineno = n->nredir.linno; | 10717 | errlinno = lineno = n->nredir.linno; |
9596 | 10718 | ||
10719 | #if ENABLE_PLATFORM_MINGW32 | ||
10720 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) { | ||
10721 | expredir(n->nredir.redirect); | ||
10722 | redirect(n->nredir.redirect, 0); | ||
10723 | evaltreenr(n->nredir.n, flags); | ||
10724 | /* never returns */ | ||
10725 | } | ||
10726 | #else | ||
9597 | expredir(n->nredir.redirect); | 10727 | expredir(n->nredir.redirect); |
9598 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) | 10728 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) |
9599 | goto nofork; | 10729 | goto nofork; |
10730 | #endif | ||
9600 | INT_OFF; | 10731 | INT_OFF; |
9601 | if (backgnd == FORK_FG) | 10732 | if (backgnd == FORK_FG) |
9602 | get_tty_state(); | 10733 | get_tty_state(); |
9603 | jp = makejob(/*n,*/ 1); | 10734 | jp = makejob(/*n,*/ 1); |
10735 | #if ENABLE_PLATFORM_MINGW32 | ||
10736 | memset(&fs, 0, sizeof(fs)); | ||
10737 | fs.fpid = FS_EVALSUBSHELL; | ||
10738 | fs.n = n; | ||
10739 | fs.flags = flags; | ||
10740 | spawn_forkshell(&fs, jp, n, backgnd); | ||
10741 | #else | ||
9604 | if (forkshell(jp, n, backgnd) == 0) { | 10742 | if (forkshell(jp, n, backgnd) == 0) { |
9605 | /* child */ | 10743 | /* child */ |
9606 | INT_ON; | 10744 | INT_ON; |
@@ -9612,6 +10750,7 @@ evalsubshell(union node *n, int flags) | |||
9612 | evaltreenr(n->nredir.n, flags); | 10750 | evaltreenr(n->nredir.n, flags); |
9613 | /* never returns */ | 10751 | /* never returns */ |
9614 | } | 10752 | } |
10753 | #endif | ||
9615 | /* parent */ | 10754 | /* parent */ |
9616 | status = 0; | 10755 | status = 0; |
9617 | if (backgnd == FORK_FG) | 10756 | if (backgnd == FORK_FG) |
@@ -9692,6 +10831,7 @@ expredir(union node *n) | |||
9692 | static int | 10831 | static int |
9693 | evalpipe(union node *n, int flags) | 10832 | evalpipe(union node *n, int flags) |
9694 | { | 10833 | { |
10834 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
9695 | struct job *jp; | 10835 | struct job *jp; |
9696 | struct nodelist *lp; | 10836 | struct nodelist *lp; |
9697 | int pipelen; | 10837 | int pipelen; |
@@ -9718,6 +10858,16 @@ evalpipe(union node *n, int flags) | |||
9718 | ash_msg_and_raise_perror("can't create pipe"); | 10858 | ash_msg_and_raise_perror("can't create pipe"); |
9719 | } | 10859 | } |
9720 | } | 10860 | } |
10861 | #if ENABLE_PLATFORM_MINGW32 | ||
10862 | memset(&fs, 0, sizeof(fs)); | ||
10863 | fs.fpid = FS_EVALPIPE; | ||
10864 | fs.flags = flags; | ||
10865 | fs.n = lp->n; | ||
10866 | fs.fd[0] = pip[0]; | ||
10867 | fs.fd[1] = pip[1]; | ||
10868 | fs.fd[2] = prevfd; | ||
10869 | spawn_forkshell(&fs, jp, lp->n, n->npipe.pipe_backgnd); | ||
10870 | #else | ||
9721 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { | 10871 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { |
9722 | /* child */ | 10872 | /* child */ |
9723 | INT_ON; | 10873 | INT_ON; |
@@ -9735,6 +10885,7 @@ evalpipe(union node *n, int flags) | |||
9735 | evaltreenr(lp->n, flags); | 10885 | evaltreenr(lp->n, flags); |
9736 | /* never returns */ | 10886 | /* never returns */ |
9737 | } | 10887 | } |
10888 | #endif | ||
9738 | /* parent */ | 10889 | /* parent */ |
9739 | if (prevfd >= 0) | 10890 | if (prevfd >= 0) |
9740 | close(prevfd); | 10891 | close(prevfd); |
@@ -9792,6 +10943,9 @@ setinteractive(int on) | |||
9792 | line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); | 10943 | line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); |
9793 | # if ENABLE_FEATURE_TAB_COMPLETION | 10944 | # if ENABLE_FEATURE_TAB_COMPLETION |
9794 | line_input_state->get_exe_name = ash_command_name; | 10945 | line_input_state->get_exe_name = ash_command_name; |
10946 | # if ENABLE_ASH_GLOB_OPTIONS | ||
10947 | line_input_state->sh_accept_glob = ash_accept_glob; | ||
10948 | # endif | ||
9795 | # endif | 10949 | # endif |
9796 | # if EDITING_HAS_sh_get_var | 10950 | # if EDITING_HAS_sh_get_var |
9797 | line_input_state->sh_get_var = lookupvar; | 10951 | line_input_state->sh_get_var = lookupvar; |
@@ -9819,6 +10973,12 @@ optschanged(void) | |||
9819 | #else | 10973 | #else |
9820 | viflag = 0; /* forcibly keep the option off */ | 10974 | viflag = 0; /* forcibly keep the option off */ |
9821 | #endif | 10975 | #endif |
10976 | #if ENABLE_ASH_NOCONSOLE | ||
10977 | hide_console(noconsole); | ||
10978 | #endif | ||
10979 | #if ENABLE_PLATFORM_MINGW32 | ||
10980 | setwinxp(winxp); | ||
10981 | #endif | ||
9822 | } | 10982 | } |
9823 | 10983 | ||
9824 | struct localvar_list { | 10984 | struct localvar_list { |
@@ -9838,6 +10998,9 @@ poplocalvars(int keep) | |||
9838 | struct localvar_list *ll; | 10998 | struct localvar_list *ll; |
9839 | struct localvar *lvp, *next; | 10999 | struct localvar *lvp, *next; |
9840 | struct var *vp; | 11000 | struct var *vp; |
11001 | #if ENABLE_PLATFORM_MINGW32 | ||
11002 | int var_type; | ||
11003 | #endif | ||
9841 | 11004 | ||
9842 | INT_OFF; | 11005 | INT_OFF; |
9843 | ll = localvar_stack; | 11006 | ll = localvar_stack; |
@@ -9880,6 +11043,17 @@ poplocalvars(int keep) | |||
9880 | free((char*)vp->var_text); | 11043 | free((char*)vp->var_text); |
9881 | vp->flags = lvp->flags; | 11044 | vp->flags = lvp->flags; |
9882 | vp->var_text = lvp->text; | 11045 | vp->var_text = lvp->text; |
11046 | #if ENABLE_PLATFORM_MINGW32 | ||
11047 | var_type = is_bb_var(lvp->text); | ||
11048 | if (var_type == BB_VAR_ASSIGN && (lvp->flags & VEXPORT)) | ||
11049 | putenv(lvp->text); | ||
11050 | else if (var_type) { | ||
11051 | char *var = xstrdup(lvp->text); | ||
11052 | *strchrnul(var, '=') = '\0'; | ||
11053 | unsetenv(var); | ||
11054 | free(var); | ||
11055 | } | ||
11056 | #endif | ||
9883 | } | 11057 | } |
9884 | free(lvp); | 11058 | free(lvp); |
9885 | } | 11059 | } |
@@ -10102,7 +11276,7 @@ execcmd(int argc UNUSED_PARAM, char **argv) | |||
10102 | prog = argv[0]; | 11276 | prog = argv[0]; |
10103 | if (optionarg) | 11277 | if (optionarg) |
10104 | argv[0] = optionarg; | 11278 | argv[0] = optionarg; |
10105 | shellexec(prog, argv, pathval(), 0); | 11279 | shellexec(prog, argv, pathval(), 0, FALSE); |
10106 | /* NOTREACHED */ | 11280 | /* NOTREACHED */ |
10107 | } | 11281 | } |
10108 | return 0; | 11282 | return 0; |
@@ -10155,6 +11329,9 @@ static int readcmd(int, char **) FAST_FUNC; | |||
10155 | static int setcmd(int, char **) FAST_FUNC; | 11329 | static int setcmd(int, char **) FAST_FUNC; |
10156 | static int shiftcmd(int, char **) FAST_FUNC; | 11330 | static int shiftcmd(int, char **) FAST_FUNC; |
10157 | static int timescmd(int, char **) FAST_FUNC; | 11331 | static int timescmd(int, char **) FAST_FUNC; |
11332 | #if ENABLE_PLATFORM_MINGW32 | ||
11333 | static int titlecmd(int, char **) FAST_FUNC; | ||
11334 | #endif | ||
10158 | static int trapcmd(int, char **) FAST_FUNC; | 11335 | static int trapcmd(int, char **) FAST_FUNC; |
10159 | static int umaskcmd(int, char **) FAST_FUNC; | 11336 | static int umaskcmd(int, char **) FAST_FUNC; |
10160 | static int unsetcmd(int, char **) FAST_FUNC; | 11337 | static int unsetcmd(int, char **) FAST_FUNC; |
@@ -10227,7 +11404,7 @@ static const struct builtincmd builtintab[] = { | |||
10227 | #if MAX_HISTORY | 11404 | #if MAX_HISTORY |
10228 | { BUILTIN_NOSPEC "history" , historycmd }, | 11405 | { BUILTIN_NOSPEC "history" , historycmd }, |
10229 | #endif | 11406 | #endif |
10230 | #if JOBS | 11407 | #if JOBS || JOBS_WIN32 |
10231 | { BUILTIN_REGULAR "jobs" , jobscmd }, | 11408 | { BUILTIN_REGULAR "jobs" , jobscmd }, |
10232 | { BUILTIN_REGULAR "kill" , killcmd }, | 11409 | { BUILTIN_REGULAR "kill" , killcmd }, |
10233 | #endif | 11410 | #endif |
@@ -10254,6 +11431,9 @@ static const struct builtincmd builtintab[] = { | |||
10254 | { BUILTIN_REGULAR "test" , testcmd }, | 11431 | { BUILTIN_REGULAR "test" , testcmd }, |
10255 | #endif | 11432 | #endif |
10256 | { BUILTIN_SPEC_REG "times" , timescmd }, | 11433 | { BUILTIN_SPEC_REG "times" , timescmd }, |
11434 | #if ENABLE_PLATFORM_MINGW32 | ||
11435 | { BUILTIN_REGULAR "title" , titlecmd }, | ||
11436 | #endif | ||
10257 | { BUILTIN_SPEC_REG "trap" , trapcmd }, | 11437 | { BUILTIN_SPEC_REG "trap" , trapcmd }, |
10258 | { BUILTIN_REGULAR "true" , truecmd }, | 11438 | { BUILTIN_REGULAR "true" , truecmd }, |
10259 | { BUILTIN_REGULAR "type" , typecmd }, | 11439 | { BUILTIN_REGULAR "type" , typecmd }, |
@@ -10272,7 +11452,7 @@ static const struct builtincmd builtintab[] = { | |||
10272 | /* [ */ 1 * ENABLE_ASH_TEST + \ | 11452 | /* [ */ 1 * ENABLE_ASH_TEST + \ |
10273 | /* [[ */ 1 * BASH_TEST2 + \ | 11453 | /* [[ */ 1 * BASH_TEST2 + \ |
10274 | /* alias */ 1 * ENABLE_ASH_ALIAS + \ | 11454 | /* alias */ 1 * ENABLE_ASH_ALIAS + \ |
10275 | /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \ | 11455 | /* bg */ 1 * JOBS + \ |
10276 | /* break cd cddir */ 3) | 11456 | /* break cd cddir */ 3) |
10277 | #define EVALCMD (COMMANDCMD + \ | 11457 | #define EVALCMD (COMMANDCMD + \ |
10278 | /* command */ 1 * ENABLE_ASH_CMDCMD + \ | 11458 | /* command */ 1 * ENABLE_ASH_CMDCMD + \ |
@@ -10353,6 +11533,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
10353 | * as POSIX mandates */ | 11533 | * as POSIX mandates */ |
10354 | return back_exitstatus; | 11534 | return back_exitstatus; |
10355 | } | 11535 | } |
11536 | |||
10356 | static int | 11537 | static int |
10357 | evalcommand(union node *cmd, int flags) | 11538 | evalcommand(union node *cmd, int flags) |
10358 | { | 11539 | { |
@@ -10452,9 +11633,19 @@ evalcommand(union node *cmd, int flags) | |||
10452 | 11633 | ||
10453 | localvar_stop = pushlocalvars(vlocal); | 11634 | localvar_stop = pushlocalvars(vlocal); |
10454 | 11635 | ||
11636 | #if ENABLE_PLATFORM_MINGW32 | ||
11637 | # if ENABLE_FEATURE_SH_STANDALONE | ||
11638 | /* Reserve two extra spots at the front for shellexec. */ | ||
11639 | nargv = stalloc(sizeof(char *) * (argc + 3)); | ||
11640 | argv = nargv = nargv + 2; | ||
11641 | # else | ||
11642 | argv = nargv = stalloc(sizeof(char *) * (argc + 1)); | ||
11643 | # endif | ||
11644 | #else | ||
10455 | /* Reserve one extra spot at the front for shellexec. */ | 11645 | /* Reserve one extra spot at the front for shellexec. */ |
10456 | nargv = stalloc(sizeof(char *) * (argc + 2)); | 11646 | nargv = stalloc(sizeof(char *) * (argc + 2)); |
10457 | argv = ++nargv; | 11647 | argv = ++nargv; |
11648 | #endif | ||
10458 | for (sp = arglist.list; sp; sp = sp->next) { | 11649 | for (sp = arglist.list; sp; sp = sp->next) { |
10459 | TRACE(("evalcommand arg: %s\n", sp->text)); | 11650 | TRACE(("evalcommand arg: %s\n", sp->text)); |
10460 | *nargv++ = sp->text; | 11651 | *nargv++ = sp->text; |
@@ -10563,9 +11754,11 @@ evalcommand(union node *cmd, int flags) | |||
10563 | 11754 | ||
10564 | default: { | 11755 | default: { |
10565 | 11756 | ||
11757 | //TODO: find a better solution for Windows on ARM than ignoring NOFORK | ||
10566 | #if ENABLE_FEATURE_SH_STANDALONE \ | 11758 | #if ENABLE_FEATURE_SH_STANDALONE \ |
10567 | && ENABLE_FEATURE_SH_NOFORK \ | 11759 | && ENABLE_FEATURE_SH_NOFORK \ |
10568 | && NUM_APPLETS > 1 | 11760 | && NUM_APPLETS > 1 \ |
11761 | && !(defined(_ARM64_) && !defined(_UCRT) && ENABLE_PLATFORM_MINGW32) | ||
10569 | /* (1) BUG: if variables are set, we need to fork, or save/restore them | 11762 | /* (1) BUG: if variables are set, we need to fork, or save/restore them |
10570 | * around run_nofork_applet() call. | 11763 | * around run_nofork_applet() call. |
10571 | * (2) Should this check also be done in forkshell()? | 11764 | * (2) Should this check also be done in forkshell()? |
@@ -10575,6 +11768,9 @@ evalcommand(union node *cmd, int flags) | |||
10575 | int applet_no = (- cmdentry.u.index - 2); | 11768 | int applet_no = (- cmdentry.u.index - 2); |
10576 | if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { | 11769 | if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { |
10577 | char **sv_environ; | 11770 | char **sv_environ; |
11771 | #if ENABLE_PLATFORM_MINGW32 | ||
11772 | char *sv_argv0; | ||
11773 | #endif | ||
10578 | 11774 | ||
10579 | INT_OFF; | 11775 | INT_OFF; |
10580 | sv_environ = environ; | 11776 | sv_environ = environ; |
@@ -10587,8 +11783,16 @@ evalcommand(union node *cmd, int flags) | |||
10587 | * and/or wait for user input ineligible for NOFORK: | 11783 | * and/or wait for user input ineligible for NOFORK: |
10588 | * for example, "yes" or "rm" (rm -i waits for input). | 11784 | * for example, "yes" or "rm" (rm -i waits for input). |
10589 | */ | 11785 | */ |
11786 | #if ENABLE_PLATFORM_MINGW32 | ||
11787 | sv_argv0 = __argv[0]; | ||
11788 | argv[0] = (char *)bb_basename(argv[0]); | ||
11789 | __argv[0] = argv[0]; | ||
11790 | #endif | ||
10590 | exitstatus = run_nofork_applet(applet_no, argv); | 11791 | exitstatus = run_nofork_applet(applet_no, argv); |
10591 | environ = sv_environ; | 11792 | environ = sv_environ; |
11793 | #if ENABLE_PLATFORM_MINGW32 | ||
11794 | __argv[0] = sv_argv0; | ||
11795 | #endif | ||
10592 | /* | 11796 | /* |
10593 | * Try enabling NOFORK for "yes" applet. | 11797 | * Try enabling NOFORK for "yes" applet. |
10594 | * ^C _will_ stop it (write returns EINTR), | 11798 | * ^C _will_ stop it (write returns EINTR), |
@@ -10606,6 +11810,22 @@ evalcommand(union node *cmd, int flags) | |||
10606 | * in a script or a subshell does not need forking, | 11810 | * in a script or a subshell does not need forking, |
10607 | * we can just exec it. | 11811 | * we can just exec it. |
10608 | */ | 11812 | */ |
11813 | #if ENABLE_PLATFORM_MINGW32 | ||
11814 | if (!(flags & EV_EXIT) || may_have_traps IF_SUW32(|| delayexit)) { | ||
11815 | /* No, forking off a child is necessary */ | ||
11816 | struct forkshell fs; | ||
11817 | |||
11818 | INT_OFF; | ||
11819 | memset(&fs, 0, sizeof(fs)); | ||
11820 | fs.fpid = FS_SHELLEXEC; | ||
11821 | fs.argv = argv; | ||
11822 | fs.path = (char*)path; | ||
11823 | fs.fd[0] = cmdentry.u.index; | ||
11824 | jp = makejob(/*cmd,*/ 1); | ||
11825 | spawn_forkshell(&fs, jp, cmd, FORK_FG); | ||
11826 | break; | ||
11827 | } | ||
11828 | #else | ||
10609 | if (!(flags & EV_EXIT) || may_have_traps) { | 11829 | if (!(flags & EV_EXIT) || may_have_traps) { |
10610 | /* No, forking off a child is necessary */ | 11830 | /* No, forking off a child is necessary */ |
10611 | INT_OFF; | 11831 | INT_OFF; |
@@ -10619,7 +11839,8 @@ evalcommand(union node *cmd, int flags) | |||
10619 | FORCE_INT_ON; | 11839 | FORCE_INT_ON; |
10620 | /* fall through to exec'ing external program */ | 11840 | /* fall through to exec'ing external program */ |
10621 | } | 11841 | } |
10622 | shellexec(argv[0], argv, path, cmdentry.u.index); | 11842 | #endif |
11843 | shellexec(argv[0], argv, path, cmdentry.u.index, FALSE); | ||
10623 | /* NOTREACHED */ | 11844 | /* NOTREACHED */ |
10624 | } /* default */ | 11845 | } /* default */ |
10625 | case CMDBUILTIN: | 11846 | case CMDBUILTIN: |
@@ -10831,6 +12052,54 @@ static void popstring(void) | |||
10831 | INT_ON; | 12052 | INT_ON; |
10832 | } | 12053 | } |
10833 | 12054 | ||
12055 | #if ENABLE_PLATFORM_MINGW32 | ||
12056 | /* | ||
12057 | * Wrapper around nonblock_immune_read() to remove CRs, but only from | ||
12058 | * CRLF pairs. The tricky part is handling a CR at the end of the buffer. | ||
12059 | */ | ||
12060 | static inline ssize_t | ||
12061 | nonblock_immune_wrapper(struct parsefile *pf, char *buffer, size_t count) | ||
12062 | { | ||
12063 | int nr, injected_cr; | ||
12064 | |||
12065 | // Inject unprocessed CR from previous read into the buffer. | ||
12066 | if (pf->cr) | ||
12067 | *buffer = '\r'; | ||
12068 | retry: | ||
12069 | nr = nonblock_immune_read(pf->pf_fd, buffer + pf->cr, count - pf->cr); | ||
12070 | if (nr < 0) | ||
12071 | return nr; | ||
12072 | |||
12073 | injected_cr = pf->cr; | ||
12074 | nr += pf->cr; | ||
12075 | pf->cr = 0; | ||
12076 | |||
12077 | if (nr > 0) { | ||
12078 | nr = remove_cr(buffer, nr); | ||
12079 | // remove_cr() won't reduce size to zero, so [nr - 1] is OK. | ||
12080 | if (buffer[nr - 1] == '\r') { | ||
12081 | if (nr > 1) { | ||
12082 | // Ignore trailing CR for now: we'll deal with it later. | ||
12083 | pf->cr = 1; | ||
12084 | --nr; | ||
12085 | } else if (injected_cr) { // nr == 1 | ||
12086 | // Buffer only contains an injected CR. This means the | ||
12087 | // read returned EOF. Return the buffer as-is. The | ||
12088 | // next call will detect EOF. | ||
12089 | } else { | ||
12090 | // Buffer only contains a CR from the most recent read. | ||
12091 | // Try another read, treating the CR as injected. We'll | ||
12092 | // either get more characters or EOF. Either way we | ||
12093 | // won't end up here again. | ||
12094 | pf->cr = 1; | ||
12095 | goto retry; | ||
12096 | } | ||
12097 | } | ||
12098 | } | ||
12099 | return nr; | ||
12100 | } | ||
12101 | #endif | ||
12102 | |||
10834 | static int | 12103 | static int |
10835 | preadfd(void) | 12104 | preadfd(void) |
10836 | { | 12105 | { |
@@ -10841,7 +12110,11 @@ preadfd(void) | |||
10841 | #if ENABLE_FEATURE_EDITING | 12110 | #if ENABLE_FEATURE_EDITING |
10842 | /* retry: */ | 12111 | /* retry: */ |
10843 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) | 12112 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) |
12113 | #if ENABLE_PLATFORM_MINGW32 | ||
12114 | nr = nonblock_immune_wrapper(g_parsefile, buf, IBUFSIZ - 1); | ||
12115 | #else | ||
10844 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); | 12116 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
12117 | #endif | ||
10845 | else { | 12118 | else { |
10846 | # if ENABLE_ASH_IDLE_TIMEOUT | 12119 | # if ENABLE_ASH_IDLE_TIMEOUT |
10847 | int timeout = -1; | 12120 | int timeout = -1; |
@@ -10880,12 +12153,21 @@ preadfd(void) | |||
10880 | INT_ON; /* here non-blocked SIGINT will longjmp */ | 12153 | INT_ON; /* here non-blocked SIGINT will longjmp */ |
10881 | if (nr == 0) { | 12154 | if (nr == 0) { |
10882 | /* ^C pressed, "convert" to SIGINT */ | 12155 | /* ^C pressed, "convert" to SIGINT */ |
12156 | # if !ENABLE_PLATFORM_MINGW32 | ||
10883 | write(STDOUT_FILENO, "^C\n", 3); | 12157 | write(STDOUT_FILENO, "^C\n", 3); |
10884 | raise(SIGINT); /* here non-blocked SIGINT will longjmp */ | 12158 | raise(SIGINT); /* here non-blocked SIGINT will longjmp */ |
10885 | /* raise(SIGINT) did not work! (e.g. if SIGINT | 12159 | /* raise(SIGINT) did not work! (e.g. if SIGINT |
10886 | * is SIG_IGNed on startup, it stays SIG_IGNed) | 12160 | * is SIG_IGNed on startup, it stays SIG_IGNed) |
10887 | */ | 12161 | */ |
12162 | # else | ||
12163 | raise_interrupt(); | ||
12164 | write(STDOUT_FILENO, "^C\n", 3); | ||
12165 | # endif | ||
10888 | if (trap[SIGINT]) { | 12166 | if (trap[SIGINT]) { |
12167 | # if ENABLE_PLATFORM_MINGW32 | ||
12168 | pending_int = 1; | ||
12169 | dotrap(); | ||
12170 | # endif | ||
10889 | empty_line_input: | 12171 | empty_line_input: |
10890 | buf[0] = '\n'; | 12172 | buf[0] = '\n'; |
10891 | buf[1] = '\0'; | 12173 | buf[1] = '\0'; |
@@ -10914,7 +12196,11 @@ preadfd(void) | |||
10914 | } | 12196 | } |
10915 | } | 12197 | } |
10916 | #else | 12198 | #else |
12199 | # if ENABLE_PLATFORM_MINGW32 | ||
12200 | nr = nonblock_immune_wrapper(g_parsefile, buf, IBUFSIZ - 1); | ||
12201 | # else | ||
10917 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); | 12202 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
12203 | # endif | ||
10918 | #endif | 12204 | #endif |
10919 | 12205 | ||
10920 | #if 0 /* disabled: nonblock_immune_read() handles this problem */ | 12206 | #if 0 /* disabled: nonblock_immune_read() handles this problem */ |
@@ -11213,6 +12499,7 @@ popallfiles(void) | |||
11213 | unwindfiles(&basepf); | 12499 | unwindfiles(&basepf); |
11214 | } | 12500 | } |
11215 | 12501 | ||
12502 | #if !ENABLE_PLATFORM_MINGW32 | ||
11216 | /* | 12503 | /* |
11217 | * Close the file(s) that the shell is reading commands from. Called | 12504 | * Close the file(s) that the shell is reading commands from. Called |
11218 | * after a fork is done. | 12505 | * after a fork is done. |
@@ -11226,6 +12513,7 @@ closescript(void) | |||
11226 | g_parsefile->pf_fd = 0; | 12513 | g_parsefile->pf_fd = 0; |
11227 | } | 12514 | } |
11228 | } | 12515 | } |
12516 | #endif | ||
11229 | 12517 | ||
11230 | /* | 12518 | /* |
11231 | * Like setinputfile, but takes an open file descriptor. Call this with | 12519 | * Like setinputfile, but takes an open file descriptor. Call this with |
@@ -11462,8 +12750,19 @@ options(int *login_sh) | |||
11462 | int val; | 12750 | int val; |
11463 | int c; | 12751 | int c; |
11464 | 12752 | ||
11465 | if (login_sh != NULL) /* if we came from startup code */ | 12753 | #if ENABLE_ASH_NOCONSOLE |
12754 | noconsole = console_state(); | ||
12755 | #endif | ||
12756 | if (login_sh != NULL) { /* if we came from startup code */ | ||
11466 | minusc = NULL; | 12757 | minusc = NULL; |
12758 | #if ENABLE_PLATFORM_MINGW32 | ||
12759 | dirarg = NULL; | ||
12760 | title = NULL; | ||
12761 | # if ENABLE_SUW32 | ||
12762 | delayexit = 0; | ||
12763 | # endif | ||
12764 | #endif | ||
12765 | } | ||
11467 | while ((p = *argptr) != NULL) { | 12766 | while ((p = *argptr) != NULL) { |
11468 | c = *p++; | 12767 | c = *p++; |
11469 | if (c != '-' && c != '+') | 12768 | if (c != '-' && c != '+') |
@@ -11493,6 +12792,31 @@ options(int *login_sh) | |||
11493 | cflag = 1; | 12792 | cflag = 1; |
11494 | continue; | 12793 | continue; |
11495 | } | 12794 | } |
12795 | #if ENABLE_PLATFORM_MINGW32 | ||
12796 | /* Undocumented flags; | ||
12797 | * -d force current directory | ||
12798 | * -t title to display in console window | ||
12799 | * -N prompt user before exit | ||
12800 | * Must appear before -s or -c. */ | ||
12801 | if (c == 'd' && val == 1) { | ||
12802 | if (*argptr == NULL) | ||
12803 | ash_msg_and_raise_error(bb_msg_requires_arg, "-d"); | ||
12804 | dirarg = *argptr++; | ||
12805 | continue; | ||
12806 | } | ||
12807 | if (c == 't' && val == 1) { | ||
12808 | if (*argptr == NULL) | ||
12809 | ash_msg_and_raise_error(bb_msg_requires_arg, "-t"); | ||
12810 | title = *argptr++; | ||
12811 | continue; | ||
12812 | } | ||
12813 | # if ENABLE_SUW32 | ||
12814 | if (c == 'N' && val == 1) { | ||
12815 | delayexit = 1; | ||
12816 | continue; | ||
12817 | } | ||
12818 | # endif | ||
12819 | #endif | ||
11496 | if (c == 's') { /* -s, +s */ | 12820 | if (c == 's') { /* -s, +s */ |
11497 | sflag = 1; | 12821 | sflag = 1; |
11498 | continue; | 12822 | continue; |
@@ -13528,6 +14852,9 @@ evalstring(char *s, int flags) | |||
13528 | int status; | 14852 | int status; |
13529 | 14853 | ||
13530 | s = sstrdup(s); | 14854 | s = sstrdup(s); |
14855 | #if ENABLE_PLATFORM_MINGW32 | ||
14856 | remove_cr(s, strlen(s)+1); | ||
14857 | #endif | ||
13531 | setinputstring(s); | 14858 | setinputstring(s); |
13532 | setstackmark(&smark); | 14859 | setstackmark(&smark); |
13533 | 14860 | ||
@@ -13615,7 +14942,7 @@ cmdloop(int top) | |||
13615 | int skip; | 14942 | int skip; |
13616 | 14943 | ||
13617 | setstackmark(&smark); | 14944 | setstackmark(&smark); |
13618 | #if JOBS | 14945 | #if JOBS || JOBS_WIN32 |
13619 | if (doing_jobctl) | 14946 | if (doing_jobctl) |
13620 | showjobs(SHOW_CHANGED|SHOW_STDERR); | 14947 | showjobs(SHOW_CHANGED|SHOW_STDERR); |
13621 | #endif | 14948 | #endif |
@@ -13623,6 +14950,9 @@ cmdloop(int top) | |||
13623 | if (iflag && top) { | 14950 | if (iflag && top) { |
13624 | inter++; | 14951 | inter++; |
13625 | chkmail(); | 14952 | chkmail(); |
14953 | #if ENABLE_PLATFORM_MINGW32 | ||
14954 | terminal_mode(TRUE); | ||
14955 | #endif | ||
13626 | } | 14956 | } |
13627 | n = parsecmd(inter); | 14957 | n = parsecmd(inter); |
13628 | #if DEBUG | 14958 | #if DEBUG |
@@ -13646,8 +14976,10 @@ cmdloop(int top) | |||
13646 | } else { | 14976 | } else { |
13647 | int i; | 14977 | int i; |
13648 | 14978 | ||
14979 | #if !ENABLE_PLATFORM_MINGW32 | ||
13649 | /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */ | 14980 | /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */ |
13650 | job_warning >>= 1; | 14981 | job_warning >>= 1; |
14982 | #endif | ||
13651 | numeof = 0; | 14983 | numeof = 0; |
13652 | i = evaltree(n, 0); | 14984 | i = evaltree(n, 0); |
13653 | if (n) | 14985 | if (n) |
@@ -13677,7 +15009,7 @@ find_dot_file(char *basename) | |||
13677 | int len; | 15009 | int len; |
13678 | 15010 | ||
13679 | /* don't try this for absolute or relative paths */ | 15011 | /* don't try this for absolute or relative paths */ |
13680 | if (strchr(basename, '/')) | 15012 | if (strchr(basename, '/') IF_PLATFORM_MINGW32(|| strchr(basename, '\\'))) |
13681 | return basename; | 15013 | return basename; |
13682 | 15014 | ||
13683 | path = pathval(); | 15015 | path = pathval(); |
@@ -13842,6 +15174,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13842 | struct builtincmd *bcmd; | 15174 | struct builtincmd *bcmd; |
13843 | int len; | 15175 | int len; |
13844 | 15176 | ||
15177 | #if !ENABLE_PLATFORM_MINGW32 | ||
13845 | /* If name contains a slash, don't use PATH or hash table */ | 15178 | /* If name contains a slash, don't use PATH or hash table */ |
13846 | if (strchr(name, '/') != NULL) { | 15179 | if (strchr(name, '/') != NULL) { |
13847 | entry->u.index = -1; | 15180 | entry->u.index = -1; |
@@ -13861,6 +15194,35 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13861 | entry->cmdtype = CMDNORMAL; | 15194 | entry->cmdtype = CMDNORMAL; |
13862 | return; | 15195 | return; |
13863 | } | 15196 | } |
15197 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
15198 | /* If name contains a slash or drive prefix, don't use PATH or hash table */ | ||
15199 | if (has_path(name)) { | ||
15200 | entry->u.index = -1; | ||
15201 | entry->cmdtype = CMDNORMAL; | ||
15202 | fullname = stack_add_ext_space(name); | ||
15203 | if (add_win32_extension(fullname)) { | ||
15204 | return; | ||
15205 | } else if (unix_path(name)) { | ||
15206 | name = (char *)bb_basename(name); | ||
15207 | if ( | ||
15208 | # if ENABLE_FEATURE_SH_STANDALONE | ||
15209 | find_applet_by_name_for_sh(name, path) >= 0 || | ||
15210 | # endif | ||
15211 | !find_builtin(bb_basename(name)) | ||
15212 | ) { | ||
15213 | act |= DO_NOFUNC; | ||
15214 | } else if (act & DO_ABS) { | ||
15215 | entry->cmdtype = CMDUNKNOWN; | ||
15216 | return; | ||
15217 | } | ||
15218 | } else if (act & DO_ABS) { | ||
15219 | entry->cmdtype = CMDUNKNOWN; | ||
15220 | return; | ||
15221 | } else { | ||
15222 | return; | ||
15223 | } | ||
15224 | } | ||
15225 | #endif /* ENABLE_PLATFORM_MINGW32 */ | ||
13864 | 15226 | ||
13865 | /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ | 15227 | /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ |
13866 | 15228 | ||
@@ -13915,7 +15277,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13915 | 15277 | ||
13916 | #if ENABLE_FEATURE_SH_STANDALONE | 15278 | #if ENABLE_FEATURE_SH_STANDALONE |
13917 | { | 15279 | { |
13918 | int applet_no = find_applet_by_name(name); | 15280 | int applet_no = find_applet_by_name_for_sh(name, path); |
13919 | if (applet_no >= 0) { | 15281 | if (applet_no >= 0) { |
13920 | entry->cmdtype = CMDNORMAL; | 15282 | entry->cmdtype = CMDNORMAL; |
13921 | entry->u.index = -2 - applet_no; | 15283 | entry->u.index = -2 - applet_no; |
@@ -13954,12 +15316,15 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13954 | } | 15316 | } |
13955 | } | 15317 | } |
13956 | /* if rehash, don't redo absolute path names */ | 15318 | /* if rehash, don't redo absolute path names */ |
13957 | if (fullname[0] == '/' && idx <= prev) { | 15319 | if (!is_relative_path(fullname) && idx <= prev) { |
13958 | if (idx < prev) | 15320 | if (idx < prev) |
13959 | continue; | 15321 | continue; |
13960 | TRACE(("searchexec \"%s\": no change\n", name)); | 15322 | TRACE(("searchexec \"%s\": no change\n", name)); |
13961 | goto success; | 15323 | goto success; |
13962 | } | 15324 | } |
15325 | #if ENABLE_PLATFORM_MINGW32 | ||
15326 | add_win32_extension(fullname); | ||
15327 | #endif | ||
13963 | while (stat(fullname, &statb) < 0) { | 15328 | while (stat(fullname, &statb) < 0) { |
13964 | #ifdef SYSV | 15329 | #ifdef SYSV |
13965 | if (errno == EINTR) | 15330 | if (errno == EINTR) |
@@ -14098,19 +15463,45 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14098 | if (LONE_DASH(action)) | 15463 | if (LONE_DASH(action)) |
14099 | action = NULL; | 15464 | action = NULL; |
14100 | else { | 15465 | else { |
15466 | #if !ENABLE_PLATFORM_MINGW32 | ||
14101 | if (action[0]) /* not NULL and not "" and not "-" */ | 15467 | if (action[0]) /* not NULL and not "" and not "-" */ |
14102 | may_have_traps = 1; | 15468 | may_have_traps = 1; |
15469 | #endif | ||
14103 | action = ckstrdup(action); | 15470 | action = ckstrdup(action); |
14104 | } | 15471 | } |
14105 | } | 15472 | } |
14106 | free(trap[signo]); | 15473 | free(trap[signo]); |
14107 | trap[signo] = action; | 15474 | trap[signo] = action; |
15475 | #if ENABLE_PLATFORM_MINGW32 | ||
15476 | if (signo == SIGINT) { | ||
15477 | // trap '' INT disables Ctrl-C, anything else enables it | ||
15478 | if (action && action[0] == '\0') { | ||
15479 | SetConsoleCtrlHandler(NULL, TRUE); | ||
15480 | # if ENABLE_FEATURE_EDITING | ||
15481 | if (line_input_state) { | ||
15482 | line_input_state->flags |= IGNORE_CTRL_C; | ||
15483 | } | ||
15484 | # endif | ||
15485 | } else { | ||
15486 | SetConsoleCtrlHandler(NULL, FALSE); | ||
15487 | # if ENABLE_FEATURE_EDITING | ||
15488 | if (line_input_state) { | ||
15489 | line_input_state->flags &= ~IGNORE_CTRL_C; | ||
15490 | } | ||
15491 | # endif | ||
15492 | } | ||
15493 | } | ||
15494 | #else | ||
14108 | if (signo != 0 && signo < NSIG) | 15495 | if (signo != 0 && signo < NSIG) |
14109 | setsignal(signo); | 15496 | setsignal(signo); |
15497 | #endif | ||
14110 | INT_ON; | 15498 | INT_ON; |
14111 | next: | 15499 | next: |
14112 | ap++; | 15500 | ap++; |
14113 | } | 15501 | } |
15502 | #if ENABLE_PLATFORM_MINGW32 | ||
15503 | may_have_traps = trap[SIGINT] && trap[SIGINT][0] != '\0'; | ||
15504 | #endif | ||
14114 | return exitcode; | 15505 | return exitcode; |
14115 | } | 15506 | } |
14116 | 15507 | ||
@@ -14139,10 +15530,12 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14139 | { | 15530 | { |
14140 | const char *a = applet_names; | 15531 | const char *a = applet_names; |
14141 | while (*a) { | 15532 | while (*a) { |
14142 | col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a); | 15533 | if (prefer_applet(a, pathval())) { |
14143 | if (col > 60) { | 15534 | col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a); |
14144 | out1fmt("\n"); | 15535 | if (col > 60) { |
14145 | col = 0; | 15536 | out1fmt("\n"); |
15537 | col = 0; | ||
15538 | } | ||
14146 | } | 15539 | } |
14147 | while (*a++ != '\0') | 15540 | while (*a++ != '\0') |
14148 | continue; | 15541 | continue; |
@@ -14204,7 +15597,24 @@ exportcmd(int argc UNUSED_PARAM, char **argv) | |||
14204 | } else { | 15597 | } else { |
14205 | vp = *findvar(name); | 15598 | vp = *findvar(name); |
14206 | if (vp) { | 15599 | if (vp) { |
15600 | #if ENABLE_PLATFORM_MINGW32 | ||
15601 | if (is_bb_var(name) == BB_VAR_EXACT) { | ||
15602 | if (flag_off == ~VEXPORT) | ||
15603 | unsetenv(name); | ||
15604 | else if (flag == VEXPORT && !(vp->flags & VUNSET)) | ||
15605 | putenv(vp->var_text); | ||
15606 | } | ||
15607 | #endif | ||
14207 | vp->flags = ((vp->flags | flag) & flag_off); | 15608 | vp->flags = ((vp->flags | flag) & flag_off); |
15609 | #if ENABLE_PLATFORM_MINGW32 | ||
15610 | /* Unexporting a variable imported from the | ||
15611 | * environment restores its original value and | ||
15612 | * removes the VIMPORT flag. */ | ||
15613 | if ((vp->flags & VIMPORT) && (flag_off == ~VEXPORT)) { | ||
15614 | vp->flags &= ~VIMPORT; | ||
15615 | p = getenv(name); | ||
15616 | } else | ||
15617 | #endif | ||
14208 | continue; | 15618 | continue; |
14209 | } | 15619 | } |
14210 | } | 15620 | } |
@@ -14295,6 +15705,21 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14295 | return 0; | 15705 | return 0; |
14296 | } | 15706 | } |
14297 | 15707 | ||
15708 | #if ENABLE_PLATFORM_MINGW32 | ||
15709 | static int FAST_FUNC | ||
15710 | titlecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | ||
15711 | { | ||
15712 | if (*argptr == NULL) { | ||
15713 | char buffer[256]; | ||
15714 | if (get_title(buffer, sizeof(buffer))) | ||
15715 | puts(buffer); | ||
15716 | } else { | ||
15717 | set_title(*argptr); | ||
15718 | } | ||
15719 | return 0; | ||
15720 | } | ||
15721 | #endif | ||
15722 | |||
14298 | #if ENABLE_FEATURE_SH_MATH | 15723 | #if ENABLE_FEATURE_SH_MATH |
14299 | /* | 15724 | /* |
14300 | * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell. | 15725 | * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell. |
@@ -14395,6 +15820,27 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14395 | goto again; | 15820 | goto again; |
14396 | } | 15821 | } |
14397 | 15822 | ||
15823 | #if ENABLE_PLATFORM_MINGW32 | ||
15824 | if ((uintptr_t)r == 2) { | ||
15825 | /* ^C pressed, propagate event */ | ||
15826 | if (trap[SIGINT]) { | ||
15827 | write(STDOUT_FILENO, "^C", 2); | ||
15828 | pending_int = 1; | ||
15829 | dotrap(); | ||
15830 | if (!(rootshell && iflag)) | ||
15831 | return (uintptr_t)0; | ||
15832 | else | ||
15833 | goto again; | ||
15834 | } else if (iflag) { | ||
15835 | raise_interrupt(); | ||
15836 | } else { | ||
15837 | GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); | ||
15838 | exitshell(); | ||
15839 | } | ||
15840 | return (uintptr_t)r; | ||
15841 | } | ||
15842 | #endif | ||
15843 | |||
14398 | if ((uintptr_t)r > 1) | 15844 | if ((uintptr_t)r > 1) |
14399 | ash_msg_and_raise_error(r); | 15845 | ash_msg_and_raise_error(r); |
14400 | 15846 | ||
@@ -14455,6 +15901,9 @@ umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14455 | if (!isdigit(modestr[0])) | 15901 | if (!isdigit(modestr[0])) |
14456 | mask ^= 0777; | 15902 | mask ^= 0777; |
14457 | umask(mask); | 15903 | umask(mask); |
15904 | #if ENABLE_PLATFORM_MINGW32 | ||
15905 | setvareq(xasprintf("BB_UMASK=0%o", mask), VEXPORT|VNOSAVE); | ||
15906 | #endif | ||
14458 | } | 15907 | } |
14459 | return 0; | 15908 | return 0; |
14460 | } | 15909 | } |
@@ -14538,6 +15987,13 @@ exitshell(void) | |||
14538 | /*free(p); - we'll exit soon */ | 15987 | /*free(p); - we'll exit soon */ |
14539 | } | 15988 | } |
14540 | out: | 15989 | out: |
15990 | #if ENABLE_SUW32 | ||
15991 | if (delayexit) { | ||
15992 | #define EXIT_MSG "Press any key to exit..." | ||
15993 | console_write(EXIT_MSG, sizeof(EXIT_MSG) - 1); | ||
15994 | _getch(); | ||
15995 | } | ||
15996 | #endif | ||
14541 | exitreset(); | 15997 | exitreset(); |
14542 | /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". | 15998 | /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". |
14543 | * our setjobctl(0) does not panic if tcsetpgrp fails inside it. | 15999 | * our setjobctl(0) does not panic if tcsetpgrp fails inside it. |
@@ -14548,22 +16004,97 @@ exitshell(void) | |||
14548 | /* NOTREACHED */ | 16004 | /* NOTREACHED */ |
14549 | } | 16005 | } |
14550 | 16006 | ||
16007 | #if ENABLE_PLATFORM_MINGW32 | ||
16008 | /* We need to see if HOME is *really* unset */ | ||
16009 | # undef getenv | ||
16010 | static void setvar_if_unset(const char *key, const char *value) | ||
16011 | { | ||
16012 | if (!getenv(key) || getuid() == 0) | ||
16013 | setvar(key, value, VEXPORT); | ||
16014 | } | ||
16015 | #endif | ||
16016 | |||
14551 | /* Don't inline: conserve stack of caller from having our locals too */ | 16017 | /* Don't inline: conserve stack of caller from having our locals too */ |
14552 | static NOINLINE void | 16018 | static NOINLINE void |
14553 | init(void) | 16019 | init(void) |
14554 | { | 16020 | { |
16021 | #if ENABLE_PLATFORM_MINGW32 | ||
16022 | int import = 0; | ||
16023 | #else | ||
14555 | /* we will never free this */ | 16024 | /* we will never free this */ |
14556 | basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ); | 16025 | basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ); |
14557 | basepf.linno = 1; | 16026 | basepf.linno = 1; |
14558 | 16027 | ||
14559 | sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ | 16028 | sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ |
14560 | setsignal(SIGCHLD); | 16029 | setsignal(SIGCHLD); |
16030 | #endif | ||
14561 | 16031 | ||
14562 | { | 16032 | { |
14563 | char **envp; | 16033 | char **envp; |
14564 | const char *p; | 16034 | const char *p; |
14565 | 16035 | ||
14566 | initvar(); | 16036 | initvar(); |
16037 | |||
16038 | #if ENABLE_PLATFORM_MINGW32 | ||
16039 | /* | ||
16040 | * case insensitive env names from Windows world | ||
16041 | * | ||
16042 | * Some standard env names such as PATH is named Path and so on | ||
16043 | * ash itself is case sensitive, so "Path" will confuse it, as | ||
16044 | * MSVC getenv() is case insensitive. | ||
16045 | * | ||
16046 | * We may end up having both Path and PATH. Then Path will be chosen | ||
16047 | * because it appears first. | ||
16048 | */ | ||
16049 | if (windows_env()) { | ||
16050 | /* | ||
16051 | * If we get here it's because the environment suggests we | ||
16052 | * haven't been invoked from an earlier instance of BusyBox. | ||
16053 | */ | ||
16054 | char *start, *end; | ||
16055 | struct passwd *pw; | ||
16056 | |||
16057 | /* mintty sets HOME: unset it */ | ||
16058 | const char *tty = getenv("TERM_PROGRAM"); | ||
16059 | if (tty && strcmp(tty, "mintty") == 0) { | ||
16060 | unsetenv("HOME"); | ||
16061 | } | ||
16062 | |||
16063 | import = VIMPORT; | ||
16064 | for (envp = environ; envp && *envp; envp++) { | ||
16065 | if (!(end=strchr(*envp, '='))) | ||
16066 | continue; | ||
16067 | |||
16068 | /* check for invalid characters in name */ | ||
16069 | start = (char *)endofname(*envp); | ||
16070 | if (*start != '=') { | ||
16071 | /* Make a copy of the original variable */ | ||
16072 | setvareq(xstrdup(*envp), VEXPORT|VNOSAVE); | ||
16073 | |||
16074 | /* Replace invalid characters with underscores */ | ||
16075 | for (; start < end; start++) { | ||
16076 | if (!isalnum(*start)) { | ||
16077 | *start = '_'; | ||
16078 | } | ||
16079 | } | ||
16080 | } | ||
16081 | |||
16082 | /* make all variable names uppercase */ | ||
16083 | for (start = *envp;start < end;start++) | ||
16084 | *start = toupper(*start); | ||
16085 | } | ||
16086 | |||
16087 | /* Initialise some variables normally set at login, but | ||
16088 | * only if someone hasn't already set them or we're root. */ | ||
16089 | pw = getpwuid(getuid()); | ||
16090 | if (pw) { | ||
16091 | setvar_if_unset("USER", pw->pw_name); | ||
16092 | setvar_if_unset("LOGNAME", pw->pw_name); | ||
16093 | setvar_if_unset("HOME", pw->pw_dir); | ||
16094 | } | ||
16095 | setvar_if_unset("SHELL", DEFAULT_SHELL); | ||
16096 | } | ||
16097 | #endif | ||
14567 | for (envp = environ; envp && *envp; envp++) { | 16098 | for (envp = environ; envp && *envp; envp++) { |
14568 | /* Used to have | 16099 | /* Used to have |
14569 | * p = endofname(*envp); | 16100 | * p = endofname(*envp); |
@@ -14577,7 +16108,11 @@ init(void) | |||
14577 | * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this | 16108 | * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this |
14578 | */ | 16109 | */ |
14579 | if (strchr(*envp, '=')) { | 16110 | if (strchr(*envp, '=')) { |
16111 | #if !ENABLE_PLATFORM_MINGW32 | ||
14580 | setvareq(*envp, VEXPORT|VTEXTFIXED); | 16112 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
16113 | #else | ||
16114 | setvareq(*envp, VEXPORT|import); | ||
16115 | #endif | ||
14581 | } | 16116 | } |
14582 | } | 16117 | } |
14583 | 16118 | ||
@@ -14628,7 +16163,11 @@ procargs(char **argv) | |||
14628 | int login_sh; | 16163 | int login_sh; |
14629 | 16164 | ||
14630 | xargv = argv; | 16165 | xargv = argv; |
16166 | #if ENABLE_PLATFORM_MINGW32 | ||
16167 | login_sh = applet_name[0] == 'l'; | ||
16168 | #else | ||
14631 | login_sh = xargv[0] && xargv[0][0] == '-'; | 16169 | login_sh = xargv[0] && xargv[0][0] == '-'; |
16170 | #endif | ||
14632 | #if NUM_SCRIPTS > 0 | 16171 | #if NUM_SCRIPTS > 0 |
14633 | if (minusc) | 16172 | if (minusc) |
14634 | goto setarg0; | 16173 | goto setarg0; |
@@ -14652,7 +16191,9 @@ procargs(char **argv) | |||
14652 | } | 16191 | } |
14653 | if (iflag == 2 /* no explicit -i given */ | 16192 | if (iflag == 2 /* no explicit -i given */ |
14654 | && sflag == 1 /* -s given (or implied) */ | 16193 | && sflag == 1 /* -s given (or implied) */ |
16194 | #if !ENABLE_PLATFORM_MINGW32 | ||
14655 | && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */ | 16195 | && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */ |
16196 | #endif | ||
14656 | && isatty(0) && isatty(1) /* we are on tty */ | 16197 | && isatty(0) && isatty(1) /* we are on tty */ |
14657 | ) { | 16198 | ) { |
14658 | iflag = 1; | 16199 | iflag = 1; |
@@ -14672,6 +16213,9 @@ procargs(char **argv) | |||
14672 | goto setarg0; | 16213 | goto setarg0; |
14673 | } else if (!sflag) { | 16214 | } else if (!sflag) { |
14674 | setinputfile(*xargv, 0); | 16215 | setinputfile(*xargv, 0); |
16216 | #if ENABLE_PLATFORM_MINGW32 | ||
16217 | bs_to_slash(*xargv); | ||
16218 | #endif | ||
14675 | setarg0: | 16219 | setarg0: |
14676 | arg0 = *xargv++; | 16220 | arg0 = *xargv++; |
14677 | commandname = arg0; | 16221 | commandname = arg0; |
@@ -14695,8 +16239,10 @@ procargs(char **argv) | |||
14695 | * NB: must do it before setting up signals (in optschanged()) | 16239 | * NB: must do it before setting up signals (in optschanged()) |
14696 | * and reading .profile etc (after we return from here): | 16240 | * and reading .profile etc (after we return from here): |
14697 | */ | 16241 | */ |
16242 | #if !ENABLE_PLATFORM_MINGW32 | ||
14698 | if (iflag) | 16243 | if (iflag) |
14699 | signal(SIGHUP, SIG_DFL); | 16244 | signal(SIGHUP, SIG_DFL); |
16245 | #endif | ||
14700 | 16246 | ||
14701 | optschanged(); | 16247 | optschanged(); |
14702 | 16248 | ||
@@ -14741,9 +16287,25 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14741 | struct stackmark smark; | 16287 | struct stackmark smark; |
14742 | int login_sh; | 16288 | int login_sh; |
14743 | 16289 | ||
16290 | #if ENABLE_PLATFORM_MINGW32 | ||
16291 | INIT_G_memstack(); | ||
16292 | |||
16293 | /* from init() */ | ||
16294 | basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ); | ||
16295 | basepf.linno = 1; | ||
16296 | |||
16297 | if (argc == 3 && !strcmp(argv[1], "--fs")) { | ||
16298 | forkshell_init(argv[2]); | ||
16299 | /* only reached in case of error */ | ||
16300 | bb_error_msg_and_die("forkshell failed"); | ||
16301 | } | ||
16302 | #endif | ||
16303 | |||
14744 | /* Initialize global data */ | 16304 | /* Initialize global data */ |
14745 | INIT_G_misc(); | 16305 | INIT_G_misc(); |
16306 | #if !ENABLE_PLATFORM_MINGW32 | ||
14746 | INIT_G_memstack(); | 16307 | INIT_G_memstack(); |
16308 | #endif | ||
14747 | INIT_G_var(); | 16309 | INIT_G_var(); |
14748 | #if ENABLE_ASH_ALIAS | 16310 | #if ENABLE_ASH_ALIAS |
14749 | INIT_G_alias(); | 16311 | INIT_G_alias(); |
@@ -14789,6 +16351,10 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14789 | init(); | 16351 | init(); |
14790 | setstackmark(&smark); | 16352 | setstackmark(&smark); |
14791 | 16353 | ||
16354 | #if ENABLE_PLATFORM_MINGW32 | ||
16355 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
16356 | #endif | ||
16357 | |||
14792 | #if NUM_SCRIPTS > 0 | 16358 | #if NUM_SCRIPTS > 0 |
14793 | if (argc < 0) | 16359 | if (argc < 0) |
14794 | /* Non-NULL minusc tells procargs that an embedded script is being run */ | 16360 | /* Non-NULL minusc tells procargs that an embedded script is being run */ |
@@ -14800,11 +16366,45 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14800 | trace_puts_args(argv); | 16366 | trace_puts_args(argv); |
14801 | #endif | 16367 | #endif |
14802 | 16368 | ||
16369 | #if ENABLE_PLATFORM_MINGW32 | ||
16370 | if (!dirarg && !login_sh && iflag) { | ||
16371 | char *cwd = getcwd(NULL, 0); | ||
16372 | if (cwd) { | ||
16373 | chdir(cwd); | ||
16374 | setpwd(NULL, 0); | ||
16375 | free(cwd); | ||
16376 | } | ||
16377 | } | ||
16378 | |||
16379 | if (title) | ||
16380 | set_title(title); | ||
16381 | #endif | ||
16382 | |||
14803 | if (login_sh) { | 16383 | if (login_sh) { |
14804 | const char *hp; | 16384 | const char *hp; |
14805 | 16385 | ||
16386 | #if ENABLE_PLATFORM_MINGW32 | ||
16387 | if (!dirarg) { | ||
16388 | hp = lookupvar("HOME"); | ||
16389 | if (hp == NULL || *hp == '\0') | ||
16390 | hp = xgetpwuid(getuid())->pw_dir; | ||
16391 | chdir(hp); | ||
16392 | setpwd(NULL, 0); | ||
16393 | } | ||
16394 | #endif | ||
16395 | |||
14806 | state = 1; | 16396 | state = 1; |
16397 | #if ENABLE_PLATFORM_MINGW32 | ||
16398 | hp = concat_path_file(get_system_drive(), "/etc/profile"); | ||
16399 | read_profile(hp); | ||
16400 | free((void *)hp); | ||
16401 | |||
16402 | hp = exe_relative_path("/etc/profile"); | ||
16403 | read_profile(hp); | ||
16404 | free((void *)hp); | ||
16405 | #else | ||
14807 | read_profile("/etc/profile"); | 16406 | read_profile("/etc/profile"); |
16407 | #endif | ||
14808 | state1: | 16408 | state1: |
14809 | state = 2; | 16409 | state = 2; |
14810 | hp = lookupvar("HOME"); | 16410 | hp = lookupvar("HOME"); |
@@ -14813,10 +16413,18 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14813 | } | 16413 | } |
14814 | state2: | 16414 | state2: |
14815 | state = 3; | 16415 | state = 3; |
16416 | #if ENABLE_PLATFORM_MINGW32 | ||
16417 | if (dirarg) { | ||
16418 | chdir(dirarg); | ||
16419 | setpwd(NULL, 0); | ||
16420 | } | ||
16421 | #endif | ||
14816 | if (iflag | 16422 | if (iflag |
16423 | #if ENABLE_PLATFORM_POSIX | ||
14817 | #ifndef linux | 16424 | #ifndef linux |
14818 | && getuid() == geteuid() && getgid() == getegid() | 16425 | && getuid() == geteuid() && getgid() == getegid() |
14819 | #endif | 16426 | #endif |
16427 | #endif | ||
14820 | ) { | 16428 | ) { |
14821 | const char *shinit = lookupvar("ENV"); | 16429 | const char *shinit = lookupvar("ENV"); |
14822 | if (shinit != NULL && *shinit != '\0') | 16430 | if (shinit != NULL && *shinit != '\0') |
@@ -14841,7 +16449,11 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14841 | // ash -sc 'echo $-' | 16449 | // ash -sc 'echo $-' |
14842 | // continue reading input from stdin after running 'echo'. | 16450 | // continue reading input from stdin after running 'echo'. |
14843 | // bash does not do this: it prints "hBcs" and exits. | 16451 | // bash does not do this: it prints "hBcs" and exits. |
16452 | #if !ENABLE_PLATFORM_MINGW32 | ||
14844 | evalstring(minusc, EV_EXIT); | 16453 | evalstring(minusc, EV_EXIT); |
16454 | #else | ||
16455 | evalstring(minusc, sflag ? 0 : EV_EXIT); | ||
16456 | #endif | ||
14845 | } | 16457 | } |
14846 | 16458 | ||
14847 | if (sflag || minusc == NULL) { | 16459 | if (sflag || minusc == NULL) { |
@@ -14884,6 +16496,1101 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14884 | /* NOTREACHED */ | 16496 | /* NOTREACHED */ |
14885 | } | 16497 | } |
14886 | 16498 | ||
16499 | #if ENABLE_PLATFORM_MINGW32 | ||
16500 | static void | ||
16501 | forkshell_openhere(struct forkshell *fs) | ||
16502 | { | ||
16503 | const char *p = fs->path; | ||
16504 | size_t len = strlen(p); | ||
16505 | int pip[2]; | ||
16506 | |||
16507 | pip[0] = fs->fd[0]; | ||
16508 | pip[1] = fs->fd[1]; | ||
16509 | |||
16510 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
16511 | |||
16512 | close(pip[0]); | ||
16513 | ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); | ||
16514 | ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); | ||
16515 | ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); | ||
16516 | ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); | ||
16517 | signal(SIGPIPE, SIG_DFL); | ||
16518 | xwrite(pip[1], p, len); | ||
16519 | _exit_SUCCESS(); | ||
16520 | } | ||
16521 | |||
16522 | static void | ||
16523 | forkshell_evalbackcmd(struct forkshell *fs) | ||
16524 | { | ||
16525 | #if BASH_PROCESS_SUBST | ||
16526 | /* determine end of pipe used by parent (ip) and child (ic) */ | ||
16527 | const int ctl = fs->fd[2]; | ||
16528 | const int ip = (ctl == CTLTOPROC); | ||
16529 | const int ic = !(ctl == CTLTOPROC); | ||
16530 | #else | ||
16531 | const int ip = 0; | ||
16532 | const int ic = 1; | ||
16533 | #endif | ||
16534 | union node *n = fs->n; | ||
16535 | int pip[2]; | ||
16536 | |||
16537 | pip[ip] = fs->fd[ip]; | ||
16538 | pip[ic] = fs->fd[ic]; | ||
16539 | |||
16540 | FORCE_INT_ON; | ||
16541 | close(pip[ip]); | ||
16542 | if (pip[ic] != ic) { | ||
16543 | /*close(ic);*/ | ||
16544 | dup2_or_raise(pip[ic], ic); | ||
16545 | close(pip[ic]); | ||
16546 | } | ||
16547 | eflag = 0; | ||
16548 | ifsfree(); | ||
16549 | evaltreenr(n, EV_EXIT); | ||
16550 | /* NOTREACHED */ | ||
16551 | } | ||
16552 | |||
16553 | static void | ||
16554 | forkshell_evalsubshell(struct forkshell *fs) | ||
16555 | { | ||
16556 | union node *n = fs->n; | ||
16557 | int flags = fs->flags; | ||
16558 | |||
16559 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
16560 | INT_ON; | ||
16561 | flags |= EV_EXIT; | ||
16562 | if (fs->mode) | ||
16563 | flags &= ~EV_TESTED; | ||
16564 | expredir(n->nredir.redirect); | ||
16565 | redirect(n->nredir.redirect, 0); | ||
16566 | evaltreenr(n->nredir.n, flags); | ||
16567 | /* never returns */ | ||
16568 | } | ||
16569 | |||
16570 | static void | ||
16571 | forkshell_evalpipe(struct forkshell *fs) | ||
16572 | { | ||
16573 | union node *n = fs->n; | ||
16574 | int flags = fs->flags; | ||
16575 | int prevfd = fs->fd[2]; | ||
16576 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
16577 | |||
16578 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
16579 | INT_ON; | ||
16580 | if (pip[1] >= 0) { | ||
16581 | close(pip[0]); | ||
16582 | } | ||
16583 | if (prevfd > 0) { | ||
16584 | dup2(prevfd, 0); | ||
16585 | close(prevfd); | ||
16586 | } | ||
16587 | if (pip[1] > 1) { | ||
16588 | dup2(pip[1], 1); | ||
16589 | close(pip[1]); | ||
16590 | } | ||
16591 | evaltreenr(n, flags); | ||
16592 | } | ||
16593 | |||
16594 | static void | ||
16595 | forkshell_shellexec(struct forkshell *fs) | ||
16596 | { | ||
16597 | int idx = fs->fd[0]; | ||
16598 | char **argv = fs->argv; | ||
16599 | char *path = fs->path; | ||
16600 | |||
16601 | FORCE_INT_ON; | ||
16602 | shellexec(argv[0], argv, path, idx, TRUE); | ||
16603 | } | ||
16604 | |||
16605 | static void | ||
16606 | forkshell_child(struct forkshell *fs) | ||
16607 | { | ||
16608 | switch ( fs->fpid ) { | ||
16609 | case FS_OPENHERE: | ||
16610 | forkshell_openhere(fs); | ||
16611 | break; | ||
16612 | case FS_EVALBACKCMD: | ||
16613 | forkshell_evalbackcmd(fs); | ||
16614 | break; | ||
16615 | case FS_EVALSUBSHELL: | ||
16616 | forkshell_evalsubshell(fs); | ||
16617 | break; | ||
16618 | case FS_EVALPIPE: | ||
16619 | forkshell_evalpipe(fs); | ||
16620 | break; | ||
16621 | case FS_SHELLEXEC: | ||
16622 | forkshell_shellexec(fs); | ||
16623 | break; | ||
16624 | } | ||
16625 | } | ||
16626 | |||
16627 | /* | ||
16628 | * Reinitialise the builtin environment variables in varinit. Their | ||
16629 | * current settings have been copied from the parent in vartab. Look | ||
16630 | * these up using the names from varinit_data, copy the details from | ||
16631 | * vartab to varinit and replace the old copy in vartab with the new | ||
16632 | * one in varinit. | ||
16633 | * | ||
16634 | * Also reinitialise the function pointers and line number variable. | ||
16635 | */ | ||
16636 | static void | ||
16637 | reinitvar(void) | ||
16638 | { | ||
16639 | int i; | ||
16640 | const char *name; | ||
16641 | struct var **old; | ||
16642 | |||
16643 | for (i=0; i<ARRAY_SIZE(varinit); ++i) { | ||
16644 | if (i == LINENO_INDEX) | ||
16645 | name = "LINENO="; | ||
16646 | else if (i == FUNCNAME_INDEX) | ||
16647 | name = "FUNCNAME="; | ||
16648 | else | ||
16649 | name = varinit_data[i].var_text; | ||
16650 | if ((old = findvar(name)) != NULL) { | ||
16651 | varinit[i] = **old; | ||
16652 | *old = varinit+i; | ||
16653 | } | ||
16654 | varinit[i].var_func = varinit_data[i].var_func; | ||
16655 | } | ||
16656 | vlineno.var_text = linenovar; | ||
16657 | vfuncname.var_text = funcnamevar; | ||
16658 | } | ||
16659 | |||
16660 | static void | ||
16661 | spawn_forkshell(struct forkshell *fs, struct job *jp, union node *n, int mode) | ||
16662 | { | ||
16663 | struct forkshell *new; | ||
16664 | char buf[32]; | ||
16665 | const char *argv[] = { "sh", "--fs", NULL, NULL }; | ||
16666 | intptr_t ret; | ||
16667 | |||
16668 | new = forkshell_prepare(fs); | ||
16669 | if (new == NULL) | ||
16670 | goto fail; | ||
16671 | |||
16672 | new->mode = mode; | ||
16673 | new->nprocs = jp == NULL ? 0 : jp->nprocs; | ||
16674 | #if JOBS_WIN32 | ||
16675 | new->jpnull = jp == NULL; | ||
16676 | #endif | ||
16677 | sprintf(buf, "%p", new->hMapFile); | ||
16678 | argv[2] = buf; | ||
16679 | ret = spawnve(P_NOWAIT, bb_busybox_exec_path, (char *const *)argv, NULL); | ||
16680 | CloseHandle(new->hMapFile); | ||
16681 | UnmapViewOfFile(new); | ||
16682 | if (ret == -1) { | ||
16683 | fail: | ||
16684 | if (jp) | ||
16685 | freejob(jp); | ||
16686 | ash_msg_and_raise_error("unable to spawn shell"); | ||
16687 | } | ||
16688 | forkparent(jp, n, mode, (HANDLE)ret); | ||
16689 | } | ||
16690 | |||
16691 | /* | ||
16692 | * forkshell_prepare() and friends | ||
16693 | * | ||
16694 | * The sequence is as follows: | ||
16695 | * - funcblocksize is initialized | ||
16696 | * - forkshell_size(fs) is called to calculate the exact memory needed | ||
16697 | * - a new struct is allocated | ||
16698 | * - funcblock, funcstring, relocate are initialized from the new block | ||
16699 | * - forkshell_copy(fs) is called to copy recursively everything over | ||
16700 | * it will record all relocations along the way | ||
16701 | * | ||
16702 | * When this memory is mapped elsewhere, pointer fixup will be needed | ||
16703 | */ | ||
16704 | |||
16705 | /* redefine without test that fs_size is nonzero */ | ||
16706 | #undef SAVE_PTR | ||
16707 | #undef SAVE_PTR2 | ||
16708 | #undef SAVE_PTR3 | ||
16709 | #define SAVE_PTR(dst,note,flag) {MARK_PTR(dst,note,flag);} | ||
16710 | |||
16711 | static int align_len(const char *s) | ||
16712 | { | ||
16713 | return s ? SHELL_ALIGN(strlen(s)+1) : 0; | ||
16714 | } | ||
16715 | |||
16716 | struct datasize { | ||
16717 | int funcblocksize; | ||
16718 | int funcstringsize; | ||
16719 | }; | ||
16720 | |||
16721 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
16722 | static struct datasize \ | ||
16723 | name(struct datasize ds, type *p) \ | ||
16724 | { \ | ||
16725 | while (p) { \ | ||
16726 | ds.funcblocksize += sizeof(type); | ||
16727 | /* do something here with p */ | ||
16728 | #define SLIST_SIZE_END() \ | ||
16729 | p = p->next; \ | ||
16730 | } \ | ||
16731 | return ds; \ | ||
16732 | } | ||
16733 | |||
16734 | #define SLIST_COPY_BEGIN(name,type) \ | ||
16735 | static type * \ | ||
16736 | name(type *vp) \ | ||
16737 | { \ | ||
16738 | type *start; \ | ||
16739 | type **vpp; \ | ||
16740 | vpp = &start; \ | ||
16741 | while (vp) { \ | ||
16742 | *vpp = funcblock; \ | ||
16743 | funcblock = (char *) funcblock + sizeof(type); | ||
16744 | /* do something here with vpp and vp */ | ||
16745 | #define SLIST_COPY_END() \ | ||
16746 | SAVE_PTR((*vpp)->next, "(*vpp)->next", NO_FREE); \ | ||
16747 | vp = vp->next; \ | ||
16748 | vpp = &(*vpp)->next; \ | ||
16749 | } \ | ||
16750 | *vpp = NULL; \ | ||
16751 | return start; \ | ||
16752 | } | ||
16753 | |||
16754 | /* | ||
16755 | * struct var | ||
16756 | */ | ||
16757 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
16758 | ds.funcstringsize += align_len(p->var_text); | ||
16759 | SLIST_SIZE_END() | ||
16760 | |||
16761 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
16762 | (*vpp)->var_text = nodeckstrdup(vp->var_text); | ||
16763 | (*vpp)->flags = vp->flags; | ||
16764 | (*vpp)->var_func = NULL; | ||
16765 | SAVE_PTR((*vpp)->var_text, xasprintf("(*vpp)->var_text '%s'", vp->var_text ?: "NULL"), FREE); | ||
16766 | SLIST_COPY_END() | ||
16767 | |||
16768 | /* | ||
16769 | * struct tblentry | ||
16770 | */ | ||
16771 | static struct datasize | ||
16772 | tblentry_size(struct datasize ds, struct tblentry *tep) | ||
16773 | { | ||
16774 | while (tep) { | ||
16775 | ds.funcblocksize += sizeof(struct tblentry) + align_len(tep->cmdname); | ||
16776 | /* CMDBUILTIN, e->param.cmd needs no pointer relocation */ | ||
16777 | if (tep->cmdtype == CMDFUNCTION) { | ||
16778 | ds.funcblocksize += offsetof(struct funcnode, n); | ||
16779 | ds.funcblocksize = calcsize(ds.funcblocksize, &tep->param.func->n); | ||
16780 | } | ||
16781 | tep = tep->next; | ||
16782 | } | ||
16783 | return ds; | ||
16784 | } | ||
16785 | |||
16786 | static struct tblentry * | ||
16787 | tblentry_copy(struct tblentry *tep) | ||
16788 | { | ||
16789 | struct tblentry *start; | ||
16790 | struct tblentry **newp; | ||
16791 | int size; | ||
16792 | |||
16793 | newp = &start; | ||
16794 | while (tep) { | ||
16795 | *newp = funcblock; | ||
16796 | size = sizeof(struct tblentry) + align_len(tep->cmdname); | ||
16797 | |||
16798 | funcblock = (char *) funcblock + size; | ||
16799 | memcpy(*newp, tep, sizeof(struct tblentry)+strlen(tep->cmdname)); | ||
16800 | switch (tep->cmdtype) { | ||
16801 | case CMDBUILTIN: | ||
16802 | /* Save index of builtin, not pointer; fixed by forkshell_init() */ | ||
16803 | (*newp)->param.index = tep->param.cmd - builtintab; | ||
16804 | break; | ||
16805 | case CMDFUNCTION: | ||
16806 | (*newp)->param.func = funcblock; | ||
16807 | funcblock = (char *) funcblock + offsetof(struct funcnode, n); | ||
16808 | copynode(&tep->param.func->n); | ||
16809 | SAVE_PTR((*newp)->param.func, "param.func", NO_FREE); | ||
16810 | break; | ||
16811 | default: | ||
16812 | break; | ||
16813 | } | ||
16814 | SAVE_PTR((*newp)->next, xasprintf("cmdname '%s'", tep->cmdname), FREE); | ||
16815 | tep = tep->next; | ||
16816 | newp = &(*newp)->next; | ||
16817 | } | ||
16818 | *newp = NULL; | ||
16819 | return start; | ||
16820 | } | ||
16821 | |||
16822 | static struct datasize | ||
16823 | cmdtable_size(struct datasize ds) | ||
16824 | { | ||
16825 | int i; | ||
16826 | ds.funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE; | ||
16827 | for (i = 0; i < CMDTABLESIZE; i++) | ||
16828 | ds = tblentry_size(ds, cmdtable[i]); | ||
16829 | return ds; | ||
16830 | } | ||
16831 | |||
16832 | static struct tblentry ** | ||
16833 | cmdtable_copy(void) | ||
16834 | { | ||
16835 | struct tblentry **new = funcblock; | ||
16836 | int i; | ||
16837 | |||
16838 | funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE; | ||
16839 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
16840 | new[i] = tblentry_copy(cmdtable[i]); | ||
16841 | SAVE_PTR(new[i], xasprintf("cmdtable[%d]", i), FREE); | ||
16842 | } | ||
16843 | return new; | ||
16844 | } | ||
16845 | |||
16846 | #if ENABLE_ASH_ALIAS | ||
16847 | /* | ||
16848 | * struct alias | ||
16849 | */ | ||
16850 | SLIST_SIZE_BEGIN(alias_size,struct alias) | ||
16851 | ds.funcstringsize += align_len(p->name); | ||
16852 | ds.funcstringsize += align_len(p->val); | ||
16853 | SLIST_SIZE_END() | ||
16854 | |||
16855 | SLIST_COPY_BEGIN(alias_copy,struct alias) | ||
16856 | (*vpp)->name = nodeckstrdup(vp->name); | ||
16857 | (*vpp)->val = nodeckstrdup(vp->val); | ||
16858 | (*vpp)->flag = vp->flag; | ||
16859 | SAVE_PTR((*vpp)->name, xasprintf("(*vpp)->name '%s'", vp->name ?: "NULL"), FREE); | ||
16860 | SAVE_PTR((*vpp)->val, xasprintf("(*vpp)->val '%s'", vp->val ?: "NULL"), FREE); | ||
16861 | SLIST_COPY_END() | ||
16862 | |||
16863 | static struct datasize | ||
16864 | atab_size(struct datasize ds) | ||
16865 | { | ||
16866 | int i; | ||
16867 | ds.funcblocksize += sizeof(struct alias *)*ATABSIZE; | ||
16868 | for (i = 0; i < ATABSIZE; i++) | ||
16869 | ds = alias_size(ds, atab[i]); | ||
16870 | return ds; | ||
16871 | } | ||
16872 | |||
16873 | static struct alias ** | ||
16874 | atab_copy(void) | ||
16875 | { | ||
16876 | struct alias **new = funcblock; | ||
16877 | int i; | ||
16878 | |||
16879 | funcblock = (char *) funcblock + sizeof(struct alias *)*ATABSIZE; | ||
16880 | for (i = 0; i < ATABSIZE; i++) { | ||
16881 | new[i] = alias_copy(atab[i]); | ||
16882 | SAVE_PTR(new[i], xasprintf("atab[%d]", i), FREE); | ||
16883 | } | ||
16884 | return new; | ||
16885 | } | ||
16886 | #endif | ||
16887 | |||
16888 | /* | ||
16889 | * char ** | ||
16890 | */ | ||
16891 | static struct datasize | ||
16892 | argv_size(struct datasize ds, char **p) | ||
16893 | { | ||
16894 | if (p) { | ||
16895 | while (*p) { | ||
16896 | ds.funcblocksize += sizeof(char *); | ||
16897 | ds.funcstringsize += align_len(*p); | ||
16898 | p++; | ||
16899 | } | ||
16900 | // Allow two extra elements for tryexec(). | ||
16901 | ds.funcblocksize += 3 * sizeof(char *); | ||
16902 | } | ||
16903 | return ds; | ||
16904 | } | ||
16905 | |||
16906 | static char ** | ||
16907 | argv_copy(char **p) | ||
16908 | { | ||
16909 | char **new, **start = funcblock; | ||
16910 | #if FORKSHELL_DEBUG | ||
16911 | int i = 0; | ||
16912 | #endif | ||
16913 | |||
16914 | if (p) { | ||
16915 | // Allow two extra elements for tryexec(). | ||
16916 | funcblock = (char *) funcblock + 2 * sizeof(char *); | ||
16917 | while (*p) { | ||
16918 | new = funcblock; | ||
16919 | funcblock = (char *) funcblock + sizeof(char *); | ||
16920 | *new = nodeckstrdup(*p); | ||
16921 | SAVE_PTR(*new, xasprintf("argv[%d] '%s'", i++, *p), FREE); | ||
16922 | p++; | ||
16923 | } | ||
16924 | new = funcblock; | ||
16925 | funcblock = (char *) funcblock + sizeof(char *); | ||
16926 | *new = NULL; | ||
16927 | return start + 2; | ||
16928 | } | ||
16929 | return NULL; | ||
16930 | } | ||
16931 | |||
16932 | #if MAX_HISTORY | ||
16933 | static struct datasize | ||
16934 | history_size(struct datasize ds) | ||
16935 | { | ||
16936 | int i; | ||
16937 | line_input_t *st = line_input_state; | ||
16938 | |||
16939 | ds.funcblocksize += sizeof(char *) * st->cnt_history; | ||
16940 | for (i = 0; i < st->cnt_history; i++) { | ||
16941 | ds.funcstringsize += align_len(st->history[i]); | ||
16942 | } | ||
16943 | return ds; | ||
16944 | } | ||
16945 | |||
16946 | static char ** | ||
16947 | history_copy(void) | ||
16948 | { | ||
16949 | line_input_t *st = line_input_state; | ||
16950 | char **new = funcblock; | ||
16951 | int i; | ||
16952 | |||
16953 | funcblock = (char *)funcblock + sizeof(char *) * st->cnt_history; | ||
16954 | for (i = 0; i < st->cnt_history; i++) { | ||
16955 | new[i] = nodeckstrdup(st->history[i]); | ||
16956 | SAVE_PTR(new[i], | ||
16957 | xasprintf("history[%d] '%s'", i, st->history[i]), FREE); | ||
16958 | } | ||
16959 | return new; | ||
16960 | } | ||
16961 | #endif | ||
16962 | |||
16963 | #if JOBS_WIN32 | ||
16964 | /* | ||
16965 | * struct procstat | ||
16966 | */ | ||
16967 | static struct datasize | ||
16968 | procstat_size(struct datasize ds, int nj) | ||
16969 | { | ||
16970 | struct job *jp = jobtab + nj; | ||
16971 | |||
16972 | if (jp->ps != &jp->ps0) | ||
16973 | ds.funcblocksize += sizeof(struct procstat) * jp->nprocs; | ||
16974 | |||
16975 | for (int i = 0; i < jp->nprocs; i++) | ||
16976 | ds.funcstringsize += align_len(jp->ps[i].ps_cmd); | ||
16977 | |||
16978 | return ds; | ||
16979 | } | ||
16980 | |||
16981 | static struct procstat * | ||
16982 | procstat_copy(int nj) | ||
16983 | { | ||
16984 | struct job *jp = jobtab + nj; | ||
16985 | struct procstat *new = funcblock; | ||
16986 | |||
16987 | funcblock = (char *)funcblock + sizeof(struct procstat) * jp->nprocs; | ||
16988 | memcpy(new, jp->ps, sizeof(struct procstat) * jp->nprocs); | ||
16989 | |||
16990 | for (int i = 0; i < jp->nprocs; i++) { | ||
16991 | new[i].ps_cmd = nodeckstrdup(jp->ps[i].ps_cmd); | ||
16992 | SAVE_PTR(new[i].ps_cmd, | ||
16993 | xasprintf("jobtab[%d].ps[%d].ps_cmd '%s'", | ||
16994 | nj, i, jp->ps[i].ps_cmd), FREE); | ||
16995 | } | ||
16996 | return new; | ||
16997 | } | ||
16998 | |||
16999 | /* | ||
17000 | * struct jobs | ||
17001 | */ | ||
17002 | static struct datasize | ||
17003 | jobtab_size(struct datasize ds) | ||
17004 | { | ||
17005 | ds.funcblocksize += sizeof(struct job) * njobs; | ||
17006 | for (int i = 0; i < njobs; i++) { | ||
17007 | if (jobtab[i].used) | ||
17008 | ds = procstat_size(ds, i); | ||
17009 | } | ||
17010 | return ds; | ||
17011 | } | ||
17012 | |||
17013 | static struct job * | ||
17014 | jobtab_copy(void) | ||
17015 | { | ||
17016 | struct job *new = funcblock; | ||
17017 | int i; | ||
17018 | |||
17019 | funcblock = (char *)funcblock + sizeof(struct job) * njobs; | ||
17020 | memcpy(new, jobtab, sizeof(struct job) * njobs); | ||
17021 | |||
17022 | for (i = 0; i < njobs; i++) { | ||
17023 | if (!jobtab[i].used) | ||
17024 | continue; | ||
17025 | |||
17026 | if (jobtab[i].ps == &jobtab[i].ps0) { | ||
17027 | new[i].ps0.ps_cmd = nodeckstrdup(jobtab[i].ps0.ps_cmd); | ||
17028 | SAVE_PTR(new[i].ps0.ps_cmd, | ||
17029 | xasprintf("jobtab[%d].ps0.ps_cmd '%s'", | ||
17030 | i, jobtab[i].ps0.ps_cmd), FREE); | ||
17031 | new[i].ps = &new[i].ps0; | ||
17032 | } else if (jobtab[i].nprocs) { | ||
17033 | new[i].ps = procstat_copy(i); | ||
17034 | } else { | ||
17035 | new[i].ps = NULL; | ||
17036 | } | ||
17037 | SAVE_PTR(new[i].ps, xasprintf("jobtab[%d].ps", i), FREE); | ||
17038 | |||
17039 | if (jobtab[i].prev_job) { | ||
17040 | new[i].prev_job = new + (jobtab[i].prev_job - jobtab); | ||
17041 | SAVE_PTR(new[i].prev_job, | ||
17042 | xasprintf("jobtab[%d].prev_job", i), FREE); | ||
17043 | } | ||
17044 | } | ||
17045 | return new; | ||
17046 | } | ||
17047 | #endif | ||
17048 | |||
17049 | /* | ||
17050 | * struct redirtab | ||
17051 | */ | ||
17052 | static int | ||
17053 | redirtab_size(int funcblocksize, struct redirtab *rdtp) | ||
17054 | { | ||
17055 | while (rdtp) { | ||
17056 | funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
17057 | rdtp = rdtp->next; | ||
17058 | } | ||
17059 | return funcblocksize; | ||
17060 | } | ||
17061 | |||
17062 | static struct redirtab * | ||
17063 | redirtab_copy(struct redirtab *rdtp) | ||
17064 | { | ||
17065 | struct redirtab *start; | ||
17066 | struct redirtab **vpp; | ||
17067 | |||
17068 | vpp = &start; | ||
17069 | while (rdtp) { | ||
17070 | int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
17071 | *vpp = funcblock; | ||
17072 | funcblock = (char *) funcblock + size; | ||
17073 | memcpy(*vpp, rdtp, size); | ||
17074 | SAVE_PTR((*vpp)->next, "(*vpp)->next", NO_FREE); | ||
17075 | rdtp = rdtp->next; | ||
17076 | vpp = &(*vpp)->next; | ||
17077 | } | ||
17078 | *vpp = NULL; | ||
17079 | return start; | ||
17080 | } | ||
17081 | |||
17082 | static struct datasize | ||
17083 | globals_var_size(struct datasize ds) | ||
17084 | { | ||
17085 | int i; | ||
17086 | |||
17087 | ds.funcblocksize += sizeof(struct globals_var); | ||
17088 | ds.funcstringsize += align_len(funcname); | ||
17089 | ds = argv_size(ds, shellparam.p); | ||
17090 | ds.funcblocksize = redirtab_size(ds.funcblocksize, redirlist); | ||
17091 | for (i = 0; i < VTABSIZE; i++) | ||
17092 | ds = var_size(ds, vartab[i]); | ||
17093 | return ds; | ||
17094 | } | ||
17095 | |||
17096 | #undef funcname | ||
17097 | #undef shellparam | ||
17098 | #undef redirlist | ||
17099 | #undef vartab | ||
17100 | static struct globals_var * | ||
17101 | globals_var_copy(void) | ||
17102 | { | ||
17103 | int i; | ||
17104 | struct globals_var *gvp, *new; | ||
17105 | |||
17106 | gvp = ash_ptr_to_globals_var; | ||
17107 | new = funcblock; | ||
17108 | funcblock = (char *) funcblock + sizeof(struct globals_var); | ||
17109 | memcpy(new, gvp, sizeof(struct globals_var)); | ||
17110 | |||
17111 | new->funcname = nodeckstrdup(gvp->funcname); | ||
17112 | SAVE_PTR(new->funcname, xasprintf("funcname '%s'", gvp->funcname ?: "NULL"), FREE); | ||
17113 | |||
17114 | /* shparam */ | ||
17115 | new->shellparam.malloced = 0; | ||
17116 | new->shellparam.p = argv_copy(gvp->shellparam.p); | ||
17117 | SAVE_PTR(new->shellparam.p, "shellparam.p", NO_FREE); | ||
17118 | |||
17119 | new->redirlist = redirtab_copy(gvp->redirlist); | ||
17120 | SAVE_PTR(new->redirlist, "redirlist", NO_FREE); | ||
17121 | |||
17122 | for (i = 0; i < VTABSIZE; i++) { | ||
17123 | new->vartab[i] = var_copy(gvp->vartab[i]); | ||
17124 | SAVE_PTR(new->vartab[i], xasprintf("vartab[%d]", i), FREE); | ||
17125 | } | ||
17126 | |||
17127 | return new; | ||
17128 | } | ||
17129 | |||
17130 | static struct datasize | ||
17131 | globals_misc_size(struct datasize ds) | ||
17132 | { | ||
17133 | ds.funcblocksize += sizeof(struct globals_misc); | ||
17134 | ds.funcstringsize += align_len(minusc); | ||
17135 | if (curdir != nullstr) | ||
17136 | ds.funcstringsize += align_len(curdir); | ||
17137 | if (physdir != nullstr) | ||
17138 | ds.funcstringsize += align_len(physdir); | ||
17139 | ds.funcstringsize += align_len(arg0); | ||
17140 | ds.funcstringsize += align_len(commandname); | ||
17141 | for (int i = 0; i < ARRAY_SIZE(trap); i++) | ||
17142 | ds.funcstringsize += align_len(trap[i]); | ||
17143 | return ds; | ||
17144 | } | ||
17145 | |||
17146 | #undef minusc | ||
17147 | #undef curdir | ||
17148 | #undef physdir | ||
17149 | #undef arg0 | ||
17150 | #undef commandname | ||
17151 | #undef nullstr | ||
17152 | #undef trap | ||
17153 | static struct globals_misc * | ||
17154 | globals_misc_copy(void) | ||
17155 | { | ||
17156 | struct globals_misc *p = ash_ptr_to_globals_misc; | ||
17157 | struct globals_misc *new = funcblock; | ||
17158 | |||
17159 | funcblock = (char *) funcblock + sizeof(struct globals_misc); | ||
17160 | memcpy(new, p, sizeof(struct globals_misc)); | ||
17161 | |||
17162 | new->minusc = nodeckstrdup(p->minusc); | ||
17163 | new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr; | ||
17164 | new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr; | ||
17165 | new->arg0 = nodeckstrdup(p->arg0); | ||
17166 | new->commandname = nodeckstrdup(p->commandname); | ||
17167 | SAVE_PTR(new->minusc, xasprintf("minusc '%s'", p->minusc ?: "NULL"), FREE); | ||
17168 | SAVE_PTR(new->curdir, | ||
17169 | xasprintf("curdir '%s'", new->curdir ?: "NULL"), FREE); | ||
17170 | SAVE_PTR(new->physdir, | ||
17171 | xasprintf("physdir '%s'", new->physdir ?: "NULL"), FREE); | ||
17172 | SAVE_PTR(new->arg0, xasprintf("arg0 '%s'", p->arg0 ?: "NULL"), FREE); | ||
17173 | SAVE_PTR(new->commandname, | ||
17174 | xasprintf("commandname '%s'", p->commandname ?: "NULL"), FREE); | ||
17175 | for (int i = 0; i < ARRAY_SIZE(p->trap); i++) { | ||
17176 | new->trap[i] = nodeckstrdup(p->trap[i]); | ||
17177 | SAVE_PTR(new->trap[i], xasprintf("trap[%d]", i), FREE); | ||
17178 | } | ||
17179 | return new; | ||
17180 | } | ||
17181 | |||
17182 | static struct datasize | ||
17183 | forkshell_size(struct forkshell *fs) | ||
17184 | { | ||
17185 | struct datasize ds = {0, 0}; | ||
17186 | |||
17187 | ds.funcstringsize += align_len(fs->path); | ||
17188 | if (fs->fpid == FS_OPENHERE) | ||
17189 | return ds; | ||
17190 | |||
17191 | ds = globals_var_size(ds); | ||
17192 | ds = globals_misc_size(ds); | ||
17193 | ds = cmdtable_size(ds); | ||
17194 | |||
17195 | ds.funcblocksize = calcsize(ds.funcblocksize, fs->n); | ||
17196 | ds = argv_size(ds, fs->argv); | ||
17197 | |||
17198 | if ((ENABLE_ASH_ALIAS || MAX_HISTORY || JOBS_WIN32) && | ||
17199 | fs->fpid != FS_SHELLEXEC) { | ||
17200 | #if ENABLE_ASH_ALIAS | ||
17201 | ds = atab_size(ds); | ||
17202 | #endif | ||
17203 | #if MAX_HISTORY | ||
17204 | if (line_input_state) | ||
17205 | ds = history_size(ds); | ||
17206 | #endif | ||
17207 | #if JOBS_WIN32 | ||
17208 | ds = jobtab_size(ds); | ||
17209 | #endif | ||
17210 | } | ||
17211 | return ds; | ||
17212 | } | ||
17213 | |||
17214 | static void | ||
17215 | forkshell_copy(struct forkshell *fs, struct forkshell *new) | ||
17216 | { | ||
17217 | memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */ | ||
17218 | |||
17219 | new->path = nodeckstrdup(fs->path); | ||
17220 | SAVE_PTR(new->path, xasprintf("path '%s'", fs->path ?: "NULL"), FREE); | ||
17221 | if (fs->fpid == FS_OPENHERE) | ||
17222 | return; | ||
17223 | |||
17224 | new->gvp = globals_var_copy(); | ||
17225 | new->gmp = globals_misc_copy(); | ||
17226 | new->cmdtable = cmdtable_copy(); | ||
17227 | SAVE_PTR(new->gvp, "gvp", NO_FREE); | ||
17228 | SAVE_PTR(new->gmp, "gmp", NO_FREE); | ||
17229 | SAVE_PTR(new->cmdtable, "cmdtable", NO_FREE); | ||
17230 | |||
17231 | new->n = copynode(fs->n); | ||
17232 | new->argv = argv_copy(fs->argv); | ||
17233 | SAVE_PTR(new->n, "n", NO_FREE); | ||
17234 | SAVE_PTR(new->argv, "argv", NO_FREE); | ||
17235 | |||
17236 | if ((ENABLE_ASH_ALIAS || MAX_HISTORY || JOBS_WIN32) && | ||
17237 | fs->fpid != FS_SHELLEXEC) { | ||
17238 | #if ENABLE_ASH_ALIAS | ||
17239 | new->atab = atab_copy(); | ||
17240 | SAVE_PTR(new->atab, "atab", NO_FREE); | ||
17241 | #endif | ||
17242 | #if MAX_HISTORY | ||
17243 | if (line_input_state) { | ||
17244 | new->history = history_copy(); | ||
17245 | SAVE_PTR(new->history, "history", NO_FREE); | ||
17246 | new->cnt_history = line_input_state->cnt_history; | ||
17247 | } | ||
17248 | #endif | ||
17249 | #if JOBS_WIN32 | ||
17250 | if (njobs) { | ||
17251 | new->jobtab = jobtab_copy(); | ||
17252 | SAVE_PTR(new->jobtab, "jobtab", NO_FREE); | ||
17253 | new->njobs = njobs; | ||
17254 | if (curjob) { | ||
17255 | new->curjob = new->jobtab + (curjob - jobtab); | ||
17256 | SAVE_PTR(new->curjob, "curjob", NO_FREE); | ||
17257 | } | ||
17258 | } | ||
17259 | #endif | ||
17260 | } | ||
17261 | } | ||
17262 | |||
17263 | #if FORKSHELL_DEBUG | ||
17264 | #define NUM_BLOCKS FUNCSTRING | ||
17265 | enum {GVP, GMP, CMDTABLE, NODE, ARGV, ATAB, HISTORY, JOBTAB, FUNCSTRING}; | ||
17266 | |||
17267 | /* fp0 and notes can each be NULL */ | ||
17268 | static void | ||
17269 | forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes) | ||
17270 | { | ||
17271 | FILE *fp; | ||
17272 | void *lfuncblock; | ||
17273 | char *lfuncstring; | ||
17274 | char *lrelocate; | ||
17275 | char *s; | ||
17276 | int count, i, total, bitmapsize; | ||
17277 | int size[NUM_BLOCKS]; | ||
17278 | char *lptr[NUM_BLOCKS+1]; | ||
17279 | const char *fsname[] = { | ||
17280 | "FS_OPENHERE", | ||
17281 | "FS_EVALBACKCMD", | ||
17282 | "FS_EVALSUBSHELL", | ||
17283 | "FS_EVALPIPE", | ||
17284 | "FS_SHELLEXEC" | ||
17285 | }; | ||
17286 | |||
17287 | if (fp0 != NULL) { | ||
17288 | fp = fp0; | ||
17289 | } | ||
17290 | else { | ||
17291 | char name[64]; | ||
17292 | static int num = 0; | ||
17293 | |||
17294 | sprintf(name, "fs_%d_%03d.out", getpid(), ++num % 100); | ||
17295 | if ((fp=fopen(name, "w")) == NULL) | ||
17296 | return; | ||
17297 | } | ||
17298 | |||
17299 | bitmapsize = (fs->relocatesize + 7)/8; | ||
17300 | total = sizeof(struct forkshell) + fs->funcblocksize + | ||
17301 | fs->funcstringsize + bitmapsize; | ||
17302 | fprintf(fp, "total size %6d = %d + %d + %d + %d = %d\n", | ||
17303 | fs->size + bitmapsize, | ||
17304 | (int)sizeof(struct forkshell), fs->funcblocksize, | ||
17305 | fs->funcstringsize, bitmapsize, total); | ||
17306 | |||
17307 | lfuncblock = (char *)(fs + 1); | ||
17308 | lfuncstring = (char *)lfuncblock + fs->funcblocksize; | ||
17309 | lrelocate = (char *)lfuncstring + fs->funcstringsize; | ||
17310 | |||
17311 | /* funcblocksize is zero for FS_OPENHERE */ | ||
17312 | if (fs->funcblocksize != 0) { | ||
17313 | /* Depending on the configuration and the type of forkshell | ||
17314 | * some items may not be present. */ | ||
17315 | lptr[FUNCSTRING] = lfuncstring; | ||
17316 | #if JOBS_WIN32 | ||
17317 | lptr[JOBTAB] = fs->jobtab ? (char *)fs->jobtab : lptr[FUNCSTRING]; | ||
17318 | #else | ||
17319 | lptr[JOBTAB] = lptr[FUNCSTRING]; | ||
17320 | #endif | ||
17321 | #if MAX_HISTORY | ||
17322 | lptr[HISTORY] = fs->history ? (char *)fs->history : lptr[JOBTAB]; | ||
17323 | #else | ||
17324 | lptr[HISTORY] = lptr[JOBTAB]; | ||
17325 | #endif | ||
17326 | lptr[ATAB] = IF_ASH_ALIAS(fs->atab ? (char *)fs->atab :) lptr[HISTORY]; | ||
17327 | lptr[ARGV] = fs->argv ? (char *)fs->argv : lptr[ATAB]; | ||
17328 | lptr[NODE] = fs->n ? (char *)fs->n : lptr[ARGV]; | ||
17329 | lptr[CMDTABLE] = (char *)fs->cmdtable; | ||
17330 | lptr[GMP] = (char *)fs->gmp; | ||
17331 | lptr[GVP] = (char *)fs->gvp; | ||
17332 | |||
17333 | fprintf(fp, "funcblocksize %6d = ", fs->funcblocksize); | ||
17334 | total = 0; | ||
17335 | for (i=0; i<NUM_BLOCKS; ++i) { | ||
17336 | size[i] = (int)(lptr[i+1] - lptr[i]); | ||
17337 | total += size[i]; | ||
17338 | fprintf(fp, "%d %c ", size[i], i == NUM_BLOCKS - 1 ? '=' : '+'); | ||
17339 | } | ||
17340 | fprintf(fp, "%d\n\n", total); | ||
17341 | } | ||
17342 | else { | ||
17343 | fprintf(fp, "\n"); | ||
17344 | } | ||
17345 | |||
17346 | fprintf(fp, "%s\n\n", fsname[fs->fpid]); | ||
17347 | fprintf(fp, "--- relocate ---\n"); | ||
17348 | count = 0; | ||
17349 | for (i = 0; i < fs->relocatesize; ++i) { | ||
17350 | if (lrelocate[i/8] & (1 << i % 8)) { | ||
17351 | char **ptr = (char **)((char *)fs + i * sizeof(char *)); | ||
17352 | fprintf(fp, "%p %p %s\n", ptr, *ptr, | ||
17353 | notes && notes[i] ? notes[i] : ""); | ||
17354 | ++count; | ||
17355 | } | ||
17356 | } | ||
17357 | fprintf(fp, "--- %d relocations ---\n\n", count); | ||
17358 | |||
17359 | fprintf(fp, "--- funcstring ---\n"); | ||
17360 | count = 0; | ||
17361 | s = lfuncstring; | ||
17362 | while (s-lfuncstring < fs->funcstringsize) { | ||
17363 | if (!*s) { | ||
17364 | ++s; | ||
17365 | continue; | ||
17366 | } | ||
17367 | fprintf(fp, "%p '%s'\n", s, s); | ||
17368 | s += strlen(s)+1; | ||
17369 | ++count; | ||
17370 | } | ||
17371 | fprintf(fp, "--- %d strings ---\n", count); | ||
17372 | |||
17373 | if (fp0 == NULL) | ||
17374 | fclose(fp); | ||
17375 | } | ||
17376 | #endif | ||
17377 | |||
17378 | static struct forkshell * | ||
17379 | forkshell_prepare(struct forkshell *fs) | ||
17380 | { | ||
17381 | struct forkshell *new; | ||
17382 | struct datasize ds; | ||
17383 | int size, relocatesize, bitmapsize; | ||
17384 | HANDLE h; | ||
17385 | SECURITY_ATTRIBUTES sa; | ||
17386 | #if FORKSHELL_DEBUG | ||
17387 | char *relocate; | ||
17388 | char name[64]; | ||
17389 | FILE *fp; | ||
17390 | static int num = 0; | ||
17391 | #endif | ||
17392 | |||
17393 | /* calculate size of structure, funcblock and funcstring */ | ||
17394 | ds = forkshell_size(fs); | ||
17395 | size = sizeof(struct forkshell) + ds.funcblocksize + ds.funcstringsize; | ||
17396 | relocatesize = (sizeof(struct forkshell) + ds.funcblocksize)/sizeof(char *); | ||
17397 | bitmapsize = (relocatesize + 7)/8; | ||
17398 | |||
17399 | /* Allocate shared memory region */ | ||
17400 | memset(&sa, 0, sizeof(sa)); | ||
17401 | sa.nLength = sizeof(sa); | ||
17402 | sa.lpSecurityDescriptor = NULL; | ||
17403 | sa.bInheritHandle = TRUE; | ||
17404 | h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, | ||
17405 | size+bitmapsize, NULL); | ||
17406 | |||
17407 | /* Initialise pointers */ | ||
17408 | new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
17409 | if (new == NULL) | ||
17410 | return NULL; | ||
17411 | fs_size = size; | ||
17412 | fs_start = new; | ||
17413 | funcblock = (char *)(new + 1); | ||
17414 | funcstring_end = (char *)new + size; | ||
17415 | #if FORKSHELL_DEBUG | ||
17416 | fs_funcstring = (char *)new + sizeof(struct forkshell) + ds.funcblocksize; | ||
17417 | relocate = (char *)new + size; | ||
17418 | annot = (const char **)xzalloc(sizeof(char *)*relocatesize); | ||
17419 | annot_free = xzalloc(relocatesize); | ||
17420 | #endif | ||
17421 | |||
17422 | /* Now pack them all */ | ||
17423 | forkshell_copy(fs, new); | ||
17424 | |||
17425 | /* Finish it up */ | ||
17426 | new->size = size; | ||
17427 | new->relocatesize = relocatesize; | ||
17428 | new->old_base = (char *)new; | ||
17429 | new->hMapFile = h; | ||
17430 | #if FORKSHELL_DEBUG | ||
17431 | sprintf(name, "fs_%d_%03d.out", getpid(), ++num % 100); | ||
17432 | if ((fp=fopen(name, "w")) != NULL) { | ||
17433 | int i; | ||
17434 | |||
17435 | new->funcblocksize = (char *)funcblock - (char *)(new + 1); | ||
17436 | new->funcstringsize = (char *)new + size - funcstring_end; | ||
17437 | |||
17438 | /* perform some sanity checks on pointers */ | ||
17439 | fprintf(fp, "forkshell %p %6d\n", new, (int)sizeof(*new)); | ||
17440 | fprintf(fp, "funcblock %p %6d\n", new+1, new->funcblocksize); | ||
17441 | fprintf(fp, "funcstring %p %6d\n", funcstring_end, | ||
17442 | new->funcstringsize); | ||
17443 | if ((char *)funcblock != funcstring_end) | ||
17444 | fprintf(fp, " funcstring != end funcblock + 1 %p\n", funcblock); | ||
17445 | fprintf(fp, "relocate %p %6d\n\n", relocate, bitmapsize); | ||
17446 | |||
17447 | forkshell_print(fp, new, annot); | ||
17448 | |||
17449 | for (i = 0; i < relocatesize; ++i) { | ||
17450 | if (annot_free[i]) { | ||
17451 | free((void *)annot[i]); | ||
17452 | } | ||
17453 | } | ||
17454 | free(annot); | ||
17455 | free(annot_free); | ||
17456 | annot = NULL; | ||
17457 | fclose(fp); | ||
17458 | } | ||
17459 | #endif | ||
17460 | return new; | ||
17461 | } | ||
17462 | |||
17463 | #undef trap_ptr | ||
17464 | static void | ||
17465 | forkshell_init(const char *idstr) | ||
17466 | { | ||
17467 | struct forkshell *fs; | ||
17468 | void *map_handle; | ||
17469 | HANDLE h; | ||
17470 | int i; | ||
17471 | char **ptr; | ||
17472 | char *lrelocate; | ||
17473 | struct jmploc jmploc; | ||
17474 | |||
17475 | if (sscanf(idstr, "%p", &map_handle) != 1) | ||
17476 | return; | ||
17477 | |||
17478 | h = (HANDLE)map_handle; | ||
17479 | fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
17480 | if (!fs) | ||
17481 | return; | ||
17482 | |||
17483 | /* this memory can't be freed */ | ||
17484 | sticky_mem_start = fs; | ||
17485 | sticky_mem_end = (char *) fs + fs->size; | ||
17486 | |||
17487 | /* pointer fixup */ | ||
17488 | lrelocate = (char *)fs + fs->size; | ||
17489 | for (i = 0; i < fs->relocatesize; i++) { | ||
17490 | if (lrelocate[i/8] & (1 << i % 8)) { | ||
17491 | ptr = (char **)((char *)fs + i * sizeof(char *)); | ||
17492 | if (*ptr) | ||
17493 | *ptr = (char *)fs + (*ptr - fs->old_base); | ||
17494 | } | ||
17495 | } | ||
17496 | |||
17497 | if (fs->fpid == FS_OPENHERE) | ||
17498 | goto end; | ||
17499 | |||
17500 | /* Now fix up stuff that can't be transferred */ | ||
17501 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
17502 | struct tblentry *e = fs->cmdtable[i]; | ||
17503 | while (e) { | ||
17504 | if (e->cmdtype == CMDBUILTIN) | ||
17505 | e->param.cmd = builtintab + e->param.index; | ||
17506 | e = e->next; | ||
17507 | } | ||
17508 | } | ||
17509 | fs->gmp->trap_ptr = fs->gmp->trap; | ||
17510 | |||
17511 | /* Set global variables */ | ||
17512 | ASSIGN_CONST_PTR(&ash_ptr_to_globals_var, fs->gvp); | ||
17513 | ASSIGN_CONST_PTR(&ash_ptr_to_globals_misc, fs->gmp); | ||
17514 | cmdtable = fs->cmdtable; | ||
17515 | #if ENABLE_ASH_ALIAS | ||
17516 | atab = fs->atab; /* will be NULL for FS_SHELLEXEC */ | ||
17517 | #endif | ||
17518 | #if MAX_HISTORY | ||
17519 | if (fs->cnt_history) { | ||
17520 | line_input_state = new_line_input_t(FOR_SHELL); | ||
17521 | line_input_state->cnt_history = fs->cnt_history; | ||
17522 | for (i = 0; i < line_input_state->cnt_history; i++) | ||
17523 | line_input_state->history[i] = fs->history[i]; | ||
17524 | } | ||
17525 | #endif | ||
17526 | #if JOBS_WIN32 | ||
17527 | jobtab = fs->jobtab; | ||
17528 | njobs = fs->njobs; | ||
17529 | curjob = fs->curjob; | ||
17530 | #endif | ||
17531 | |||
17532 | CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */ | ||
17533 | |||
17534 | reinitvar(); | ||
17535 | |||
17536 | if (setjmp(jmploc.loc)) { | ||
17537 | exitreset(); | ||
17538 | exitshell(); | ||
17539 | } | ||
17540 | exception_handler = &jmploc; | ||
17541 | |||
17542 | shlvl++; | ||
17543 | if (fs->mode == FORK_BG) { | ||
17544 | SetConsoleCtrlHandler(NULL, TRUE); | ||
17545 | if (fs->nprocs == 0) { | ||
17546 | close(0); | ||
17547 | if (open(bb_dev_null, O_RDONLY) != 0) | ||
17548 | ash_msg_and_raise_perror("can't open '%s'", bb_dev_null); | ||
17549 | } | ||
17550 | } | ||
17551 | else { | ||
17552 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
17553 | } | ||
17554 | |||
17555 | if (fs->n && fs->n->type == NCMD /* is it single cmd? */ | ||
17556 | /* && n->ncmd.args->type == NARG - always true? */ | ||
17557 | && fs->n->ncmd.args && strcmp(fs->n->ncmd.args->narg.text, "trap") == 0 | ||
17558 | && fs->n->ncmd.args->narg.next == NULL /* "trap" with no arguments */ | ||
17559 | /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */ | ||
17560 | ) { | ||
17561 | TRACE(("Trap hack\n")); | ||
17562 | /* Save trap handler strings for trap builtin to print */ | ||
17563 | fs->gmp->trap_ptr = xmemdup(fs->gmp->trap, sizeof(fs->gmp->trap)); | ||
17564 | /* Fall through into clearing traps */ | ||
17565 | } | ||
17566 | clear_traps(); | ||
17567 | #if JOBS_WIN32 | ||
17568 | /* do job control only in root shell */ | ||
17569 | doing_jobctl = 0; | ||
17570 | |||
17571 | if (fs->n && fs->n->type == NCMD && fs->n->ncmd.args && | ||
17572 | strcmp(fs->n->ncmd.args->narg.text, "jobs") == 0) { | ||
17573 | TRACE(("Job hack\n")); | ||
17574 | if (!fs->jpnull) | ||
17575 | freejob(curjob); | ||
17576 | goto end; | ||
17577 | } | ||
17578 | for (struct job *jp = curjob; jp; jp = jp->prev_job) | ||
17579 | freejob(jp); | ||
17580 | #endif | ||
17581 | end: | ||
17582 | forkshell_child(fs); | ||
17583 | } | ||
17584 | |||
17585 | #undef free | ||
17586 | static void | ||
17587 | sticky_free(void *base) | ||
17588 | { | ||
17589 | if (base >= sticky_mem_start && base < sticky_mem_end) | ||
17590 | return; | ||
17591 | free(base); | ||
17592 | } | ||
17593 | #endif | ||
14887 | 17594 | ||
14888 | /*- | 17595 | /*- |
14889 | * Copyright (c) 1989, 1991, 1993, 1994 | 17596 | * Copyright (c) 1989, 1991, 1993, 1994 |