diff options
Diffstat (limited to 'shell/ash.c')
| -rw-r--r-- | shell/ash.c | 2834 |
1 files changed, 2795 insertions, 39 deletions
diff --git a/shell/ash.c b/shell/ash.c index 841ffe880..12c95c338 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,94 @@ 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 | #if defined(_WIN64) | ||
| 388 | # define ALIGN64 ALIGNED(16) | ||
| 389 | #else | ||
| 390 | # define ALIGN64 | ||
| 391 | #endif | ||
| 392 | |||
| 393 | struct forkshell { | ||
| 394 | /* filled by forkshell_copy() */ | ||
| 395 | struct globals_misc *gmp; | ||
| 396 | struct globals_var *gvp; | ||
| 397 | struct tblentry **cmdtable; | ||
| 398 | #if ENABLE_ASH_ALIAS | ||
| 399 | struct alias **atab; | ||
| 400 | #endif | ||
| 401 | #if MAX_HISTORY | ||
| 402 | char **history; | ||
| 403 | int cnt_history; | ||
| 404 | #endif | ||
| 405 | #if JOBS_WIN32 | ||
| 406 | struct job *jobtab; | ||
| 407 | unsigned njobs; | ||
| 408 | struct job *curjob; | ||
| 409 | #endif | ||
| 410 | HANDLE hMapFile; | ||
| 411 | char *old_base; | ||
| 412 | int size; | ||
| 413 | # if FORKSHELL_DEBUG | ||
| 414 | int funcblocksize; | ||
| 415 | int funcstringsize; | ||
| 416 | # endif | ||
| 417 | int relocatesize; | ||
| 418 | |||
| 419 | /* type of forkshell */ | ||
| 420 | int fpid; | ||
| 421 | |||
| 422 | /* generic data, used by forkshell_child */ | ||
| 423 | int mode; | ||
| 424 | int nprocs; | ||
| 425 | #if JOBS_WIN32 | ||
| 426 | int jpnull; | ||
| 427 | #endif | ||
| 428 | |||
| 429 | /* optional data, used by forkshell_child */ | ||
| 430 | int flags; | ||
| 431 | int fd[3]; | ||
| 432 | union node *n; | ||
| 433 | char **argv; | ||
| 434 | const char *path; | ||
| 435 | } ALIGN64; | ||
| 436 | |||
| 437 | enum { | ||
| 438 | FS_OPENHERE, | ||
| 439 | FS_EVALBACKCMD, | ||
| 440 | FS_EVALSUBSHELL, | ||
| 441 | FS_EVALPIPE, | ||
| 442 | FS_SHELLEXEC | ||
| 443 | }; | ||
| 444 | |||
| 445 | static struct forkshell* forkshell_prepare(struct forkshell *fs); | ||
| 446 | static void forkshell_init(const char *idstr); | ||
| 447 | static void *sticky_mem_start, *sticky_mem_end; | ||
| 448 | static void sticky_free(void *p); | ||
| 449 | # define free(p) sticky_free(p) | ||
| 450 | #if !JOBS && !JOBS_WIN32 | ||
| 451 | #define spawn_forkshell(fs, jp, n, mode) spawn_forkshell(fs, jp, mode) | ||
| 452 | #endif | ||
| 453 | static void spawn_forkshell(struct forkshell *fs, struct job *jp, | ||
| 454 | union node *n, int mode); | ||
| 455 | # if FORKSHELL_DEBUG | ||
| 456 | static void forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes); | ||
| 457 | # endif | ||
| 458 | #endif | ||
| 459 | |||
| 323 | /* ============ Hash table sizes. Configurable. */ | 460 | /* ============ Hash table sizes. Configurable. */ |
| 324 | 461 | ||
| 325 | #define VTABSIZE 39 | 462 | #define VTABSIZE 39 |
| @@ -347,7 +484,11 @@ static const char *const optletters_optnames[] ALIGN_PTR = { | |||
| 347 | "m" "monitor", | 484 | "m" "monitor", |
| 348 | "n" "noexec", | 485 | "n" "noexec", |
| 349 | /* Ditto: bash has no "set -s", "set -c" */ | 486 | /* Ditto: bash has no "set -s", "set -c" */ |
| 487 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 350 | "s" "", | 488 | "s" "", |
| 489 | #else | ||
| 490 | "s" "stdin", | ||
| 491 | #endif | ||
| 351 | "c" "", | 492 | "c" "", |
| 352 | "x" "xtrace", | 493 | "x" "xtrace", |
| 353 | "v" "verbose", | 494 | "v" "verbose", |
| @@ -364,6 +505,18 @@ static const char *const optletters_optnames[] ALIGN_PTR = { | |||
| 364 | ,"\0" "nolog" | 505 | ,"\0" "nolog" |
| 365 | ,"\0" "debug" | 506 | ,"\0" "debug" |
| 366 | #endif | 507 | #endif |
| 508 | #if ENABLE_PLATFORM_MINGW32 | ||
| 509 | ,"X" "winxp" | ||
| 510 | #endif | ||
| 511 | #if ENABLE_ASH_NOCONSOLE | ||
| 512 | ,"\0" "noconsole" | ||
| 513 | ,"\0" "noiconify" | ||
| 514 | #endif | ||
| 515 | #if ENABLE_ASH_GLOB_OPTIONS | ||
| 516 | ,"\0" "nocaseglob" | ||
| 517 | ,"\0" "nohiddenglob" | ||
| 518 | ,"\0" "nohidsysglob" | ||
| 519 | #endif | ||
| 367 | }; | 520 | }; |
| 368 | //bash 4.4.23 also has these opts (with these defaults): | 521 | //bash 4.4.23 also has these opts (with these defaults): |
| 369 | //braceexpand on | 522 | //braceexpand on |
| @@ -437,6 +590,11 @@ struct parsefile { | |||
| 437 | 590 | ||
| 438 | /* Number of outstanding calls to pungetc. */ | 591 | /* Number of outstanding calls to pungetc. */ |
| 439 | int unget; | 592 | int unget; |
| 593 | |||
| 594 | #if ENABLE_PLATFORM_MINGW32 | ||
| 595 | /* True if a trailing CR from a previous read was left unprocessed. */ | ||
| 596 | int cr; | ||
| 597 | #endif | ||
| 440 | }; | 598 | }; |
| 441 | 599 | ||
| 442 | 600 | ||
| @@ -460,17 +618,31 @@ struct jmploc { | |||
| 460 | struct globals_misc { | 618 | struct globals_misc { |
| 461 | uint8_t exitstatus; /* exit status of last command */ | 619 | uint8_t exitstatus; /* exit status of last command */ |
| 462 | uint8_t back_exitstatus;/* exit status of backquoted command */ | 620 | uint8_t back_exitstatus;/* exit status of backquoted command */ |
| 621 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 463 | smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ | 622 | smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ |
| 623 | #endif | ||
| 464 | smallint inps4; /* Prevent PS4 nesting. */ | 624 | smallint inps4; /* Prevent PS4 nesting. */ |
| 625 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 465 | smallint vforked; | 626 | smallint vforked; |
| 627 | #endif | ||
| 466 | int savestatus; /* exit status of last command outside traps */ | 628 | int savestatus; /* exit status of last command outside traps */ |
| 467 | int rootpid; /* pid of main shell */ | 629 | int rootpid; /* pid of main shell */ |
| 468 | /* shell level: 0 for the main shell, 1 for its children, and so on */ | 630 | /* shell level: 0 for the main shell, 1 for its children, and so on */ |
| 469 | int shlvl; | 631 | int shlvl; |
| 632 | #if ENABLE_PLATFORM_MINGW32 | ||
| 633 | int loopnest; /* current loop nesting level */ | ||
| 634 | #endif | ||
| 470 | #define rootshell (!shlvl) | 635 | #define rootshell (!shlvl) |
| 471 | int errlinno; | 636 | int errlinno; |
| 472 | 637 | ||
| 473 | char *minusc; /* argument to -c option */ | 638 | char *minusc; /* argument to -c option */ |
| 639 | #if ENABLE_PLATFORM_MINGW32 | ||
| 640 | char *dirarg; /* argument to -d option */ | ||
| 641 | char *title; /* argument to -t option */ | ||
| 642 | #if ENABLE_SUW32 | ||
| 643 | int delayexit; /* set by -N option */ | ||
| 644 | # endif | ||
| 645 | #endif | ||
| 474 | 646 | ||
| 475 | char *curdir; // = nullstr; /* current working directory */ | 647 | char *curdir; // = nullstr; /* current working directory */ |
| 476 | char *physdir; // = nullstr; /* physical working directory */ | 648 | char *physdir; // = nullstr; /* physical working directory */ |
| @@ -486,8 +658,12 @@ struct globals_misc { | |||
| 486 | * but we do read it async. | 658 | * but we do read it async. |
| 487 | */ | 659 | */ |
| 488 | volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ | 660 | volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ |
| 661 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 489 | volatile /*sig_atomic_t*/ smallint gotsigchld; /* 1 = got SIGCHLD */ | 662 | volatile /*sig_atomic_t*/ smallint gotsigchld; /* 1 = got SIGCHLD */ |
| 490 | volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */ | 663 | volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */ |
| 664 | #else | ||
| 665 | volatile /*sig_atomic_t*/ smallint waitcmd_int; /* SIGINT in wait */ | ||
| 666 | #endif | ||
| 491 | smallint exception_type; /* kind of exception: */ | 667 | smallint exception_type; /* kind of exception: */ |
| 492 | #define EXINT 0 /* SIGINT received */ | 668 | #define EXINT 0 /* SIGINT received */ |
| 493 | #define EXERROR 1 /* a generic error */ | 669 | #define EXERROR 1 /* a generic error */ |
| @@ -522,8 +698,21 @@ struct globals_misc { | |||
| 522 | # define nolog optlist[16 + BASH_PIPEFAIL] | 698 | # define nolog optlist[16 + BASH_PIPEFAIL] |
| 523 | # define debug optlist[17 + BASH_PIPEFAIL] | 699 | # define debug optlist[17 + BASH_PIPEFAIL] |
| 524 | #endif | 700 | #endif |
| 701 | #if ENABLE_PLATFORM_MINGW32 | ||
| 702 | # define winxp optlist[16 + BASH_PIPEFAIL + 2*(DEBUG != 0)] | ||
| 703 | # if ENABLE_ASH_NOCONSOLE | ||
| 704 | # define noconsole optlist[17 + BASH_PIPEFAIL + 2*(DEBUG != 0)] | ||
| 705 | # define noiconify optlist[18 + BASH_PIPEFAIL + 2*(DEBUG != 0)] | ||
| 706 | # endif | ||
| 707 | # if ENABLE_ASH_GLOB_OPTIONS | ||
| 708 | # define nocaseglob optlist[17 + BASH_PIPEFAIL + 2*(DEBUG != 0) + 2*ENABLE_ASH_NOCONSOLE] | ||
| 709 | # define nohiddenglob optlist[18 + BASH_PIPEFAIL + 2*(DEBUG != 0) + 2*ENABLE_ASH_NOCONSOLE] | ||
| 710 | # define nohidsysglob optlist[19 + BASH_PIPEFAIL + 2*(DEBUG != 0) + 2*ENABLE_ASH_NOCONSOLE] | ||
| 711 | # endif | ||
| 712 | #endif | ||
| 525 | 713 | ||
| 526 | /* trap handler commands */ | 714 | /* trap handler commands */ |
| 715 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 527 | /* | 716 | /* |
| 528 | * Sigmode records the current value of the signal handlers for the various | 717 | * Sigmode records the current value of the signal handlers for the various |
| 529 | * modes. A value of zero means that the current handler is not known. | 718 | * modes. A value of zero means that the current handler is not known. |
| @@ -537,6 +726,7 @@ struct globals_misc { | |||
| 537 | 726 | ||
| 538 | /* indicates specified signal received */ | 727 | /* indicates specified signal received */ |
| 539 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ | 728 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ |
| 729 | #endif | ||
| 540 | uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ | 730 | uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ |
| 541 | char *trap[NSIG + 1]; | 731 | char *trap[NSIG + 1]; |
| 542 | /* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */ | 732 | /* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */ |
| @@ -567,12 +757,24 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
| 567 | #define back_exitstatus (G_misc.back_exitstatus ) | 757 | #define back_exitstatus (G_misc.back_exitstatus ) |
| 568 | #define job_warning (G_misc.job_warning) | 758 | #define job_warning (G_misc.job_warning) |
| 569 | #define inps4 (G_misc.inps4 ) | 759 | #define inps4 (G_misc.inps4 ) |
| 760 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 570 | #define vforked (G_misc.vforked ) | 761 | #define vforked (G_misc.vforked ) |
| 762 | #else | ||
| 763 | #define vforked 0 | ||
| 764 | #endif | ||
| 571 | #define savestatus (G_misc.savestatus ) | 765 | #define savestatus (G_misc.savestatus ) |
| 572 | #define rootpid (G_misc.rootpid ) | 766 | #define rootpid (G_misc.rootpid ) |
| 573 | #define shlvl (G_misc.shlvl ) | 767 | #define shlvl (G_misc.shlvl ) |
| 574 | #define errlinno (G_misc.errlinno ) | 768 | #define errlinno (G_misc.errlinno ) |
| 769 | #if ENABLE_PLATFORM_MINGW32 | ||
| 770 | #define loopnest (G_misc.loopnest ) | ||
| 771 | #endif | ||
| 575 | #define minusc (G_misc.minusc ) | 772 | #define minusc (G_misc.minusc ) |
| 773 | #if ENABLE_PLATFORM_MINGW32 | ||
| 774 | #define dirarg (G_misc.dirarg ) | ||
| 775 | #define title (G_misc.title ) | ||
| 776 | #define delayexit (G_misc.delayexit ) | ||
| 777 | #endif | ||
| 576 | #define curdir (G_misc.curdir ) | 778 | #define curdir (G_misc.curdir ) |
| 577 | #define physdir (G_misc.physdir ) | 779 | #define physdir (G_misc.physdir ) |
| 578 | #define arg0 (G_misc.arg0 ) | 780 | #define arg0 (G_misc.arg0 ) |
| @@ -580,6 +782,9 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
| 580 | #define exception_type (G_misc.exception_type ) | 782 | #define exception_type (G_misc.exception_type ) |
| 581 | #define suppress_int (G_misc.suppress_int ) | 783 | #define suppress_int (G_misc.suppress_int ) |
| 582 | #define pending_int (G_misc.pending_int ) | 784 | #define pending_int (G_misc.pending_int ) |
| 785 | #if ENABLE_PLATFORM_MINGW32 | ||
| 786 | #define waitcmd_int (G_misc.waitcmd_int ) | ||
| 787 | #endif | ||
| 583 | #define gotsigchld (G_misc.gotsigchld ) | 788 | #define gotsigchld (G_misc.gotsigchld ) |
| 584 | #define pending_sig (G_misc.pending_sig ) | 789 | #define pending_sig (G_misc.pending_sig ) |
| 585 | #define nullstr (G_misc.nullstr ) | 790 | #define nullstr (G_misc.nullstr ) |
| @@ -596,6 +801,13 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
| 596 | #define groupinfo (G_misc.groupinfo ) | 801 | #define groupinfo (G_misc.groupinfo ) |
| 597 | #define random_gen (G_misc.random_gen ) | 802 | #define random_gen (G_misc.random_gen ) |
| 598 | #define backgndpid (G_misc.backgndpid ) | 803 | #define backgndpid (G_misc.backgndpid ) |
| 804 | |||
| 805 | #if ENABLE_PLATFORM_MINGW32 | ||
| 806 | #undef got_sigchld | ||
| 807 | #undef pending_sig | ||
| 808 | #define pending_sig (0) | ||
| 809 | #endif | ||
| 810 | |||
| 599 | #define INIT_G_misc() do { \ | 811 | #define INIT_G_misc() do { \ |
| 600 | XZALLOC_CONST_PTR(&ash_ptr_to_globals_misc, sizeof(G_misc)); \ | 812 | XZALLOC_CONST_PTR(&ash_ptr_to_globals_misc, sizeof(G_misc)); \ |
| 601 | savestatus = -1; \ | 813 | savestatus = -1; \ |
| @@ -614,6 +826,9 @@ static void trace_printf(const char *fmt, ...); | |||
| 614 | static void trace_vprintf(const char *fmt, va_list va); | 826 | static void trace_vprintf(const char *fmt, va_list va); |
| 615 | # define TRACE(param) trace_printf param | 827 | # define TRACE(param) trace_printf param |
| 616 | # define TRACEV(param) trace_vprintf param | 828 | # define TRACEV(param) trace_vprintf param |
| 829 | # if ENABLE_PLATFORM_MINGW32 && defined(close) | ||
| 830 | # undef close | ||
| 831 | # endif | ||
| 617 | # define close(fd) do { \ | 832 | # define close(fd) do { \ |
| 618 | int dfd = (fd); \ | 833 | int dfd = (fd); \ |
| 619 | if (close(dfd) < 0) \ | 834 | if (close(dfd) < 0) \ |
| @@ -647,6 +862,7 @@ var_end(const char *var) | |||
| 647 | return var; | 862 | return var; |
| 648 | } | 863 | } |
| 649 | 864 | ||
| 865 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 650 | /* Our signal logic never blocks individual signals | 866 | /* Our signal logic never blocks individual signals |
| 651 | * using signal mask - only by setting SIG_IGN handler. | 867 | * using signal mask - only by setting SIG_IGN handler. |
| 652 | * Therefore just unmasking all of them instead of "restore old mask" | 868 | * Therefore just unmasking all of them instead of "restore old mask" |
| @@ -658,6 +874,7 @@ sigclearmask(void) | |||
| 658 | { | 874 | { |
| 659 | sigprocmask_allsigs(SIG_UNBLOCK); | 875 | sigprocmask_allsigs(SIG_UNBLOCK); |
| 660 | } | 876 | } |
| 877 | #endif | ||
| 661 | 878 | ||
| 662 | /* Reset handler when entering a subshell */ | 879 | /* Reset handler when entering a subshell */ |
| 663 | static void | 880 | static void |
| @@ -718,6 +935,14 @@ raise_exception(int e) | |||
| 718 | } while (0) | 935 | } while (0) |
| 719 | #endif | 936 | #endif |
| 720 | 937 | ||
| 938 | #if ENABLE_PLATFORM_MINGW32 | ||
| 939 | static void | ||
| 940 | write_ctrl_c(void) | ||
| 941 | { | ||
| 942 | console_write("^C", 2); | ||
| 943 | } | ||
| 944 | #endif | ||
| 945 | |||
| 721 | /* | 946 | /* |
| 722 | * Called when a SIGINT is received. (If the user specifies | 947 | * Called when a SIGINT is received. (If the user specifies |
| 723 | * that SIGINT is to be trapped or ignored using the trap builtin, then | 948 | * that SIGINT is to be trapped or ignored using the trap builtin, then |
| @@ -730,16 +955,28 @@ static void | |||
| 730 | raise_interrupt(void) | 955 | raise_interrupt(void) |
| 731 | { | 956 | { |
| 732 | pending_int = 0; | 957 | pending_int = 0; |
| 958 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 733 | /* Signal is not automatically unmasked after it is raised, | 959 | /* Signal is not automatically unmasked after it is raised, |
| 734 | * do it ourself - unmask all signals */ | 960 | * do it ourself - unmask all signals */ |
| 735 | sigprocmask_allsigs(SIG_UNBLOCK); | 961 | sigprocmask_allsigs(SIG_UNBLOCK); |
| 962 | #endif | ||
| 736 | /* pending_sig = 0; - now done in signal_handler() */ | 963 | /* pending_sig = 0; - now done in signal_handler() */ |
| 737 | 964 | ||
| 738 | if (!(rootshell && iflag)) { | 965 | if (!(rootshell && iflag)) { |
| 966 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 739 | /* Kill ourself with SIGINT */ | 967 | /* Kill ourself with SIGINT */ |
| 740 | signal(SIGINT, SIG_DFL); | 968 | signal(SIGINT, SIG_DFL); |
| 741 | raise(SIGINT); | 969 | raise(SIGINT); |
| 970 | #else | ||
| 971 | fflush_all(); | ||
| 972 | kill(-getpid(), SIGINT); | ||
| 973 | _exit(SIGINT << 24); | ||
| 974 | #endif | ||
| 742 | } | 975 | } |
| 976 | #if ENABLE_PLATFORM_MINGW32 | ||
| 977 | if (iflag) | ||
| 978 | write_ctrl_c(); | ||
| 979 | #endif | ||
| 743 | /* bash: ^C even on empty command line sets $? */ | 980 | /* bash: ^C even on empty command line sets $? */ |
| 744 | exitstatus = SIGINT + 128; | 981 | exitstatus = SIGINT + 128; |
| 745 | raise_exception(EXINT); | 982 | raise_exception(EXINT); |
| @@ -2094,6 +2331,18 @@ maybe_single_quote(const char *s) | |||
| 2094 | return single_quote(s); | 2331 | return single_quote(s); |
| 2095 | } | 2332 | } |
| 2096 | 2333 | ||
| 2334 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2335 | /* Copy path to a string on the stack long enough to allow a file extension | ||
| 2336 | * to be added. */ | ||
| 2337 | static char * | ||
| 2338 | stack_add_ext_space(const char *path) | ||
| 2339 | { | ||
| 2340 | char *p = growstackto(strlen(path) + 5); | ||
| 2341 | strcpy(p, path); | ||
| 2342 | return p; | ||
| 2343 | } | ||
| 2344 | #endif | ||
| 2345 | |||
| 2097 | 2346 | ||
| 2098 | /* ============ nextopt */ | 2347 | /* ============ nextopt */ |
| 2099 | 2348 | ||
| @@ -2216,6 +2465,9 @@ struct localvar { | |||
| 2216 | #else | 2465 | #else |
| 2217 | # define VDYNAMIC 0 | 2466 | # define VDYNAMIC 0 |
| 2218 | #endif | 2467 | #endif |
| 2468 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2469 | # define VIMPORT 0x400 /* variable was imported from environment */ | ||
| 2470 | #endif | ||
| 2219 | 2471 | ||
| 2220 | /* Need to be before varinit_data[] */ | 2472 | /* Need to be before varinit_data[] */ |
| 2221 | #if ENABLE_LOCALE_SUPPORT | 2473 | #if ENABLE_LOCALE_SUPPORT |
| @@ -2244,6 +2496,24 @@ static void change_seconds(const char *) FAST_FUNC; | |||
| 2244 | static void change_realtime(const char *) FAST_FUNC; | 2496 | static void change_realtime(const char *) FAST_FUNC; |
| 2245 | #endif | 2497 | #endif |
| 2246 | 2498 | ||
| 2499 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2500 | static void FAST_FUNC | ||
| 2501 | change_terminal_mode(const char *newval UNUSED_PARAM) | ||
| 2502 | { | ||
| 2503 | terminal_mode(TRUE); | ||
| 2504 | } | ||
| 2505 | |||
| 2506 | static void clearcmdentry(void); | ||
| 2507 | static void FAST_FUNC | ||
| 2508 | change_override_applets(const char *newval UNUSED_PARAM) | ||
| 2509 | { | ||
| 2510 | clearcmdentry(); | ||
| 2511 | } | ||
| 2512 | |||
| 2513 | # define LINENO_INDEX (5 + 2 * ENABLE_ASH_MAIL + ENABLE_ASH_GETOPTS) | ||
| 2514 | # define FUNCNAME_INDEX (LINENO_INDEX + 1) | ||
| 2515 | #endif | ||
| 2516 | |||
| 2247 | static const struct { | 2517 | static const struct { |
| 2248 | int flags; | 2518 | int flags; |
| 2249 | const char *var_text; | 2519 | const char *var_text; |
| @@ -2281,6 +2551,12 @@ static const struct { | |||
| 2281 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 2551 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY |
| 2282 | { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL }, | 2552 | { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL }, |
| 2283 | #endif | 2553 | #endif |
| 2554 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2555 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_SKIP_ANSI_EMULATION, change_terminal_mode }, | ||
| 2556 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_TERMINAL_MODE, change_terminal_mode }, | ||
| 2557 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_OVERRIDE_APPLETS, change_override_applets }, | ||
| 2558 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_CRITICAL_ERROR_DIALOGS, change_critical_error_dialogs }, | ||
| 2559 | #endif | ||
| 2284 | }; | 2560 | }; |
| 2285 | 2561 | ||
| 2286 | struct redirtab; | 2562 | struct redirtab; |
| @@ -2504,6 +2780,65 @@ bltinlookup(const char *name) | |||
| 2504 | return lookupvar(name); | 2780 | return lookupvar(name); |
| 2505 | } | 2781 | } |
| 2506 | 2782 | ||
| 2783 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2784 | static char * | ||
| 2785 | fix_pathvar(const char *path, int len) | ||
| 2786 | { | ||
| 2787 | char *newpath = xstrdup(path); | ||
| 2788 | char *p; | ||
| 2789 | int modified = FALSE; | ||
| 2790 | |||
| 2791 | p = newpath + len; | ||
| 2792 | while (*p) { | ||
| 2793 | if (*p != ':' && *p != ';') { | ||
| 2794 | /* skip drive */ | ||
| 2795 | if (isalpha(*p) && p[1] == ':') | ||
| 2796 | p += 2; | ||
| 2797 | /* skip through path component */ | ||
| 2798 | for (; *p != '\0' && *p != ':' && *p != ';'; ++p) | ||
| 2799 | continue; | ||
| 2800 | } | ||
| 2801 | /* *p is ':', ';' or '\0' here */ | ||
| 2802 | if (*p == ':') { | ||
| 2803 | *p++ = ';'; | ||
| 2804 | modified = TRUE; | ||
| 2805 | } | ||
| 2806 | else if (*p == ';') { | ||
| 2807 | ++p; | ||
| 2808 | } | ||
| 2809 | } | ||
| 2810 | |||
| 2811 | if (!modified) { | ||
| 2812 | free(newpath); | ||
| 2813 | newpath = NULL; | ||
| 2814 | } | ||
| 2815 | return newpath; | ||
| 2816 | } | ||
| 2817 | |||
| 2818 | #define BB_VAR_EXACT 1 /* exact match for name */ | ||
| 2819 | #define BB_VAR_ASSIGN -1 /* matches name followed by '=' */ | ||
| 2820 | |||
| 2821 | /* Match variables that should be placed in the environment immediately | ||
| 2822 | * they're exported and removed immediately they're no longer exported */ | ||
| 2823 | static int | ||
| 2824 | is_bb_var(const char *s) | ||
| 2825 | { | ||
| 2826 | const char *p; | ||
| 2827 | int len; | ||
| 2828 | |||
| 2829 | for (p = bbvar; *p; p += len + 1) { | ||
| 2830 | len = strlen(p); | ||
| 2831 | if (strncmp(s, p, len) == 0) { | ||
| 2832 | if (s[len] == '\0') | ||
| 2833 | return BB_VAR_EXACT; | ||
| 2834 | else if (s[len] == '=') | ||
| 2835 | return BB_VAR_ASSIGN; | ||
| 2836 | } | ||
| 2837 | } | ||
| 2838 | return FALSE; | ||
| 2839 | } | ||
| 2840 | #endif | ||
| 2841 | |||
| 2507 | /* | 2842 | /* |
| 2508 | * Same as setvar except that the variable and value are passed in | 2843 | * Same as setvar except that the variable and value are passed in |
| 2509 | * the first argument as name=value. Since the first argument will | 2844 | * the first argument as name=value. Since the first argument will |
| @@ -2515,6 +2850,26 @@ static struct var * | |||
| 2515 | setvareq(char *s, int flags) | 2850 | setvareq(char *s, int flags) |
| 2516 | { | 2851 | { |
| 2517 | struct var *vp, **vpp; | 2852 | struct var *vp, **vpp; |
| 2853 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2854 | const char *paths = "PATH=\0""CDPATH=\0""MANPATH=\0"; | ||
| 2855 | const char *p; | ||
| 2856 | int len; | ||
| 2857 | |||
| 2858 | for (p = paths; *p; p += len + 1) { | ||
| 2859 | len = strlen(p); | ||
| 2860 | if (strncmp(s, p, len) == 0) { | ||
| 2861 | char *newpath = fix_pathvar(s, len); | ||
| 2862 | if (newpath) { | ||
| 2863 | if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE) | ||
| 2864 | free(s); | ||
| 2865 | flags |= VNOSAVE; | ||
| 2866 | flags &= ~(VTEXTFIXED|VSTACK); | ||
| 2867 | s = newpath; | ||
| 2868 | } | ||
| 2869 | break; | ||
| 2870 | } | ||
| 2871 | } | ||
| 2872 | #endif | ||
| 2518 | 2873 | ||
| 2519 | flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); | 2874 | flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); |
| 2520 | vpp = findvar(s); | 2875 | vpp = findvar(s); |
| @@ -2539,6 +2894,11 @@ setvareq(char *s, int flags) | |||
| 2539 | if (!(vp->flags & (VTEXTFIXED|VSTACK))) | 2894 | if (!(vp->flags & (VTEXTFIXED|VSTACK))) |
| 2540 | free((char*)vp->var_text); | 2895 | free((char*)vp->var_text); |
| 2541 | 2896 | ||
| 2897 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2898 | if ((flags & VUNSET) && (vp->flags & VEXPORT) && | ||
| 2899 | is_bb_var(s) == BB_VAR_EXACT) | ||
| 2900 | unsetenv(s); | ||
| 2901 | #endif | ||
| 2542 | if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) { | 2902 | if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) { |
| 2543 | *vpp = vp->next; | 2903 | *vpp = vp->next; |
| 2544 | free(vp); | 2904 | free(vp); |
| @@ -2568,6 +2928,10 @@ setvareq(char *s, int flags) | |||
| 2568 | s = ckstrdup(s); | 2928 | s = ckstrdup(s); |
| 2569 | vp->var_text = s; | 2929 | vp->var_text = s; |
| 2570 | vp->flags = flags; | 2930 | vp->flags = flags; |
| 2931 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2932 | if ((flags & VEXPORT) && is_bb_var(s) == BB_VAR_ASSIGN) | ||
| 2933 | putenv(s); | ||
| 2934 | #endif | ||
| 2571 | 2935 | ||
| 2572 | out: | 2936 | out: |
| 2573 | return vp; | 2937 | return vp; |
| @@ -2689,6 +3053,65 @@ listvars(int on, int off, struct strlist *lp, char ***end) | |||
| 2689 | return grabstackstr(ep); | 3053 | return grabstackstr(ep); |
| 2690 | } | 3054 | } |
| 2691 | 3055 | ||
| 3056 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3057 | /* Adjust directory separator in variables imported from the environment */ | ||
| 3058 | static void | ||
| 3059 | setwinxp(int on) | ||
| 3060 | { | ||
| 3061 | static smallint is_winxp = 1; | ||
| 3062 | struct var **vpp; | ||
| 3063 | struct var *vp; | ||
| 3064 | |||
| 3065 | if (on == is_winxp) | ||
| 3066 | return; | ||
| 3067 | is_winxp = on; | ||
| 3068 | |||
| 3069 | for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) { | ||
| 3070 | for (vp = *vpp; vp; vp = vp->next) { | ||
| 3071 | if ((vp->flags & VIMPORT)) { | ||
| 3072 | char *end = strchr(vp->var_text, '='); | ||
| 3073 | if (!end || is_prefixed_with(vp->var_text, "COMSPEC=") || | ||
| 3074 | is_prefixed_with(vp->var_text, "SYSTEMROOT=")) | ||
| 3075 | continue; | ||
| 3076 | if (!on) | ||
| 3077 | bs_to_slash(end + 1); | ||
| 3078 | else | ||
| 3079 | slash_to_bs(end + 1); | ||
| 3080 | } | ||
| 3081 | } | ||
| 3082 | } | ||
| 3083 | } | ||
| 3084 | |||
| 3085 | # if ENABLE_ASH_NOCONSOLE | ||
| 3086 | /* | ||
| 3087 | * Console state is either: | ||
| 3088 | * 0 normal | ||
| 3089 | * 1 iconified/hidden | ||
| 3090 | * 2 unknown | ||
| 3091 | */ | ||
| 3092 | static int console_state(void) | ||
| 3093 | { | ||
| 3094 | DECLARE_PROC_ADDR(BOOL, ShowWindow, HWND, int); | ||
| 3095 | |||
| 3096 | if (INIT_PROC_ADDR(user32.dll, ShowWindow)) { | ||
| 3097 | BOOL visible = IsWindowVisible(GetConsoleWindow()); | ||
| 3098 | BOOL iconified = IsIconic(GetConsoleWindow()); | ||
| 3099 | |||
| 3100 | return !visible || iconified; | ||
| 3101 | } | ||
| 3102 | return 2; | ||
| 3103 | } | ||
| 3104 | |||
| 3105 | static void hide_console(int hide) | ||
| 3106 | { | ||
| 3107 | // Switch console state if it's known and isn't the required state | ||
| 3108 | if (console_state() == !hide) | ||
| 3109 | ShowWindow(GetConsoleWindow(), hide ? | ||
| 3110 | (noiconify ? SW_HIDE : SW_MINIMIZE) : SW_NORMAL); | ||
| 3111 | } | ||
| 3112 | # endif | ||
| 3113 | #endif | ||
| 3114 | |||
| 2692 | 3115 | ||
| 2693 | /* ============ Path search helper */ | 3116 | /* ============ Path search helper */ |
| 2694 | static const char * | 3117 | static const char * |
| @@ -2732,7 +3155,7 @@ static const char *pathopt; /* set by padvance */ | |||
| 2732 | static int | 3155 | static int |
| 2733 | padvance_magic(const char **path, const char *name, int magic) | 3156 | padvance_magic(const char **path, const char *name, int magic) |
| 2734 | { | 3157 | { |
| 2735 | const char *term = "%:"; | 3158 | const char *term = "%"PATH_SEP_STR; |
| 2736 | const char *lpathopt; | 3159 | const char *lpathopt; |
| 2737 | const char *p; | 3160 | const char *p; |
| 2738 | char *q; | 3161 | char *q; |
| @@ -2749,14 +3172,14 @@ padvance_magic(const char **path, const char *name, int magic) | |||
| 2749 | if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) { | 3172 | if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) { |
| 2750 | lpathopt = start + 1; | 3173 | lpathopt = start + 1; |
| 2751 | start = p; | 3174 | start = p; |
| 2752 | term = ":"; | 3175 | term = PATH_SEP_STR; |
| 2753 | } | 3176 | } |
| 2754 | 3177 | ||
| 2755 | len = strcspn(start, term); | 3178 | len = strcspn(start, term); |
| 2756 | p = start + len; | 3179 | p = start + len; |
| 2757 | 3180 | ||
| 2758 | if (*p == '%') { | 3181 | if (*p == '%') { |
| 2759 | size_t extra = strchrnul(p, ':') - p; | 3182 | size_t extra = strchrnul(p, PATH_SEP) - p; |
| 2760 | 3183 | ||
| 2761 | if (legal_pathopt(p + 1, term, magic)) | 3184 | if (legal_pathopt(p + 1, term, magic)) |
| 2762 | lpathopt = p + 1; | 3185 | lpathopt = p + 1; |
| @@ -2767,14 +3190,18 @@ padvance_magic(const char **path, const char *name, int magic) | |||
| 2767 | } | 3190 | } |
| 2768 | 3191 | ||
| 2769 | pathopt = lpathopt; | 3192 | pathopt = lpathopt; |
| 2770 | *path = *p == ':' ? p + 1 : NULL; | 3193 | *path = *p == PATH_SEP ? p + 1 : NULL; |
| 2771 | 3194 | ||
| 2772 | /* "2" is for '/' and '\0' */ | 3195 | /* "2" is for '/' and '\0' */ |
| 2773 | qlen = len + strlen(name) + 2; | 3196 | /* reserve space for suffix on WIN32 */ |
| 3197 | qlen = len + strlen(name) + 2 IF_PLATFORM_MINGW32(+ 4); | ||
| 2774 | q = growstackto(qlen); | 3198 | q = growstackto(qlen); |
| 2775 | 3199 | ||
| 2776 | if (len) { | 3200 | if (len) { |
| 2777 | q = mempcpy(q, start, len); | 3201 | q = mempcpy(q, start, len); |
| 3202 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3203 | if (q[-1] != '/' && q[-1] != '\\') | ||
| 3204 | #endif | ||
| 2778 | *q++ = '/'; | 3205 | *q++ = '/'; |
| 2779 | } | 3206 | } |
| 2780 | strcpy(q, name); | 3207 | strcpy(q, name); |
| @@ -2865,6 +3292,7 @@ setprompt_if(smallint do_set, int whichprompt) | |||
| 2865 | 3292 | ||
| 2866 | #define CD_PHYSICAL 1 | 3293 | #define CD_PHYSICAL 1 |
| 2867 | #define CD_PRINT 2 | 3294 | #define CD_PRINT 2 |
| 3295 | #define CD_PRINT_ALL 4 | ||
| 2868 | 3296 | ||
| 2869 | static int | 3297 | static int |
| 2870 | cdopt(void) | 3298 | cdopt(void) |
| @@ -2873,7 +3301,14 @@ cdopt(void) | |||
| 2873 | int i, j; | 3301 | int i, j; |
| 2874 | 3302 | ||
| 2875 | j = 'L'; | 3303 | j = 'L'; |
| 3304 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3305 | while ((i = nextopt("LPa")) != '\0') { | ||
| 3306 | if (i == 'a') | ||
| 3307 | flags |= CD_PRINT_ALL; | ||
| 3308 | else | ||
| 3309 | #else | ||
| 2876 | while ((i = nextopt("LP")) != '\0') { | 3310 | while ((i = nextopt("LP")) != '\0') { |
| 3311 | #endif | ||
| 2877 | if (i != j) { | 3312 | if (i != j) { |
| 2878 | flags ^= CD_PHYSICAL; | 3313 | flags ^= CD_PHYSICAL; |
| 2879 | j = i; | 3314 | j = i; |
| @@ -2890,6 +3325,130 @@ cdopt(void) | |||
| 2890 | static const char * | 3325 | static const char * |
| 2891 | updatepwd(const char *dir) | 3326 | updatepwd(const char *dir) |
| 2892 | { | 3327 | { |
| 3328 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3329 | /* | ||
| 3330 | * Due to Windows drive notion, getting pwd is a completely | ||
| 3331 | * different thing. Handle it in a separate routine | ||
| 3332 | */ | ||
| 3333 | |||
| 3334 | char *new; | ||
| 3335 | char *p; | ||
| 3336 | char *cdcomppath; | ||
| 3337 | const char *lim; | ||
| 3338 | int len; | ||
| 3339 | char buffer[PATH_MAX]; | ||
| 3340 | /* | ||
| 3341 | * There are five cases that make some kind of sense | ||
| 3342 | * | ||
| 3343 | * Absolute paths: | ||
| 3344 | * c:/path | ||
| 3345 | * //host/share | ||
| 3346 | * | ||
| 3347 | * Relative to current working directory of other drive: | ||
| 3348 | * c:path | ||
| 3349 | * | ||
| 3350 | * Relative to current root (drive/share): | ||
| 3351 | * /path | ||
| 3352 | * | ||
| 3353 | * Relative to current working directory of current root (drive/share): | ||
| 3354 | * path | ||
| 3355 | */ | ||
| 3356 | enum {ABS_DRIVE, ABS_SHARE, REL_OTHER, REL_ROOT, REL_CWD} target; | ||
| 3357 | |||
| 3358 | /* skip multiple leading separators unless dir is a UNC path */ | ||
| 3359 | if (is_dir_sep(*dir) && unc_root_len(dir) == 0) { | ||
| 3360 | while (is_dir_sep(dir[1])) | ||
| 3361 | ++dir; | ||
| 3362 | } | ||
| 3363 | |||
| 3364 | len = strlen(dir); | ||
| 3365 | if (len >= 2 && has_dos_drive_prefix(dir)) | ||
| 3366 | target = len >= 3 && is_dir_sep(dir[2]) ? ABS_DRIVE : REL_OTHER; | ||
| 3367 | else if (unc_root_len(dir) != 0) | ||
| 3368 | target = ABS_SHARE; | ||
| 3369 | else if (is_dir_sep(*dir)) | ||
| 3370 | target = REL_ROOT; | ||
| 3371 | else | ||
| 3372 | target = REL_CWD; | ||
| 3373 | |||
| 3374 | cdcomppath = sstrdup(dir); | ||
| 3375 | STARTSTACKSTR(new); | ||
| 3376 | |||
| 3377 | switch (target) { | ||
| 3378 | case REL_OTHER: | ||
| 3379 | /* c:path */ | ||
| 3380 | if (get_drive_cwd(dir, buffer, PATH_MAX) == NULL) | ||
| 3381 | return 0; | ||
| 3382 | new = stack_putstr(buffer, new); | ||
| 3383 | len = 2; | ||
| 3384 | cdcomppath += len; | ||
| 3385 | dir += len; | ||
| 3386 | break; | ||
| 3387 | case REL_CWD: | ||
| 3388 | case REL_ROOT: | ||
| 3389 | /* path or /path */ | ||
| 3390 | len = root_len(curdir); | ||
| 3391 | if (len == 0) | ||
| 3392 | return 0; | ||
| 3393 | new = target == REL_CWD ? stack_putstr(curdir, new) : | ||
| 3394 | stnputs(curdir, len, new); | ||
| 3395 | break; | ||
| 3396 | default: | ||
| 3397 | /* //host/share or c:/path */ | ||
| 3398 | len = root_len(dir); | ||
| 3399 | if (len == 0) | ||
| 3400 | return 0; | ||
| 3401 | new = stnputs(dir, len, new); | ||
| 3402 | cdcomppath += len; | ||
| 3403 | dir += len; | ||
| 3404 | break; | ||
| 3405 | } | ||
| 3406 | |||
| 3407 | new = makestrspace(strlen(dir) + 2, new); | ||
| 3408 | lim = (char *)stackblock() + len + 1; | ||
| 3409 | |||
| 3410 | if (!is_dir_sep(*dir)) { | ||
| 3411 | if (!is_dir_sep(new[-1])) | ||
| 3412 | USTPUTC('/', new); | ||
| 3413 | if (new > lim && is_dir_sep(*lim)) | ||
| 3414 | lim++; | ||
| 3415 | } else { | ||
| 3416 | USTPUTC('/', new); | ||
| 3417 | cdcomppath++; | ||
| 3418 | if (is_dir_sep(dir[1]) && !is_dir_sep(dir[2])) { | ||
| 3419 | USTPUTC('/', new); | ||
| 3420 | cdcomppath++; | ||
| 3421 | lim++; | ||
| 3422 | } | ||
| 3423 | } | ||
| 3424 | p = strtok(cdcomppath, "/\\"); | ||
| 3425 | while (p) { | ||
| 3426 | switch (*p) { | ||
| 3427 | case '.': | ||
| 3428 | if (p[1] == '.' && p[2] == '\0') { | ||
| 3429 | while (new > lim) { | ||
| 3430 | STUNPUTC(new); | ||
| 3431 | if (is_dir_sep(new[-1])) | ||
| 3432 | break; | ||
| 3433 | } | ||
| 3434 | break; | ||
| 3435 | } | ||
| 3436 | if (p[1] == '\0') | ||
| 3437 | break; | ||
| 3438 | /* fall through */ | ||
| 3439 | default: | ||
| 3440 | new = stack_putstr(p, new); | ||
| 3441 | USTPUTC('/', new); | ||
| 3442 | } | ||
| 3443 | p = strtok(NULL, "/\\"); | ||
| 3444 | } | ||
| 3445 | if (new > lim) | ||
| 3446 | STUNPUTC(new); | ||
| 3447 | *new = 0; | ||
| 3448 | strip_dot_space((char *)stackblock()); | ||
| 3449 | fix_path_case((char *)stackblock()); | ||
| 3450 | return bs_to_slash((char *)stackblock()); | ||
| 3451 | #else | ||
| 2893 | char *new; | 3452 | char *new; |
| 2894 | char *p; | 3453 | char *p; |
| 2895 | char *cdcomppath; | 3454 | char *cdcomppath; |
| @@ -2943,6 +3502,7 @@ updatepwd(const char *dir) | |||
| 2943 | STUNPUTC(new); | 3502 | STUNPUTC(new); |
| 2944 | *new = 0; | 3503 | *new = 0; |
| 2945 | return stackblock(); | 3504 | return stackblock(); |
| 3505 | #endif | ||
| 2946 | } | 3506 | } |
| 2947 | 3507 | ||
| 2948 | /* | 3508 | /* |
| @@ -3038,7 +3598,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 3038 | } | 3598 | } |
| 3039 | if (!dest) | 3599 | if (!dest) |
| 3040 | dest = nullstr; | 3600 | dest = nullstr; |
| 3041 | if (*dest == '/') | 3601 | if (!is_relative_path(dest)) |
| 3042 | goto step6; | 3602 | goto step6; |
| 3043 | if (*dest == '.') { | 3603 | if (*dest == '.') { |
| 3044 | c = dest[1]; | 3604 | c = dest[1]; |
| @@ -3061,7 +3621,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 3061 | p = stalloc(len); | 3621 | p = stalloc(len); |
| 3062 | 3622 | ||
| 3063 | if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { | 3623 | if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { |
| 3064 | if (c && c != ':') | 3624 | if (c && c != PATH_SEP) |
| 3065 | flags |= CD_PRINT; | 3625 | flags |= CD_PRINT; |
| 3066 | docd: | 3626 | docd: |
| 3067 | if (!docd(p, flags)) | 3627 | if (!docd(p, flags)) |
| @@ -3083,6 +3643,26 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 3083 | return 0; | 3643 | return 0; |
| 3084 | } | 3644 | } |
| 3085 | 3645 | ||
| 3646 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3647 | static void | ||
| 3648 | print_all_cwd(void) | ||
| 3649 | { | ||
| 3650 | FILE *mnt; | ||
| 3651 | struct mntent *entry; | ||
| 3652 | char buffer[PATH_MAX]; | ||
| 3653 | |||
| 3654 | mnt = setmntent(bb_path_mtab_file, "r"); | ||
| 3655 | if (mnt) { | ||
| 3656 | while ((entry=getmntent(mnt)) != NULL) { | ||
| 3657 | entry->mnt_dir[2] = '\0'; | ||
| 3658 | if (get_drive_cwd(entry->mnt_dir, buffer, PATH_MAX) != NULL) | ||
| 3659 | out1fmt("%s\n", buffer); | ||
| 3660 | } | ||
| 3661 | endmntent(mnt); | ||
| 3662 | } | ||
| 3663 | } | ||
| 3664 | #endif | ||
| 3665 | |||
| 3086 | static int FAST_FUNC | 3666 | static int FAST_FUNC |
| 3087 | pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 3667 | pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) |
| 3088 | { | 3668 | { |
| @@ -3090,6 +3670,12 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 3090 | const char *dir = curdir; | 3670 | const char *dir = curdir; |
| 3091 | 3671 | ||
| 3092 | flags = cdopt(); | 3672 | flags = cdopt(); |
| 3673 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3674 | if (flags & CD_PRINT_ALL) { | ||
| 3675 | print_all_cwd(); | ||
| 3676 | return 0; | ||
| 3677 | } | ||
| 3678 | #endif | ||
| 3093 | if (flags) { | 3679 | if (flags) { |
| 3094 | if (physdir == nullstr) | 3680 | if (physdir == nullstr) |
| 3095 | setpwd(dir, 0); | 3681 | setpwd(dir, 0); |
| @@ -3714,7 +4300,12 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 3714 | struct procstat { | 4300 | struct procstat { |
| 3715 | pid_t ps_pid; /* process id */ | 4301 | pid_t ps_pid; /* process id */ |
| 3716 | int ps_status; /* last process status from wait() */ | 4302 | int ps_status; /* last process status from wait() */ |
| 4303 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 3717 | char *ps_cmd; /* text of command being run */ | 4304 | char *ps_cmd; /* text of command being run */ |
| 4305 | #endif | ||
| 4306 | #if ENABLE_PLATFORM_MINGW32 | ||
| 4307 | HANDLE ps_proc; | ||
| 4308 | #endif | ||
| 3718 | }; | 4309 | }; |
| 3719 | 4310 | ||
| 3720 | struct job { | 4311 | struct job { |
| @@ -3730,8 +4321,10 @@ struct job { | |||
| 3730 | #define JOBDONE 2 /* all procs are completed */ | 4321 | #define JOBDONE 2 /* all procs are completed */ |
| 3731 | unsigned | 4322 | unsigned |
| 3732 | state: 8, | 4323 | state: 8, |
| 3733 | #if JOBS | 4324 | #if JOBS || ENABLE_PLATFORM_MINGW32 |
| 3734 | sigint: 1, /* job was killed by SIGINT */ | 4325 | sigint: 1, /* job was killed by SIGINT */ |
| 4326 | #endif | ||
| 4327 | #if JOBS | ||
| 3735 | jobctl: 1, /* job running under job control */ | 4328 | jobctl: 1, /* job running under job control */ |
| 3736 | #endif | 4329 | #endif |
| 3737 | waited: 1, /* true if this entry has been waited for */ | 4330 | waited: 1, /* true if this entry has been waited for */ |
| @@ -3740,17 +4333,23 @@ struct job { | |||
| 3740 | struct job *prev_job; /* previous job */ | 4333 | struct job *prev_job; /* previous job */ |
| 3741 | }; | 4334 | }; |
| 3742 | 4335 | ||
| 4336 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 3743 | static int forkshell(struct job *, union node *, int); | 4337 | static int forkshell(struct job *, union node *, int); |
| 4338 | #endif | ||
| 3744 | static int waitforjob(struct job *); | 4339 | static int waitforjob(struct job *); |
| 3745 | 4340 | ||
| 3746 | #if !JOBS | 4341 | #if !JOBS && !JOBS_WIN32 |
| 3747 | enum { jobctl = 0 }; | 4342 | enum { jobctl = 0 }; |
| 3748 | #define setjobctl(on) do {} while (0) | 4343 | #define setjobctl(on) do {} while (0) |
| 3749 | #else | 4344 | #elif JOBS_WIN32 |
| 4345 | static smallint jobctl; //references:8 | ||
| 4346 | #define setjobctl(on) do { if (rootshell) jobctl = on; } while (0) | ||
| 4347 | #else /* JOBS */ | ||
| 3750 | static smallint jobctl; //references:8 | 4348 | static smallint jobctl; //references:8 |
| 3751 | static void setjobctl(int); | 4349 | static void setjobctl(int); |
| 3752 | #endif | 4350 | #endif |
| 3753 | 4351 | ||
| 4352 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 3754 | /* | 4353 | /* |
| 3755 | * Ignore a signal. | 4354 | * Ignore a signal. |
| 3756 | */ | 4355 | */ |
| @@ -3910,6 +4509,10 @@ setsignal(int signo) | |||
| 3910 | 4509 | ||
| 3911 | sigaction_set(signo, &act); | 4510 | sigaction_set(signo, &act); |
| 3912 | } | 4511 | } |
| 4512 | #else | ||
| 4513 | #define setsignal(s) | ||
| 4514 | #define ignoresig(s) | ||
| 4515 | #endif | ||
| 3913 | 4516 | ||
| 3914 | /* mode flags for set_curjob */ | 4517 | /* mode flags for set_curjob */ |
| 3915 | #define CUR_DELETE 2 | 4518 | #define CUR_DELETE 2 |
| @@ -4043,7 +4646,7 @@ set_curjob(struct job *jp, unsigned mode) | |||
| 4043 | } | 4646 | } |
| 4044 | } | 4647 | } |
| 4045 | 4648 | ||
| 4046 | #if JOBS || DEBUG | 4649 | #if JOBS || ENABLE_PLATFORM_MINGW32 || DEBUG |
| 4047 | static int | 4650 | static int |
| 4048 | jobno(const struct job *jp) | 4651 | jobno(const struct job *jp) |
| 4049 | { | 4652 | { |
| @@ -4061,7 +4664,9 @@ static struct job * | |||
| 4061 | getjob(const char *name, int getctl) | 4664 | getjob(const char *name, int getctl) |
| 4062 | { | 4665 | { |
| 4063 | struct job *jp; | 4666 | struct job *jp; |
| 4667 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 4064 | struct job *found; | 4668 | struct job *found; |
| 4669 | #endif | ||
| 4065 | const char *err_msg = "%s: no such job"; | 4670 | const char *err_msg = "%s: no such job"; |
| 4066 | unsigned num; | 4671 | unsigned num; |
| 4067 | int c; | 4672 | int c; |
| @@ -4106,6 +4711,7 @@ getjob(const char *name, int getctl) | |||
| 4106 | } | 4711 | } |
| 4107 | } | 4712 | } |
| 4108 | 4713 | ||
| 4714 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 4109 | found = NULL; | 4715 | found = NULL; |
| 4110 | while (jp) { | 4716 | while (jp) { |
| 4111 | if (*p == '?' | 4717 | if (*p == '?' |
| @@ -4122,6 +4728,9 @@ getjob(const char *name, int getctl) | |||
| 4122 | if (!found) | 4728 | if (!found) |
| 4123 | goto err; | 4729 | goto err; |
| 4124 | jp = found; | 4730 | jp = found; |
| 4731 | #else | ||
| 4732 | goto err; | ||
| 4733 | #endif | ||
| 4125 | 4734 | ||
| 4126 | gotit: | 4735 | gotit: |
| 4127 | #if JOBS | 4736 | #if JOBS |
| @@ -4140,14 +4749,18 @@ getjob(const char *name, int getctl) | |||
| 4140 | static void | 4749 | static void |
| 4141 | freejob(struct job *jp) | 4750 | freejob(struct job *jp) |
| 4142 | { | 4751 | { |
| 4752 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 4143 | struct procstat *ps; | 4753 | struct procstat *ps; |
| 4144 | int i; | 4754 | int i; |
| 4755 | #endif | ||
| 4145 | 4756 | ||
| 4146 | INTOFF; | 4757 | INTOFF; |
| 4758 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 4147 | for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { | 4759 | for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { |
| 4148 | if (ps->ps_cmd != nullstr) | 4760 | if (ps->ps_cmd != nullstr) |
| 4149 | free(ps->ps_cmd); | 4761 | free(ps->ps_cmd); |
| 4150 | } | 4762 | } |
| 4763 | #endif | ||
| 4151 | if (jp->ps != &jp->ps0) | 4764 | if (jp->ps != &jp->ps0) |
| 4152 | free(jp->ps); | 4765 | free(jp->ps); |
| 4153 | jp->used = 0; | 4766 | jp->used = 0; |
| @@ -4255,7 +4868,9 @@ setjobctl(int on) | |||
| 4255 | ttyfd = fd; | 4868 | ttyfd = fd; |
| 4256 | jobctl = on; | 4869 | jobctl = on; |
| 4257 | } | 4870 | } |
| 4871 | #endif | ||
| 4258 | 4872 | ||
| 4873 | #if JOBS || JOBS_WIN32 | ||
| 4259 | static int FAST_FUNC | 4874 | static int FAST_FUNC |
| 4260 | killcmd(int argc, char **argv) | 4875 | killcmd(int argc, char **argv) |
| 4261 | { | 4876 | { |
| @@ -4285,8 +4900,10 @@ killcmd(int argc, char **argv) | |||
| 4285 | * sh -c 'true|sleep 1 & sleep 2; kill %1' | 4900 | * sh -c 'true|sleep 1 & sleep 2; kill %1' |
| 4286 | */ | 4901 | */ |
| 4287 | n = jp->nprocs; /* can't be 0 (I hope) */ | 4902 | n = jp->nprocs; /* can't be 0 (I hope) */ |
| 4903 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 4288 | if (jp->jobctl) | 4904 | if (jp->jobctl) |
| 4289 | n = 1; | 4905 | n = 1; |
| 4906 | #endif | ||
| 4290 | dst = alloca(n * sizeof(int)*4); | 4907 | dst = alloca(n * sizeof(int)*4); |
| 4291 | argv[i] = dst; | 4908 | argv[i] = dst; |
| 4292 | for (j = 0; j < n; j++) { | 4909 | for (j = 0; j < n; j++) { |
| @@ -4301,7 +4918,11 @@ killcmd(int argc, char **argv) | |||
| 4301 | * leading space. Needed to not confuse | 4918 | * leading space. Needed to not confuse |
| 4302 | * negative pids with "kill -SIGNAL_NO" syntax | 4919 | * negative pids with "kill -SIGNAL_NO" syntax |
| 4303 | */ | 4920 | */ |
| 4921 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 4304 | dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); | 4922 | dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); |
| 4923 | #else | ||
| 4924 | dst += sprintf(dst, " -%u", (int)ps->ps_pid); | ||
| 4925 | #endif | ||
| 4305 | } | 4926 | } |
| 4306 | *dst = '\0'; | 4927 | *dst = '\0'; |
| 4307 | } | 4928 | } |
| @@ -4309,7 +4930,9 @@ killcmd(int argc, char **argv) | |||
| 4309 | } | 4930 | } |
| 4310 | return kill_main(argc, argv); | 4931 | return kill_main(argc, argv); |
| 4311 | } | 4932 | } |
| 4933 | #endif | ||
| 4312 | 4934 | ||
| 4935 | #if JOBS | ||
| 4313 | static void | 4936 | static void |
| 4314 | showpipe(struct job *jp /*, FILE *out*/) | 4937 | showpipe(struct job *jp /*, FILE *out*/) |
| 4315 | { | 4938 | { |
| @@ -4414,6 +5037,69 @@ sprint_status48(char *os, int status, int sigonly) | |||
| 4414 | return s - os; | 5037 | return s - os; |
| 4415 | } | 5038 | } |
| 4416 | 5039 | ||
| 5040 | #if ENABLE_PLATFORM_MINGW32 | ||
| 5041 | static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) | ||
| 5042 | { | ||
| 5043 | if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { | ||
| 5044 | # if ENABLE_FEATURE_EDITING | ||
| 5045 | bb_got_signal = SIGINT; /* for read_line_input: "we got a signal" */ | ||
| 5046 | # endif | ||
| 5047 | waitcmd_int = -waitcmd_int; | ||
| 5048 | if (!trap[SIGINT]) { | ||
| 5049 | if (!suppress_int && !(rootshell && iflag)) | ||
| 5050 | raise_interrupt(); | ||
| 5051 | pending_int = 1; | ||
| 5052 | } | ||
| 5053 | return TRUE; | ||
| 5054 | } | ||
| 5055 | return FALSE; | ||
| 5056 | } | ||
| 5057 | |||
| 5058 | /* | ||
| 5059 | * Windows does not know about parent-child relationship | ||
| 5060 | * They don't support waitpid(-1) | ||
| 5061 | */ | ||
| 5062 | static pid_t | ||
| 5063 | waitpid_child(int *status, DWORD blocking) | ||
| 5064 | { | ||
| 5065 | struct job *jb; | ||
| 5066 | int pid_nr = 0; | ||
| 5067 | static HANDLE *proclist = NULL; | ||
| 5068 | static int pid_max = 0; | ||
| 5069 | pid_t pid = -1; | ||
| 5070 | DWORD win_status, idx; | ||
| 5071 | int i; | ||
| 5072 | |||
| 5073 | for (jb = curjob; jb; jb = jb->prev_job) { | ||
| 5074 | if (jb->state != JOBDONE) { | ||
| 5075 | if (pid_nr + jb->nprocs > pid_max) { | ||
| 5076 | pid_max = pid_nr + jb->nprocs; | ||
| 5077 | proclist = ckrealloc(proclist, sizeof(*proclist) * pid_max); | ||
| 5078 | } | ||
| 5079 | |||
| 5080 | for (i = 0; i < jb->nprocs; ++i) { | ||
| 5081 | if (jb->ps[i].ps_proc) { | ||
| 5082 | proclist[pid_nr++] = jb->ps[i].ps_proc; | ||
| 5083 | } | ||
| 5084 | } | ||
| 5085 | } | ||
| 5086 | } | ||
| 5087 | |||
| 5088 | if (pid_nr) { | ||
| 5089 | do { | ||
| 5090 | idx = WaitForMultipleObjects(pid_nr, proclist, FALSE, blocking); | ||
| 5091 | if (idx < pid_nr) { | ||
| 5092 | GetExitCodeProcess(proclist[idx], &win_status); | ||
| 5093 | *status = exit_code_to_wait_status(win_status); | ||
| 5094 | pid = GetProcessId(proclist[idx]); | ||
| 5095 | break; | ||
| 5096 | } | ||
| 5097 | } while (blocking && !pending_int && waitcmd_int != 1); | ||
| 5098 | } | ||
| 5099 | return pid; | ||
| 5100 | } | ||
| 5101 | #endif | ||
| 5102 | |||
| 4417 | /* Inside dowait(): */ | 5103 | /* Inside dowait(): */ |
| 4418 | #define DOWAIT_NONBLOCK 0 /* waitpid() will use WNOHANG and won't wait for signals */ | 5104 | #define DOWAIT_NONBLOCK 0 /* waitpid() will use WNOHANG and won't wait for signals */ |
| 4419 | #define DOWAIT_BLOCK 1 /* waitpid() will NOT use WNOHANG */ | 5105 | #define DOWAIT_BLOCK 1 /* waitpid() will NOT use WNOHANG */ |
| @@ -4425,6 +5111,7 @@ sprint_status48(char *os, int status, int sigonly) | |||
| 4425 | static int | 5111 | static int |
| 4426 | waitproc(int block, int *status) | 5112 | waitproc(int block, int *status) |
| 4427 | { | 5113 | { |
| 5114 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 4428 | sigset_t oldmask; | 5115 | sigset_t oldmask; |
| 4429 | int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; | 5116 | int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; |
| 4430 | int err; | 5117 | int err; |
| @@ -4464,6 +5151,11 @@ waitproc(int block, int *status) | |||
| 4464 | /* If we fall off the loop, err is 0, which means we got a !SIGCHLD signal */ | 5151 | /* If we fall off the loop, err is 0, which means we got a !SIGCHLD signal */ |
| 4465 | 5152 | ||
| 4466 | return err; | 5153 | return err; |
| 5154 | #else | ||
| 5155 | // Only DOWAIT_NONBLOCK is non-blocking, other values block. | ||
| 5156 | *status = 0; | ||
| 5157 | return waitpid_child(status, block != DOWAIT_NONBLOCK); | ||
| 5158 | #endif | ||
| 4467 | } | 5159 | } |
| 4468 | 5160 | ||
| 4469 | static int waitone(int block, struct job *job) | 5161 | static int waitone(int block, struct job *job) |
| @@ -4517,6 +5209,10 @@ static int waitone(int block, struct job *job) | |||
| 4517 | TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->ps_status, status)); | 5209 | TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->ps_status, status)); |
| 4518 | sp->ps_status = status; | 5210 | sp->ps_status = status; |
| 4519 | thisjob = jp; | 5211 | thisjob = jp; |
| 5212 | #if ENABLE_PLATFORM_MINGW32 | ||
| 5213 | CloseHandle(sp->ps_proc); | ||
| 5214 | sp->ps_proc = NULL; | ||
| 5215 | #endif | ||
| 4520 | } | 5216 | } |
| 4521 | if (sp->ps_status == -1) | 5217 | if (sp->ps_status == -1) |
| 4522 | jobstate = JOBRUNNING; | 5218 | jobstate = JOBRUNNING; |
| @@ -4577,6 +5273,7 @@ static int waitone(int block, struct job *job) | |||
| 4577 | 5273 | ||
| 4578 | static int dowait(int block, struct job *jp) | 5274 | static int dowait(int block, struct job *jp) |
| 4579 | { | 5275 | { |
| 5276 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 4580 | smallint gotchld = *(volatile smallint *)&gotsigchld; | 5277 | smallint gotchld = *(volatile smallint *)&gotsigchld; |
| 4581 | int rpid; | 5278 | int rpid; |
| 4582 | int pid; | 5279 | int pid; |
| @@ -4598,9 +5295,17 @@ static int dowait(int block, struct job *jp) | |||
| 4598 | } while (pid >= 0); | 5295 | } while (pid >= 0); |
| 4599 | 5296 | ||
| 4600 | return rpid; | 5297 | return rpid; |
| 5298 | #else | ||
| 5299 | int pid = 1; | ||
| 5300 | |||
| 5301 | while ((jp ? jp->state == JOBRUNNING : pid > 0) && waitcmd_int != 1) | ||
| 5302 | pid = waitone(block, jp); | ||
| 5303 | |||
| 5304 | return pid; | ||
| 5305 | #endif | ||
| 4601 | } | 5306 | } |
| 4602 | 5307 | ||
| 4603 | #if JOBS | 5308 | #if JOBS || JOBS_WIN32 |
| 4604 | static void | 5309 | static void |
| 4605 | showjob(struct job *jp, int mode) | 5310 | showjob(struct job *jp, int mode) |
| 4606 | { | 5311 | { |
| @@ -4615,7 +5320,7 @@ showjob(struct job *jp, int mode) | |||
| 4615 | 5320 | ||
| 4616 | if (mode & SHOW_ONLY_PGID) { /* jobs -p */ | 5321 | if (mode & SHOW_ONLY_PGID) { /* jobs -p */ |
| 4617 | /* just output process (group) id of pipeline */ | 5322 | /* just output process (group) id of pipeline */ |
| 4618 | fprintf(out, "%d\n", ps->ps_pid); | 5323 | fprintf(out, "%"PID_FMT"d\n", ps->ps_pid); |
| 4619 | return; | 5324 | return; |
| 4620 | } | 5325 | } |
| 4621 | 5326 | ||
| @@ -4628,7 +5333,7 @@ showjob(struct job *jp, int mode) | |||
| 4628 | s[col - 3] = '-'; | 5333 | s[col - 3] = '-'; |
| 4629 | 5334 | ||
| 4630 | if (mode & SHOW_PIDS) | 5335 | if (mode & SHOW_PIDS) |
| 4631 | col += fmtstr(s + col, 16, "%d ", ps->ps_pid); | 5336 | col += fmtstr(s + col, 16, "%"PID_FMT"d ", ps->ps_pid); |
| 4632 | 5337 | ||
| 4633 | psend = ps + jp->nprocs; | 5338 | psend = ps + jp->nprocs; |
| 4634 | 5339 | ||
| @@ -4637,8 +5342,10 @@ showjob(struct job *jp, int mode) | |||
| 4637 | col += sizeof("Running") - 1; | 5342 | col += sizeof("Running") - 1; |
| 4638 | } else { | 5343 | } else { |
| 4639 | int status = psend[-1].ps_status; | 5344 | int status = psend[-1].ps_status; |
| 5345 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 4640 | if (jp->state == JOBSTOPPED) | 5346 | if (jp->state == JOBSTOPPED) |
| 4641 | status = jp->stopstatus; | 5347 | status = jp->stopstatus; |
| 5348 | #endif | ||
| 4642 | col += sprint_status48(s + col, status, 0); | 5349 | col += sprint_status48(s + col, status, 0); |
| 4643 | } | 5350 | } |
| 4644 | /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ | 5351 | /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ |
| @@ -4657,14 +5364,18 @@ showjob(struct job *jp, int mode) | |||
| 4657 | s[0] = '\0'; | 5364 | s[0] = '\0'; |
| 4658 | col = 33; | 5365 | col = 33; |
| 4659 | if (mode & SHOW_PIDS) | 5366 | if (mode & SHOW_PIDS) |
| 4660 | col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1; | 5367 | col = fmtstr(s, 48, "\n%*c%"PID_FMT"d ", indent_col, ' ', ps->ps_pid) - 1; |
| 4661 | start: | 5368 | start: |
| 5369 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 4662 | fprintf(out, "%s%*c%s%s", | 5370 | fprintf(out, "%s%*c%s%s", |
| 4663 | s, | 5371 | s, |
| 4664 | 33 - col >= 0 ? 33 - col : 0, ' ', | 5372 | 33 - col >= 0 ? 33 - col : 0, ' ', |
| 4665 | ps == jp->ps ? "" : "| ", | 5373 | ps == jp->ps ? "" : "| ", |
| 4666 | ps->ps_cmd | 5374 | ps->ps_cmd |
| 4667 | ); | 5375 | ); |
| 5376 | #else | ||
| 5377 | fprintf(out, "%s", s); | ||
| 5378 | #endif | ||
| 4668 | } while (++ps != psend); | 5379 | } while (++ps != psend); |
| 4669 | newline_and_flush(out); | 5380 | newline_and_flush(out); |
| 4670 | 5381 | ||
| @@ -4749,7 +5460,7 @@ getstatus(struct job *job) | |||
| 4749 | { | 5460 | { |
| 4750 | /* XXX: limits number of signals */ | 5461 | /* XXX: limits number of signals */ |
| 4751 | retval = WTERMSIG(status); | 5462 | retval = WTERMSIG(status); |
| 4752 | #if JOBS | 5463 | #if JOBS || ENABLE_PLATFORM_MINGW32 |
| 4753 | if (retval == SIGINT) | 5464 | if (retval == SIGINT) |
| 4754 | job->sigint = 1; | 5465 | job->sigint = 1; |
| 4755 | #endif | 5466 | #endif |
| @@ -4800,6 +5511,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
| 4800 | * with an exit status greater than 128, immediately after which | 5511 | * with an exit status greater than 128, immediately after which |
| 4801 | * the trap is executed." | 5512 | * the trap is executed." |
| 4802 | */ | 5513 | */ |
| 5514 | #if ENABLE_PLATFORM_MINGW32 | ||
| 5515 | waitcmd_int = -1; | ||
| 5516 | #endif | ||
| 4803 | #if BASH_WAIT_N | 5517 | #if BASH_WAIT_N |
| 4804 | status = dowait(DOWAIT_CHILD_OR_SIG | DOWAIT_JOBSTATUS, NULL); | 5518 | status = dowait(DOWAIT_CHILD_OR_SIG | DOWAIT_JOBSTATUS, NULL); |
| 4805 | #else | 5519 | #else |
| @@ -4809,8 +5523,16 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
| 4809 | * dowait() returns pid > 0. Check this case, | 5523 | * dowait() returns pid > 0. Check this case, |
| 4810 | * not "if (dowait() < 0)"! | 5524 | * not "if (dowait() < 0)"! |
| 4811 | */ | 5525 | */ |
| 5526 | #if ENABLE_PLATFORM_MINGW32 | ||
| 5527 | if (waitcmd_int == 1) { | ||
| 5528 | write_ctrl_c(); | ||
| 5529 | return 128 | SIGINT; | ||
| 5530 | } | ||
| 5531 | waitcmd_int = 0; | ||
| 5532 | #else | ||
| 4812 | if (pending_sig) | 5533 | if (pending_sig) |
| 4813 | goto sigout; | 5534 | goto sigout; |
| 5535 | #endif | ||
| 4814 | #if BASH_WAIT_N | 5536 | #if BASH_WAIT_N |
| 4815 | if (one) { | 5537 | if (one) { |
| 4816 | /* wait -n waits for one _job_, not one _process_. | 5538 | /* wait -n waits for one _job_, not one _process_. |
| @@ -4921,7 +5643,7 @@ makejob(int nprocs) | |||
| 4921 | break; | 5643 | break; |
| 4922 | if (jp->state != JOBDONE || !jp->waited) | 5644 | if (jp->state != JOBDONE || !jp->waited) |
| 4923 | continue; | 5645 | continue; |
| 4924 | #if JOBS | 5646 | #if JOBS || JOBS_WIN32 |
| 4925 | if (jobctl) | 5647 | if (jobctl) |
| 4926 | continue; | 5648 | continue; |
| 4927 | #endif | 5649 | #endif |
| @@ -4947,7 +5669,7 @@ makejob(int nprocs) | |||
| 4947 | return jp; | 5669 | return jp; |
| 4948 | } | 5670 | } |
| 4949 | 5671 | ||
| 4950 | #if JOBS | 5672 | #if JOBS || JOBS_WIN32 |
| 4951 | /* | 5673 | /* |
| 4952 | * Return a string identifying a command (to be printed by the | 5674 | * Return a string identifying a command (to be printed by the |
| 4953 | * jobs command). | 5675 | * jobs command). |
| @@ -5287,6 +6009,7 @@ clear_traps(void) | |||
| 5287 | INTON; | 6009 | INTON; |
| 5288 | } | 6010 | } |
| 5289 | 6011 | ||
| 6012 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 5290 | /* Lives far away from here, needed for forkchild */ | 6013 | /* Lives far away from here, needed for forkchild */ |
| 5291 | static void closescript(void); | 6014 | static void closescript(void); |
| 5292 | 6015 | ||
| @@ -5425,14 +6148,22 @@ forkchild(struct job *jp, union node *n, int mode) | |||
| 5425 | for (jp = curjob; jp; jp = jp->prev_job) | 6148 | for (jp = curjob; jp; jp = jp->prev_job) |
| 5426 | freejob(jp); | 6149 | freejob(jp); |
| 5427 | } | 6150 | } |
| 6151 | #endif | ||
| 5428 | 6152 | ||
| 5429 | /* Called after fork(), in parent */ | 6153 | /* Called after fork(), in parent */ |
| 5430 | #if !JOBS | 6154 | #if !JOBS && !JOBS_WIN32 |
| 5431 | #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) | 6155 | #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) |
| 5432 | #endif | 6156 | #endif |
| 5433 | static void | 6157 | static void |
| 6158 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 5434 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 6159 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
| 6160 | #else | ||
| 6161 | forkparent(struct job *jp, union node *n, int mode, HANDLE proc) | ||
| 6162 | #endif | ||
| 5435 | { | 6163 | { |
| 6164 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6165 | pid_t pid = GetProcessId(proc); | ||
| 6166 | #else | ||
| 5436 | if (pid < 0) { | 6167 | if (pid < 0) { |
| 5437 | TRACE(("Fork failed, errno=%d", errno)); | 6168 | TRACE(("Fork failed, errno=%d", errno)); |
| 5438 | if (jp) | 6169 | if (jp) |
| @@ -5440,6 +6171,7 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) | |||
| 5440 | ash_msg_and_raise_perror("can't fork"); | 6171 | ash_msg_and_raise_perror("can't fork"); |
| 5441 | /* NOTREACHED */ | 6172 | /* NOTREACHED */ |
| 5442 | } | 6173 | } |
| 6174 | #endif | ||
| 5443 | 6175 | ||
| 5444 | TRACE(("In parent shell: child = %d\n", pid)); | 6176 | TRACE(("In parent shell: child = %d\n", pid)); |
| 5445 | if (!jp) /* jp is NULL when called by openhere() for heredoc support */ | 6177 | if (!jp) /* jp is NULL when called by openhere() for heredoc support */ |
| @@ -5459,19 +6191,29 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) | |||
| 5459 | if (mode == FORK_BG) { | 6191 | if (mode == FORK_BG) { |
| 5460 | backgndpid = pid; /* set $! */ | 6192 | backgndpid = pid; /* set $! */ |
| 5461 | set_curjob(jp, CUR_RUNNING); | 6193 | set_curjob(jp, CUR_RUNNING); |
| 6194 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6195 | if (iflag && jp && jp->nprocs == 0) | ||
| 6196 | fprintf(stderr, "[%d] %"PID_FMT"d\n", jobno(jp), pid); | ||
| 6197 | #endif | ||
| 5462 | } | 6198 | } |
| 5463 | if (jp) { | 6199 | if (jp) { |
| 5464 | struct procstat *ps = &jp->ps[jp->nprocs++]; | 6200 | struct procstat *ps = &jp->ps[jp->nprocs++]; |
| 5465 | ps->ps_pid = pid; | 6201 | ps->ps_pid = pid; |
| 5466 | ps->ps_status = -1; | 6202 | ps->ps_status = -1; |
| 6203 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 5467 | ps->ps_cmd = nullstr; | 6204 | ps->ps_cmd = nullstr; |
| 5468 | #if JOBS | 6205 | #endif |
| 6206 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6207 | ps->ps_proc = proc; | ||
| 6208 | #endif | ||
| 6209 | #if JOBS || JOBS_WIN32 | ||
| 5469 | if (jobctl && n) | 6210 | if (jobctl && n) |
| 5470 | ps->ps_cmd = commandtext(n); | 6211 | ps->ps_cmd = commandtext(n); |
| 5471 | #endif | 6212 | #endif |
| 5472 | } | 6213 | } |
| 5473 | } | 6214 | } |
| 5474 | 6215 | ||
| 6216 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 5475 | /* jp and n are NULL when called by openhere() for heredoc support */ | 6217 | /* jp and n are NULL when called by openhere() for heredoc support */ |
| 5476 | static int | 6218 | static int |
| 5477 | forkshell(struct job *jp, union node *n, int mode) | 6219 | forkshell(struct job *jp, union node *n, int mode) |
| @@ -5517,6 +6259,7 @@ vforkexec(union node *n, char **argv, const char *path, int idx) | |||
| 5517 | 6259 | ||
| 5518 | return jp; | 6260 | return jp; |
| 5519 | } | 6261 | } |
| 6262 | #endif | ||
| 5520 | 6263 | ||
| 5521 | /* | 6264 | /* |
| 5522 | * Wait for job to finish. | 6265 | * Wait for job to finish. |
| @@ -5580,6 +6323,10 @@ waitforjob(struct job *jp) | |||
| 5580 | return exitstatus; | 6323 | return exitstatus; |
| 5581 | 6324 | ||
| 5582 | st = getstatus(jp); | 6325 | st = getstatus(jp); |
| 6326 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6327 | if (!jp->sigint && iflag && rootshell) | ||
| 6328 | pending_int = 0; | ||
| 6329 | #endif | ||
| 5583 | #if JOBS | 6330 | #if JOBS |
| 5584 | if (jp->jobctl) { | 6331 | if (jp->jobctl) { |
| 5585 | xtcsetpgrp(ttyfd, rootpid); | 6332 | xtcsetpgrp(ttyfd, rootpid); |
| @@ -5605,6 +6352,7 @@ waitforjob(struct job *jp) | |||
| 5605 | /* | 6352 | /* |
| 5606 | * return 1 if there are stopped jobs, otherwise 0 | 6353 | * return 1 if there are stopped jobs, otherwise 0 |
| 5607 | */ | 6354 | */ |
| 6355 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 5608 | static int | 6356 | static int |
| 5609 | stoppedjobs(void) | 6357 | stoppedjobs(void) |
| 5610 | { | 6358 | { |
| @@ -5623,6 +6371,17 @@ stoppedjobs(void) | |||
| 5623 | out: | 6371 | out: |
| 5624 | return retval; | 6372 | return retval; |
| 5625 | } | 6373 | } |
| 6374 | #else | ||
| 6375 | static int | ||
| 6376 | stoppedjobs(void) | ||
| 6377 | { | ||
| 6378 | if (iflag && curjob) { | ||
| 6379 | out2str("You have background jobs.\n"); | ||
| 6380 | return 1; | ||
| 6381 | } | ||
| 6382 | return 0; | ||
| 6383 | } | ||
| 6384 | #endif | ||
| 5626 | 6385 | ||
| 5627 | /* | 6386 | /* |
| 5628 | * Code for dealing with input/output redirection. | 6387 | * Code for dealing with input/output redirection. |
| @@ -5641,11 +6400,21 @@ stoppedjobs(void) | |||
| 5641 | static int | 6400 | static int |
| 5642 | write2pipe(int pip[2], const char *p, size_t len) | 6401 | write2pipe(int pip[2], const char *p, size_t len) |
| 5643 | { | 6402 | { |
| 6403 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
| 6404 | |||
| 5644 | if (len <= PIPE_BUF) { | 6405 | if (len <= PIPE_BUF) { |
| 5645 | xwrite(pip[1], p, len); | 6406 | xwrite(pip[1], p, len); |
| 5646 | goto out; | 6407 | goto out; |
| 5647 | } | 6408 | } |
| 5648 | 6409 | ||
| 6410 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6411 | memset(&fs, 0, sizeof(fs)); | ||
| 6412 | fs.fpid = FS_OPENHERE; | ||
| 6413 | fs.fd[0] = pip[0]; | ||
| 6414 | fs.fd[1] = pip[1]; | ||
| 6415 | fs.path = p; | ||
| 6416 | spawn_forkshell(&fs, NULL, NULL, FORK_NOJOB); | ||
| 6417 | #else | ||
| 5649 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | 6418 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { |
| 5650 | /* child */ | 6419 | /* child */ |
| 5651 | close(pip[0]); | 6420 | close(pip[0]); |
| @@ -5657,6 +6426,7 @@ write2pipe(int pip[2], const char *p, size_t len) | |||
| 5657 | xwrite(pip[1], p, len); | 6426 | xwrite(pip[1], p, len); |
| 5658 | _exit_SUCCESS(); | 6427 | _exit_SUCCESS(); |
| 5659 | } | 6428 | } |
| 6429 | #endif | ||
| 5660 | out: | 6430 | out: |
| 5661 | close(pip[1]); | 6431 | close(pip[1]); |
| 5662 | return pip[0]; | 6432 | return pip[0]; |
| @@ -5711,6 +6481,10 @@ openredirect(union node *redir) | |||
| 5711 | flags = O_RDONLY; | 6481 | flags = O_RDONLY; |
| 5712 | do_open: | 6482 | do_open: |
| 5713 | f = sh_open(redir->nfile.expfname, flags, 0); | 6483 | f = sh_open(redir->nfile.expfname, flags, 0); |
| 6484 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6485 | if (redir->nfile.type == NAPPEND) | ||
| 6486 | lseek(f, 0, SEEK_END); | ||
| 6487 | #endif | ||
| 5714 | break; | 6488 | break; |
| 5715 | case NFROMSTR: | 6489 | case NFROMSTR: |
| 5716 | f = openherestr(redir->nfile.expfname); | 6490 | f = openherestr(redir->nfile.expfname); |
| @@ -5967,6 +6741,12 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq) | |||
| 5967 | if (fd == preverrout_fd) | 6741 | if (fd == preverrout_fd) |
| 5968 | preverrout_fd = new_fd; | 6742 | preverrout_fd = new_fd; |
| 5969 | 6743 | ||
| 6744 | #if ENABLE_PLATFORM_MINGW32 && !defined(_UCRT) | ||
| 6745 | // Workaround for problems with stderr in MSVCRT | ||
| 6746 | if (fd == fileno(stderr)) | ||
| 6747 | setvbuf(stderr, NULL, _IONBF, 0); | ||
| 6748 | #endif | ||
| 6749 | |||
| 5970 | return 0; /* "we did not close fd" */ | 6750 | return 0; /* "we did not close fd" */ |
| 5971 | } | 6751 | } |
| 5972 | 6752 | ||
| @@ -6320,6 +7100,9 @@ ifsbreakup(char *string, struct arglist *arglist) | |||
| 6320 | const char *ifs, *realifs; | 7100 | const char *ifs, *realifs; |
| 6321 | int ifsspc; | 7101 | int ifsspc; |
| 6322 | int nulonly; | 7102 | int nulonly; |
| 7103 | #if ENABLE_PLATFORM_MINGW32 | ||
| 7104 | int lshift = 0; | ||
| 7105 | #endif | ||
| 6323 | 7106 | ||
| 6324 | start = string; | 7107 | start = string; |
| 6325 | if (ifslastp != NULL) { | 7108 | if (ifslastp != NULL) { |
| @@ -6330,7 +7113,33 @@ ifsbreakup(char *string, struct arglist *arglist) | |||
| 6330 | do { | 7113 | do { |
| 6331 | int afternul; | 7114 | int afternul; |
| 6332 | 7115 | ||
| 7116 | #if ENABLE_PLATFORM_MINGW32 | ||
| 7117 | /* Adjust region offsets for left-shifted string. */ | ||
| 7118 | ifsp->begoff -= lshift; | ||
| 7119 | ifsp->endoff -= lshift; | ||
| 7120 | #endif | ||
| 6333 | p = string + ifsp->begoff; | 7121 | p = string + ifsp->begoff; |
| 7122 | #if ENABLE_PLATFORM_MINGW32 | ||
| 7123 | if (ifsp->endoff > ifsp->begoff + 1) { | ||
| 7124 | /* Transform CRLF to LF. Skip regions having zero or | ||
| 7125 | * one characters: they can't contain CRLF. If the | ||
| 7126 | * region shrinks shift the rest of the string left. */ | ||
| 7127 | int oldlen = ifsp->endoff - ifsp->begoff; | ||
| 7128 | int newlen = remove_cr(p, oldlen); | ||
| 7129 | int delta = oldlen - newlen; | ||
| 7130 | |||
| 7131 | if (delta > 0) { | ||
| 7132 | char *t = string + ifsp->endoff; | ||
| 7133 | char *s = string + ifsp->endoff - delta; | ||
| 7134 | |||
| 7135 | while (*t) | ||
| 7136 | *s++ = *t++; | ||
| 7137 | *s = '\0'; | ||
| 7138 | lshift += delta; | ||
| 7139 | ifsp->endoff -= delta; | ||
| 7140 | } | ||
| 7141 | } | ||
| 7142 | #endif | ||
| 6334 | afternul = nulonly; | 7143 | afternul = nulonly; |
| 6335 | nulonly = ifsp->nulonly; | 7144 | nulonly = ifsp->nulonly; |
| 6336 | ifs = nulonly ? nullstr : realifs; | 7145 | ifs = nulonly ? nullstr : realifs; |
| @@ -6775,6 +7584,7 @@ evalbackcmd(union node *n, struct backcmd *result | |||
| 6775 | const int ip = 0; | 7584 | const int ip = 0; |
| 6776 | const int ic = 1; | 7585 | const int ic = 1; |
| 6777 | #endif | 7586 | #endif |
| 7587 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
| 6778 | 7588 | ||
| 6779 | result->fd = -1; | 7589 | result->fd = -1; |
| 6780 | result->buf = NULL; | 7590 | result->buf = NULL; |
| @@ -6788,6 +7598,15 @@ evalbackcmd(union node *n, struct backcmd *result | |||
| 6788 | ash_msg_and_raise_perror("can't create pipe"); | 7598 | ash_msg_and_raise_perror("can't create pipe"); |
| 6789 | /* process substitution uses NULL job, like openhere() */ | 7599 | /* process substitution uses NULL job, like openhere() */ |
| 6790 | jp = (ctl == CTLBACKQ) ? makejob(1) : NULL; | 7600 | jp = (ctl == CTLBACKQ) ? makejob(1) : NULL; |
| 7601 | #if ENABLE_PLATFORM_MINGW32 | ||
| 7602 | memset(&fs, 0, sizeof(fs)); | ||
| 7603 | fs.fpid = FS_EVALBACKCMD; | ||
| 7604 | fs.n = n; | ||
| 7605 | fs.fd[0] = pip[0]; | ||
| 7606 | fs.fd[1] = pip[1]; | ||
| 7607 | fs.fd[2] = ctl; | ||
| 7608 | spawn_forkshell(&fs, jp, n, FORK_NOJOB); | ||
| 7609 | #else | ||
| 6791 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 7610 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
| 6792 | /* child */ | 7611 | /* child */ |
| 6793 | reset_exception_handler(); | 7612 | reset_exception_handler(); |
| @@ -6812,6 +7631,7 @@ evalbackcmd(union node *n, struct backcmd *result | |||
| 6812 | evaltreenr(n, EV_EXIT); | 7631 | evaltreenr(n, EV_EXIT); |
| 6813 | /* NOTREACHED */ | 7632 | /* NOTREACHED */ |
| 6814 | } | 7633 | } |
| 7634 | #endif | ||
| 6815 | /* parent */ | 7635 | /* parent */ |
| 6816 | #if BASH_PROCESS_SUBST | 7636 | #if BASH_PROCESS_SUBST |
| 6817 | if (ctl != CTLBACKQ) { | 7637 | if (ctl != CTLBACKQ) { |
| @@ -6890,8 +7710,14 @@ expbackq(union node *cmd, int flag IF_BASH_PROCESS_SUBST(, int ctl)) | |||
| 6890 | 7710 | ||
| 6891 | /* Eat all trailing newlines */ | 7711 | /* Eat all trailing newlines */ |
| 6892 | dest = expdest; | 7712 | dest = expdest; |
| 6893 | for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';) | 7713 | for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';) { |
| 6894 | STUNPUTC(dest); | 7714 | STUNPUTC(dest); |
| 7715 | #if ENABLE_PLATFORM_MINGW32 | ||
| 7716 | if (dest > ((char *)stackblock() + startloc) && dest[-1] == '\r') { | ||
| 7717 | STUNPUTC(dest); | ||
| 7718 | } | ||
| 7719 | #endif | ||
| 7720 | } | ||
| 6895 | expdest = dest; | 7721 | expdest = dest; |
| 6896 | 7722 | ||
| 6897 | if (!(flag & EXP_QUOTED)) | 7723 | if (!(flag & EXP_QUOTED)) |
| @@ -8038,6 +8864,26 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
| 8038 | #else | 8864 | #else |
| 8039 | /* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */ | 8865 | /* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */ |
| 8040 | 8866 | ||
| 8867 | #if ENABLE_ASH_GLOB_OPTIONS | ||
| 8868 | static int FAST_FUNC | ||
| 8869 | ash_accept_glob(const char *name) | ||
| 8870 | { | ||
| 8871 | struct stat st; | ||
| 8872 | |||
| 8873 | if (nohiddenglob || nohidsysglob) { | ||
| 8874 | if (!lstat(name, &st)) { | ||
| 8875 | if ((st.st_attr & FILE_ATTRIBUTE_HIDDEN)) { | ||
| 8876 | if (nohiddenglob || | ||
| 8877 | (st.st_attr & FILE_ATTRIBUTE_SYSTEM)) { | ||
| 8878 | return FALSE; | ||
| 8879 | } | ||
| 8880 | } | ||
| 8881 | } | ||
| 8882 | } | ||
| 8883 | return TRUE; | ||
| 8884 | } | ||
| 8885 | #endif | ||
| 8886 | |||
| 8041 | /* | 8887 | /* |
| 8042 | * Do metacharacter (i.e. *, ?, [...]) expansion. | 8888 | * Do metacharacter (i.e. *, ?, [...]) expansion. |
| 8043 | */ | 8889 | */ |
| @@ -8065,6 +8911,10 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
| 8065 | 8911 | ||
| 8066 | metaflag = 0; | 8912 | metaflag = 0; |
| 8067 | start = name; | 8913 | start = name; |
| 8914 | #if ENABLE_PLATFORM_MINGW32 | ||
| 8915 | if (expdir_len == 0 && has_dos_drive_prefix(start) && start[2] != '/') | ||
| 8916 | start += 2; | ||
| 8917 | #endif | ||
| 8068 | for (p = name; esc = 0, *p; p += esc + 1) { | 8918 | for (p = name; esc = 0, *p; p += esc + 1) { |
| 8069 | if (*p == '*' || *p == '?') | 8919 | if (*p == '*' || *p == '?') |
| 8070 | metaflag = 1; | 8920 | metaflag = 1; |
| @@ -8139,8 +8989,16 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
| 8139 | while (!pending_int && (dp = readdir(dirp)) != NULL) { | 8989 | while (!pending_int && (dp = readdir(dirp)) != NULL) { |
| 8140 | if (dp->d_name[0] == '.' && !matchdot) | 8990 | if (dp->d_name[0] == '.' && !matchdot) |
| 8141 | continue; | 8991 | continue; |
| 8992 | #if ENABLE_ASH_GLOB_OPTIONS | ||
| 8993 | # undef pmatch | ||
| 8994 | # define pmatch(a, b) !fnmatch((a), (b), nocaseglob ? FNM_CASEFOLD : 0) | ||
| 8995 | #endif | ||
| 8142 | if (pmatch(start, dp->d_name)) { | 8996 | if (pmatch(start, dp->d_name)) { |
| 8143 | if (atend) { | 8997 | if (atend) { |
| 8998 | #if ENABLE_ASH_GLOB_OPTIONS | ||
| 8999 | if (!ash_accept_glob(dp->d_name)) | ||
| 9000 | continue; | ||
| 9001 | #endif | ||
| 8144 | strcpy(enddir, dp->d_name); | 9002 | strcpy(enddir, dp->d_name); |
| 8145 | addfname(expdir); | 9003 | addfname(expdir); |
| 8146 | } else { | 9004 | } else { |
| @@ -8168,6 +9026,10 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
| 8168 | endname[-esc - 1] = esc ? '\\' : '/'; | 9026 | endname[-esc - 1] = esc ? '\\' : '/'; |
| 8169 | #undef expdir | 9027 | #undef expdir |
| 8170 | #undef expdir_max | 9028 | #undef expdir_max |
| 9029 | #if ENABLE_ASH_GLOB_OPTIONS | ||
| 9030 | # undef pmatch | ||
| 9031 | # define pmatch(a, b) !fnmatch((a), (b), 0) | ||
| 9032 | #endif | ||
| 8171 | } | 9033 | } |
| 8172 | 9034 | ||
| 8173 | static struct strlist * | 9035 | static struct strlist * |
| @@ -8440,14 +9302,40 @@ static int builtinloc = -1; /* index in path of %builtin, or -1 */ | |||
| 8440 | 9302 | ||
| 8441 | 9303 | ||
| 8442 | static void | 9304 | static void |
| 9305 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9306 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no, const char *path, int noexec,) | ||
| 9307 | const char *cmd, char **argv, char **envp) | ||
| 9308 | #else | ||
| 8443 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp) | 9309 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp) |
| 9310 | #endif | ||
| 8444 | { | 9311 | { |
| 9312 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
| 9313 | interp_t interp; | ||
| 9314 | #endif | ||
| 8445 | #if ENABLE_FEATURE_SH_STANDALONE | 9315 | #if ENABLE_FEATURE_SH_STANDALONE |
| 8446 | if (applet_no >= 0) { | 9316 | if (applet_no >= 0) { |
| 9317 | # if ENABLE_PLATFORM_MINGW32 | ||
| 9318 | /* Treat all applets as NOEXEC, including the shell itself | ||
| 9319 | * if we were called from forkshell_shellexec(). */ | ||
| 9320 | run_noexec: | ||
| 9321 | if (applet_main[applet_no] != ash_main || noexec) { | ||
| 9322 | /* mingw-w64's getopt() uses __argv[0] as the program name */ | ||
| 9323 | __argv[0] = (char *)cmd; | ||
| 9324 | /* 'which' wants to know if it was invoked from a standalone | ||
| 9325 | * shell. 'Which' in argv[0] indicates this. */ | ||
| 9326 | if (strcmp(argv[0], "which") == 0) { | ||
| 9327 | argv[0] = (char *)"Which"; | ||
| 9328 | } | ||
| 9329 | # else | ||
| 8447 | if (!vforked && APPLET_IS_NOEXEC(applet_no)) { | 9330 | if (!vforked && APPLET_IS_NOEXEC(applet_no)) { |
| 9331 | # endif | ||
| 9332 | #if !ENABLE_PLATFORM_MINGW32 || !defined(_UCRT) | ||
| 9333 | /* If building for UCRT move this up into shellexec() to | ||
| 9334 | * work around a bug. */ | ||
| 8448 | clearenv(); | 9335 | clearenv(); |
| 8449 | while (*envp) | 9336 | while (*envp) |
| 8450 | putenv(*envp++); | 9337 | putenv(*envp++); |
| 9338 | #endif | ||
| 8451 | popredir(/*drop:*/ 1); | 9339 | popredir(/*drop:*/ 1); |
| 8452 | run_noexec_applet_and_exit(applet_no, cmd, argv); | 9340 | run_noexec_applet_and_exit(applet_no, cmd, argv); |
| 8453 | } | 9341 | } |
| @@ -8458,6 +9346,44 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
| 8458 | } | 9346 | } |
| 8459 | #endif | 9347 | #endif |
| 8460 | 9348 | ||
| 9349 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9350 | /* Workaround for libtool, which assumes the host is an MSYS2 | ||
| 9351 | * environment and requires special-case escaping for cmd.exe. | ||
| 9352 | * https://github.com/skeeto/w64devkit/issues/50 */ | ||
| 9353 | if (string_array_len(argv) >= 3 && | ||
| 9354 | strcmp(argv[0], "cmd") == 0 && | ||
| 9355 | strcmp(argv[1], "//c") == 0 && | ||
| 9356 | strcmp(argv[2], "echo") == 0) { | ||
| 9357 | argv[1]++; /* drop extra slash */ | ||
| 9358 | } | ||
| 9359 | |||
| 9360 | /* cmd was allocated on the stack with room for an extension */ | ||
| 9361 | add_win32_extension((char *)cmd); | ||
| 9362 | |||
| 9363 | # if ENABLE_FEATURE_SH_STANDALONE | ||
| 9364 | /* If the command is a script with an interpreter which is an | ||
| 9365 | * applet, we can run it as if it were a noexec applet. */ | ||
| 9366 | if (parse_interpreter(cmd, &interp)) { | ||
| 9367 | applet_no = find_applet_by_name_for_sh(interp.name, path); | ||
| 9368 | if (applet_no >= 0) { | ||
| 9369 | argv[0] = (char *)cmd; | ||
| 9370 | /* evalcommand()/spawn_forkshell() add two elements before argv */ | ||
| 9371 | if (interp.opts) { | ||
| 9372 | argv--; | ||
| 9373 | argv[0] = (char *)interp.opts; | ||
| 9374 | } | ||
| 9375 | argv--; | ||
| 9376 | cmd = argv[0] = (char *)interp.name; | ||
| 9377 | /* Identify the index of the script file in argv */ | ||
| 9378 | set_interp(1 + (interp.opts != NULL)); | ||
| 9379 | goto run_noexec; | ||
| 9380 | } | ||
| 9381 | } | ||
| 9382 | # endif | ||
| 9383 | |||
| 9384 | execve(cmd, argv, envp); | ||
| 9385 | /* skip POSIX-mandated retry on ENOEXEC */ | ||
| 9386 | #else /* !ENABLE_PLATFORM_MINGW32 */ | ||
| 8461 | repeat: | 9387 | repeat: |
| 8462 | #ifdef SYSV | 9388 | #ifdef SYSV |
| 8463 | do { | 9389 | do { |
| @@ -8493,14 +9419,25 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
| 8493 | argv[0] = (char*) "ash"; | 9419 | argv[0] = (char*) "ash"; |
| 8494 | goto repeat; | 9420 | goto repeat; |
| 8495 | } | 9421 | } |
| 9422 | #endif /* !ENABLE_PLATFORM_MINGW32 */ | ||
| 8496 | } | 9423 | } |
| 8497 | 9424 | ||
| 9425 | #if !ENABLE_PLATFORM_MINGW32 || !ENABLE_FEATURE_SH_STANDALONE | ||
| 9426 | # define shellexec(prg, a, pth, i, n) shellexec(prg, a, pth, i) | ||
| 9427 | #endif | ||
| 9428 | |||
| 8498 | /* | 9429 | /* |
| 8499 | * Exec a program. Never returns. If you change this routine, you may | 9430 | * Exec a program. Never returns. If you change this routine, you may |
| 8500 | * have to change the find_command routine as well. | 9431 | * have to change the find_command routine as well. |
| 8501 | * argv[-1] must exist and be writable! See tryexec() for why. | 9432 | * argv[-1] must exist and be writable! See tryexec() for why. |
| 8502 | */ | 9433 | */ |
| 8503 | static void shellexec(char *prog, char **argv, const char *path, int idx) | 9434 | #if ENABLE_PLATFORM_MINGW32 |
| 9435 | static struct builtincmd *find_builtin(const char *name); | ||
| 9436 | static void shellexec(char *prog, char **argv, const char *path, int idx, | ||
| 9437 | int noexec) NORETURN; | ||
| 9438 | #endif | ||
| 9439 | static void shellexec(char *prog, char **argv, const char *path, int idx, | ||
| 9440 | int noexec) | ||
| 8504 | { | 9441 | { |
| 8505 | char *cmdname; | 9442 | char *cmdname; |
| 8506 | int e; | 9443 | int e; |
| @@ -8509,12 +9446,30 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
| 8509 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ | 9446 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ |
| 8510 | 9447 | ||
| 8511 | envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); | 9448 | envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); |
| 9449 | #if ENABLE_FEATURE_SH_STANDALONE && ENABLE_PLATFORM_MINGW32 && defined(_UCRT) | ||
| 9450 | /* Avoid UCRT bug by updating parent's environment and passing a | ||
| 9451 | * NULL environment pointer to execve(). */ | ||
| 9452 | clearenv(); | ||
| 9453 | while (*envp) | ||
| 9454 | putenv(*envp++); | ||
| 9455 | envp = NULL; | ||
| 9456 | #endif | ||
| 9457 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 8512 | if (strchr(prog, '/') != NULL | 9458 | if (strchr(prog, '/') != NULL |
| 9459 | #else | ||
| 9460 | if (has_path(prog) | ||
| 9461 | #endif | ||
| 8513 | #if ENABLE_FEATURE_SH_STANDALONE | 9462 | #if ENABLE_FEATURE_SH_STANDALONE |
| 8514 | || (applet_no = find_applet_by_name(prog)) >= 0 | 9463 | || (applet_no = find_applet_by_name_for_sh(prog, path)) >= 0 |
| 8515 | #endif | 9464 | #endif |
| 8516 | ) { | 9465 | ) { |
| 9466 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9467 | char *progext = stack_add_ext_space(prog); | ||
| 9468 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no, path, noexec,) | ||
| 9469 | progext, argv, envp); | ||
| 9470 | #else | ||
| 8517 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); | 9471 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); |
| 9472 | #endif | ||
| 8518 | if (applet_no >= 0) { | 9473 | if (applet_no >= 0) { |
| 8519 | /* We tried execing ourself, but it didn't work. | 9474 | /* We tried execing ourself, but it didn't work. |
| 8520 | * Maybe /proc/self/exe doesn't exist? | 9475 | * Maybe /proc/self/exe doesn't exist? |
| @@ -8523,13 +9478,33 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
| 8523 | goto try_PATH; | 9478 | goto try_PATH; |
| 8524 | } | 9479 | } |
| 8525 | e = errno; | 9480 | e = errno; |
| 9481 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9482 | if (unix_path(prog)) { | ||
| 9483 | const char *name = bb_basename(prog); | ||
| 9484 | # if ENABLE_FEATURE_SH_STANDALONE | ||
| 9485 | if ((applet_no = find_applet_by_name_for_sh(name, path)) >= 0) { | ||
| 9486 | tryexec(applet_no, path, noexec, name, argv, envp); | ||
| 9487 | e = errno; | ||
| 9488 | } | ||
| 9489 | # endif | ||
| 9490 | if (!find_builtin(name)) { | ||
| 9491 | argv[0] = (char *)name; | ||
| 9492 | goto try_PATH; | ||
| 9493 | } | ||
| 9494 | } | ||
| 9495 | #endif | ||
| 8526 | } else { | 9496 | } else { |
| 8527 | try_PATH: | 9497 | try_PATH: |
| 8528 | e = ENOENT; | 9498 | e = ENOENT; |
| 8529 | while (padvance(&path, argv[0]) >= 0) { | 9499 | while (padvance(&path, argv[0]) >= 0) { |
| 8530 | cmdname = stackblock(); | 9500 | cmdname = stackblock(); |
| 8531 | if (--idx < 0 && pathopt == NULL) { | 9501 | if (--idx < 0 && pathopt == NULL) { |
| 9502 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9503 | tryexec(IF_FEATURE_SH_STANDALONE(-1, path, noexec,) | ||
| 9504 | cmdname, argv, envp); | ||
| 9505 | #else | ||
| 8532 | tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp); | 9506 | tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp); |
| 9507 | #endif | ||
| 8533 | if (errno != ENOENT && errno != ENOTDIR) | 9508 | if (errno != ENOENT && errno != ENOTDIR) |
| 8534 | e = errno; | 9509 | e = errno; |
| 8535 | } | 9510 | } |
| @@ -8568,6 +9543,9 @@ printentry(struct tblentry *cmdp) | |||
| 8568 | padvance(&path, cmdp->cmdname); | 9543 | padvance(&path, cmdp->cmdname); |
| 8569 | } while (--idx >= 0); | 9544 | } while (--idx >= 0); |
| 8570 | name = stackblock(); | 9545 | name = stackblock(); |
| 9546 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9547 | add_win32_extension(name); | ||
| 9548 | #endif | ||
| 8571 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); | 9549 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); |
| 8572 | } | 9550 | } |
| 8573 | 9551 | ||
| @@ -8768,7 +9746,7 @@ changepath(const char *newval) | |||
| 8768 | bltin = idx; | 9746 | bltin = idx; |
| 8769 | break; | 9747 | break; |
| 8770 | } | 9748 | } |
| 8771 | new = strchr(new, ':'); | 9749 | new = strchr(new, PATH_SEP); |
| 8772 | if (!new) | 9750 | if (!new) |
| 8773 | break; | 9751 | break; |
| 8774 | idx++; | 9752 | idx++; |
| @@ -8945,14 +9923,37 @@ describe_command(char *command, const char *path, int describe_command_verbose) | |||
| 8945 | case CMDNORMAL: { | 9923 | case CMDNORMAL: { |
| 8946 | int j = entry.u.index; | 9924 | int j = entry.u.index; |
| 8947 | char *p; | 9925 | char *p; |
| 9926 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
| 9927 | if (j < -1) { | ||
| 9928 | p = (char *)bb_basename(command); | ||
| 9929 | if (describe_command_verbose) { | ||
| 9930 | out1fmt(" is a builtin applet"); | ||
| 9931 | } else { | ||
| 9932 | out1str(applet_to_exe(p)); | ||
| 9933 | } | ||
| 9934 | break; | ||
| 9935 | } | ||
| 9936 | #endif | ||
| 8948 | if (j < 0) { | 9937 | if (j < 0) { |
| 9938 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9939 | p = stack_add_ext_space(command); | ||
| 9940 | #else | ||
| 8949 | p = command; | 9941 | p = command; |
| 9942 | #endif | ||
| 8950 | } else { | 9943 | } else { |
| 9944 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9945 | if (unix_path(command)) | ||
| 9946 | command = (char *)bb_basename(command); | ||
| 9947 | #endif | ||
| 8951 | do { | 9948 | do { |
| 8952 | padvance(&path, command); | 9949 | padvance(&path, command); |
| 8953 | } while (--j >= 0); | 9950 | } while (--j >= 0); |
| 8954 | p = stackblock(); | 9951 | p = stackblock(); |
| 8955 | } | 9952 | } |
| 9953 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9954 | add_win32_extension(p); | ||
| 9955 | bs_to_slash(p); | ||
| 9956 | #endif | ||
| 8956 | if (describe_command_verbose) { | 9957 | if (describe_command_verbose) { |
| 8957 | out1fmt(" is %s", p); | 9958 | out1fmt(" is %s", p); |
| 8958 | } else { | 9959 | } else { |
| @@ -9107,6 +10108,15 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 9107 | /*static int funcstringsize; // size of strings in node */ | 10108 | /*static int funcstringsize; // size of strings in node */ |
| 9108 | static void *funcblock; /* block to allocate function from */ | 10109 | static void *funcblock; /* block to allocate function from */ |
| 9109 | static char *funcstring_end; /* end of block to allocate strings from */ | 10110 | static char *funcstring_end; /* end of block to allocate strings from */ |
| 10111 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10112 | static int fs_size; | ||
| 10113 | static void *fs_start; | ||
| 10114 | # if FORKSHELL_DEBUG | ||
| 10115 | static void *fs_funcstring; | ||
| 10116 | static const char **annot; | ||
| 10117 | static char *annot_free; | ||
| 10118 | # endif | ||
| 10119 | #endif | ||
| 9110 | 10120 | ||
| 9111 | static const uint8_t nodesize[N_NUMBER] ALIGN1 = { | 10121 | static const uint8_t nodesize[N_NUMBER] ALIGN1 = { |
| 9112 | [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), | 10122 | [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), |
| @@ -9240,14 +10250,79 @@ calcsize(int funcblocksize, union node *n) | |||
| 9240 | } | 10250 | } |
| 9241 | 10251 | ||
| 9242 | static char * | 10252 | static char * |
| 9243 | nodeckstrdup(char *s) | 10253 | nodeckstrdup(const char *s) |
| 9244 | { | 10254 | { |
| 10255 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10256 | if(!s) | ||
| 10257 | return NULL; | ||
| 10258 | #endif | ||
| 9245 | funcstring_end -= SHELL_ALIGN(strlen(s) + 1); | 10259 | funcstring_end -= SHELL_ALIGN(strlen(s) + 1); |
| 9246 | return strcpy(funcstring_end, s); | 10260 | return strcpy(funcstring_end, s); |
| 9247 | } | 10261 | } |
| 9248 | 10262 | ||
| 9249 | static union node *copynode(union node *); | 10263 | static union node *copynode(union node *); |
| 9250 | 10264 | ||
| 10265 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10266 | # if FORKSHELL_DEBUG | ||
| 10267 | # define MARK_PTR(dst,note,flag) forkshell_mark_ptr((void *)&dst, note, flag) | ||
| 10268 | # else | ||
| 10269 | # define MARK_PTR(dst,note,flag) forkshell_mark_ptr((void *)&dst) | ||
| 10270 | # endif | ||
| 10271 | |||
| 10272 | #define NO_FREE 0 | ||
| 10273 | #define FREE 1 | ||
| 10274 | |||
| 10275 | #if FORKSHELL_DEBUG | ||
| 10276 | static void forkshell_mark_ptr(void *dst, const char *note, int flag) | ||
| 10277 | #else | ||
| 10278 | static void forkshell_mark_ptr(void *dst) | ||
| 10279 | #endif | ||
| 10280 | { | ||
| 10281 | char *lrelocate = (char *)fs_start + fs_size; | ||
| 10282 | int index = ((char *)dst - (char *)fs_start)/sizeof(char *); | ||
| 10283 | |||
| 10284 | lrelocate[index/8] |= 1 << (index % 8); | ||
| 10285 | |||
| 10286 | #if FORKSHELL_DEBUG | ||
| 10287 | if (dst < fs_start || dst >= fs_funcstring) { | ||
| 10288 | fprintf(stderr, "dst (%p) out of range (%p %p)\n", | ||
| 10289 | dst, fs_start, fs_funcstring); | ||
| 10290 | } | ||
| 10291 | if (annot) { | ||
| 10292 | if (annot[index]) { | ||
| 10293 | fprintf(stderr, "duplicate annotation: %s %s\n", | ||
| 10294 | annot[index], note); | ||
| 10295 | } | ||
| 10296 | annot[index] = note; | ||
| 10297 | annot_free[index] = flag; | ||
| 10298 | } | ||
| 10299 | #endif | ||
| 10300 | } | ||
| 10301 | |||
| 10302 | # define SAVE_PTR(dst,note,flag) { \ | ||
| 10303 | if (fs_size) { \ | ||
| 10304 | MARK_PTR(dst,note,flag); \ | ||
| 10305 | } \ | ||
| 10306 | } | ||
| 10307 | # define SAVE_PTR2(dst1,note1,flag1,dst2,note2,flag2) { \ | ||
| 10308 | if (fs_size) { \ | ||
| 10309 | MARK_PTR(dst1,note1,flag1); \ | ||
| 10310 | MARK_PTR(dst2,note2,flag2); \ | ||
| 10311 | } \ | ||
| 10312 | } | ||
| 10313 | # define SAVE_PTR3(dst1,note1,flag1,dst2,note2,flag2,dst3,note3,flag3) { \ | ||
| 10314 | if (fs_size) { \ | ||
| 10315 | MARK_PTR(dst1,note1,flag1); \ | ||
| 10316 | MARK_PTR(dst2,note2,flag2); \ | ||
| 10317 | MARK_PTR(dst3,note3,flag3); \ | ||
| 10318 | } \ | ||
| 10319 | } | ||
| 10320 | #else | ||
| 10321 | # define SAVE_PTR(dst,note,flag) | ||
| 10322 | # define SAVE_PTR2(dst1,note1,flag1,dst2,note2,flag2) | ||
| 10323 | # define SAVE_PTR3(dst1,note1,flag1,dst2,note2,flag2,dst3,note3,flag3) | ||
| 10324 | #endif | ||
| 10325 | |||
| 9251 | static struct nodelist * | 10326 | static struct nodelist * |
| 9252 | copynodelist(struct nodelist *lp) | 10327 | copynodelist(struct nodelist *lp) |
| 9253 | { | 10328 | { |
| @@ -9259,6 +10334,8 @@ copynodelist(struct nodelist *lp) | |||
| 9259 | *lpp = funcblock; | 10334 | *lpp = funcblock; |
| 9260 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); | 10335 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); |
| 9261 | (*lpp)->n = copynode(lp->n); | 10336 | (*lpp)->n = copynode(lp->n); |
| 10337 | SAVE_PTR2((*lpp)->n, "(*lpp)->next", NO_FREE, | ||
| 10338 | (*lpp)->next, "(*lpp)->next", NO_FREE); | ||
| 9262 | lp = lp->next; | 10339 | lp = lp->next; |
| 9263 | lpp = &(*lpp)->next; | 10340 | lpp = &(*lpp)->next; |
| 9264 | } | 10341 | } |
| @@ -9282,10 +10359,14 @@ copynode(union node *n) | |||
| 9282 | new->ncmd.args = copynode(n->ncmd.args); | 10359 | new->ncmd.args = copynode(n->ncmd.args); |
| 9283 | new->ncmd.assign = copynode(n->ncmd.assign); | 10360 | new->ncmd.assign = copynode(n->ncmd.assign); |
| 9284 | new->ncmd.linno = n->ncmd.linno; | 10361 | new->ncmd.linno = n->ncmd.linno; |
| 10362 | SAVE_PTR3(new->ncmd.redirect, "ncmd.redirect", NO_FREE, | ||
| 10363 | new->ncmd.args, "ncmd.args", NO_FREE, | ||
| 10364 | new->ncmd.assign, "ncmd.assign", NO_FREE); | ||
| 9285 | break; | 10365 | break; |
| 9286 | case NPIPE: | 10366 | case NPIPE: |
| 9287 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | 10367 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); |
| 9288 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; | 10368 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; |
| 10369 | SAVE_PTR(new->npipe.cmdlist, "npipe.cmdlist", NO_FREE); | ||
| 9289 | break; | 10370 | break; |
| 9290 | case NREDIR: | 10371 | case NREDIR: |
| 9291 | case NBACKGND: | 10372 | case NBACKGND: |
| @@ -9293,6 +10374,8 @@ copynode(union node *n) | |||
| 9293 | new->nredir.redirect = copynode(n->nredir.redirect); | 10374 | new->nredir.redirect = copynode(n->nredir.redirect); |
| 9294 | new->nredir.n = copynode(n->nredir.n); | 10375 | new->nredir.n = copynode(n->nredir.n); |
| 9295 | new->nredir.linno = n->nredir.linno; | 10376 | new->nredir.linno = n->nredir.linno; |
| 10377 | SAVE_PTR2(new->nredir.redirect, "nredir.redirect", NO_FREE, | ||
| 10378 | new->nredir.n, "nredir.n", NO_FREE); | ||
| 9296 | break; | 10379 | break; |
| 9297 | case NAND: | 10380 | case NAND: |
| 9298 | case NOR: | 10381 | case NOR: |
| @@ -9301,37 +10384,58 @@ copynode(union node *n) | |||
| 9301 | case NUNTIL: | 10384 | case NUNTIL: |
| 9302 | new->nbinary.ch2 = copynode(n->nbinary.ch2); | 10385 | new->nbinary.ch2 = copynode(n->nbinary.ch2); |
| 9303 | new->nbinary.ch1 = copynode(n->nbinary.ch1); | 10386 | new->nbinary.ch1 = copynode(n->nbinary.ch1); |
| 10387 | SAVE_PTR2(new->nbinary.ch1, "nbinary.ch1", NO_FREE, | ||
| 10388 | new->nbinary.ch2, "nbinary.ch2", NO_FREE); | ||
| 9304 | break; | 10389 | break; |
| 9305 | case NIF: | 10390 | case NIF: |
| 9306 | new->nif.elsepart = copynode(n->nif.elsepart); | 10391 | new->nif.elsepart = copynode(n->nif.elsepart); |
| 9307 | new->nif.ifpart = copynode(n->nif.ifpart); | 10392 | new->nif.ifpart = copynode(n->nif.ifpart); |
| 9308 | new->nif.test = copynode(n->nif.test); | 10393 | new->nif.test = copynode(n->nif.test); |
| 10394 | SAVE_PTR3(new->nif.elsepart, "nif.elsepart", NO_FREE, | ||
| 10395 | new->nif.ifpart, "nif.ifpart", NO_FREE, | ||
| 10396 | new->nif.test, "nif.test", NO_FREE); | ||
| 9309 | break; | 10397 | break; |
| 9310 | case NFOR: | 10398 | case NFOR: |
| 9311 | new->nfor.var = nodeckstrdup(n->nfor.var); | 10399 | new->nfor.var = nodeckstrdup(n->nfor.var); |
| 9312 | new->nfor.body = copynode(n->nfor.body); | 10400 | new->nfor.body = copynode(n->nfor.body); |
| 9313 | new->nfor.args = copynode(n->nfor.args); | 10401 | new->nfor.args = copynode(n->nfor.args); |
| 9314 | new->nfor.linno = n->nfor.linno; | 10402 | new->nfor.linno = n->nfor.linno; |
| 10403 | SAVE_PTR3(new->nfor.var, | ||
| 10404 | xasprintf("nfor.var '%s'", n->nfor.var ?: "NULL"), FREE, | ||
| 10405 | new->nfor.body, "nfor.body", NO_FREE, | ||
| 10406 | new->nfor.args, "nfor.args", NO_FREE); | ||
| 9315 | break; | 10407 | break; |
| 9316 | case NCASE: | 10408 | case NCASE: |
| 9317 | new->ncase.cases = copynode(n->ncase.cases); | 10409 | new->ncase.cases = copynode(n->ncase.cases); |
| 9318 | new->ncase.expr = copynode(n->ncase.expr); | 10410 | new->ncase.expr = copynode(n->ncase.expr); |
| 9319 | new->ncase.linno = n->ncase.linno; | 10411 | new->ncase.linno = n->ncase.linno; |
| 10412 | SAVE_PTR2(new->ncase.cases, "ncase.cases", NO_FREE, | ||
| 10413 | new->ncase.expr, "ncase.expr", NO_FREE); | ||
| 9320 | break; | 10414 | break; |
| 9321 | case NCLIST: | 10415 | case NCLIST: |
| 9322 | new->nclist.body = copynode(n->nclist.body); | 10416 | new->nclist.body = copynode(n->nclist.body); |
| 9323 | new->nclist.pattern = copynode(n->nclist.pattern); | 10417 | new->nclist.pattern = copynode(n->nclist.pattern); |
| 9324 | new->nclist.next = copynode(n->nclist.next); | 10418 | new->nclist.next = copynode(n->nclist.next); |
| 10419 | SAVE_PTR3(new->nclist.body, "nclist.body", NO_FREE, | ||
| 10420 | new->nclist.pattern, "nclist.pattern", NO_FREE, | ||
| 10421 | new->nclist.next, "nclist.next", NO_FREE); | ||
| 9325 | break; | 10422 | break; |
| 9326 | case NDEFUN: | 10423 | case NDEFUN: |
| 9327 | new->ndefun.body = copynode(n->ndefun.body); | 10424 | new->ndefun.body = copynode(n->ndefun.body); |
| 9328 | new->ndefun.text = nodeckstrdup(n->ndefun.text); | 10425 | new->ndefun.text = nodeckstrdup(n->ndefun.text); |
| 9329 | new->ndefun.linno = n->ndefun.linno; | 10426 | new->ndefun.linno = n->ndefun.linno; |
| 10427 | SAVE_PTR2(new->ndefun.body, "ndefun.body", NO_FREE, | ||
| 10428 | new->ndefun.text, | ||
| 10429 | xasprintf("ndefun.text '%s'", n->ndefun.text ?: "NULL"), FREE); | ||
| 9330 | break; | 10430 | break; |
| 9331 | case NARG: | 10431 | case NARG: |
| 9332 | new->narg.backquote = copynodelist(n->narg.backquote); | 10432 | new->narg.backquote = copynodelist(n->narg.backquote); |
| 9333 | new->narg.text = nodeckstrdup(n->narg.text); | 10433 | new->narg.text = nodeckstrdup(n->narg.text); |
| 9334 | new->narg.next = copynode(n->narg.next); | 10434 | new->narg.next = copynode(n->narg.next); |
| 10435 | SAVE_PTR3(new->narg.backquote, "narg.backquote", NO_FREE, | ||
| 10436 | new->narg.text, | ||
| 10437 | xasprintf("narg.text '%s'", n->narg.text ?: "NULL"), FREE, | ||
| 10438 | new->narg.next, "narg.next", NO_FREE); | ||
| 9335 | break; | 10439 | break; |
| 9336 | case NTO: | 10440 | case NTO: |
| 9337 | #if BASH_REDIR_OUTPUT | 10441 | #if BASH_REDIR_OUTPUT |
| @@ -9345,6 +10449,8 @@ copynode(union node *n) | |||
| 9345 | new->nfile.fname = copynode(n->nfile.fname); | 10449 | new->nfile.fname = copynode(n->nfile.fname); |
| 9346 | new->nfile.fd = n->nfile.fd; | 10450 | new->nfile.fd = n->nfile.fd; |
| 9347 | new->nfile.next = copynode(n->nfile.next); | 10451 | new->nfile.next = copynode(n->nfile.next); |
| 10452 | SAVE_PTR2(new->nfile.fname, "nfile.fname", NO_FREE, | ||
| 10453 | new->nfile.next, "nfile.next", NO_FREE); | ||
| 9348 | break; | 10454 | break; |
| 9349 | case NTOFD: | 10455 | case NTOFD: |
| 9350 | case NFROMFD: | 10456 | case NFROMFD: |
| @@ -9352,15 +10458,20 @@ copynode(union node *n) | |||
| 9352 | new->ndup.dupfd = n->ndup.dupfd; | 10458 | new->ndup.dupfd = n->ndup.dupfd; |
| 9353 | new->ndup.fd = n->ndup.fd; | 10459 | new->ndup.fd = n->ndup.fd; |
| 9354 | new->ndup.next = copynode(n->ndup.next); | 10460 | new->ndup.next = copynode(n->ndup.next); |
| 10461 | SAVE_PTR2(new->ndup.vname, "ndup.vname", NO_FREE, | ||
| 10462 | new->ndup.next, "ndup.next", NO_FREE); | ||
| 9355 | break; | 10463 | break; |
| 9356 | case NHERE: | 10464 | case NHERE: |
| 9357 | case NXHERE: | 10465 | case NXHERE: |
| 9358 | new->nhere.doc = copynode(n->nhere.doc); | 10466 | new->nhere.doc = copynode(n->nhere.doc); |
| 9359 | new->nhere.fd = n->nhere.fd; | 10467 | new->nhere.fd = n->nhere.fd; |
| 9360 | new->nhere.next = copynode(n->nhere.next); | 10468 | new->nhere.next = copynode(n->nhere.next); |
| 10469 | SAVE_PTR2(new->nhere.doc, "nhere.doc", NO_FREE, | ||
| 10470 | new->nhere.next, "nhere.next", NO_FREE); | ||
| 9361 | break; | 10471 | break; |
| 9362 | case NNOT: | 10472 | case NNOT: |
| 9363 | new->nnot.com = copynode(n->nnot.com); | 10473 | new->nnot.com = copynode(n->nnot.com); |
| 10474 | SAVE_PTR(new->nnot.com, "nnot.com", NO_FREE); | ||
| 9364 | break; | 10475 | break; |
| 9365 | }; | 10476 | }; |
| 9366 | new->type = n->type; | 10477 | new->type = n->type; |
| @@ -9381,6 +10492,7 @@ copyfunc(union node *n) | |||
| 9381 | f = ckzalloc(blocksize /* + funcstringsize */); | 10492 | f = ckzalloc(blocksize /* + funcstringsize */); |
| 9382 | funcblock = (char *) f + offsetof(struct funcnode, n); | 10493 | funcblock = (char *) f + offsetof(struct funcnode, n); |
| 9383 | funcstring_end = (char *) f + blocksize; | 10494 | funcstring_end = (char *) f + blocksize; |
| 10495 | IF_PLATFORM_MINGW32(fs_size = 0); | ||
| 9384 | copynode(n); | 10496 | copynode(n); |
| 9385 | /* f->count = 0; - ckzalloc did it */ | 10497 | /* f->count = 0; - ckzalloc did it */ |
| 9386 | return f; | 10498 | return f; |
| @@ -9408,12 +10520,15 @@ defun(union node *func) | |||
| 9408 | #define SKIPFUNCDEF (1 << 3) | 10520 | #define SKIPFUNCDEF (1 << 3) |
| 9409 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ | 10521 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ |
| 9410 | static int skipcount; /* number of levels to skip */ | 10522 | static int skipcount; /* number of levels to skip */ |
| 10523 | #if ENABLE_PLATFORM_POSIX | ||
| 9411 | static int loopnest; /* current loop nesting level */ | 10524 | static int loopnest; /* current loop nesting level */ |
| 10525 | #endif | ||
| 9412 | static int funcline; /* starting line number of current function, or 0 if not in a function */ | 10526 | static int funcline; /* starting line number of current function, or 0 if not in a function */ |
| 9413 | 10527 | ||
| 9414 | /* Forward decl way out to parsing code - dotrap needs it */ | 10528 | /* Forward decl way out to parsing code - dotrap needs it */ |
| 9415 | static int evalstring(char *s, int flags); | 10529 | static int evalstring(char *s, int flags); |
| 9416 | 10530 | ||
| 10531 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 9417 | /* Called to execute a trap. | 10532 | /* Called to execute a trap. |
| 9418 | * Single callsite - at the end of evaltree(). | 10533 | * Single callsite - at the end of evaltree(). |
| 9419 | * If we return non-zero, evaltree raises EXEXIT exception. | 10534 | * If we return non-zero, evaltree raises EXEXIT exception. |
| @@ -9472,6 +10587,47 @@ dotrap(void) | |||
| 9472 | savestatus = last_status; | 10587 | savestatus = last_status; |
| 9473 | TRACE(("dotrap returns\n")); | 10588 | TRACE(("dotrap returns\n")); |
| 9474 | } | 10589 | } |
| 10590 | #else | ||
| 10591 | static void | ||
| 10592 | dotrap(void) | ||
| 10593 | { | ||
| 10594 | int status, last_status; | ||
| 10595 | char *p; | ||
| 10596 | |||
| 10597 | if (!pending_int && waitcmd_int != 1) { | ||
| 10598 | waitcmd_int = 0; | ||
| 10599 | return; | ||
| 10600 | } | ||
| 10601 | |||
| 10602 | status = savestatus; | ||
| 10603 | last_status = status; | ||
| 10604 | if (status < 0) { | ||
| 10605 | status = exitstatus; | ||
| 10606 | savestatus = status; | ||
| 10607 | } | ||
| 10608 | pending_int = waitcmd_int = 0; | ||
| 10609 | barrier(); | ||
| 10610 | |||
| 10611 | TRACE(("dotrap entered\n")); | ||
| 10612 | if (evalskip) { | ||
| 10613 | pending_int = 1; | ||
| 10614 | return; | ||
| 10615 | } | ||
| 10616 | |||
| 10617 | p = trap[SIGINT]; | ||
| 10618 | if (p) { | ||
| 10619 | TRACE(("sig %d is active, will run handler '%s'\n", SIGINT, p)); | ||
| 10620 | trap_depth++; | ||
| 10621 | evalstring(p, 0); | ||
| 10622 | trap_depth--; | ||
| 10623 | if (evalskip != SKIPFUNC) | ||
| 10624 | exitstatus = status; | ||
| 10625 | } | ||
| 10626 | |||
| 10627 | savestatus = last_status; | ||
| 10628 | TRACE(("dotrap returns\n")); | ||
| 10629 | } | ||
| 10630 | #endif | ||
| 9475 | 10631 | ||
| 9476 | /* forward declarations - evaluation is fairly recursive business... */ | 10632 | /* forward declarations - evaluation is fairly recursive business... */ |
| 9477 | static int evalloop(union node *, int); | 10633 | static int evalloop(union node *, int); |
| @@ -9758,19 +10914,37 @@ evalcase(union node *n, int flags) | |||
| 9758 | static int | 10914 | static int |
| 9759 | evalsubshell(union node *n, int flags) | 10915 | evalsubshell(union node *n, int flags) |
| 9760 | { | 10916 | { |
| 10917 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
| 9761 | struct job *jp; | 10918 | struct job *jp; |
| 9762 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ | 10919 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ |
| 9763 | int status; | 10920 | int status; |
| 9764 | 10921 | ||
| 9765 | errlinno = lineno = n->nredir.linno; | 10922 | errlinno = lineno = n->nredir.linno; |
| 9766 | 10923 | ||
| 10924 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10925 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) { | ||
| 10926 | reset_exception_handler(); | ||
| 10927 | expredir(n->nredir.redirect); | ||
| 10928 | redirect(n->nredir.redirect, 0); | ||
| 10929 | evaltreenr(n->nredir.n, flags); | ||
| 10930 | /* never returns */ | ||
| 10931 | } | ||
| 10932 | #else | ||
| 9767 | expredir(n->nredir.redirect); | 10933 | expredir(n->nredir.redirect); |
| 9768 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) | 10934 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) |
| 9769 | goto nofork; | 10935 | goto nofork; |
| 10936 | #endif | ||
| 9770 | INTOFF; | 10937 | INTOFF; |
| 9771 | if (backgnd == FORK_FG) | 10938 | if (backgnd == FORK_FG) |
| 9772 | get_tty_state(); | 10939 | get_tty_state(); |
| 9773 | jp = makejob(1); | 10940 | jp = makejob(1); |
| 10941 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10942 | memset(&fs, 0, sizeof(fs)); | ||
| 10943 | fs.fpid = FS_EVALSUBSHELL; | ||
| 10944 | fs.n = n; | ||
| 10945 | fs.flags = flags; | ||
| 10946 | spawn_forkshell(&fs, jp, n, backgnd); | ||
| 10947 | #else | ||
| 9774 | if (forkshell(jp, n, backgnd) == 0) { | 10948 | if (forkshell(jp, n, backgnd) == 0) { |
| 9775 | /* child */ | 10949 | /* child */ |
| 9776 | INTON; | 10950 | INTON; |
| @@ -9783,6 +10957,7 @@ evalsubshell(union node *n, int flags) | |||
| 9783 | evaltreenr(n->nredir.n, flags); | 10957 | evaltreenr(n->nredir.n, flags); |
| 9784 | /* never returns */ | 10958 | /* never returns */ |
| 9785 | } | 10959 | } |
| 10960 | #endif | ||
| 9786 | /* parent */ | 10961 | /* parent */ |
| 9787 | status = 0; | 10962 | status = 0; |
| 9788 | if (backgnd == FORK_FG) | 10963 | if (backgnd == FORK_FG) |
| @@ -9864,6 +11039,7 @@ expredir(union node *n) | |||
| 9864 | static int | 11039 | static int |
| 9865 | evalpipe(union node *n, int flags) | 11040 | evalpipe(union node *n, int flags) |
| 9866 | { | 11041 | { |
| 11042 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
| 9867 | struct job *jp; | 11043 | struct job *jp; |
| 9868 | struct nodelist *lp; | 11044 | struct nodelist *lp; |
| 9869 | int pipelen; | 11045 | int pipelen; |
| @@ -9890,6 +11066,16 @@ evalpipe(union node *n, int flags) | |||
| 9890 | ash_msg_and_raise_perror("can't create pipe"); | 11066 | ash_msg_and_raise_perror("can't create pipe"); |
| 9891 | } | 11067 | } |
| 9892 | } | 11068 | } |
| 11069 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11070 | memset(&fs, 0, sizeof(fs)); | ||
| 11071 | fs.fpid = FS_EVALPIPE; | ||
| 11072 | fs.flags = flags; | ||
| 11073 | fs.n = lp->n; | ||
| 11074 | fs.fd[0] = pip[0]; | ||
| 11075 | fs.fd[1] = pip[1]; | ||
| 11076 | fs.fd[2] = prevfd; | ||
| 11077 | spawn_forkshell(&fs, jp, lp->n, n->npipe.pipe_backgnd); | ||
| 11078 | #else | ||
| 9893 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { | 11079 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { |
| 9894 | /* child */ | 11080 | /* child */ |
| 9895 | reset_exception_handler(); | 11081 | reset_exception_handler(); |
| @@ -9908,6 +11094,7 @@ evalpipe(union node *n, int flags) | |||
| 9908 | evaltreenr(lp->n, flags); | 11094 | evaltreenr(lp->n, flags); |
| 9909 | /* never returns */ | 11095 | /* never returns */ |
| 9910 | } | 11096 | } |
| 11097 | #endif | ||
| 9911 | /* parent */ | 11098 | /* parent */ |
| 9912 | if (prevfd >= 0) | 11099 | if (prevfd >= 0) |
| 9913 | close(prevfd); | 11100 | close(prevfd); |
| @@ -9965,6 +11152,9 @@ setinteractive(int on) | |||
| 9965 | line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); | 11152 | line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); |
| 9966 | # if ENABLE_FEATURE_TAB_COMPLETION | 11153 | # if ENABLE_FEATURE_TAB_COMPLETION |
| 9967 | line_input_state->get_exe_name = ash_command_name; | 11154 | line_input_state->get_exe_name = ash_command_name; |
| 11155 | # if ENABLE_ASH_GLOB_OPTIONS | ||
| 11156 | line_input_state->sh_accept_glob = ash_accept_glob; | ||
| 11157 | # endif | ||
| 9968 | # endif | 11158 | # endif |
| 9969 | # if EDITING_HAS_sh_get_var | 11159 | # if EDITING_HAS_sh_get_var |
| 9970 | line_input_state->sh_get_var = lookupvar; | 11160 | line_input_state->sh_get_var = lookupvar; |
| @@ -9992,6 +11182,12 @@ optschanged(void) | |||
| 9992 | #else | 11182 | #else |
| 9993 | viflag = 0; /* forcibly keep the option off */ | 11183 | viflag = 0; /* forcibly keep the option off */ |
| 9994 | #endif | 11184 | #endif |
| 11185 | #if ENABLE_ASH_NOCONSOLE | ||
| 11186 | hide_console(noconsole); | ||
| 11187 | #endif | ||
| 11188 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11189 | setwinxp(winxp); | ||
| 11190 | #endif | ||
| 9995 | } | 11191 | } |
| 9996 | 11192 | ||
| 9997 | struct localvar_list { | 11193 | struct localvar_list { |
| @@ -10011,6 +11207,9 @@ poplocalvars(int keep) | |||
| 10011 | struct localvar_list *ll; | 11207 | struct localvar_list *ll; |
| 10012 | struct localvar *lvp, *next; | 11208 | struct localvar *lvp, *next; |
| 10013 | struct var *vp; | 11209 | struct var *vp; |
| 11210 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11211 | int var_type; | ||
| 11212 | #endif | ||
| 10014 | 11213 | ||
| 10015 | INTOFF; | 11214 | INTOFF; |
| 10016 | ll = localvar_stack; | 11215 | ll = localvar_stack; |
| @@ -10053,6 +11252,17 @@ poplocalvars(int keep) | |||
| 10053 | free((char*)vp->var_text); | 11252 | free((char*)vp->var_text); |
| 10054 | vp->flags = lvp->flags; | 11253 | vp->flags = lvp->flags; |
| 10055 | vp->var_text = lvp->text; | 11254 | vp->var_text = lvp->text; |
| 11255 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11256 | var_type = is_bb_var(lvp->text); | ||
| 11257 | if (var_type == BB_VAR_ASSIGN && (lvp->flags & VEXPORT)) | ||
| 11258 | putenv(lvp->text); | ||
| 11259 | else if (var_type) { | ||
| 11260 | char *var = xstrdup(lvp->text); | ||
| 11261 | *strchrnul(var, '=') = '\0'; | ||
| 11262 | unsetenv(var); | ||
| 11263 | free(var); | ||
| 11264 | } | ||
| 11265 | #endif | ||
| 10056 | } | 11266 | } |
| 10057 | free(lvp); | 11267 | free(lvp); |
| 10058 | } | 11268 | } |
| @@ -10275,7 +11485,7 @@ execcmd(int argc UNUSED_PARAM, char **argv) | |||
| 10275 | prog = argv[0]; | 11485 | prog = argv[0]; |
| 10276 | if (optionarg) | 11486 | if (optionarg) |
| 10277 | argv[0] = optionarg; | 11487 | argv[0] = optionarg; |
| 10278 | shellexec(prog, argv, pathval(), 0); | 11488 | shellexec(prog, argv, pathval(), 0, FALSE); |
| 10279 | /* NOTREACHED */ | 11489 | /* NOTREACHED */ |
| 10280 | } | 11490 | } |
| 10281 | return 0; | 11491 | return 0; |
| @@ -10328,6 +11538,9 @@ static int readcmd(int, char **) FAST_FUNC; | |||
| 10328 | static int setcmd(int, char **) FAST_FUNC; | 11538 | static int setcmd(int, char **) FAST_FUNC; |
| 10329 | static int shiftcmd(int, char **) FAST_FUNC; | 11539 | static int shiftcmd(int, char **) FAST_FUNC; |
| 10330 | static int timescmd(int, char **) FAST_FUNC; | 11540 | static int timescmd(int, char **) FAST_FUNC; |
| 11541 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11542 | static int titlecmd(int, char **) FAST_FUNC; | ||
| 11543 | #endif | ||
| 10331 | static int trapcmd(int, char **) FAST_FUNC; | 11544 | static int trapcmd(int, char **) FAST_FUNC; |
| 10332 | static int umaskcmd(int, char **) FAST_FUNC; | 11545 | static int umaskcmd(int, char **) FAST_FUNC; |
| 10333 | static int unsetcmd(int, char **) FAST_FUNC; | 11546 | static int unsetcmd(int, char **) FAST_FUNC; |
| @@ -10400,7 +11613,7 @@ static const struct builtincmd builtintab[] = { | |||
| 10400 | #if MAX_HISTORY | 11613 | #if MAX_HISTORY |
| 10401 | { BUILTIN_NOSPEC "history" , historycmd }, | 11614 | { BUILTIN_NOSPEC "history" , historycmd }, |
| 10402 | #endif | 11615 | #endif |
| 10403 | #if JOBS | 11616 | #if JOBS || JOBS_WIN32 |
| 10404 | { BUILTIN_REGULAR "jobs" , jobscmd }, | 11617 | { BUILTIN_REGULAR "jobs" , jobscmd }, |
| 10405 | { BUILTIN_REGULAR "kill" , killcmd }, | 11618 | { BUILTIN_REGULAR "kill" , killcmd }, |
| 10406 | #endif | 11619 | #endif |
| @@ -10427,6 +11640,9 @@ static const struct builtincmd builtintab[] = { | |||
| 10427 | { BUILTIN_REGULAR "test" , testcmd }, | 11640 | { BUILTIN_REGULAR "test" , testcmd }, |
| 10428 | #endif | 11641 | #endif |
| 10429 | { BUILTIN_SPEC_REG "times" , timescmd }, | 11642 | { BUILTIN_SPEC_REG "times" , timescmd }, |
| 11643 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11644 | { BUILTIN_REGULAR "title" , titlecmd }, | ||
| 11645 | #endif | ||
| 10430 | { BUILTIN_SPEC_REG "trap" , trapcmd }, | 11646 | { BUILTIN_SPEC_REG "trap" , trapcmd }, |
| 10431 | { BUILTIN_REGULAR "true" , truecmd }, | 11647 | { BUILTIN_REGULAR "true" , truecmd }, |
| 10432 | { BUILTIN_REGULAR "type" , typecmd }, | 11648 | { BUILTIN_REGULAR "type" , typecmd }, |
| @@ -10445,7 +11661,7 @@ static const struct builtincmd builtintab[] = { | |||
| 10445 | /* [ */ 1 * ENABLE_ASH_TEST + \ | 11661 | /* [ */ 1 * ENABLE_ASH_TEST + \ |
| 10446 | /* [[ */ 1 * BASH_TEST2 + \ | 11662 | /* [[ */ 1 * BASH_TEST2 + \ |
| 10447 | /* alias */ 1 * ENABLE_ASH_ALIAS + \ | 11663 | /* alias */ 1 * ENABLE_ASH_ALIAS + \ |
| 10448 | /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \ | 11664 | /* bg */ 1 * JOBS + \ |
| 10449 | /* break cd cddir */ 3) | 11665 | /* break cd cddir */ 3) |
| 10450 | #define EVALCMD (COMMANDCMD + \ | 11666 | #define EVALCMD (COMMANDCMD + \ |
| 10451 | /* command */ 1 * ENABLE_ASH_CMDCMD + \ | 11667 | /* command */ 1 * ENABLE_ASH_CMDCMD + \ |
| @@ -10526,6 +11742,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 10526 | * as POSIX mandates */ | 11742 | * as POSIX mandates */ |
| 10527 | return back_exitstatus; | 11743 | return back_exitstatus; |
| 10528 | } | 11744 | } |
| 11745 | |||
| 10529 | static int | 11746 | static int |
| 10530 | evalcommand(union node *cmd, int flags) | 11747 | evalcommand(union node *cmd, int flags) |
| 10531 | { | 11748 | { |
| @@ -10625,9 +11842,19 @@ evalcommand(union node *cmd, int flags) | |||
| 10625 | 11842 | ||
| 10626 | localvar_stop = pushlocalvars(vlocal); | 11843 | localvar_stop = pushlocalvars(vlocal); |
| 10627 | 11844 | ||
| 11845 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11846 | # if ENABLE_FEATURE_SH_STANDALONE | ||
| 11847 | /* Reserve two extra spots at the front for shellexec. */ | ||
| 11848 | nargv = stalloc(sizeof(char *) * (argc + 3)); | ||
| 11849 | argv = nargv = nargv + 2; | ||
| 11850 | # else | ||
| 11851 | argv = nargv = stalloc(sizeof(char *) * (argc + 1)); | ||
| 11852 | # endif | ||
| 11853 | #else | ||
| 10628 | /* Reserve one extra spot at the front for shellexec. */ | 11854 | /* Reserve one extra spot at the front for shellexec. */ |
| 10629 | nargv = stalloc(sizeof(char *) * (argc + 2)); | 11855 | nargv = stalloc(sizeof(char *) * (argc + 2)); |
| 10630 | argv = ++nargv; | 11856 | argv = ++nargv; |
| 11857 | #endif | ||
| 10631 | for (sp = arglist.list; sp; sp = sp->next) { | 11858 | for (sp = arglist.list; sp; sp = sp->next) { |
| 10632 | TRACE(("evalcommand arg: %s\n", sp->text)); | 11859 | TRACE(("evalcommand arg: %s\n", sp->text)); |
| 10633 | *nargv++ = sp->text; | 11860 | *nargv++ = sp->text; |
| @@ -10736,9 +11963,11 @@ evalcommand(union node *cmd, int flags) | |||
| 10736 | 11963 | ||
| 10737 | default: { | 11964 | default: { |
| 10738 | 11965 | ||
| 11966 | //TODO: find a better solution for Windows on ARM than ignoring NOFORK | ||
| 10739 | #if ENABLE_FEATURE_SH_STANDALONE \ | 11967 | #if ENABLE_FEATURE_SH_STANDALONE \ |
| 10740 | && ENABLE_FEATURE_SH_NOFORK \ | 11968 | && ENABLE_FEATURE_SH_NOFORK \ |
| 10741 | && NUM_APPLETS > 1 | 11969 | && NUM_APPLETS > 1 \ |
| 11970 | && !(defined(_ARM64_) && !defined(_UCRT) && ENABLE_PLATFORM_MINGW32) | ||
| 10742 | /* (1) BUG: if variables are set, we need to fork, or save/restore them | 11971 | /* (1) BUG: if variables are set, we need to fork, or save/restore them |
| 10743 | * around run_nofork_applet() call. | 11972 | * around run_nofork_applet() call. |
| 10744 | * (2) Should this check also be done in forkshell()? | 11973 | * (2) Should this check also be done in forkshell()? |
| @@ -10748,6 +11977,9 @@ evalcommand(union node *cmd, int flags) | |||
| 10748 | int applet_no = (- cmdentry.u.index - 2); | 11977 | int applet_no = (- cmdentry.u.index - 2); |
| 10749 | if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { | 11978 | if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { |
| 10750 | char **sv_environ; | 11979 | char **sv_environ; |
| 11980 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11981 | char *sv_argv0; | ||
| 11982 | #endif | ||
| 10751 | 11983 | ||
| 10752 | INTOFF; | 11984 | INTOFF; |
| 10753 | sv_environ = environ; | 11985 | sv_environ = environ; |
| @@ -10760,8 +11992,16 @@ evalcommand(union node *cmd, int flags) | |||
| 10760 | * and/or wait for user input ineligible for NOFORK: | 11992 | * and/or wait for user input ineligible for NOFORK: |
| 10761 | * for example, "yes" or "rm" (rm -i waits for input). | 11993 | * for example, "yes" or "rm" (rm -i waits for input). |
| 10762 | */ | 11994 | */ |
| 11995 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11996 | sv_argv0 = __argv[0]; | ||
| 11997 | argv[0] = (char *)bb_basename(argv[0]); | ||
| 11998 | __argv[0] = argv[0]; | ||
| 11999 | #endif | ||
| 10763 | exitstatus = run_nofork_applet(applet_no, argv); | 12000 | exitstatus = run_nofork_applet(applet_no, argv); |
| 10764 | environ = sv_environ; | 12001 | environ = sv_environ; |
| 12002 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12003 | __argv[0] = sv_argv0; | ||
| 12004 | #endif | ||
| 10765 | /* | 12005 | /* |
| 10766 | * Try enabling NOFORK for "yes" applet. | 12006 | * Try enabling NOFORK for "yes" applet. |
| 10767 | * ^C _will_ stop it (write returns EINTR), | 12007 | * ^C _will_ stop it (write returns EINTR), |
| @@ -10780,6 +12020,22 @@ evalcommand(union node *cmd, int flags) | |||
| 10780 | * in a script or a subshell does not need forking, | 12020 | * in a script or a subshell does not need forking, |
| 10781 | * we can just exec it. | 12021 | * we can just exec it. |
| 10782 | */ | 12022 | */ |
| 12023 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12024 | if (!(flags & EV_EXIT) || may_have_traps IF_SUW32(|| delayexit)) { | ||
| 12025 | /* No, forking off a child is necessary */ | ||
| 12026 | struct forkshell fs; | ||
| 12027 | |||
| 12028 | INTOFF; | ||
| 12029 | memset(&fs, 0, sizeof(fs)); | ||
| 12030 | fs.fpid = FS_SHELLEXEC; | ||
| 12031 | fs.argv = argv; | ||
| 12032 | fs.path = (char*)path; | ||
| 12033 | fs.fd[0] = cmdentry.u.index; | ||
| 12034 | jp = makejob(/*cmd,*/ 1); | ||
| 12035 | spawn_forkshell(&fs, jp, cmd, FORK_FG); | ||
| 12036 | break; | ||
| 12037 | } | ||
| 12038 | #else | ||
| 10783 | if (!(flags & EV_EXIT) || may_have_traps) { | 12039 | if (!(flags & EV_EXIT) || may_have_traps) { |
| 10784 | /* No, forking off a child is necessary */ | 12040 | /* No, forking off a child is necessary */ |
| 10785 | INTOFF; | 12041 | INTOFF; |
| @@ -10787,7 +12043,8 @@ evalcommand(union node *cmd, int flags) | |||
| 10787 | jp = vforkexec(cmd, argv, path, cmdentry.u.index); | 12043 | jp = vforkexec(cmd, argv, path, cmdentry.u.index); |
| 10788 | break; | 12044 | break; |
| 10789 | } | 12045 | } |
| 10790 | shellexec(argv[0], argv, path, cmdentry.u.index); | 12046 | #endif |
| 12047 | shellexec(argv[0], argv, path, cmdentry.u.index, FALSE); | ||
| 10791 | /* NOTREACHED */ | 12048 | /* NOTREACHED */ |
| 10792 | } /* default */ | 12049 | } /* default */ |
| 10793 | case CMDBUILTIN: | 12050 | case CMDBUILTIN: |
| @@ -10998,6 +12255,54 @@ static void popstring(void) | |||
| 10998 | INTON; | 12255 | INTON; |
| 10999 | } | 12256 | } |
| 11000 | 12257 | ||
| 12258 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12259 | /* | ||
| 12260 | * Wrapper around nonblock_immune_read() to remove CRs, but only from | ||
| 12261 | * CRLF pairs. The tricky part is handling a CR at the end of the buffer. | ||
| 12262 | */ | ||
| 12263 | static inline ssize_t | ||
| 12264 | nonblock_immune_wrapper(struct parsefile *pf, char *buffer, size_t count) | ||
| 12265 | { | ||
| 12266 | int nr, injected_cr; | ||
| 12267 | |||
| 12268 | // Inject unprocessed CR from previous read into the buffer. | ||
| 12269 | if (pf->cr) | ||
| 12270 | *buffer = '\r'; | ||
| 12271 | retry: | ||
| 12272 | nr = nonblock_immune_read(pf->pf_fd, buffer + pf->cr, count - pf->cr); | ||
| 12273 | if (nr < 0) | ||
| 12274 | return nr; | ||
| 12275 | |||
| 12276 | injected_cr = pf->cr; | ||
| 12277 | nr += pf->cr; | ||
| 12278 | pf->cr = 0; | ||
| 12279 | |||
| 12280 | if (nr > 0) { | ||
| 12281 | nr = remove_cr(buffer, nr); | ||
| 12282 | // remove_cr() won't reduce size to zero, so [nr - 1] is OK. | ||
| 12283 | if (buffer[nr - 1] == '\r') { | ||
| 12284 | if (nr > 1) { | ||
| 12285 | // Ignore trailing CR for now: we'll deal with it later. | ||
| 12286 | pf->cr = 1; | ||
| 12287 | --nr; | ||
| 12288 | } else if (injected_cr) { // nr == 1 | ||
| 12289 | // Buffer only contains an injected CR. This means the | ||
| 12290 | // read returned EOF. Return the buffer as-is. The | ||
| 12291 | // next call will detect EOF. | ||
| 12292 | } else { | ||
| 12293 | // Buffer only contains a CR from the most recent read. | ||
| 12294 | // Try another read, treating the CR as injected. We'll | ||
| 12295 | // either get more characters or EOF. Either way we | ||
| 12296 | // won't end up here again. | ||
| 12297 | pf->cr = 1; | ||
| 12298 | goto retry; | ||
| 12299 | } | ||
| 12300 | } | ||
| 12301 | } | ||
| 12302 | return nr; | ||
| 12303 | } | ||
| 12304 | #endif | ||
| 12305 | |||
| 11001 | static int | 12306 | static int |
| 11002 | preadfd(void) | 12307 | preadfd(void) |
| 11003 | { | 12308 | { |
| @@ -11008,7 +12313,11 @@ preadfd(void) | |||
| 11008 | #if ENABLE_FEATURE_EDITING | 12313 | #if ENABLE_FEATURE_EDITING |
| 11009 | /* retry: */ | 12314 | /* retry: */ |
| 11010 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) | 12315 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) |
| 12316 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12317 | nr = nonblock_immune_wrapper(g_parsefile, buf, IBUFSIZ - 1); | ||
| 12318 | #else | ||
| 11011 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); | 12319 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
| 12320 | #endif | ||
| 11012 | else { | 12321 | else { |
| 11013 | # if ENABLE_ASH_IDLE_TIMEOUT | 12322 | # if ENABLE_ASH_IDLE_TIMEOUT |
| 11014 | int timeout = -1; | 12323 | int timeout = -1; |
| @@ -11047,17 +12356,29 @@ preadfd(void) | |||
| 11047 | INTON; /* here non-blocked SIGINT will longjmp */ | 12356 | INTON; /* here non-blocked SIGINT will longjmp */ |
| 11048 | if (nr == 0) { | 12357 | if (nr == 0) { |
| 11049 | /* ^C pressed, "convert" to SIGINT */ | 12358 | /* ^C pressed, "convert" to SIGINT */ |
| 12359 | # if !ENABLE_PLATFORM_MINGW32 | ||
| 11050 | write(STDOUT_FILENO, "^C\n", 3); | 12360 | write(STDOUT_FILENO, "^C\n", 3); |
| 11051 | raise(SIGINT); /* here non-blocked SIGINT will longjmp */ | 12361 | raise(SIGINT); /* here non-blocked SIGINT will longjmp */ |
| 11052 | /* raise(SIGINT) did not work! (e.g. if SIGINT | 12362 | /* raise(SIGINT) did not work! (e.g. if SIGINT |
| 11053 | * is SIG_IGNed on startup, it stays SIG_IGNed) | 12363 | * is SIG_IGNed on startup, it stays SIG_IGNed) |
| 11054 | */ | 12364 | */ |
| 12365 | # else | ||
| 12366 | write(STDOUT_FILENO, "^C\n", 3); | ||
| 12367 | # endif | ||
| 11055 | if (trap[SIGINT]) { | 12368 | if (trap[SIGINT]) { |
| 12369 | # if ENABLE_PLATFORM_MINGW32 | ||
| 12370 | pending_int = 1; | ||
| 12371 | dotrap(); | ||
| 12372 | # endif | ||
| 11056 | empty_line_input: | 12373 | empty_line_input: |
| 11057 | buf[0] = '\n'; | 12374 | buf[0] = '\n'; |
| 11058 | buf[1] = '\0'; | 12375 | buf[1] = '\0'; |
| 11059 | return 1; | 12376 | return 1; |
| 11060 | } | 12377 | } |
| 12378 | # if ENABLE_PLATFORM_MINGW32 | ||
| 12379 | else | ||
| 12380 | raise_interrupt(); | ||
| 12381 | # endif | ||
| 11061 | exitstatus = 128 + SIGINT; | 12382 | exitstatus = 128 + SIGINT; |
| 11062 | /* bash behavior on ^C + ignored SIGINT: */ | 12383 | /* bash behavior on ^C + ignored SIGINT: */ |
| 11063 | goto again; | 12384 | goto again; |
| @@ -11081,7 +12402,11 @@ preadfd(void) | |||
| 11081 | } | 12402 | } |
| 11082 | } | 12403 | } |
| 11083 | #else | 12404 | #else |
| 12405 | # if ENABLE_PLATFORM_MINGW32 | ||
| 12406 | nr = nonblock_immune_wrapper(g_parsefile, buf, IBUFSIZ - 1); | ||
| 12407 | # else | ||
| 11084 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); | 12408 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
| 12409 | # endif | ||
| 11085 | #endif | 12410 | #endif |
| 11086 | 12411 | ||
| 11087 | #if 0 /* disabled: nonblock_immune_read() handles this problem */ | 12412 | #if 0 /* disabled: nonblock_immune_read() handles this problem */ |
| @@ -11380,6 +12705,7 @@ popallfiles(void) | |||
| 11380 | unwindfiles(&basepf); | 12705 | unwindfiles(&basepf); |
| 11381 | } | 12706 | } |
| 11382 | 12707 | ||
| 12708 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 11383 | /* | 12709 | /* |
| 11384 | * Close the file(s) that the shell is reading commands from. Called | 12710 | * Close the file(s) that the shell is reading commands from. Called |
| 11385 | * after a fork is done. | 12711 | * after a fork is done. |
| @@ -11393,6 +12719,7 @@ closescript(void) | |||
| 11393 | g_parsefile->pf_fd = 0; | 12719 | g_parsefile->pf_fd = 0; |
| 11394 | } | 12720 | } |
| 11395 | } | 12721 | } |
| 12722 | #endif | ||
| 11396 | 12723 | ||
| 11397 | /* | 12724 | /* |
| 11398 | * Like setinputfile, but takes an open file descriptor. Call this with | 12725 | * Like setinputfile, but takes an open file descriptor. Call this with |
| @@ -11625,8 +12952,19 @@ options(int *login_sh) | |||
| 11625 | int val; | 12952 | int val; |
| 11626 | int c; | 12953 | int c; |
| 11627 | 12954 | ||
| 11628 | if (login_sh != NULL) /* if we came from startup code */ | 12955 | #if ENABLE_ASH_NOCONSOLE |
| 12956 | noconsole = console_state(); | ||
| 12957 | #endif | ||
| 12958 | if (login_sh != NULL) { /* if we came from startup code */ | ||
| 11629 | minusc = NULL; | 12959 | minusc = NULL; |
| 12960 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12961 | dirarg = NULL; | ||
| 12962 | title = NULL; | ||
| 12963 | # if ENABLE_SUW32 | ||
| 12964 | delayexit = 0; | ||
| 12965 | # endif | ||
| 12966 | #endif | ||
| 12967 | } | ||
| 11630 | while ((p = *argptr) != NULL) { | 12968 | while ((p = *argptr) != NULL) { |
| 11631 | c = *p++; | 12969 | c = *p++; |
| 11632 | if (c != '-' && c != '+') | 12970 | if (c != '-' && c != '+') |
| @@ -11656,6 +12994,31 @@ options(int *login_sh) | |||
| 11656 | cflag = 1; | 12994 | cflag = 1; |
| 11657 | continue; | 12995 | continue; |
| 11658 | } | 12996 | } |
| 12997 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12998 | /* Undocumented flags; | ||
| 12999 | * -d force current directory | ||
| 13000 | * -t title to display in console window | ||
| 13001 | * -N prompt user before exit | ||
| 13002 | * Must appear before -s or -c. */ | ||
| 13003 | if (c == 'd' && val == 1) { | ||
| 13004 | if (*argptr == NULL) | ||
| 13005 | ash_msg_and_raise_error(bb_msg_requires_arg, "-d"); | ||
| 13006 | dirarg = *argptr++; | ||
| 13007 | continue; | ||
| 13008 | } | ||
| 13009 | if (c == 't' && val == 1) { | ||
| 13010 | if (*argptr == NULL) | ||
| 13011 | ash_msg_and_raise_error(bb_msg_requires_arg, "-t"); | ||
| 13012 | title = *argptr++; | ||
| 13013 | continue; | ||
| 13014 | } | ||
| 13015 | # if ENABLE_SUW32 | ||
| 13016 | if (c == 'N' && val == 1) { | ||
| 13017 | delayexit = 1; | ||
| 13018 | continue; | ||
| 13019 | } | ||
| 13020 | # endif | ||
| 13021 | #endif | ||
| 11659 | if (c == 's') { /* -s, +s */ | 13022 | if (c == 's') { /* -s, +s */ |
| 11660 | sflag = 1; | 13023 | sflag = 1; |
| 11661 | continue; | 13024 | continue; |
| @@ -13699,6 +15062,9 @@ evalstring(char *s, int flags) | |||
| 13699 | int status; | 15062 | int status; |
| 13700 | 15063 | ||
| 13701 | s = sstrdup(s); | 15064 | s = sstrdup(s); |
| 15065 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15066 | remove_cr(s, strlen(s)+1); | ||
| 15067 | #endif | ||
| 13702 | setinputstring(s); | 15068 | setinputstring(s); |
| 13703 | setstackmark(&smark); | 15069 | setstackmark(&smark); |
| 13704 | 15070 | ||
| @@ -13786,7 +15152,7 @@ cmdloop(int top) | |||
| 13786 | int skip; | 15152 | int skip; |
| 13787 | 15153 | ||
| 13788 | setstackmark(&smark); | 15154 | setstackmark(&smark); |
| 13789 | #if JOBS | 15155 | #if JOBS || JOBS_WIN32 |
| 13790 | if (jobctl) | 15156 | if (jobctl) |
| 13791 | showjobs(SHOW_CHANGED|SHOW_STDERR); | 15157 | showjobs(SHOW_CHANGED|SHOW_STDERR); |
| 13792 | #endif | 15158 | #endif |
| @@ -13794,6 +15160,9 @@ cmdloop(int top) | |||
| 13794 | if (iflag && top) { | 15160 | if (iflag && top) { |
| 13795 | inter++; | 15161 | inter++; |
| 13796 | chkmail(); | 15162 | chkmail(); |
| 15163 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15164 | terminal_mode(TRUE); | ||
| 15165 | #endif | ||
| 13797 | } | 15166 | } |
| 13798 | n = parsecmd(inter); | 15167 | n = parsecmd(inter); |
| 13799 | #if DEBUG | 15168 | #if DEBUG |
| @@ -13817,8 +15186,10 @@ cmdloop(int top) | |||
| 13817 | } else { | 15186 | } else { |
| 13818 | int i; | 15187 | int i; |
| 13819 | 15188 | ||
| 15189 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 13820 | /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */ | 15190 | /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */ |
| 13821 | job_warning >>= 1; | 15191 | job_warning >>= 1; |
| 15192 | #endif | ||
| 13822 | numeof = 0; | 15193 | numeof = 0; |
| 13823 | i = evaltree(n, 0); | 15194 | i = evaltree(n, 0); |
| 13824 | if (n) | 15195 | if (n) |
| @@ -13848,7 +15219,7 @@ find_dot_file(char *basename) | |||
| 13848 | int len; | 15219 | int len; |
| 13849 | 15220 | ||
| 13850 | /* don't try this for absolute or relative paths */ | 15221 | /* don't try this for absolute or relative paths */ |
| 13851 | if (strchr(basename, '/')) | 15222 | if (strchr(basename, '/') IF_PLATFORM_MINGW32(|| strchr(basename, '\\'))) |
| 13852 | return basename; | 15223 | return basename; |
| 13853 | 15224 | ||
| 13854 | path = pathval(); | 15225 | path = pathval(); |
| @@ -14013,6 +15384,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
| 14013 | struct builtincmd *bcmd; | 15384 | struct builtincmd *bcmd; |
| 14014 | int len; | 15385 | int len; |
| 14015 | 15386 | ||
| 15387 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14016 | /* If name contains a slash, don't use PATH or hash table */ | 15388 | /* If name contains a slash, don't use PATH or hash table */ |
| 14017 | if (strchr(name, '/') != NULL) { | 15389 | if (strchr(name, '/') != NULL) { |
| 14018 | entry->u.index = -1; | 15390 | entry->u.index = -1; |
| @@ -14032,6 +15404,35 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
| 14032 | entry->cmdtype = CMDNORMAL; | 15404 | entry->cmdtype = CMDNORMAL; |
| 14033 | return; | 15405 | return; |
| 14034 | } | 15406 | } |
| 15407 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
| 15408 | /* If name contains a slash or drive prefix, don't use PATH or hash table */ | ||
| 15409 | if (has_path(name)) { | ||
| 15410 | entry->u.index = -1; | ||
| 15411 | entry->cmdtype = CMDNORMAL; | ||
| 15412 | fullname = stack_add_ext_space(name); | ||
| 15413 | if (add_win32_extension(fullname)) { | ||
| 15414 | return; | ||
| 15415 | } else if (unix_path(name)) { | ||
| 15416 | name = (char *)bb_basename(name); | ||
| 15417 | if ( | ||
| 15418 | # if ENABLE_FEATURE_SH_STANDALONE | ||
| 15419 | find_applet_by_name_for_sh(name, path) >= 0 || | ||
| 15420 | # endif | ||
| 15421 | !find_builtin(bb_basename(name)) | ||
| 15422 | ) { | ||
| 15423 | act |= DO_NOFUNC; | ||
| 15424 | } else if (act & DO_ABS) { | ||
| 15425 | entry->cmdtype = CMDUNKNOWN; | ||
| 15426 | return; | ||
| 15427 | } | ||
| 15428 | } else if (act & DO_ABS) { | ||
| 15429 | entry->cmdtype = CMDUNKNOWN; | ||
| 15430 | return; | ||
| 15431 | } else { | ||
| 15432 | return; | ||
| 15433 | } | ||
| 15434 | } | ||
| 15435 | #endif /* ENABLE_PLATFORM_MINGW32 */ | ||
| 14035 | 15436 | ||
| 14036 | /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ | 15437 | /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ |
| 14037 | 15438 | ||
| @@ -14086,7 +15487,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
| 14086 | 15487 | ||
| 14087 | #if ENABLE_FEATURE_SH_STANDALONE | 15488 | #if ENABLE_FEATURE_SH_STANDALONE |
| 14088 | { | 15489 | { |
| 14089 | int applet_no = find_applet_by_name(name); | 15490 | int applet_no = find_applet_by_name_for_sh(name, path); |
| 14090 | if (applet_no >= 0) { | 15491 | if (applet_no >= 0) { |
| 14091 | entry->cmdtype = CMDNORMAL; | 15492 | entry->cmdtype = CMDNORMAL; |
| 14092 | entry->u.index = -2 - applet_no; | 15493 | entry->u.index = -2 - applet_no; |
| @@ -14125,12 +15526,15 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
| 14125 | } | 15526 | } |
| 14126 | } | 15527 | } |
| 14127 | /* if rehash, don't redo absolute path names */ | 15528 | /* if rehash, don't redo absolute path names */ |
| 14128 | if (fullname[0] == '/' && idx <= prev) { | 15529 | if (!is_relative_path(fullname) && idx <= prev) { |
| 14129 | if (idx < prev) | 15530 | if (idx < prev) |
| 14130 | continue; | 15531 | continue; |
| 14131 | TRACE(("searchexec \"%s\": no change\n", name)); | 15532 | TRACE(("searchexec \"%s\": no change\n", name)); |
| 14132 | goto success; | 15533 | goto success; |
| 14133 | } | 15534 | } |
| 15535 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15536 | add_win32_extension(fullname); | ||
| 15537 | #endif | ||
| 14134 | while (stat(fullname, &statb) < 0) { | 15538 | while (stat(fullname, &statb) < 0) { |
| 14135 | #ifdef SYSV | 15539 | #ifdef SYSV |
| 14136 | if (errno == EINTR) | 15540 | if (errno == EINTR) |
| @@ -14268,19 +15672,45 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14268 | if (LONE_DASH(action)) | 15672 | if (LONE_DASH(action)) |
| 14269 | action = NULL; | 15673 | action = NULL; |
| 14270 | else { | 15674 | else { |
| 15675 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14271 | if (action[0]) /* not NULL and not "" and not "-" */ | 15676 | if (action[0]) /* not NULL and not "" and not "-" */ |
| 14272 | may_have_traps = 1; | 15677 | may_have_traps = 1; |
| 15678 | #endif | ||
| 14273 | action = ckstrdup(action); | 15679 | action = ckstrdup(action); |
| 14274 | } | 15680 | } |
| 14275 | } | 15681 | } |
| 14276 | free(trap[signo]); | 15682 | free(trap[signo]); |
| 14277 | trap[signo] = action; | 15683 | trap[signo] = action; |
| 15684 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15685 | if (signo == SIGINT) { | ||
| 15686 | // trap '' INT disables Ctrl-C, anything else enables it | ||
| 15687 | if (action && action[0] == '\0') { | ||
| 15688 | SetConsoleCtrlHandler(NULL, TRUE); | ||
| 15689 | # if ENABLE_FEATURE_EDITING | ||
| 15690 | if (line_input_state) { | ||
| 15691 | line_input_state->flags |= IGNORE_CTRL_C; | ||
| 15692 | } | ||
| 15693 | # endif | ||
| 15694 | } else { | ||
| 15695 | SetConsoleCtrlHandler(NULL, FALSE); | ||
| 15696 | # if ENABLE_FEATURE_EDITING | ||
| 15697 | if (line_input_state) { | ||
| 15698 | line_input_state->flags &= ~IGNORE_CTRL_C; | ||
| 15699 | } | ||
| 15700 | # endif | ||
| 15701 | } | ||
| 15702 | } | ||
| 15703 | #else | ||
| 14278 | if (signo != 0 && signo < NSIG) | 15704 | if (signo != 0 && signo < NSIG) |
| 14279 | setsignal(signo); | 15705 | setsignal(signo); |
| 15706 | #endif | ||
| 14280 | INTON; | 15707 | INTON; |
| 14281 | next: | 15708 | next: |
| 14282 | ap++; | 15709 | ap++; |
| 14283 | } | 15710 | } |
| 15711 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15712 | may_have_traps = trap[SIGINT] && trap[SIGINT][0] != '\0'; | ||
| 15713 | #endif | ||
| 14284 | return exitcode; | 15714 | return exitcode; |
| 14285 | } | 15715 | } |
| 14286 | 15716 | ||
| @@ -14309,10 +15739,12 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14309 | { | 15739 | { |
| 14310 | const char *a = applet_names; | 15740 | const char *a = applet_names; |
| 14311 | while (*a) { | 15741 | while (*a) { |
| 14312 | col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a); | 15742 | if (prefer_applet(a, pathval())) { |
| 14313 | if (col > 60) { | 15743 | col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a); |
| 14314 | out1fmt("\n"); | 15744 | if (col > 60) { |
| 14315 | col = 0; | 15745 | out1fmt("\n"); |
| 15746 | col = 0; | ||
| 15747 | } | ||
| 14316 | } | 15748 | } |
| 14317 | while (*a++ != '\0') | 15749 | while (*a++ != '\0') |
| 14318 | continue; | 15750 | continue; |
| @@ -14374,7 +15806,24 @@ exportcmd(int argc UNUSED_PARAM, char **argv) | |||
| 14374 | } else { | 15806 | } else { |
| 14375 | vp = *findvar(name); | 15807 | vp = *findvar(name); |
| 14376 | if (vp) { | 15808 | if (vp) { |
| 15809 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15810 | if (is_bb_var(name) == BB_VAR_EXACT) { | ||
| 15811 | if (flag_off == ~VEXPORT) | ||
| 15812 | unsetenv(name); | ||
| 15813 | else if (flag == VEXPORT && !(vp->flags & VUNSET)) | ||
| 15814 | putenv(vp->var_text); | ||
| 15815 | } | ||
| 15816 | #endif | ||
| 14377 | vp->flags = ((vp->flags | flag) & flag_off); | 15817 | vp->flags = ((vp->flags | flag) & flag_off); |
| 15818 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15819 | /* Unexporting a variable imported from the | ||
| 15820 | * environment restores its original value and | ||
| 15821 | * removes the VIMPORT flag. */ | ||
| 15822 | if ((vp->flags & VIMPORT) && (flag_off == ~VEXPORT)) { | ||
| 15823 | vp->flags &= ~VIMPORT; | ||
| 15824 | p = getenv(name); | ||
| 15825 | } else | ||
| 15826 | #endif | ||
| 14378 | continue; | 15827 | continue; |
| 14379 | } | 15828 | } |
| 14380 | } | 15829 | } |
| @@ -14465,6 +15914,21 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14465 | return 0; | 15914 | return 0; |
| 14466 | } | 15915 | } |
| 14467 | 15916 | ||
| 15917 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15918 | static int FAST_FUNC | ||
| 15919 | titlecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | ||
| 15920 | { | ||
| 15921 | if (*argptr == NULL) { | ||
| 15922 | char buffer[256]; | ||
| 15923 | if (get_title(buffer, sizeof(buffer))) | ||
| 15924 | puts(buffer); | ||
| 15925 | } else { | ||
| 15926 | set_title(*argptr); | ||
| 15927 | } | ||
| 15928 | return 0; | ||
| 15929 | } | ||
| 15930 | #endif | ||
| 15931 | |||
| 14468 | #if ENABLE_FEATURE_SH_MATH | 15932 | #if ENABLE_FEATURE_SH_MATH |
| 14469 | /* | 15933 | /* |
| 14470 | * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell. | 15934 | * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell. |
| @@ -14557,6 +16021,7 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14557 | r = shell_builtin_read(¶ms); | 16021 | r = shell_builtin_read(¶ms); |
| 14558 | INTON; | 16022 | INTON; |
| 14559 | 16023 | ||
| 16024 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14560 | if ((uintptr_t)r == 1 && errno == EINTR) { | 16025 | if ((uintptr_t)r == 1 && errno == EINTR) { |
| 14561 | /* To get SIGCHLD: sleep 1 & read x; echo $x | 16026 | /* To get SIGCHLD: sleep 1 & read x; echo $x |
| 14562 | * Correct behavior is to not exit "read" | 16027 | * Correct behavior is to not exit "read" |
| @@ -14569,6 +16034,29 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14569 | /* bash: "The exit status is greater than 128 if the timeout is exceeded." */ | 16034 | /* bash: "The exit status is greater than 128 if the timeout is exceeded." */ |
| 14570 | /* The actual value observed with bash 5.2.15: */ | 16035 | /* The actual value observed with bash 5.2.15: */ |
| 14571 | return 128 + SIGALRM; | 16036 | return 128 + SIGALRM; |
| 16037 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
| 16038 | if ((uintptr_t)r == 2) { | ||
| 16039 | /* Timeout, return 128 + SIGALRM */ | ||
| 16040 | return 142; | ||
| 16041 | } else if ((uintptr_t)r == 3) { | ||
| 16042 | /* ^C pressed, propagate event */ | ||
| 16043 | if (trap[SIGINT]) { | ||
| 16044 | write_ctrl_c(); | ||
| 16045 | pending_int = 1; | ||
| 16046 | dotrap(); | ||
| 16047 | if (!(rootshell && iflag)) | ||
| 16048 | return (uintptr_t)0; | ||
| 16049 | else | ||
| 16050 | goto again; | ||
| 16051 | } else if (iflag) { | ||
| 16052 | raise_interrupt(); | ||
| 16053 | } else { | ||
| 16054 | GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); | ||
| 16055 | exitshell(); | ||
| 16056 | } | ||
| 16057 | return (uintptr_t)r; | ||
| 16058 | } | ||
| 16059 | #endif | ||
| 14572 | 16060 | ||
| 14573 | if ((uintptr_t)r > 1) | 16061 | if ((uintptr_t)r > 1) |
| 14574 | ash_msg_and_raise_error(r); | 16062 | ash_msg_and_raise_error(r); |
| @@ -14630,6 +16118,9 @@ umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14630 | if (!isdigit(modestr[0])) | 16118 | if (!isdigit(modestr[0])) |
| 14631 | mask ^= 0777; | 16119 | mask ^= 0777; |
| 14632 | umask(mask); | 16120 | umask(mask); |
| 16121 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16122 | setvareq(xasprintf("BB_UMASK=0%o", mask), VEXPORT|VNOSAVE); | ||
| 16123 | #endif | ||
| 14633 | } | 16124 | } |
| 14634 | return 0; | 16125 | return 0; |
| 14635 | } | 16126 | } |
| @@ -14730,6 +16221,13 @@ exitshell(void) | |||
| 14730 | /*free(p); - we'll exit soon */ | 16221 | /*free(p); - we'll exit soon */ |
| 14731 | } | 16222 | } |
| 14732 | out: | 16223 | out: |
| 16224 | #if ENABLE_SUW32 | ||
| 16225 | if (delayexit) { | ||
| 16226 | #define EXIT_MSG "Press any key to exit..." | ||
| 16227 | console_write(EXIT_MSG, sizeof(EXIT_MSG) - 1); | ||
| 16228 | _getch(); | ||
| 16229 | } | ||
| 16230 | #endif | ||
| 14733 | exitreset(); | 16231 | exitreset(); |
| 14734 | /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". | 16232 | /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". |
| 14735 | * our setjobctl(0) does not panic if tcsetpgrp fails inside it. | 16233 | * our setjobctl(0) does not panic if tcsetpgrp fails inside it. |
| @@ -14740,22 +16238,99 @@ exitshell(void) | |||
| 14740 | /* NOTREACHED */ | 16238 | /* NOTREACHED */ |
| 14741 | } | 16239 | } |
| 14742 | 16240 | ||
| 16241 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16242 | /* We need to see if HOME is *really* unset */ | ||
| 16243 | # undef getenv | ||
| 16244 | static void setvar_if_unset(const char *key, const char *value) | ||
| 16245 | { | ||
| 16246 | if (!getenv(key) || getuid() == 0) | ||
| 16247 | setvar(key, value, VEXPORT); | ||
| 16248 | } | ||
| 16249 | #endif | ||
| 16250 | |||
| 14743 | /* Don't inline: conserve stack of caller from having our locals too */ | 16251 | /* Don't inline: conserve stack of caller from having our locals too */ |
| 14744 | static NOINLINE void | 16252 | static NOINLINE void |
| 14745 | init(void) | 16253 | init(void) |
| 14746 | { | 16254 | { |
| 16255 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16256 | int import = 0; | ||
| 16257 | #endif | ||
| 16258 | |||
| 14747 | /* we will never free this */ | 16259 | /* we will never free this */ |
| 14748 | basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ); | 16260 | basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ); |
| 14749 | basepf.linno = 1; | 16261 | basepf.linno = 1; |
| 14750 | 16262 | ||
| 16263 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14751 | sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ | 16264 | sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ |
| 14752 | setsignal(SIGCHLD); | 16265 | setsignal(SIGCHLD); |
| 16266 | #endif | ||
| 14753 | 16267 | ||
| 14754 | { | 16268 | { |
| 14755 | char **envp; | 16269 | char **envp; |
| 14756 | const char *p; | 16270 | const char *p; |
| 14757 | 16271 | ||
| 14758 | initvar(); | 16272 | initvar(); |
| 16273 | |||
| 16274 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16275 | /* | ||
| 16276 | * case insensitive env names from Windows world | ||
| 16277 | * | ||
| 16278 | * Some standard env names such as PATH is named Path and so on | ||
| 16279 | * ash itself is case sensitive, so "Path" will confuse it, as | ||
| 16280 | * MSVC getenv() is case insensitive. | ||
| 16281 | * | ||
| 16282 | * We may end up having both Path and PATH. Then Path will be chosen | ||
| 16283 | * because it appears first. | ||
| 16284 | */ | ||
| 16285 | if (windows_env()) { | ||
| 16286 | /* | ||
| 16287 | * If we get here it's because the environment suggests we | ||
| 16288 | * haven't been invoked from an earlier instance of BusyBox. | ||
| 16289 | */ | ||
| 16290 | char *start, *end; | ||
| 16291 | struct passwd *pw; | ||
| 16292 | |||
| 16293 | /* mintty sets HOME: unset it */ | ||
| 16294 | const char *tty = getenv("TERM_PROGRAM"); | ||
| 16295 | if (tty && strcmp(tty, "mintty") == 0) { | ||
| 16296 | unsetenv("HOME"); | ||
| 16297 | } | ||
| 16298 | |||
| 16299 | import = VIMPORT; | ||
| 16300 | for (envp = environ; envp && *envp; envp++) { | ||
| 16301 | if (!(end=strchr(*envp, '='))) | ||
| 16302 | continue; | ||
| 16303 | |||
| 16304 | /* check for invalid characters in name */ | ||
| 16305 | start = (char *)endofname(*envp); | ||
| 16306 | if (*start != '=') { | ||
| 16307 | /* Make a copy of the original variable */ | ||
| 16308 | setvareq(xstrdup(*envp), VEXPORT|VNOSAVE); | ||
| 16309 | |||
| 16310 | /* Replace invalid characters with underscores */ | ||
| 16311 | for (; start < end; start++) { | ||
| 16312 | if (!isalnum(*start)) { | ||
| 16313 | *start = '_'; | ||
| 16314 | } | ||
| 16315 | } | ||
| 16316 | } | ||
| 16317 | |||
| 16318 | /* make all variable names uppercase */ | ||
| 16319 | for (start = *envp;start < end;start++) | ||
| 16320 | *start = toupper(*start); | ||
| 16321 | } | ||
| 16322 | |||
| 16323 | /* Initialise some variables normally set at login, but | ||
| 16324 | * only if someone hasn't already set them or we're root. */ | ||
| 16325 | pw = getpwuid(getuid()); | ||
| 16326 | if (pw) { | ||
| 16327 | setvar_if_unset("USER", pw->pw_name); | ||
| 16328 | setvar_if_unset("LOGNAME", pw->pw_name); | ||
| 16329 | setvar_if_unset("HOME", pw->pw_dir); | ||
| 16330 | } | ||
| 16331 | setvar_if_unset("SHELL", DEFAULT_SHELL); | ||
| 16332 | } | ||
| 16333 | #endif | ||
| 14759 | for (envp = environ; envp && *envp; envp++) { | 16334 | for (envp = environ; envp && *envp; envp++) { |
| 14760 | /* Used to have | 16335 | /* Used to have |
| 14761 | * p = endofname(*envp); | 16336 | * p = endofname(*envp); |
| @@ -14769,7 +16344,11 @@ init(void) | |||
| 14769 | * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this | 16344 | * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this |
| 14770 | */ | 16345 | */ |
| 14771 | if (strchr(*envp, '=')) { | 16346 | if (strchr(*envp, '=')) { |
| 16347 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14772 | setvareq(*envp, VEXPORT|VTEXTFIXED); | 16348 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
| 16349 | #else | ||
| 16350 | setvareq(*envp, VEXPORT|import); | ||
| 16351 | #endif | ||
| 14773 | } | 16352 | } |
| 14774 | } | 16353 | } |
| 14775 | 16354 | ||
| @@ -14816,7 +16395,11 @@ procargs(char **xargv) | |||
| 14816 | int i; | 16395 | int i; |
| 14817 | int login_sh; | 16396 | int login_sh; |
| 14818 | 16397 | ||
| 16398 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16399 | login_sh = applet_name[0] == 'l'; | ||
| 16400 | #else | ||
| 14819 | login_sh = /*xargv[0] &&*/ xargv[0][0] == '-'; | 16401 | login_sh = /*xargv[0] &&*/ xargv[0][0] == '-'; |
| 16402 | #endif | ||
| 14820 | #if NUM_SCRIPTS > 0 | 16403 | #if NUM_SCRIPTS > 0 |
| 14821 | if (minusc) | 16404 | if (minusc) |
| 14822 | goto setarg0; | 16405 | goto setarg0; |
| @@ -14839,7 +16422,9 @@ procargs(char **xargv) | |||
| 14839 | } | 16422 | } |
| 14840 | if (iflag == 2 /* no explicit -i given */ | 16423 | if (iflag == 2 /* no explicit -i given */ |
| 14841 | && sflag == 1 /* -s given (or implied) */ | 16424 | && sflag == 1 /* -s given (or implied) */ |
| 16425 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14842 | && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */ | 16426 | && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */ |
| 16427 | #endif | ||
| 14843 | && isatty(0) && isatty(1) /* we are on tty */ | 16428 | && isatty(0) && isatty(1) /* we are on tty */ |
| 14844 | ) { | 16429 | ) { |
| 14845 | iflag = 1; | 16430 | iflag = 1; |
| @@ -14859,6 +16444,9 @@ procargs(char **xargv) | |||
| 14859 | goto setarg0; | 16444 | goto setarg0; |
| 14860 | } else if (!sflag) { | 16445 | } else if (!sflag) { |
| 14861 | setinputfile(*xargv, 0); | 16446 | setinputfile(*xargv, 0); |
| 16447 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16448 | bs_to_slash(*xargv); | ||
| 16449 | #endif | ||
| 14862 | setarg0: | 16450 | setarg0: |
| 14863 | arg0 = *xargv++; | 16451 | arg0 = *xargv++; |
| 14864 | } | 16452 | } |
| @@ -14881,8 +16469,10 @@ procargs(char **xargv) | |||
| 14881 | * NB: must do it before setting up signals (in optschanged()) | 16469 | * NB: must do it before setting up signals (in optschanged()) |
| 14882 | * and reading .profile etc (after we return from here): | 16470 | * and reading .profile etc (after we return from here): |
| 14883 | */ | 16471 | */ |
| 16472 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14884 | if (iflag) | 16473 | if (iflag) |
| 14885 | signal(SIGHUP, SIG_DFL); | 16474 | signal(SIGHUP, SIG_DFL); |
| 16475 | #endif | ||
| 14886 | 16476 | ||
| 14887 | optschanged(); | 16477 | optschanged(); |
| 14888 | 16478 | ||
| @@ -14926,9 +16516,21 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14926 | struct stackmark smark; | 16516 | struct stackmark smark; |
| 14927 | int login_sh; | 16517 | int login_sh; |
| 14928 | 16518 | ||
| 16519 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16520 | INIT_G_memstack(); | ||
| 16521 | |||
| 16522 | if (argc == 3 && !strcmp(argv[1], "--fs")) { | ||
| 16523 | forkshell_init(argv[2]); | ||
| 16524 | /* only reached in case of error */ | ||
| 16525 | bb_error_msg_and_die("forkshell failed"); | ||
| 16526 | } | ||
| 16527 | #endif | ||
| 16528 | |||
| 14929 | /* Initialize global data */ | 16529 | /* Initialize global data */ |
| 14930 | INIT_G_misc(); | 16530 | INIT_G_misc(); |
| 16531 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14931 | INIT_G_memstack(); | 16532 | INIT_G_memstack(); |
| 16533 | #endif | ||
| 14932 | INIT_G_var(); | 16534 | INIT_G_var(); |
| 14933 | #if ENABLE_ASH_ALIAS | 16535 | #if ENABLE_ASH_ALIAS |
| 14934 | INIT_G_alias(); | 16536 | INIT_G_alias(); |
| @@ -14974,6 +16576,10 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14974 | init(); | 16576 | init(); |
| 14975 | setstackmark(&smark); | 16577 | setstackmark(&smark); |
| 14976 | 16578 | ||
| 16579 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16580 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
| 16581 | #endif | ||
| 16582 | |||
| 14977 | #if NUM_SCRIPTS > 0 | 16583 | #if NUM_SCRIPTS > 0 |
| 14978 | if (argc < 0) | 16584 | if (argc < 0) |
| 14979 | /* Non-NULL minusc tells procargs that an embedded script is being run */ | 16585 | /* Non-NULL minusc tells procargs that an embedded script is being run */ |
| @@ -14985,11 +16591,45 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14985 | trace_puts_args(argv); | 16591 | trace_puts_args(argv); |
| 14986 | #endif | 16592 | #endif |
| 14987 | 16593 | ||
| 16594 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16595 | if (!dirarg && !login_sh && iflag) { | ||
| 16596 | char *cwd = getcwd(NULL, 0); | ||
| 16597 | if (cwd) { | ||
| 16598 | chdir(cwd); | ||
| 16599 | setpwd(NULL, 0); | ||
| 16600 | free(cwd); | ||
| 16601 | } | ||
| 16602 | } | ||
| 16603 | |||
| 16604 | if (title) | ||
| 16605 | set_title(title); | ||
| 16606 | #endif | ||
| 16607 | |||
| 14988 | if (login_sh) { | 16608 | if (login_sh) { |
| 14989 | const char *hp; | 16609 | const char *hp; |
| 14990 | 16610 | ||
| 16611 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16612 | if (!dirarg) { | ||
| 16613 | hp = lookupvar("HOME"); | ||
| 16614 | if (hp == NULL || *hp == '\0') | ||
| 16615 | hp = xgetpwuid(getuid())->pw_dir; | ||
| 16616 | chdir(hp); | ||
| 16617 | setpwd(NULL, 0); | ||
| 16618 | } | ||
| 16619 | #endif | ||
| 16620 | |||
| 14991 | state = 1; | 16621 | state = 1; |
| 16622 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16623 | hp = concat_path_file(get_system_drive(), "/etc/profile"); | ||
| 16624 | read_profile(hp); | ||
| 16625 | free((void *)hp); | ||
| 16626 | |||
| 16627 | hp = exe_relative_path("/etc/profile"); | ||
| 16628 | read_profile(hp); | ||
| 16629 | free((void *)hp); | ||
| 16630 | #else | ||
| 14992 | read_profile("/etc/profile"); | 16631 | read_profile("/etc/profile"); |
| 16632 | #endif | ||
| 14993 | state1: | 16633 | state1: |
| 14994 | state = 2; | 16634 | state = 2; |
| 14995 | hp = lookupvar("HOME"); | 16635 | hp = lookupvar("HOME"); |
| @@ -14998,10 +16638,18 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14998 | } | 16638 | } |
| 14999 | state2: | 16639 | state2: |
| 15000 | state = 3; | 16640 | state = 3; |
| 16641 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16642 | if (dirarg) { | ||
| 16643 | chdir(dirarg); | ||
| 16644 | setpwd(NULL, 0); | ||
| 16645 | } | ||
| 16646 | #endif | ||
| 15001 | if (iflag | 16647 | if (iflag |
| 16648 | #if ENABLE_PLATFORM_POSIX | ||
| 15002 | #ifndef linux | 16649 | #ifndef linux |
| 15003 | && getuid() == geteuid() && getgid() == getegid() | 16650 | && getuid() == geteuid() && getgid() == getegid() |
| 15004 | #endif | 16651 | #endif |
| 16652 | #endif | ||
| 15005 | ) { | 16653 | ) { |
| 15006 | const char *shinit = lookupvar("ENV"); | 16654 | const char *shinit = lookupvar("ENV"); |
| 15007 | if (shinit != NULL && *shinit != '\0') | 16655 | if (shinit != NULL && *shinit != '\0') |
| @@ -15026,7 +16674,11 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 15026 | // ash -sc 'echo $-' | 16674 | // ash -sc 'echo $-' |
| 15027 | // continue reading input from stdin after running 'echo'. | 16675 | // continue reading input from stdin after running 'echo'. |
| 15028 | // bash does not do this: it prints "hBcs" and exits. | 16676 | // bash does not do this: it prints "hBcs" and exits. |
| 16677 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 15029 | evalstring(minusc, EV_EXIT); | 16678 | evalstring(minusc, EV_EXIT); |
| 16679 | #else | ||
| 16680 | evalstring(minusc, sflag ? 0 : EV_EXIT); | ||
| 16681 | #endif | ||
| 15030 | } | 16682 | } |
| 15031 | 16683 | ||
| 15032 | if (sflag || minusc == NULL) { | 16684 | if (sflag || minusc == NULL) { |
| @@ -15074,6 +16726,1110 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 15074 | /* NOTREACHED */ | 16726 | /* NOTREACHED */ |
| 15075 | } | 16727 | } |
| 15076 | 16728 | ||
| 16729 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16730 | static void | ||
| 16731 | forkshell_openhere(struct forkshell *fs) | ||
| 16732 | { | ||
| 16733 | const char *p = fs->path; | ||
| 16734 | size_t len = strlen(p); | ||
| 16735 | int pip[2]; | ||
| 16736 | |||
| 16737 | pip[0] = fs->fd[0]; | ||
| 16738 | pip[1] = fs->fd[1]; | ||
| 16739 | |||
| 16740 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
| 16741 | |||
| 16742 | close(pip[0]); | ||
| 16743 | ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); | ||
| 16744 | ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); | ||
| 16745 | ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); | ||
| 16746 | ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); | ||
| 16747 | signal(SIGPIPE, SIG_DFL); | ||
| 16748 | xwrite(pip[1], p, len); | ||
| 16749 | _exit_SUCCESS(); | ||
| 16750 | } | ||
| 16751 | |||
| 16752 | static void | ||
| 16753 | forkshell_evalbackcmd(struct forkshell *fs) | ||
| 16754 | { | ||
| 16755 | #if BASH_PROCESS_SUBST | ||
| 16756 | /* determine end of pipe used by parent (ip) and child (ic) */ | ||
| 16757 | const int ctl = fs->fd[2]; | ||
| 16758 | const int ip = (ctl == CTLTOPROC); | ||
| 16759 | const int ic = !(ctl == CTLTOPROC); | ||
| 16760 | #else | ||
| 16761 | const int ip = 0; | ||
| 16762 | const int ic = 1; | ||
| 16763 | #endif | ||
| 16764 | union node *n = fs->n; | ||
| 16765 | int pip[2]; | ||
| 16766 | |||
| 16767 | pip[ip] = fs->fd[ip]; | ||
| 16768 | pip[ic] = fs->fd[ic]; | ||
| 16769 | |||
| 16770 | FORCEINTON; | ||
| 16771 | close(pip[ip]); | ||
| 16772 | if (pip[ic] != ic) { | ||
| 16773 | /*close(ic);*/ | ||
| 16774 | dup2_or_raise(pip[ic], ic); | ||
| 16775 | close(pip[ic]); | ||
| 16776 | } | ||
| 16777 | eflag = 0; | ||
| 16778 | ifsfree(); | ||
| 16779 | evaltreenr(n, EV_EXIT); | ||
| 16780 | /* NOTREACHED */ | ||
| 16781 | } | ||
| 16782 | |||
| 16783 | static void | ||
| 16784 | forkshell_evalsubshell(struct forkshell *fs) | ||
| 16785 | { | ||
| 16786 | union node *n = fs->n; | ||
| 16787 | int flags = fs->flags; | ||
| 16788 | |||
| 16789 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
| 16790 | INTON; | ||
| 16791 | flags |= EV_EXIT; | ||
| 16792 | if (fs->mode) | ||
| 16793 | flags &= ~EV_TESTED; | ||
| 16794 | expredir(n->nredir.redirect); | ||
| 16795 | redirect(n->nredir.redirect, 0); | ||
| 16796 | evaltreenr(n->nredir.n, flags); | ||
| 16797 | /* never returns */ | ||
| 16798 | } | ||
| 16799 | |||
| 16800 | static void | ||
| 16801 | forkshell_evalpipe(struct forkshell *fs) | ||
| 16802 | { | ||
| 16803 | union node *n = fs->n; | ||
| 16804 | int flags = fs->flags; | ||
| 16805 | int prevfd = fs->fd[2]; | ||
| 16806 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
| 16807 | |||
| 16808 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
| 16809 | INTON; | ||
| 16810 | if (pip[1] >= 0) { | ||
| 16811 | close(pip[0]); | ||
| 16812 | } | ||
| 16813 | if (prevfd > 0) { | ||
| 16814 | dup2(prevfd, 0); | ||
| 16815 | close(prevfd); | ||
| 16816 | } | ||
| 16817 | if (pip[1] > 1) { | ||
| 16818 | dup2(pip[1], 1); | ||
| 16819 | close(pip[1]); | ||
| 16820 | } | ||
| 16821 | evaltreenr(n, flags); | ||
| 16822 | } | ||
| 16823 | |||
| 16824 | static void | ||
| 16825 | forkshell_shellexec(struct forkshell *fs) | ||
| 16826 | { | ||
| 16827 | int idx = fs->fd[0]; | ||
| 16828 | char **argv = fs->argv; | ||
| 16829 | const char *path = fs->path; | ||
| 16830 | |||
| 16831 | FORCEINTON; | ||
| 16832 | shellexec(argv[0], argv, path, idx, TRUE); | ||
| 16833 | } | ||
| 16834 | |||
| 16835 | static void | ||
| 16836 | forkshell_child(struct forkshell *fs) | ||
| 16837 | { | ||
| 16838 | switch ( fs->fpid ) { | ||
| 16839 | case FS_OPENHERE: | ||
| 16840 | forkshell_openhere(fs); | ||
| 16841 | break; | ||
| 16842 | case FS_EVALBACKCMD: | ||
| 16843 | forkshell_evalbackcmd(fs); | ||
| 16844 | break; | ||
| 16845 | case FS_EVALSUBSHELL: | ||
| 16846 | forkshell_evalsubshell(fs); | ||
| 16847 | break; | ||
| 16848 | case FS_EVALPIPE: | ||
| 16849 | forkshell_evalpipe(fs); | ||
| 16850 | break; | ||
| 16851 | case FS_SHELLEXEC: | ||
| 16852 | forkshell_shellexec(fs); | ||
| 16853 | break; | ||
| 16854 | } | ||
| 16855 | } | ||
| 16856 | |||
| 16857 | /* | ||
| 16858 | * Reinitialise the builtin environment variables in varinit. Their | ||
| 16859 | * current settings have been copied from the parent in vartab. Look | ||
| 16860 | * these up using the names from varinit_data, copy the details from | ||
| 16861 | * vartab to varinit and replace the old copy in vartab with the new | ||
| 16862 | * one in varinit. | ||
| 16863 | * | ||
| 16864 | * Also reinitialise the function pointers and line number variable. | ||
| 16865 | */ | ||
| 16866 | static void | ||
| 16867 | reinitvar(void) | ||
| 16868 | { | ||
| 16869 | int i; | ||
| 16870 | const char *name; | ||
| 16871 | struct var **old; | ||
| 16872 | |||
| 16873 | for (i=0; i<ARRAY_SIZE(varinit); ++i) { | ||
| 16874 | if (i == LINENO_INDEX) | ||
| 16875 | name = "LINENO="; | ||
| 16876 | else if (i == FUNCNAME_INDEX) | ||
| 16877 | name = "FUNCNAME="; | ||
| 16878 | else | ||
| 16879 | name = varinit_data[i].var_text; | ||
| 16880 | if ((old = findvar(name)) != NULL) { | ||
| 16881 | varinit[i] = **old; | ||
| 16882 | *old = varinit+i; | ||
| 16883 | } | ||
| 16884 | varinit[i].var_func = varinit_data[i].var_func; | ||
| 16885 | } | ||
| 16886 | vlineno.var_text = linenovar; | ||
| 16887 | vfuncname.var_text = funcnamevar; | ||
| 16888 | } | ||
| 16889 | |||
| 16890 | static void | ||
| 16891 | spawn_forkshell(struct forkshell *fs, struct job *jp, union node *n, int mode) | ||
| 16892 | { | ||
| 16893 | struct forkshell *new; | ||
| 16894 | char buf[32]; | ||
| 16895 | const char *argv[] = { "sh", "--fs", NULL, NULL }; | ||
| 16896 | intptr_t ret; | ||
| 16897 | |||
| 16898 | new = forkshell_prepare(fs); | ||
| 16899 | if (new == NULL) | ||
| 16900 | goto fail; | ||
| 16901 | |||
| 16902 | new->mode = mode; | ||
| 16903 | new->nprocs = jp == NULL ? 0 : jp->nprocs; | ||
| 16904 | #if JOBS_WIN32 | ||
| 16905 | new->jpnull = jp == NULL; | ||
| 16906 | #endif | ||
| 16907 | sprintf(buf, "%p", new->hMapFile); | ||
| 16908 | argv[2] = buf; | ||
| 16909 | ret = spawnve(P_NOWAIT, bb_busybox_exec_path, (char *const *)argv, NULL); | ||
| 16910 | CloseHandle(new->hMapFile); | ||
| 16911 | UnmapViewOfFile(new); | ||
| 16912 | if (ret == -1) { | ||
| 16913 | fail: | ||
| 16914 | if (jp) | ||
| 16915 | freejob(jp); | ||
| 16916 | ash_msg_and_raise_error("unable to spawn shell"); | ||
| 16917 | } | ||
| 16918 | forkparent(jp, n, mode, (HANDLE)ret); | ||
| 16919 | } | ||
| 16920 | |||
| 16921 | /* | ||
| 16922 | * forkshell_prepare() and friends | ||
| 16923 | * | ||
| 16924 | * The sequence is as follows: | ||
| 16925 | * - funcblocksize is initialized | ||
| 16926 | * - forkshell_size(fs) is called to calculate the exact memory needed | ||
| 16927 | * - a new struct is allocated | ||
| 16928 | * - funcblock, funcstring, relocate are initialized from the new block | ||
| 16929 | * - forkshell_copy(fs) is called to copy recursively everything over | ||
| 16930 | * it will record all relocations along the way | ||
| 16931 | * | ||
| 16932 | * When this memory is mapped elsewhere, pointer fixup will be needed | ||
| 16933 | */ | ||
| 16934 | |||
| 16935 | /* redefine without test that fs_size is nonzero */ | ||
| 16936 | #undef SAVE_PTR | ||
| 16937 | #undef SAVE_PTR2 | ||
| 16938 | #undef SAVE_PTR3 | ||
| 16939 | #define SAVE_PTR(dst,note,flag) {MARK_PTR(dst,note,flag);} | ||
| 16940 | |||
| 16941 | static int align_len(const char *s) | ||
| 16942 | { | ||
| 16943 | return s ? SHELL_ALIGN(strlen(s)+1) : 0; | ||
| 16944 | } | ||
| 16945 | |||
| 16946 | struct datasize { | ||
| 16947 | int funcblocksize; | ||
| 16948 | int funcstringsize; | ||
| 16949 | }; | ||
| 16950 | |||
| 16951 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
| 16952 | static struct datasize \ | ||
| 16953 | name(struct datasize ds, type *p) \ | ||
| 16954 | { \ | ||
| 16955 | while (p) { \ | ||
| 16956 | ds.funcblocksize += sizeof(type); | ||
| 16957 | /* do something here with p */ | ||
| 16958 | #define SLIST_SIZE_END() \ | ||
| 16959 | p = p->next; \ | ||
| 16960 | } \ | ||
| 16961 | return ds; \ | ||
| 16962 | } | ||
| 16963 | |||
| 16964 | #define SLIST_COPY_BEGIN(name,type) \ | ||
| 16965 | static type * \ | ||
| 16966 | name(type *vp) \ | ||
| 16967 | { \ | ||
| 16968 | type *start; \ | ||
| 16969 | type **vpp; \ | ||
| 16970 | vpp = &start; \ | ||
| 16971 | while (vp) { \ | ||
| 16972 | *vpp = funcblock; \ | ||
| 16973 | funcblock = (char *) funcblock + sizeof(type); | ||
| 16974 | /* do something here with vpp and vp */ | ||
| 16975 | #define SLIST_COPY_END() \ | ||
| 16976 | SAVE_PTR((*vpp)->next, "(*vpp)->next", NO_FREE); \ | ||
| 16977 | vp = vp->next; \ | ||
| 16978 | vpp = &(*vpp)->next; \ | ||
| 16979 | } \ | ||
| 16980 | *vpp = NULL; \ | ||
| 16981 | return start; \ | ||
| 16982 | } | ||
| 16983 | |||
| 16984 | /* | ||
| 16985 | * struct var | ||
| 16986 | */ | ||
| 16987 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
| 16988 | ds.funcstringsize += align_len(p->var_text); | ||
| 16989 | SLIST_SIZE_END() | ||
| 16990 | |||
| 16991 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
| 16992 | (*vpp)->var_text = nodeckstrdup(vp->var_text); | ||
| 16993 | (*vpp)->flags = vp->flags; | ||
| 16994 | (*vpp)->var_func = NULL; | ||
| 16995 | SAVE_PTR((*vpp)->var_text, xasprintf("(*vpp)->var_text '%s'", vp->var_text ?: "NULL"), FREE); | ||
| 16996 | SLIST_COPY_END() | ||
| 16997 | |||
| 16998 | /* | ||
| 16999 | * struct tblentry | ||
| 17000 | */ | ||
| 17001 | static struct datasize | ||
| 17002 | tblentry_size(struct datasize ds, struct tblentry *tep) | ||
| 17003 | { | ||
| 17004 | while (tep) { | ||
| 17005 | ds.funcblocksize += sizeof(struct tblentry) + align_len(tep->cmdname); | ||
| 17006 | /* CMDBUILTIN, e->param.cmd needs no pointer relocation */ | ||
| 17007 | if (tep->cmdtype == CMDFUNCTION) { | ||
| 17008 | ds.funcblocksize += offsetof(struct funcnode, n); | ||
| 17009 | ds.funcblocksize = calcsize(ds.funcblocksize, &tep->param.func->n); | ||
| 17010 | } | ||
| 17011 | tep = tep->next; | ||
| 17012 | } | ||
| 17013 | return ds; | ||
| 17014 | } | ||
| 17015 | |||
| 17016 | static struct tblentry * | ||
| 17017 | tblentry_copy(struct tblentry *tep) | ||
| 17018 | { | ||
| 17019 | struct tblentry *start; | ||
| 17020 | struct tblentry **newp; | ||
| 17021 | int size; | ||
| 17022 | |||
| 17023 | newp = &start; | ||
| 17024 | while (tep) { | ||
| 17025 | *newp = funcblock; | ||
| 17026 | size = sizeof(struct tblentry) + align_len(tep->cmdname); | ||
| 17027 | |||
| 17028 | funcblock = (char *) funcblock + size; | ||
| 17029 | memcpy(*newp, tep, sizeof(struct tblentry)+strlen(tep->cmdname)); | ||
| 17030 | switch (tep->cmdtype) { | ||
| 17031 | case CMDBUILTIN: | ||
| 17032 | /* Save index of builtin, not pointer; fixed by forkshell_init() */ | ||
| 17033 | (*newp)->param.index = tep->param.cmd - builtintab; | ||
| 17034 | break; | ||
| 17035 | case CMDFUNCTION: | ||
| 17036 | (*newp)->param.func = funcblock; | ||
| 17037 | funcblock = (char *) funcblock + offsetof(struct funcnode, n); | ||
| 17038 | copynode(&tep->param.func->n); | ||
| 17039 | SAVE_PTR((*newp)->param.func, "param.func", NO_FREE); | ||
| 17040 | break; | ||
| 17041 | default: | ||
| 17042 | break; | ||
| 17043 | } | ||
| 17044 | SAVE_PTR((*newp)->next, xasprintf("cmdname '%s'", tep->cmdname), FREE); | ||
| 17045 | tep = tep->next; | ||
| 17046 | newp = &(*newp)->next; | ||
| 17047 | } | ||
| 17048 | *newp = NULL; | ||
| 17049 | return start; | ||
| 17050 | } | ||
| 17051 | |||
| 17052 | static struct datasize | ||
| 17053 | cmdtable_size(struct datasize ds) | ||
| 17054 | { | ||
| 17055 | int i; | ||
| 17056 | ds.funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE; | ||
| 17057 | for (i = 0; i < CMDTABLESIZE; i++) | ||
| 17058 | ds = tblentry_size(ds, cmdtable[i]); | ||
| 17059 | return ds; | ||
| 17060 | } | ||
| 17061 | |||
| 17062 | static struct tblentry ** | ||
| 17063 | cmdtable_copy(void) | ||
| 17064 | { | ||
| 17065 | struct tblentry **new = funcblock; | ||
| 17066 | int i; | ||
| 17067 | |||
| 17068 | funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE; | ||
| 17069 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
| 17070 | new[i] = tblentry_copy(cmdtable[i]); | ||
| 17071 | SAVE_PTR(new[i], xasprintf("cmdtable[%d]", i), FREE); | ||
| 17072 | } | ||
| 17073 | return new; | ||
| 17074 | } | ||
| 17075 | |||
| 17076 | #if ENABLE_ASH_ALIAS | ||
| 17077 | /* | ||
| 17078 | * struct alias | ||
| 17079 | */ | ||
| 17080 | SLIST_SIZE_BEGIN(alias_size,struct alias) | ||
| 17081 | ds.funcstringsize += align_len(p->name); | ||
| 17082 | ds.funcstringsize += align_len(p->val); | ||
| 17083 | SLIST_SIZE_END() | ||
| 17084 | |||
| 17085 | SLIST_COPY_BEGIN(alias_copy,struct alias) | ||
| 17086 | (*vpp)->name = nodeckstrdup(vp->name); | ||
| 17087 | (*vpp)->val = nodeckstrdup(vp->val); | ||
| 17088 | (*vpp)->flag = vp->flag; | ||
| 17089 | SAVE_PTR((*vpp)->name, xasprintf("(*vpp)->name '%s'", vp->name ?: "NULL"), FREE); | ||
| 17090 | SAVE_PTR((*vpp)->val, xasprintf("(*vpp)->val '%s'", vp->val ?: "NULL"), FREE); | ||
| 17091 | SLIST_COPY_END() | ||
| 17092 | |||
| 17093 | static struct datasize | ||
| 17094 | atab_size(struct datasize ds) | ||
| 17095 | { | ||
| 17096 | int i; | ||
| 17097 | ds.funcblocksize += sizeof(struct alias *)*ATABSIZE; | ||
| 17098 | for (i = 0; i < ATABSIZE; i++) | ||
| 17099 | ds = alias_size(ds, atab[i]); | ||
| 17100 | return ds; | ||
| 17101 | } | ||
| 17102 | |||
| 17103 | static struct alias ** | ||
| 17104 | atab_copy(void) | ||
| 17105 | { | ||
| 17106 | struct alias **new = funcblock; | ||
| 17107 | int i; | ||
| 17108 | |||
| 17109 | funcblock = (char *) funcblock + sizeof(struct alias *)*ATABSIZE; | ||
| 17110 | for (i = 0; i < ATABSIZE; i++) { | ||
| 17111 | new[i] = alias_copy(atab[i]); | ||
| 17112 | SAVE_PTR(new[i], xasprintf("atab[%d]", i), FREE); | ||
| 17113 | } | ||
| 17114 | return new; | ||
| 17115 | } | ||
| 17116 | #endif | ||
| 17117 | |||
| 17118 | /* | ||
| 17119 | * char ** | ||
| 17120 | */ | ||
| 17121 | static struct datasize | ||
| 17122 | argv_size(struct datasize ds, char **p) | ||
| 17123 | { | ||
| 17124 | if (p) { | ||
| 17125 | while (*p) { | ||
| 17126 | ds.funcblocksize += sizeof(char *); | ||
| 17127 | ds.funcstringsize += align_len(*p); | ||
| 17128 | p++; | ||
| 17129 | } | ||
| 17130 | // Allow two extra elements for tryexec(). | ||
| 17131 | ds.funcblocksize += 3 * sizeof(char *); | ||
| 17132 | } | ||
| 17133 | return ds; | ||
| 17134 | } | ||
| 17135 | |||
| 17136 | static char ** | ||
| 17137 | argv_copy(char **p) | ||
| 17138 | { | ||
| 17139 | char **new, **start = funcblock; | ||
| 17140 | #if FORKSHELL_DEBUG | ||
| 17141 | int i = 0; | ||
| 17142 | #endif | ||
| 17143 | |||
| 17144 | if (p) { | ||
| 17145 | // Allow two extra elements for tryexec(). | ||
| 17146 | funcblock = (char *) funcblock + 2 * sizeof(char *); | ||
| 17147 | while (*p) { | ||
| 17148 | new = funcblock; | ||
| 17149 | funcblock = (char *) funcblock + sizeof(char *); | ||
| 17150 | *new = nodeckstrdup(*p); | ||
| 17151 | SAVE_PTR(*new, xasprintf("argv[%d] '%s'", i++, *p), FREE); | ||
| 17152 | p++; | ||
| 17153 | } | ||
| 17154 | new = funcblock; | ||
| 17155 | funcblock = (char *) funcblock + sizeof(char *); | ||
| 17156 | *new = NULL; | ||
| 17157 | return start + 2; | ||
| 17158 | } | ||
| 17159 | return NULL; | ||
| 17160 | } | ||
| 17161 | |||
| 17162 | #if MAX_HISTORY | ||
| 17163 | static struct datasize | ||
| 17164 | history_size(struct datasize ds) | ||
| 17165 | { | ||
| 17166 | int i; | ||
| 17167 | line_input_t *st = line_input_state; | ||
| 17168 | |||
| 17169 | ds.funcblocksize += sizeof(char *) * st->cnt_history; | ||
| 17170 | for (i = 0; i < st->cnt_history; i++) { | ||
| 17171 | ds.funcstringsize += align_len(st->history[i]); | ||
| 17172 | } | ||
| 17173 | return ds; | ||
| 17174 | } | ||
| 17175 | |||
| 17176 | static char ** | ||
| 17177 | history_copy(void) | ||
| 17178 | { | ||
| 17179 | line_input_t *st = line_input_state; | ||
| 17180 | char **new = funcblock; | ||
| 17181 | int i; | ||
| 17182 | |||
| 17183 | funcblock = (char *)funcblock + sizeof(char *) * st->cnt_history; | ||
| 17184 | for (i = 0; i < st->cnt_history; i++) { | ||
| 17185 | new[i] = nodeckstrdup(st->history[i]); | ||
| 17186 | SAVE_PTR(new[i], | ||
| 17187 | xasprintf("history[%d] '%s'", i, st->history[i]), FREE); | ||
| 17188 | } | ||
| 17189 | return new; | ||
| 17190 | } | ||
| 17191 | #endif | ||
| 17192 | |||
| 17193 | #if JOBS_WIN32 | ||
| 17194 | /* | ||
| 17195 | * struct procstat | ||
| 17196 | */ | ||
| 17197 | static struct datasize | ||
| 17198 | procstat_size(struct datasize ds, int nj) | ||
| 17199 | { | ||
| 17200 | struct job *jp = jobtab + nj; | ||
| 17201 | |||
| 17202 | if (jp->ps != &jp->ps0) | ||
| 17203 | ds.funcblocksize += sizeof(struct procstat) * jp->nprocs; | ||
| 17204 | |||
| 17205 | for (int i = 0; i < jp->nprocs; i++) | ||
| 17206 | ds.funcstringsize += align_len(jp->ps[i].ps_cmd); | ||
| 17207 | |||
| 17208 | return ds; | ||
| 17209 | } | ||
| 17210 | |||
| 17211 | static struct procstat * | ||
| 17212 | procstat_copy(int nj) | ||
| 17213 | { | ||
| 17214 | struct job *jp = jobtab + nj; | ||
| 17215 | struct procstat *new = funcblock; | ||
| 17216 | |||
| 17217 | funcblock = (char *)funcblock + sizeof(struct procstat) * jp->nprocs; | ||
| 17218 | memcpy(new, jp->ps, sizeof(struct procstat) * jp->nprocs); | ||
| 17219 | |||
| 17220 | for (int i = 0; i < jp->nprocs; i++) { | ||
| 17221 | new[i].ps_cmd = nodeckstrdup(jp->ps[i].ps_cmd); | ||
| 17222 | SAVE_PTR(new[i].ps_cmd, | ||
| 17223 | xasprintf("jobtab[%d].ps[%d].ps_cmd '%s'", | ||
| 17224 | nj, i, jp->ps[i].ps_cmd), FREE); | ||
| 17225 | } | ||
| 17226 | return new; | ||
| 17227 | } | ||
| 17228 | |||
| 17229 | /* | ||
| 17230 | * struct jobs | ||
| 17231 | */ | ||
| 17232 | static struct datasize | ||
| 17233 | jobtab_size(struct datasize ds) | ||
| 17234 | { | ||
| 17235 | ds.funcblocksize += sizeof(struct job) * njobs; | ||
| 17236 | for (int i = 0; i < njobs; i++) { | ||
| 17237 | if (jobtab[i].used) | ||
| 17238 | ds = procstat_size(ds, i); | ||
| 17239 | } | ||
| 17240 | return ds; | ||
| 17241 | } | ||
| 17242 | |||
| 17243 | static struct job * | ||
| 17244 | jobtab_copy(void) | ||
| 17245 | { | ||
| 17246 | struct job *new = funcblock; | ||
| 17247 | int i; | ||
| 17248 | |||
| 17249 | funcblock = (char *)funcblock + sizeof(struct job) * njobs; | ||
| 17250 | memcpy(new, jobtab, sizeof(struct job) * njobs); | ||
| 17251 | |||
| 17252 | for (i = 0; i < njobs; i++) { | ||
| 17253 | if (!jobtab[i].used) | ||
| 17254 | continue; | ||
| 17255 | |||
| 17256 | if (jobtab[i].ps == &jobtab[i].ps0) { | ||
| 17257 | new[i].ps0.ps_cmd = nodeckstrdup(jobtab[i].ps0.ps_cmd); | ||
| 17258 | SAVE_PTR(new[i].ps0.ps_cmd, | ||
| 17259 | xasprintf("jobtab[%d].ps0.ps_cmd '%s'", | ||
| 17260 | i, jobtab[i].ps0.ps_cmd), FREE); | ||
| 17261 | new[i].ps = &new[i].ps0; | ||
| 17262 | } else if (jobtab[i].nprocs) { | ||
| 17263 | new[i].ps = procstat_copy(i); | ||
| 17264 | } else { | ||
| 17265 | new[i].ps = NULL; | ||
| 17266 | } | ||
| 17267 | SAVE_PTR(new[i].ps, xasprintf("jobtab[%d].ps", i), FREE); | ||
| 17268 | |||
| 17269 | if (jobtab[i].prev_job) { | ||
| 17270 | new[i].prev_job = new + (jobtab[i].prev_job - jobtab); | ||
| 17271 | SAVE_PTR(new[i].prev_job, | ||
| 17272 | xasprintf("jobtab[%d].prev_job", i), FREE); | ||
| 17273 | } | ||
| 17274 | } | ||
| 17275 | return new; | ||
| 17276 | } | ||
| 17277 | #endif | ||
| 17278 | |||
| 17279 | /* | ||
| 17280 | * struct redirtab | ||
| 17281 | */ | ||
| 17282 | static int | ||
| 17283 | redirtab_size(int funcblocksize, struct redirtab *rdtp) | ||
| 17284 | { | ||
| 17285 | while (rdtp) { | ||
| 17286 | funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
| 17287 | rdtp = rdtp->next; | ||
| 17288 | } | ||
| 17289 | return funcblocksize; | ||
| 17290 | } | ||
| 17291 | |||
| 17292 | static struct redirtab * | ||
| 17293 | redirtab_copy(struct redirtab *rdtp) | ||
| 17294 | { | ||
| 17295 | struct redirtab *start; | ||
| 17296 | struct redirtab **vpp; | ||
| 17297 | |||
| 17298 | vpp = &start; | ||
| 17299 | while (rdtp) { | ||
| 17300 | int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
| 17301 | *vpp = funcblock; | ||
| 17302 | funcblock = (char *) funcblock + size; | ||
| 17303 | memcpy(*vpp, rdtp, size); | ||
| 17304 | SAVE_PTR((*vpp)->next, "(*vpp)->next", NO_FREE); | ||
| 17305 | rdtp = rdtp->next; | ||
| 17306 | vpp = &(*vpp)->next; | ||
| 17307 | } | ||
| 17308 | *vpp = NULL; | ||
| 17309 | return start; | ||
| 17310 | } | ||
| 17311 | |||
| 17312 | static struct datasize | ||
| 17313 | globals_var_size(struct datasize ds) | ||
| 17314 | { | ||
| 17315 | int i; | ||
| 17316 | |||
| 17317 | ds.funcblocksize += sizeof(struct globals_var); | ||
| 17318 | ds.funcstringsize += align_len(funcname); | ||
| 17319 | ds = argv_size(ds, shellparam.p); | ||
| 17320 | ds.funcblocksize = redirtab_size(ds.funcblocksize, redirlist); | ||
| 17321 | for (i = 0; i < VTABSIZE; i++) | ||
| 17322 | ds = var_size(ds, vartab[i]); | ||
| 17323 | return ds; | ||
| 17324 | } | ||
| 17325 | |||
| 17326 | #undef funcname | ||
| 17327 | #undef shellparam | ||
| 17328 | #undef redirlist | ||
| 17329 | #undef vartab | ||
| 17330 | static struct globals_var * | ||
| 17331 | globals_var_copy(void) | ||
| 17332 | { | ||
| 17333 | int i; | ||
| 17334 | struct globals_var *gvp, *new; | ||
| 17335 | |||
| 17336 | gvp = ash_ptr_to_globals_var; | ||
| 17337 | new = funcblock; | ||
| 17338 | funcblock = (char *) funcblock + sizeof(struct globals_var); | ||
| 17339 | memcpy(new, gvp, sizeof(struct globals_var)); | ||
| 17340 | |||
| 17341 | new->funcname = nodeckstrdup(gvp->funcname); | ||
| 17342 | SAVE_PTR(new->funcname, xasprintf("funcname '%s'", gvp->funcname ?: "NULL"), FREE); | ||
| 17343 | |||
| 17344 | /* shparam */ | ||
| 17345 | new->shellparam.malloced = 0; | ||
| 17346 | new->shellparam.p = argv_copy(gvp->shellparam.p); | ||
| 17347 | SAVE_PTR(new->shellparam.p, "shellparam.p", NO_FREE); | ||
| 17348 | |||
| 17349 | new->redirlist = redirtab_copy(gvp->redirlist); | ||
| 17350 | SAVE_PTR(new->redirlist, "redirlist", NO_FREE); | ||
| 17351 | |||
| 17352 | for (i = 0; i < VTABSIZE; i++) { | ||
| 17353 | new->vartab[i] = var_copy(gvp->vartab[i]); | ||
| 17354 | SAVE_PTR(new->vartab[i], xasprintf("vartab[%d]", i), FREE); | ||
| 17355 | } | ||
| 17356 | |||
| 17357 | return new; | ||
| 17358 | } | ||
| 17359 | |||
| 17360 | static struct datasize | ||
| 17361 | globals_misc_size(struct datasize ds) | ||
| 17362 | { | ||
| 17363 | ds.funcblocksize += sizeof(struct globals_misc); | ||
| 17364 | ds.funcstringsize += align_len(minusc); | ||
| 17365 | if (curdir != nullstr) | ||
| 17366 | ds.funcstringsize += align_len(curdir); | ||
| 17367 | if (physdir != nullstr) | ||
| 17368 | ds.funcstringsize += align_len(physdir); | ||
| 17369 | ds.funcstringsize += align_len(arg0); | ||
| 17370 | ds.funcstringsize += align_len(commandname); | ||
| 17371 | for (int i = 0; i < ARRAY_SIZE(trap); i++) | ||
| 17372 | ds.funcstringsize += align_len(trap[i]); | ||
| 17373 | return ds; | ||
| 17374 | } | ||
| 17375 | |||
| 17376 | #undef minusc | ||
| 17377 | #undef curdir | ||
| 17378 | #undef physdir | ||
| 17379 | #undef arg0 | ||
| 17380 | #undef commandname | ||
| 17381 | #undef g_parsefile | ||
| 17382 | #undef basepf | ||
| 17383 | #undef nullstr | ||
| 17384 | #undef trap | ||
| 17385 | static struct globals_misc * | ||
| 17386 | globals_misc_copy(void) | ||
| 17387 | { | ||
| 17388 | struct globals_misc *p = ash_ptr_to_globals_misc; | ||
| 17389 | struct globals_misc *new = funcblock; | ||
| 17390 | |||
| 17391 | funcblock = (char *) funcblock + sizeof(struct globals_misc); | ||
| 17392 | memcpy(new, p, sizeof(struct globals_misc)); | ||
| 17393 | |||
| 17394 | new->minusc = nodeckstrdup(p->minusc); | ||
| 17395 | new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr; | ||
| 17396 | new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr; | ||
| 17397 | new->arg0 = nodeckstrdup(p->arg0); | ||
| 17398 | new->commandname = nodeckstrdup(p->commandname); | ||
| 17399 | SAVE_PTR(new->minusc, xasprintf("minusc '%s'", p->minusc ?: "NULL"), FREE); | ||
| 17400 | SAVE_PTR(new->curdir, | ||
| 17401 | xasprintf("curdir '%s'", new->curdir ?: "NULL"), FREE); | ||
| 17402 | SAVE_PTR(new->physdir, | ||
| 17403 | xasprintf("physdir '%s'", new->physdir ?: "NULL"), FREE); | ||
| 17404 | SAVE_PTR(new->arg0, xasprintf("arg0 '%s'", p->arg0 ?: "NULL"), FREE); | ||
| 17405 | SAVE_PTR(new->commandname, | ||
| 17406 | xasprintf("commandname '%s'", p->commandname ?: "NULL"), FREE); | ||
| 17407 | for (int i = 0; i < ARRAY_SIZE(p->trap); i++) { | ||
| 17408 | new->trap[i] = nodeckstrdup(p->trap[i]); | ||
| 17409 | SAVE_PTR(new->trap[i], xasprintf("trap[%d]", i), FREE); | ||
| 17410 | } | ||
| 17411 | new->g_parsefile = NULL; | ||
| 17412 | memset(&new->basepf, 0, sizeof(struct parsefile)); | ||
| 17413 | return new; | ||
| 17414 | } | ||
| 17415 | |||
| 17416 | static struct datasize | ||
| 17417 | forkshell_size(struct forkshell *fs) | ||
| 17418 | { | ||
| 17419 | struct datasize ds = {0, 0}; | ||
| 17420 | |||
| 17421 | ds.funcstringsize += align_len(fs->path); | ||
| 17422 | if (fs->fpid == FS_OPENHERE) | ||
| 17423 | return ds; | ||
| 17424 | |||
| 17425 | ds = globals_misc_size(ds); | ||
| 17426 | ds = globals_var_size(ds); | ||
| 17427 | ds = cmdtable_size(ds); | ||
| 17428 | |||
| 17429 | ds.funcblocksize = calcsize(ds.funcblocksize, fs->n); | ||
| 17430 | ds = argv_size(ds, fs->argv); | ||
| 17431 | |||
| 17432 | if ((ENABLE_ASH_ALIAS || MAX_HISTORY || JOBS_WIN32) && | ||
| 17433 | fs->fpid != FS_SHELLEXEC) { | ||
| 17434 | #if ENABLE_ASH_ALIAS | ||
| 17435 | ds = atab_size(ds); | ||
| 17436 | #endif | ||
| 17437 | #if MAX_HISTORY | ||
| 17438 | if (line_input_state) | ||
| 17439 | ds = history_size(ds); | ||
| 17440 | #endif | ||
| 17441 | #if JOBS_WIN32 | ||
| 17442 | ds = jobtab_size(ds); | ||
| 17443 | #endif | ||
| 17444 | } | ||
| 17445 | return ds; | ||
| 17446 | } | ||
| 17447 | |||
| 17448 | static void | ||
| 17449 | forkshell_copy(struct forkshell *fs, struct forkshell *new) | ||
| 17450 | { | ||
| 17451 | memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */ | ||
| 17452 | |||
| 17453 | new->path = nodeckstrdup(fs->path); | ||
| 17454 | SAVE_PTR(new->path, xasprintf("path '%s'", fs->path ?: "NULL"), FREE); | ||
| 17455 | if (fs->fpid == FS_OPENHERE) | ||
| 17456 | return; | ||
| 17457 | |||
| 17458 | new->gmp = globals_misc_copy(); | ||
| 17459 | new->gvp = globals_var_copy(); | ||
| 17460 | new->cmdtable = cmdtable_copy(); | ||
| 17461 | SAVE_PTR(new->gmp, "gmp", NO_FREE); | ||
| 17462 | SAVE_PTR(new->gvp, "gvp", NO_FREE); | ||
| 17463 | SAVE_PTR(new->cmdtable, "cmdtable", NO_FREE); | ||
| 17464 | |||
| 17465 | new->n = copynode(fs->n); | ||
| 17466 | new->argv = argv_copy(fs->argv); | ||
| 17467 | SAVE_PTR(new->n, "n", NO_FREE); | ||
| 17468 | SAVE_PTR(new->argv, "argv", NO_FREE); | ||
| 17469 | |||
| 17470 | if ((ENABLE_ASH_ALIAS || MAX_HISTORY || JOBS_WIN32) && | ||
| 17471 | fs->fpid != FS_SHELLEXEC) { | ||
| 17472 | #if ENABLE_ASH_ALIAS | ||
| 17473 | new->atab = atab_copy(); | ||
| 17474 | SAVE_PTR(new->atab, "atab", NO_FREE); | ||
| 17475 | #endif | ||
| 17476 | #if MAX_HISTORY | ||
| 17477 | if (line_input_state) { | ||
| 17478 | new->history = history_copy(); | ||
| 17479 | SAVE_PTR(new->history, "history", NO_FREE); | ||
| 17480 | new->cnt_history = line_input_state->cnt_history; | ||
| 17481 | } | ||
| 17482 | #endif | ||
| 17483 | #if JOBS_WIN32 | ||
| 17484 | if (njobs) { | ||
| 17485 | new->jobtab = jobtab_copy(); | ||
| 17486 | SAVE_PTR(new->jobtab, "jobtab", NO_FREE); | ||
| 17487 | new->njobs = njobs; | ||
| 17488 | if (curjob) { | ||
| 17489 | new->curjob = new->jobtab + (curjob - jobtab); | ||
| 17490 | SAVE_PTR(new->curjob, "curjob", NO_FREE); | ||
| 17491 | } | ||
| 17492 | } | ||
| 17493 | #endif | ||
| 17494 | } | ||
| 17495 | } | ||
| 17496 | |||
| 17497 | #if FORKSHELL_DEBUG | ||
| 17498 | #define NUM_BLOCKS FUNCSTRING | ||
| 17499 | enum {GMP, GVP, CMDTABLE, NODE, ARGV, ATAB, HISTORY, JOBTAB, FUNCSTRING}; | ||
| 17500 | |||
| 17501 | /* fp0 and notes can each be NULL */ | ||
| 17502 | static void | ||
| 17503 | forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes) | ||
| 17504 | { | ||
| 17505 | FILE *fp; | ||
| 17506 | void *lfuncblock; | ||
| 17507 | char *lfuncstring; | ||
| 17508 | char *lrelocate; | ||
| 17509 | char *s; | ||
| 17510 | int count, i, total, bitmapsize; | ||
| 17511 | int size[NUM_BLOCKS]; | ||
| 17512 | char *lptr[NUM_BLOCKS+1]; | ||
| 17513 | const char *fsname[] = { | ||
| 17514 | "FS_OPENHERE", | ||
| 17515 | "FS_EVALBACKCMD", | ||
| 17516 | "FS_EVALSUBSHELL", | ||
| 17517 | "FS_EVALPIPE", | ||
| 17518 | "FS_SHELLEXEC" | ||
| 17519 | }; | ||
| 17520 | |||
| 17521 | if (fp0 != NULL) { | ||
| 17522 | fp = fp0; | ||
| 17523 | } | ||
| 17524 | else { | ||
| 17525 | char name[64]; | ||
| 17526 | static int num = 0; | ||
| 17527 | |||
| 17528 | sprintf(name, "fs_%d_%03d.out", getpid(), ++num % 100); | ||
| 17529 | if ((fp=fopen(name, "w")) == NULL) | ||
| 17530 | return; | ||
| 17531 | } | ||
| 17532 | |||
| 17533 | bitmapsize = (fs->relocatesize + 7)/8; | ||
| 17534 | total = sizeof(struct forkshell) + fs->funcblocksize + | ||
| 17535 | fs->funcstringsize + bitmapsize; | ||
| 17536 | fprintf(fp, "total size %6d = %d + %d + %d + %d = %d\n", | ||
| 17537 | fs->size + bitmapsize, | ||
| 17538 | (int)sizeof(struct forkshell), fs->funcblocksize, | ||
| 17539 | fs->funcstringsize, bitmapsize, total); | ||
| 17540 | |||
| 17541 | lfuncblock = (char *)(fs + 1); | ||
| 17542 | lfuncstring = (char *)lfuncblock + fs->funcblocksize; | ||
| 17543 | lrelocate = (char *)lfuncstring + fs->funcstringsize; | ||
| 17544 | |||
| 17545 | /* funcblocksize is zero for FS_OPENHERE */ | ||
| 17546 | if (fs->funcblocksize != 0) { | ||
| 17547 | /* Depending on the configuration and the type of forkshell | ||
| 17548 | * some items may not be present. */ | ||
| 17549 | lptr[FUNCSTRING] = lfuncstring; | ||
| 17550 | #if JOBS_WIN32 | ||
| 17551 | lptr[JOBTAB] = fs->jobtab ? (char *)fs->jobtab : lptr[FUNCSTRING]; | ||
| 17552 | #else | ||
| 17553 | lptr[JOBTAB] = lptr[FUNCSTRING]; | ||
| 17554 | #endif | ||
| 17555 | #if MAX_HISTORY | ||
| 17556 | lptr[HISTORY] = fs->history ? (char *)fs->history : lptr[JOBTAB]; | ||
| 17557 | #else | ||
| 17558 | lptr[HISTORY] = lptr[JOBTAB]; | ||
| 17559 | #endif | ||
| 17560 | lptr[ATAB] = IF_ASH_ALIAS(fs->atab ? (char *)fs->atab :) lptr[HISTORY]; | ||
| 17561 | lptr[ARGV] = fs->argv ? (char *)fs->argv : lptr[ATAB]; | ||
| 17562 | lptr[NODE] = fs->n ? (char *)fs->n : lptr[ARGV]; | ||
| 17563 | lptr[CMDTABLE] = (char *)fs->cmdtable; | ||
| 17564 | lptr[GVP] = (char *)fs->gvp; | ||
| 17565 | lptr[GMP] = (char *)fs->gmp; | ||
| 17566 | |||
| 17567 | fprintf(fp, "funcblocksize %6d = ", fs->funcblocksize); | ||
| 17568 | total = 0; | ||
| 17569 | for (i=0; i<NUM_BLOCKS; ++i) { | ||
| 17570 | size[i] = (int)(lptr[i+1] - lptr[i]); | ||
| 17571 | total += size[i]; | ||
| 17572 | fprintf(fp, "%d %c ", size[i], i == NUM_BLOCKS - 1 ? '=' : '+'); | ||
| 17573 | } | ||
| 17574 | fprintf(fp, "%d\n\n", total); | ||
| 17575 | } | ||
| 17576 | else { | ||
| 17577 | fprintf(fp, "\n"); | ||
| 17578 | } | ||
| 17579 | |||
| 17580 | fprintf(fp, "%s\n\n", fsname[fs->fpid]); | ||
| 17581 | fprintf(fp, "--- relocate ---\n"); | ||
| 17582 | count = 0; | ||
| 17583 | for (i = 0; i < fs->relocatesize; ++i) { | ||
| 17584 | if (lrelocate[i/8] & (1 << i % 8)) { | ||
| 17585 | char **ptr = (char **)((char *)fs + i * sizeof(char *)); | ||
| 17586 | fprintf(fp, "%p %p %s\n", ptr, *ptr, | ||
| 17587 | notes && notes[i] ? notes[i] : ""); | ||
| 17588 | ++count; | ||
| 17589 | } | ||
| 17590 | } | ||
| 17591 | fprintf(fp, "--- %d relocations ---\n\n", count); | ||
| 17592 | |||
| 17593 | fprintf(fp, "--- funcstring ---\n"); | ||
| 17594 | count = 0; | ||
| 17595 | s = lfuncstring; | ||
| 17596 | while (s-lfuncstring < fs->funcstringsize) { | ||
| 17597 | if (!*s) { | ||
| 17598 | ++s; | ||
| 17599 | continue; | ||
| 17600 | } | ||
| 17601 | fprintf(fp, "%p '%s'\n", s, s); | ||
| 17602 | s += strlen(s)+1; | ||
| 17603 | ++count; | ||
| 17604 | } | ||
| 17605 | fprintf(fp, "--- %d strings ---\n", count); | ||
| 17606 | |||
| 17607 | if (fp0 == NULL) | ||
| 17608 | fclose(fp); | ||
| 17609 | } | ||
| 17610 | #endif | ||
| 17611 | |||
| 17612 | static struct forkshell * | ||
| 17613 | forkshell_prepare(struct forkshell *fs) | ||
| 17614 | { | ||
| 17615 | struct forkshell *new; | ||
| 17616 | struct datasize ds; | ||
| 17617 | int size, relocatesize, bitmapsize; | ||
| 17618 | HANDLE h; | ||
| 17619 | SECURITY_ATTRIBUTES sa; | ||
| 17620 | #if FORKSHELL_DEBUG | ||
| 17621 | char *relocate; | ||
| 17622 | char name[64]; | ||
| 17623 | FILE *fp; | ||
| 17624 | static int num = 0; | ||
| 17625 | #endif | ||
| 17626 | |||
| 17627 | /* calculate size of structure, funcblock and funcstring */ | ||
| 17628 | ds = forkshell_size(fs); | ||
| 17629 | size = sizeof(struct forkshell) + ds.funcblocksize + ds.funcstringsize; | ||
| 17630 | relocatesize = (sizeof(struct forkshell) + ds.funcblocksize)/sizeof(char *); | ||
| 17631 | bitmapsize = (relocatesize + 7)/8; | ||
| 17632 | |||
| 17633 | /* Allocate shared memory region */ | ||
| 17634 | memset(&sa, 0, sizeof(sa)); | ||
| 17635 | sa.nLength = sizeof(sa); | ||
| 17636 | sa.lpSecurityDescriptor = NULL; | ||
| 17637 | sa.bInheritHandle = TRUE; | ||
| 17638 | h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, | ||
| 17639 | size+bitmapsize, NULL); | ||
| 17640 | |||
| 17641 | /* Initialise pointers */ | ||
| 17642 | new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
| 17643 | if (new == NULL) | ||
| 17644 | return NULL; | ||
| 17645 | fs_size = size; | ||
| 17646 | fs_start = new; | ||
| 17647 | funcblock = (char *)(new + 1); | ||
| 17648 | funcstring_end = (char *)new + size; | ||
| 17649 | #if FORKSHELL_DEBUG | ||
| 17650 | fs_funcstring = (char *)new + sizeof(struct forkshell) + ds.funcblocksize; | ||
| 17651 | relocate = (char *)new + size; | ||
| 17652 | annot = (const char **)xzalloc(sizeof(char *)*relocatesize); | ||
| 17653 | annot_free = xzalloc(relocatesize); | ||
| 17654 | #endif | ||
| 17655 | |||
| 17656 | /* Now pack them all */ | ||
| 17657 | forkshell_copy(fs, new); | ||
| 17658 | |||
| 17659 | /* Finish it up */ | ||
| 17660 | new->size = size; | ||
| 17661 | new->relocatesize = relocatesize; | ||
| 17662 | new->old_base = (char *)new; | ||
| 17663 | new->hMapFile = h; | ||
| 17664 | #if FORKSHELL_DEBUG | ||
| 17665 | sprintf(name, "fs_%d_%03d.out", getpid(), ++num % 100); | ||
| 17666 | if ((fp=fopen(name, "w")) != NULL) { | ||
| 17667 | int i; | ||
| 17668 | |||
| 17669 | new->funcblocksize = (char *)funcblock - (char *)(new + 1); | ||
| 17670 | new->funcstringsize = (char *)new + size - funcstring_end; | ||
| 17671 | |||
| 17672 | /* perform some sanity checks on pointers */ | ||
| 17673 | fprintf(fp, "forkshell %p %6d\n", new, (int)sizeof(*new)); | ||
| 17674 | fprintf(fp, "funcblock %p %6d\n", new+1, new->funcblocksize); | ||
| 17675 | fprintf(fp, "funcstring %p %6d\n", funcstring_end, | ||
| 17676 | new->funcstringsize); | ||
| 17677 | if ((char *)funcblock != funcstring_end) | ||
| 17678 | fprintf(fp, " funcstring != end funcblock + 1 %p\n", funcblock); | ||
| 17679 | fprintf(fp, "relocate %p %6d\n\n", relocate, bitmapsize); | ||
| 17680 | |||
| 17681 | forkshell_print(fp, new, annot); | ||
| 17682 | |||
| 17683 | for (i = 0; i < relocatesize; ++i) { | ||
| 17684 | if (annot_free[i]) { | ||
| 17685 | free((void *)annot[i]); | ||
| 17686 | } | ||
| 17687 | } | ||
| 17688 | free(annot); | ||
| 17689 | free(annot_free); | ||
| 17690 | annot = NULL; | ||
| 17691 | fclose(fp); | ||
| 17692 | } | ||
| 17693 | #endif | ||
| 17694 | return new; | ||
| 17695 | } | ||
| 17696 | |||
| 17697 | #undef trap_ptr | ||
| 17698 | static void | ||
| 17699 | forkshell_init(const char *idstr) | ||
| 17700 | { | ||
| 17701 | struct forkshell *fs; | ||
| 17702 | void *map_handle; | ||
| 17703 | HANDLE h; | ||
| 17704 | int i; | ||
| 17705 | char **ptr; | ||
| 17706 | char *lrelocate; | ||
| 17707 | |||
| 17708 | if (sscanf(idstr, "%p", &map_handle) != 1) | ||
| 17709 | return; | ||
| 17710 | |||
| 17711 | h = (HANDLE)map_handle; | ||
| 17712 | fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
| 17713 | if (!fs) | ||
| 17714 | return; | ||
| 17715 | |||
| 17716 | /* this memory can't be freed */ | ||
| 17717 | sticky_mem_start = fs; | ||
| 17718 | sticky_mem_end = (char *) fs + fs->size; | ||
| 17719 | |||
| 17720 | /* pointer fixup */ | ||
| 17721 | lrelocate = (char *)fs + fs->size; | ||
| 17722 | for (i = 0; i < fs->relocatesize; i++) { | ||
| 17723 | if (lrelocate[i/8] & (1 << i % 8)) { | ||
| 17724 | ptr = (char **)((char *)fs + i * sizeof(char *)); | ||
| 17725 | if (*ptr) | ||
| 17726 | *ptr = (char *)fs + (*ptr - fs->old_base); | ||
| 17727 | } | ||
| 17728 | } | ||
| 17729 | |||
| 17730 | if (fs->fpid == FS_OPENHERE) | ||
| 17731 | goto end; | ||
| 17732 | |||
| 17733 | /* Now fix up stuff that can't be transferred */ | ||
| 17734 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
| 17735 | struct tblentry *e = fs->cmdtable[i]; | ||
| 17736 | while (e) { | ||
| 17737 | if (e->cmdtype == CMDBUILTIN) | ||
| 17738 | e->param.cmd = builtintab + e->param.index; | ||
| 17739 | e = e->next; | ||
| 17740 | } | ||
| 17741 | } | ||
| 17742 | fs->gmp->trap_ptr = fs->gmp->trap; | ||
| 17743 | |||
| 17744 | /* from init() */ | ||
| 17745 | fs->gmp->basepf.next_to_pgetc = fs->gmp->basepf.buf = ckzalloc(IBUFSIZ); | ||
| 17746 | fs->gmp->basepf.linno = 1; | ||
| 17747 | fs->gmp->g_parsefile = &fs->gmp->basepf; | ||
| 17748 | |||
| 17749 | /* Set global variables */ | ||
| 17750 | ASSIGN_CONST_PTR(&ash_ptr_to_globals_misc, fs->gmp); | ||
| 17751 | ASSIGN_CONST_PTR(&ash_ptr_to_globals_var, fs->gvp); | ||
| 17752 | cmdtable = fs->cmdtable; | ||
| 17753 | #if ENABLE_ASH_ALIAS | ||
| 17754 | atab = fs->atab; /* will be NULL for FS_SHELLEXEC */ | ||
| 17755 | #endif | ||
| 17756 | #if MAX_HISTORY | ||
| 17757 | if (fs->cnt_history) { | ||
| 17758 | line_input_state = new_line_input_t(FOR_SHELL); | ||
| 17759 | line_input_state->cnt_history = fs->cnt_history; | ||
| 17760 | for (i = 0; i < line_input_state->cnt_history; i++) | ||
| 17761 | line_input_state->history[i] = fs->history[i]; | ||
| 17762 | } | ||
| 17763 | #endif | ||
| 17764 | #if JOBS_WIN32 | ||
| 17765 | jobtab = fs->jobtab; | ||
| 17766 | njobs = fs->njobs; | ||
| 17767 | curjob = fs->curjob; | ||
| 17768 | #endif | ||
| 17769 | |||
| 17770 | CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */ | ||
| 17771 | |||
| 17772 | reinitvar(); | ||
| 17773 | |||
| 17774 | if (setjmp(main_handler.loc)) { | ||
| 17775 | exitreset(); | ||
| 17776 | exitshell(); | ||
| 17777 | } | ||
| 17778 | exception_handler = &main_handler; | ||
| 17779 | |||
| 17780 | shlvl++; | ||
| 17781 | if (fs->mode == FORK_BG) { | ||
| 17782 | SetConsoleCtrlHandler(NULL, TRUE); | ||
| 17783 | if (fs->nprocs == 0) { | ||
| 17784 | close(0); | ||
| 17785 | if (open(bb_dev_null, O_RDONLY) != 0) | ||
| 17786 | ash_msg_and_raise_perror("can't open '%s'", bb_dev_null); | ||
| 17787 | } | ||
| 17788 | } | ||
| 17789 | else { | ||
| 17790 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
| 17791 | } | ||
| 17792 | |||
| 17793 | if (fs->n && fs->n->type == NCMD /* is it single cmd? */ | ||
| 17794 | /* && n->ncmd.args->type == NARG - always true? */ | ||
| 17795 | && fs->n->ncmd.args && strcmp(fs->n->ncmd.args->narg.text, "trap") == 0 | ||
| 17796 | && fs->n->ncmd.args->narg.next == NULL /* "trap" with no arguments */ | ||
| 17797 | /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */ | ||
| 17798 | ) { | ||
| 17799 | TRACE(("Trap hack\n")); | ||
| 17800 | /* Save trap handler strings for trap builtin to print */ | ||
| 17801 | fs->gmp->trap_ptr = xmemdup(fs->gmp->trap, sizeof(fs->gmp->trap)); | ||
| 17802 | /* Fall through into clearing traps */ | ||
| 17803 | } | ||
| 17804 | clear_traps(); | ||
| 17805 | #if JOBS_WIN32 | ||
| 17806 | /* do job control only in root shell */ | ||
| 17807 | jobctl = 0; | ||
| 17808 | |||
| 17809 | if (fs->n && fs->n->type == NCMD && fs->n->ncmd.args && | ||
| 17810 | strcmp(fs->n->ncmd.args->narg.text, "jobs") == 0) { | ||
| 17811 | TRACE(("Job hack\n")); | ||
| 17812 | if (!fs->jpnull) | ||
| 17813 | freejob(curjob); | ||
| 17814 | goto end; | ||
| 17815 | } | ||
| 17816 | for (struct job *jp = curjob; jp; jp = jp->prev_job) | ||
| 17817 | freejob(jp); | ||
| 17818 | #endif | ||
| 17819 | end: | ||
| 17820 | forkshell_child(fs); | ||
| 17821 | } | ||
| 17822 | |||
| 17823 | #undef free | ||
| 17824 | static void | ||
| 17825 | sticky_free(void *base) | ||
| 17826 | { | ||
| 17827 | if (base >= sticky_mem_start && base < sticky_mem_end) | ||
| 17828 | return; | ||
| 17829 | free(base); | ||
| 17830 | } | ||
| 17831 | #endif | ||
| 17832 | |||
| 15077 | /*- | 17833 | /*- |
| 15078 | * Copyright (c) 1989, 1991, 1993, 1994 | 17834 | * Copyright (c) 1989, 1991, 1993, 1994 |
| 15079 | * The Regents of the University of California. All rights reserved. | 17835 | * The Regents of the University of California. All rights reserved. |
