diff options
Diffstat (limited to 'shell/ash.c')
| -rw-r--r-- | shell/ash.c | 2824 |
1 files changed, 2785 insertions, 39 deletions
diff --git a/shell/ash.c b/shell/ash.c index 841ffe880..ae49687da 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 |
| @@ -730,16 +947,28 @@ static void | |||
| 730 | raise_interrupt(void) | 947 | raise_interrupt(void) |
| 731 | { | 948 | { |
| 732 | pending_int = 0; | 949 | pending_int = 0; |
| 950 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 733 | /* Signal is not automatically unmasked after it is raised, | 951 | /* Signal is not automatically unmasked after it is raised, |
| 734 | * do it ourself - unmask all signals */ | 952 | * do it ourself - unmask all signals */ |
| 735 | sigprocmask_allsigs(SIG_UNBLOCK); | 953 | sigprocmask_allsigs(SIG_UNBLOCK); |
| 954 | #endif | ||
| 736 | /* pending_sig = 0; - now done in signal_handler() */ | 955 | /* pending_sig = 0; - now done in signal_handler() */ |
| 737 | 956 | ||
| 738 | if (!(rootshell && iflag)) { | 957 | if (!(rootshell && iflag)) { |
| 958 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 739 | /* Kill ourself with SIGINT */ | 959 | /* Kill ourself with SIGINT */ |
| 740 | signal(SIGINT, SIG_DFL); | 960 | signal(SIGINT, SIG_DFL); |
| 741 | raise(SIGINT); | 961 | raise(SIGINT); |
| 962 | #else | ||
| 963 | fflush_all(); | ||
| 964 | kill(-getpid(), SIGINT); | ||
| 965 | _exit(SIGINT << 24); | ||
| 966 | #endif | ||
| 742 | } | 967 | } |
| 968 | #if ENABLE_PLATFORM_MINGW32 | ||
| 969 | if (iflag) | ||
| 970 | write(STDOUT_FILENO, "^C", 2); | ||
| 971 | #endif | ||
| 743 | /* bash: ^C even on empty command line sets $? */ | 972 | /* bash: ^C even on empty command line sets $? */ |
| 744 | exitstatus = SIGINT + 128; | 973 | exitstatus = SIGINT + 128; |
| 745 | raise_exception(EXINT); | 974 | raise_exception(EXINT); |
| @@ -2094,6 +2323,18 @@ maybe_single_quote(const char *s) | |||
| 2094 | return single_quote(s); | 2323 | return single_quote(s); |
| 2095 | } | 2324 | } |
| 2096 | 2325 | ||
| 2326 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2327 | /* Copy path to a string on the stack long enough to allow a file extension | ||
| 2328 | * to be added. */ | ||
| 2329 | static char * | ||
| 2330 | stack_add_ext_space(const char *path) | ||
| 2331 | { | ||
| 2332 | char *p = growstackto(strlen(path) + 5); | ||
| 2333 | strcpy(p, path); | ||
| 2334 | return p; | ||
| 2335 | } | ||
| 2336 | #endif | ||
| 2337 | |||
| 2097 | 2338 | ||
| 2098 | /* ============ nextopt */ | 2339 | /* ============ nextopt */ |
| 2099 | 2340 | ||
| @@ -2216,6 +2457,9 @@ struct localvar { | |||
| 2216 | #else | 2457 | #else |
| 2217 | # define VDYNAMIC 0 | 2458 | # define VDYNAMIC 0 |
| 2218 | #endif | 2459 | #endif |
| 2460 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2461 | # define VIMPORT 0x400 /* variable was imported from environment */ | ||
| 2462 | #endif | ||
| 2219 | 2463 | ||
| 2220 | /* Need to be before varinit_data[] */ | 2464 | /* Need to be before varinit_data[] */ |
| 2221 | #if ENABLE_LOCALE_SUPPORT | 2465 | #if ENABLE_LOCALE_SUPPORT |
| @@ -2244,6 +2488,24 @@ static void change_seconds(const char *) FAST_FUNC; | |||
| 2244 | static void change_realtime(const char *) FAST_FUNC; | 2488 | static void change_realtime(const char *) FAST_FUNC; |
| 2245 | #endif | 2489 | #endif |
| 2246 | 2490 | ||
| 2491 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2492 | static void FAST_FUNC | ||
| 2493 | change_terminal_mode(const char *newval UNUSED_PARAM) | ||
| 2494 | { | ||
| 2495 | terminal_mode(TRUE); | ||
| 2496 | } | ||
| 2497 | |||
| 2498 | static void clearcmdentry(void); | ||
| 2499 | static void FAST_FUNC | ||
| 2500 | change_override_applets(const char *newval UNUSED_PARAM) | ||
| 2501 | { | ||
| 2502 | clearcmdentry(); | ||
| 2503 | } | ||
| 2504 | |||
| 2505 | # define LINENO_INDEX (5 + 2 * ENABLE_ASH_MAIL + ENABLE_ASH_GETOPTS) | ||
| 2506 | # define FUNCNAME_INDEX (LINENO_INDEX + 1) | ||
| 2507 | #endif | ||
| 2508 | |||
| 2247 | static const struct { | 2509 | static const struct { |
| 2248 | int flags; | 2510 | int flags; |
| 2249 | const char *var_text; | 2511 | const char *var_text; |
| @@ -2281,6 +2543,12 @@ static const struct { | |||
| 2281 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 2543 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY |
| 2282 | { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL }, | 2544 | { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL }, |
| 2283 | #endif | 2545 | #endif |
| 2546 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2547 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_SKIP_ANSI_EMULATION, change_terminal_mode }, | ||
| 2548 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_TERMINAL_MODE, change_terminal_mode }, | ||
| 2549 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_OVERRIDE_APPLETS, change_override_applets }, | ||
| 2550 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_CRITICAL_ERROR_DIALOGS, change_critical_error_dialogs }, | ||
| 2551 | #endif | ||
| 2284 | }; | 2552 | }; |
| 2285 | 2553 | ||
| 2286 | struct redirtab; | 2554 | struct redirtab; |
| @@ -2504,6 +2772,65 @@ bltinlookup(const char *name) | |||
| 2504 | return lookupvar(name); | 2772 | return lookupvar(name); |
| 2505 | } | 2773 | } |
| 2506 | 2774 | ||
| 2775 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2776 | static char * | ||
| 2777 | fix_pathvar(const char *path, int len) | ||
| 2778 | { | ||
| 2779 | char *newpath = xstrdup(path); | ||
| 2780 | char *p; | ||
| 2781 | int modified = FALSE; | ||
| 2782 | |||
| 2783 | p = newpath + len; | ||
| 2784 | while (*p) { | ||
| 2785 | if (*p != ':' && *p != ';') { | ||
| 2786 | /* skip drive */ | ||
| 2787 | if (isalpha(*p) && p[1] == ':') | ||
| 2788 | p += 2; | ||
| 2789 | /* skip through path component */ | ||
| 2790 | for (; *p != '\0' && *p != ':' && *p != ';'; ++p) | ||
| 2791 | continue; | ||
| 2792 | } | ||
| 2793 | /* *p is ':', ';' or '\0' here */ | ||
| 2794 | if (*p == ':') { | ||
| 2795 | *p++ = ';'; | ||
| 2796 | modified = TRUE; | ||
| 2797 | } | ||
| 2798 | else if (*p == ';') { | ||
| 2799 | ++p; | ||
| 2800 | } | ||
| 2801 | } | ||
| 2802 | |||
| 2803 | if (!modified) { | ||
| 2804 | free(newpath); | ||
| 2805 | newpath = NULL; | ||
| 2806 | } | ||
| 2807 | return newpath; | ||
| 2808 | } | ||
| 2809 | |||
| 2810 | #define BB_VAR_EXACT 1 /* exact match for name */ | ||
| 2811 | #define BB_VAR_ASSIGN -1 /* matches name followed by '=' */ | ||
| 2812 | |||
| 2813 | /* Match variables that should be placed in the environment immediately | ||
| 2814 | * they're exported and removed immediately they're no longer exported */ | ||
| 2815 | static int | ||
| 2816 | is_bb_var(const char *s) | ||
| 2817 | { | ||
| 2818 | const char *p; | ||
| 2819 | int len; | ||
| 2820 | |||
| 2821 | for (p = bbvar; *p; p += len + 1) { | ||
| 2822 | len = strlen(p); | ||
| 2823 | if (strncmp(s, p, len) == 0) { | ||
| 2824 | if (s[len] == '\0') | ||
| 2825 | return BB_VAR_EXACT; | ||
| 2826 | else if (s[len] == '=') | ||
| 2827 | return BB_VAR_ASSIGN; | ||
| 2828 | } | ||
| 2829 | } | ||
| 2830 | return FALSE; | ||
| 2831 | } | ||
| 2832 | #endif | ||
| 2833 | |||
| 2507 | /* | 2834 | /* |
| 2508 | * Same as setvar except that the variable and value are passed in | 2835 | * Same as setvar except that the variable and value are passed in |
| 2509 | * the first argument as name=value. Since the first argument will | 2836 | * the first argument as name=value. Since the first argument will |
| @@ -2515,6 +2842,26 @@ static struct var * | |||
| 2515 | setvareq(char *s, int flags) | 2842 | setvareq(char *s, int flags) |
| 2516 | { | 2843 | { |
| 2517 | struct var *vp, **vpp; | 2844 | struct var *vp, **vpp; |
| 2845 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2846 | const char *paths = "PATH=\0""CDPATH=\0""MANPATH=\0"; | ||
| 2847 | const char *p; | ||
| 2848 | int len; | ||
| 2849 | |||
| 2850 | for (p = paths; *p; p += len + 1) { | ||
| 2851 | len = strlen(p); | ||
| 2852 | if (strncmp(s, p, len) == 0) { | ||
| 2853 | char *newpath = fix_pathvar(s, len); | ||
| 2854 | if (newpath) { | ||
| 2855 | if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE) | ||
| 2856 | free(s); | ||
| 2857 | flags |= VNOSAVE; | ||
| 2858 | flags &= ~(VTEXTFIXED|VSTACK); | ||
| 2859 | s = newpath; | ||
| 2860 | } | ||
| 2861 | break; | ||
| 2862 | } | ||
| 2863 | } | ||
| 2864 | #endif | ||
| 2518 | 2865 | ||
| 2519 | flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); | 2866 | flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); |
| 2520 | vpp = findvar(s); | 2867 | vpp = findvar(s); |
| @@ -2539,6 +2886,11 @@ setvareq(char *s, int flags) | |||
| 2539 | if (!(vp->flags & (VTEXTFIXED|VSTACK))) | 2886 | if (!(vp->flags & (VTEXTFIXED|VSTACK))) |
| 2540 | free((char*)vp->var_text); | 2887 | free((char*)vp->var_text); |
| 2541 | 2888 | ||
| 2889 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2890 | if ((flags & VUNSET) && (vp->flags & VEXPORT) && | ||
| 2891 | is_bb_var(s) == BB_VAR_EXACT) | ||
| 2892 | unsetenv(s); | ||
| 2893 | #endif | ||
| 2542 | if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) { | 2894 | if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) { |
| 2543 | *vpp = vp->next; | 2895 | *vpp = vp->next; |
| 2544 | free(vp); | 2896 | free(vp); |
| @@ -2568,6 +2920,10 @@ setvareq(char *s, int flags) | |||
| 2568 | s = ckstrdup(s); | 2920 | s = ckstrdup(s); |
| 2569 | vp->var_text = s; | 2921 | vp->var_text = s; |
| 2570 | vp->flags = flags; | 2922 | vp->flags = flags; |
| 2923 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2924 | if ((flags & VEXPORT) && is_bb_var(s) == BB_VAR_ASSIGN) | ||
| 2925 | putenv(s); | ||
| 2926 | #endif | ||
| 2571 | 2927 | ||
| 2572 | out: | 2928 | out: |
| 2573 | return vp; | 2929 | return vp; |
| @@ -2689,6 +3045,65 @@ listvars(int on, int off, struct strlist *lp, char ***end) | |||
| 2689 | return grabstackstr(ep); | 3045 | return grabstackstr(ep); |
| 2690 | } | 3046 | } |
| 2691 | 3047 | ||
| 3048 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3049 | /* Adjust directory separator in variables imported from the environment */ | ||
| 3050 | static void | ||
| 3051 | setwinxp(int on) | ||
| 3052 | { | ||
| 3053 | static smallint is_winxp = 1; | ||
| 3054 | struct var **vpp; | ||
| 3055 | struct var *vp; | ||
| 3056 | |||
| 3057 | if (on == is_winxp) | ||
| 3058 | return; | ||
| 3059 | is_winxp = on; | ||
| 3060 | |||
| 3061 | for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) { | ||
| 3062 | for (vp = *vpp; vp; vp = vp->next) { | ||
| 3063 | if ((vp->flags & VIMPORT)) { | ||
| 3064 | char *end = strchr(vp->var_text, '='); | ||
| 3065 | if (!end || is_prefixed_with(vp->var_text, "COMSPEC=") || | ||
| 3066 | is_prefixed_with(vp->var_text, "SYSTEMROOT=")) | ||
| 3067 | continue; | ||
| 3068 | if (!on) | ||
| 3069 | bs_to_slash(end + 1); | ||
| 3070 | else | ||
| 3071 | slash_to_bs(end + 1); | ||
| 3072 | } | ||
| 3073 | } | ||
| 3074 | } | ||
| 3075 | } | ||
| 3076 | |||
| 3077 | # if ENABLE_ASH_NOCONSOLE | ||
| 3078 | /* | ||
| 3079 | * Console state is either: | ||
| 3080 | * 0 normal | ||
| 3081 | * 1 iconified/hidden | ||
| 3082 | * 2 unknown | ||
| 3083 | */ | ||
| 3084 | static int console_state(void) | ||
| 3085 | { | ||
| 3086 | DECLARE_PROC_ADDR(BOOL, ShowWindow, HWND, int); | ||
| 3087 | |||
| 3088 | if (INIT_PROC_ADDR(user32.dll, ShowWindow)) { | ||
| 3089 | BOOL visible = IsWindowVisible(GetConsoleWindow()); | ||
| 3090 | BOOL iconified = IsIconic(GetConsoleWindow()); | ||
| 3091 | |||
| 3092 | return !visible || iconified; | ||
| 3093 | } | ||
| 3094 | return 2; | ||
| 3095 | } | ||
| 3096 | |||
| 3097 | static void hide_console(int hide) | ||
| 3098 | { | ||
| 3099 | // Switch console state if it's known and isn't the required state | ||
| 3100 | if (console_state() == !hide) | ||
| 3101 | ShowWindow(GetConsoleWindow(), hide ? | ||
| 3102 | (noiconify ? SW_HIDE : SW_MINIMIZE) : SW_NORMAL); | ||
| 3103 | } | ||
| 3104 | # endif | ||
| 3105 | #endif | ||
| 3106 | |||
| 2692 | 3107 | ||
| 2693 | /* ============ Path search helper */ | 3108 | /* ============ Path search helper */ |
| 2694 | static const char * | 3109 | static const char * |
| @@ -2732,7 +3147,7 @@ static const char *pathopt; /* set by padvance */ | |||
| 2732 | static int | 3147 | static int |
| 2733 | padvance_magic(const char **path, const char *name, int magic) | 3148 | padvance_magic(const char **path, const char *name, int magic) |
| 2734 | { | 3149 | { |
| 2735 | const char *term = "%:"; | 3150 | const char *term = "%"PATH_SEP_STR; |
| 2736 | const char *lpathopt; | 3151 | const char *lpathopt; |
| 2737 | const char *p; | 3152 | const char *p; |
| 2738 | char *q; | 3153 | char *q; |
| @@ -2749,14 +3164,14 @@ padvance_magic(const char **path, const char *name, int magic) | |||
| 2749 | if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) { | 3164 | if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) { |
| 2750 | lpathopt = start + 1; | 3165 | lpathopt = start + 1; |
| 2751 | start = p; | 3166 | start = p; |
| 2752 | term = ":"; | 3167 | term = PATH_SEP_STR; |
| 2753 | } | 3168 | } |
| 2754 | 3169 | ||
| 2755 | len = strcspn(start, term); | 3170 | len = strcspn(start, term); |
| 2756 | p = start + len; | 3171 | p = start + len; |
| 2757 | 3172 | ||
| 2758 | if (*p == '%') { | 3173 | if (*p == '%') { |
| 2759 | size_t extra = strchrnul(p, ':') - p; | 3174 | size_t extra = strchrnul(p, PATH_SEP) - p; |
| 2760 | 3175 | ||
| 2761 | if (legal_pathopt(p + 1, term, magic)) | 3176 | if (legal_pathopt(p + 1, term, magic)) |
| 2762 | lpathopt = p + 1; | 3177 | lpathopt = p + 1; |
| @@ -2767,14 +3182,18 @@ padvance_magic(const char **path, const char *name, int magic) | |||
| 2767 | } | 3182 | } |
| 2768 | 3183 | ||
| 2769 | pathopt = lpathopt; | 3184 | pathopt = lpathopt; |
| 2770 | *path = *p == ':' ? p + 1 : NULL; | 3185 | *path = *p == PATH_SEP ? p + 1 : NULL; |
| 2771 | 3186 | ||
| 2772 | /* "2" is for '/' and '\0' */ | 3187 | /* "2" is for '/' and '\0' */ |
| 2773 | qlen = len + strlen(name) + 2; | 3188 | /* reserve space for suffix on WIN32 */ |
| 3189 | qlen = len + strlen(name) + 2 IF_PLATFORM_MINGW32(+ 4); | ||
| 2774 | q = growstackto(qlen); | 3190 | q = growstackto(qlen); |
| 2775 | 3191 | ||
| 2776 | if (len) { | 3192 | if (len) { |
| 2777 | q = mempcpy(q, start, len); | 3193 | q = mempcpy(q, start, len); |
| 3194 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3195 | if (q[-1] != '/' && q[-1] != '\\') | ||
| 3196 | #endif | ||
| 2778 | *q++ = '/'; | 3197 | *q++ = '/'; |
| 2779 | } | 3198 | } |
| 2780 | strcpy(q, name); | 3199 | strcpy(q, name); |
| @@ -2865,6 +3284,7 @@ setprompt_if(smallint do_set, int whichprompt) | |||
| 2865 | 3284 | ||
| 2866 | #define CD_PHYSICAL 1 | 3285 | #define CD_PHYSICAL 1 |
| 2867 | #define CD_PRINT 2 | 3286 | #define CD_PRINT 2 |
| 3287 | #define CD_PRINT_ALL 4 | ||
| 2868 | 3288 | ||
| 2869 | static int | 3289 | static int |
| 2870 | cdopt(void) | 3290 | cdopt(void) |
| @@ -2873,7 +3293,14 @@ cdopt(void) | |||
| 2873 | int i, j; | 3293 | int i, j; |
| 2874 | 3294 | ||
| 2875 | j = 'L'; | 3295 | j = 'L'; |
| 3296 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3297 | while ((i = nextopt("LPa")) != '\0') { | ||
| 3298 | if (i == 'a') | ||
| 3299 | flags |= CD_PRINT_ALL; | ||
| 3300 | else | ||
| 3301 | #else | ||
| 2876 | while ((i = nextopt("LP")) != '\0') { | 3302 | while ((i = nextopt("LP")) != '\0') { |
| 3303 | #endif | ||
| 2877 | if (i != j) { | 3304 | if (i != j) { |
| 2878 | flags ^= CD_PHYSICAL; | 3305 | flags ^= CD_PHYSICAL; |
| 2879 | j = i; | 3306 | j = i; |
| @@ -2890,6 +3317,130 @@ cdopt(void) | |||
| 2890 | static const char * | 3317 | static const char * |
| 2891 | updatepwd(const char *dir) | 3318 | updatepwd(const char *dir) |
| 2892 | { | 3319 | { |
| 3320 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3321 | /* | ||
| 3322 | * Due to Windows drive notion, getting pwd is a completely | ||
| 3323 | * different thing. Handle it in a separate routine | ||
| 3324 | */ | ||
| 3325 | |||
| 3326 | char *new; | ||
| 3327 | char *p; | ||
| 3328 | char *cdcomppath; | ||
| 3329 | const char *lim; | ||
| 3330 | int len; | ||
| 3331 | char buffer[PATH_MAX]; | ||
| 3332 | /* | ||
| 3333 | * There are five cases that make some kind of sense | ||
| 3334 | * | ||
| 3335 | * Absolute paths: | ||
| 3336 | * c:/path | ||
| 3337 | * //host/share | ||
| 3338 | * | ||
| 3339 | * Relative to current working directory of other drive: | ||
| 3340 | * c:path | ||
| 3341 | * | ||
| 3342 | * Relative to current root (drive/share): | ||
| 3343 | * /path | ||
| 3344 | * | ||
| 3345 | * Relative to current working directory of current root (drive/share): | ||
| 3346 | * path | ||
| 3347 | */ | ||
| 3348 | enum {ABS_DRIVE, ABS_SHARE, REL_OTHER, REL_ROOT, REL_CWD} target; | ||
| 3349 | |||
| 3350 | /* skip multiple leading separators unless dir is a UNC path */ | ||
| 3351 | if (is_dir_sep(*dir) && unc_root_len(dir) == 0) { | ||
| 3352 | while (is_dir_sep(dir[1])) | ||
| 3353 | ++dir; | ||
| 3354 | } | ||
| 3355 | |||
| 3356 | len = strlen(dir); | ||
| 3357 | if (len >= 2 && has_dos_drive_prefix(dir)) | ||
| 3358 | target = len >= 3 && is_dir_sep(dir[2]) ? ABS_DRIVE : REL_OTHER; | ||
| 3359 | else if (unc_root_len(dir) != 0) | ||
| 3360 | target = ABS_SHARE; | ||
| 3361 | else if (is_dir_sep(*dir)) | ||
| 3362 | target = REL_ROOT; | ||
| 3363 | else | ||
| 3364 | target = REL_CWD; | ||
| 3365 | |||
| 3366 | cdcomppath = sstrdup(dir); | ||
| 3367 | STARTSTACKSTR(new); | ||
| 3368 | |||
| 3369 | switch (target) { | ||
| 3370 | case REL_OTHER: | ||
| 3371 | /* c:path */ | ||
| 3372 | if (get_drive_cwd(dir, buffer, PATH_MAX) == NULL) | ||
| 3373 | return 0; | ||
| 3374 | new = stack_putstr(buffer, new); | ||
| 3375 | len = 2; | ||
| 3376 | cdcomppath += len; | ||
| 3377 | dir += len; | ||
| 3378 | break; | ||
| 3379 | case REL_CWD: | ||
| 3380 | case REL_ROOT: | ||
| 3381 | /* path or /path */ | ||
| 3382 | len = root_len(curdir); | ||
| 3383 | if (len == 0) | ||
| 3384 | return 0; | ||
| 3385 | new = target == REL_CWD ? stack_putstr(curdir, new) : | ||
| 3386 | stnputs(curdir, len, new); | ||
| 3387 | break; | ||
| 3388 | default: | ||
| 3389 | /* //host/share or c:/path */ | ||
| 3390 | len = root_len(dir); | ||
| 3391 | if (len == 0) | ||
| 3392 | return 0; | ||
| 3393 | new = stnputs(dir, len, new); | ||
| 3394 | cdcomppath += len; | ||
| 3395 | dir += len; | ||
| 3396 | break; | ||
| 3397 | } | ||
| 3398 | |||
| 3399 | new = makestrspace(strlen(dir) + 2, new); | ||
| 3400 | lim = (char *)stackblock() + len + 1; | ||
| 3401 | |||
| 3402 | if (!is_dir_sep(*dir)) { | ||
| 3403 | if (!is_dir_sep(new[-1])) | ||
| 3404 | USTPUTC('/', new); | ||
| 3405 | if (new > lim && is_dir_sep(*lim)) | ||
| 3406 | lim++; | ||
| 3407 | } else { | ||
| 3408 | USTPUTC('/', new); | ||
| 3409 | cdcomppath++; | ||
| 3410 | if (is_dir_sep(dir[1]) && !is_dir_sep(dir[2])) { | ||
| 3411 | USTPUTC('/', new); | ||
| 3412 | cdcomppath++; | ||
| 3413 | lim++; | ||
| 3414 | } | ||
| 3415 | } | ||
| 3416 | p = strtok(cdcomppath, "/\\"); | ||
| 3417 | while (p) { | ||
| 3418 | switch (*p) { | ||
| 3419 | case '.': | ||
| 3420 | if (p[1] == '.' && p[2] == '\0') { | ||
| 3421 | while (new > lim) { | ||
| 3422 | STUNPUTC(new); | ||
| 3423 | if (is_dir_sep(new[-1])) | ||
| 3424 | break; | ||
| 3425 | } | ||
| 3426 | break; | ||
| 3427 | } | ||
| 3428 | if (p[1] == '\0') | ||
| 3429 | break; | ||
| 3430 | /* fall through */ | ||
| 3431 | default: | ||
| 3432 | new = stack_putstr(p, new); | ||
| 3433 | USTPUTC('/', new); | ||
| 3434 | } | ||
| 3435 | p = strtok(NULL, "/\\"); | ||
| 3436 | } | ||
| 3437 | if (new > lim) | ||
| 3438 | STUNPUTC(new); | ||
| 3439 | *new = 0; | ||
| 3440 | strip_dot_space((char *)stackblock()); | ||
| 3441 | fix_path_case((char *)stackblock()); | ||
| 3442 | return bs_to_slash((char *)stackblock()); | ||
| 3443 | #else | ||
| 2893 | char *new; | 3444 | char *new; |
| 2894 | char *p; | 3445 | char *p; |
| 2895 | char *cdcomppath; | 3446 | char *cdcomppath; |
| @@ -2943,6 +3494,7 @@ updatepwd(const char *dir) | |||
| 2943 | STUNPUTC(new); | 3494 | STUNPUTC(new); |
| 2944 | *new = 0; | 3495 | *new = 0; |
| 2945 | return stackblock(); | 3496 | return stackblock(); |
| 3497 | #endif | ||
| 2946 | } | 3498 | } |
| 2947 | 3499 | ||
| 2948 | /* | 3500 | /* |
| @@ -3038,7 +3590,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 3038 | } | 3590 | } |
| 3039 | if (!dest) | 3591 | if (!dest) |
| 3040 | dest = nullstr; | 3592 | dest = nullstr; |
| 3041 | if (*dest == '/') | 3593 | if (!is_relative_path(dest)) |
| 3042 | goto step6; | 3594 | goto step6; |
| 3043 | if (*dest == '.') { | 3595 | if (*dest == '.') { |
| 3044 | c = dest[1]; | 3596 | c = dest[1]; |
| @@ -3061,7 +3613,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 3061 | p = stalloc(len); | 3613 | p = stalloc(len); |
| 3062 | 3614 | ||
| 3063 | if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { | 3615 | if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { |
| 3064 | if (c && c != ':') | 3616 | if (c && c != PATH_SEP) |
| 3065 | flags |= CD_PRINT; | 3617 | flags |= CD_PRINT; |
| 3066 | docd: | 3618 | docd: |
| 3067 | if (!docd(p, flags)) | 3619 | if (!docd(p, flags)) |
| @@ -3083,6 +3635,26 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 3083 | return 0; | 3635 | return 0; |
| 3084 | } | 3636 | } |
| 3085 | 3637 | ||
| 3638 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3639 | static void | ||
| 3640 | print_all_cwd(void) | ||
| 3641 | { | ||
| 3642 | FILE *mnt; | ||
| 3643 | struct mntent *entry; | ||
| 3644 | char buffer[PATH_MAX]; | ||
| 3645 | |||
| 3646 | mnt = setmntent(bb_path_mtab_file, "r"); | ||
| 3647 | if (mnt) { | ||
| 3648 | while ((entry=getmntent(mnt)) != NULL) { | ||
| 3649 | entry->mnt_dir[2] = '\0'; | ||
| 3650 | if (get_drive_cwd(entry->mnt_dir, buffer, PATH_MAX) != NULL) | ||
| 3651 | out1fmt("%s\n", buffer); | ||
| 3652 | } | ||
| 3653 | endmntent(mnt); | ||
| 3654 | } | ||
| 3655 | } | ||
| 3656 | #endif | ||
| 3657 | |||
| 3086 | static int FAST_FUNC | 3658 | static int FAST_FUNC |
| 3087 | pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 3659 | pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) |
| 3088 | { | 3660 | { |
| @@ -3090,6 +3662,12 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 3090 | const char *dir = curdir; | 3662 | const char *dir = curdir; |
| 3091 | 3663 | ||
| 3092 | flags = cdopt(); | 3664 | flags = cdopt(); |
| 3665 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3666 | if (flags & CD_PRINT_ALL) { | ||
| 3667 | print_all_cwd(); | ||
| 3668 | return 0; | ||
| 3669 | } | ||
| 3670 | #endif | ||
| 3093 | if (flags) { | 3671 | if (flags) { |
| 3094 | if (physdir == nullstr) | 3672 | if (physdir == nullstr) |
| 3095 | setpwd(dir, 0); | 3673 | setpwd(dir, 0); |
| @@ -3714,7 +4292,12 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 3714 | struct procstat { | 4292 | struct procstat { |
| 3715 | pid_t ps_pid; /* process id */ | 4293 | pid_t ps_pid; /* process id */ |
| 3716 | int ps_status; /* last process status from wait() */ | 4294 | int ps_status; /* last process status from wait() */ |
| 4295 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 3717 | char *ps_cmd; /* text of command being run */ | 4296 | char *ps_cmd; /* text of command being run */ |
| 4297 | #endif | ||
| 4298 | #if ENABLE_PLATFORM_MINGW32 | ||
| 4299 | HANDLE ps_proc; | ||
| 4300 | #endif | ||
| 3718 | }; | 4301 | }; |
| 3719 | 4302 | ||
| 3720 | struct job { | 4303 | struct job { |
| @@ -3730,8 +4313,10 @@ struct job { | |||
| 3730 | #define JOBDONE 2 /* all procs are completed */ | 4313 | #define JOBDONE 2 /* all procs are completed */ |
| 3731 | unsigned | 4314 | unsigned |
| 3732 | state: 8, | 4315 | state: 8, |
| 3733 | #if JOBS | 4316 | #if JOBS || ENABLE_PLATFORM_MINGW32 |
| 3734 | sigint: 1, /* job was killed by SIGINT */ | 4317 | sigint: 1, /* job was killed by SIGINT */ |
| 4318 | #endif | ||
| 4319 | #if JOBS | ||
| 3735 | jobctl: 1, /* job running under job control */ | 4320 | jobctl: 1, /* job running under job control */ |
| 3736 | #endif | 4321 | #endif |
| 3737 | waited: 1, /* true if this entry has been waited for */ | 4322 | waited: 1, /* true if this entry has been waited for */ |
| @@ -3740,17 +4325,23 @@ struct job { | |||
| 3740 | struct job *prev_job; /* previous job */ | 4325 | struct job *prev_job; /* previous job */ |
| 3741 | }; | 4326 | }; |
| 3742 | 4327 | ||
| 4328 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 3743 | static int forkshell(struct job *, union node *, int); | 4329 | static int forkshell(struct job *, union node *, int); |
| 4330 | #endif | ||
| 3744 | static int waitforjob(struct job *); | 4331 | static int waitforjob(struct job *); |
| 3745 | 4332 | ||
| 3746 | #if !JOBS | 4333 | #if !JOBS && !JOBS_WIN32 |
| 3747 | enum { jobctl = 0 }; | 4334 | enum { jobctl = 0 }; |
| 3748 | #define setjobctl(on) do {} while (0) | 4335 | #define setjobctl(on) do {} while (0) |
| 3749 | #else | 4336 | #elif JOBS_WIN32 |
| 4337 | static smallint jobctl; //references:8 | ||
| 4338 | #define setjobctl(on) do { if (rootshell) jobctl = on; } while (0) | ||
| 4339 | #else /* JOBS */ | ||
| 3750 | static smallint jobctl; //references:8 | 4340 | static smallint jobctl; //references:8 |
| 3751 | static void setjobctl(int); | 4341 | static void setjobctl(int); |
| 3752 | #endif | 4342 | #endif |
| 3753 | 4343 | ||
| 4344 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 3754 | /* | 4345 | /* |
| 3755 | * Ignore a signal. | 4346 | * Ignore a signal. |
| 3756 | */ | 4347 | */ |
| @@ -3910,6 +4501,10 @@ setsignal(int signo) | |||
| 3910 | 4501 | ||
| 3911 | sigaction_set(signo, &act); | 4502 | sigaction_set(signo, &act); |
| 3912 | } | 4503 | } |
| 4504 | #else | ||
| 4505 | #define setsignal(s) | ||
| 4506 | #define ignoresig(s) | ||
| 4507 | #endif | ||
| 3913 | 4508 | ||
| 3914 | /* mode flags for set_curjob */ | 4509 | /* mode flags for set_curjob */ |
| 3915 | #define CUR_DELETE 2 | 4510 | #define CUR_DELETE 2 |
| @@ -4043,7 +4638,7 @@ set_curjob(struct job *jp, unsigned mode) | |||
| 4043 | } | 4638 | } |
| 4044 | } | 4639 | } |
| 4045 | 4640 | ||
| 4046 | #if JOBS || DEBUG | 4641 | #if JOBS || ENABLE_PLATFORM_MINGW32 || DEBUG |
| 4047 | static int | 4642 | static int |
| 4048 | jobno(const struct job *jp) | 4643 | jobno(const struct job *jp) |
| 4049 | { | 4644 | { |
| @@ -4061,7 +4656,9 @@ static struct job * | |||
| 4061 | getjob(const char *name, int getctl) | 4656 | getjob(const char *name, int getctl) |
| 4062 | { | 4657 | { |
| 4063 | struct job *jp; | 4658 | struct job *jp; |
| 4659 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 4064 | struct job *found; | 4660 | struct job *found; |
| 4661 | #endif | ||
| 4065 | const char *err_msg = "%s: no such job"; | 4662 | const char *err_msg = "%s: no such job"; |
| 4066 | unsigned num; | 4663 | unsigned num; |
| 4067 | int c; | 4664 | int c; |
| @@ -4106,6 +4703,7 @@ getjob(const char *name, int getctl) | |||
| 4106 | } | 4703 | } |
| 4107 | } | 4704 | } |
| 4108 | 4705 | ||
| 4706 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 4109 | found = NULL; | 4707 | found = NULL; |
| 4110 | while (jp) { | 4708 | while (jp) { |
| 4111 | if (*p == '?' | 4709 | if (*p == '?' |
| @@ -4122,6 +4720,9 @@ getjob(const char *name, int getctl) | |||
| 4122 | if (!found) | 4720 | if (!found) |
| 4123 | goto err; | 4721 | goto err; |
| 4124 | jp = found; | 4722 | jp = found; |
| 4723 | #else | ||
| 4724 | goto err; | ||
| 4725 | #endif | ||
| 4125 | 4726 | ||
| 4126 | gotit: | 4727 | gotit: |
| 4127 | #if JOBS | 4728 | #if JOBS |
| @@ -4140,14 +4741,18 @@ getjob(const char *name, int getctl) | |||
| 4140 | static void | 4741 | static void |
| 4141 | freejob(struct job *jp) | 4742 | freejob(struct job *jp) |
| 4142 | { | 4743 | { |
| 4744 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 4143 | struct procstat *ps; | 4745 | struct procstat *ps; |
| 4144 | int i; | 4746 | int i; |
| 4747 | #endif | ||
| 4145 | 4748 | ||
| 4146 | INTOFF; | 4749 | INTOFF; |
| 4750 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 4147 | for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { | 4751 | for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { |
| 4148 | if (ps->ps_cmd != nullstr) | 4752 | if (ps->ps_cmd != nullstr) |
| 4149 | free(ps->ps_cmd); | 4753 | free(ps->ps_cmd); |
| 4150 | } | 4754 | } |
| 4755 | #endif | ||
| 4151 | if (jp->ps != &jp->ps0) | 4756 | if (jp->ps != &jp->ps0) |
| 4152 | free(jp->ps); | 4757 | free(jp->ps); |
| 4153 | jp->used = 0; | 4758 | jp->used = 0; |
| @@ -4255,7 +4860,9 @@ setjobctl(int on) | |||
| 4255 | ttyfd = fd; | 4860 | ttyfd = fd; |
| 4256 | jobctl = on; | 4861 | jobctl = on; |
| 4257 | } | 4862 | } |
| 4863 | #endif | ||
| 4258 | 4864 | ||
| 4865 | #if JOBS || JOBS_WIN32 | ||
| 4259 | static int FAST_FUNC | 4866 | static int FAST_FUNC |
| 4260 | killcmd(int argc, char **argv) | 4867 | killcmd(int argc, char **argv) |
| 4261 | { | 4868 | { |
| @@ -4285,8 +4892,10 @@ killcmd(int argc, char **argv) | |||
| 4285 | * sh -c 'true|sleep 1 & sleep 2; kill %1' | 4892 | * sh -c 'true|sleep 1 & sleep 2; kill %1' |
| 4286 | */ | 4893 | */ |
| 4287 | n = jp->nprocs; /* can't be 0 (I hope) */ | 4894 | n = jp->nprocs; /* can't be 0 (I hope) */ |
| 4895 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 4288 | if (jp->jobctl) | 4896 | if (jp->jobctl) |
| 4289 | n = 1; | 4897 | n = 1; |
| 4898 | #endif | ||
| 4290 | dst = alloca(n * sizeof(int)*4); | 4899 | dst = alloca(n * sizeof(int)*4); |
| 4291 | argv[i] = dst; | 4900 | argv[i] = dst; |
| 4292 | for (j = 0; j < n; j++) { | 4901 | for (j = 0; j < n; j++) { |
| @@ -4301,7 +4910,11 @@ killcmd(int argc, char **argv) | |||
| 4301 | * leading space. Needed to not confuse | 4910 | * leading space. Needed to not confuse |
| 4302 | * negative pids with "kill -SIGNAL_NO" syntax | 4911 | * negative pids with "kill -SIGNAL_NO" syntax |
| 4303 | */ | 4912 | */ |
| 4913 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 4304 | dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); | 4914 | dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); |
| 4915 | #else | ||
| 4916 | dst += sprintf(dst, " -%u", (int)ps->ps_pid); | ||
| 4917 | #endif | ||
| 4305 | } | 4918 | } |
| 4306 | *dst = '\0'; | 4919 | *dst = '\0'; |
| 4307 | } | 4920 | } |
| @@ -4309,7 +4922,9 @@ killcmd(int argc, char **argv) | |||
| 4309 | } | 4922 | } |
| 4310 | return kill_main(argc, argv); | 4923 | return kill_main(argc, argv); |
| 4311 | } | 4924 | } |
| 4925 | #endif | ||
| 4312 | 4926 | ||
| 4927 | #if JOBS | ||
| 4313 | static void | 4928 | static void |
| 4314 | showpipe(struct job *jp /*, FILE *out*/) | 4929 | showpipe(struct job *jp /*, FILE *out*/) |
| 4315 | { | 4930 | { |
| @@ -4414,6 +5029,69 @@ sprint_status48(char *os, int status, int sigonly) | |||
| 4414 | return s - os; | 5029 | return s - os; |
| 4415 | } | 5030 | } |
| 4416 | 5031 | ||
| 5032 | #if ENABLE_PLATFORM_MINGW32 | ||
| 5033 | static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) | ||
| 5034 | { | ||
| 5035 | if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { | ||
| 5036 | # if ENABLE_FEATURE_EDITING | ||
| 5037 | bb_got_signal = SIGINT; /* for read_line_input: "we got a signal" */ | ||
| 5038 | # endif | ||
| 5039 | waitcmd_int = -waitcmd_int; | ||
| 5040 | if (!trap[SIGINT]) { | ||
| 5041 | if (!suppress_int && !(rootshell && iflag)) | ||
| 5042 | raise_interrupt(); | ||
| 5043 | pending_int = 1; | ||
| 5044 | } | ||
| 5045 | return TRUE; | ||
| 5046 | } | ||
| 5047 | return FALSE; | ||
| 5048 | } | ||
| 5049 | |||
| 5050 | /* | ||
| 5051 | * Windows does not know about parent-child relationship | ||
| 5052 | * They don't support waitpid(-1) | ||
| 5053 | */ | ||
| 5054 | static pid_t | ||
| 5055 | waitpid_child(int *status, DWORD blocking) | ||
| 5056 | { | ||
| 5057 | struct job *jb; | ||
| 5058 | int pid_nr = 0; | ||
| 5059 | static HANDLE *proclist = NULL; | ||
| 5060 | static int pid_max = 0; | ||
| 5061 | pid_t pid = -1; | ||
| 5062 | DWORD win_status, idx; | ||
| 5063 | int i; | ||
| 5064 | |||
| 5065 | for (jb = curjob; jb; jb = jb->prev_job) { | ||
| 5066 | if (jb->state != JOBDONE) { | ||
| 5067 | if (pid_nr + jb->nprocs > pid_max) { | ||
| 5068 | pid_max = pid_nr + jb->nprocs; | ||
| 5069 | proclist = ckrealloc(proclist, sizeof(*proclist) * pid_max); | ||
| 5070 | } | ||
| 5071 | |||
| 5072 | for (i = 0; i < jb->nprocs; ++i) { | ||
| 5073 | if (jb->ps[i].ps_proc) { | ||
| 5074 | proclist[pid_nr++] = jb->ps[i].ps_proc; | ||
| 5075 | } | ||
| 5076 | } | ||
| 5077 | } | ||
| 5078 | } | ||
| 5079 | |||
| 5080 | if (pid_nr) { | ||
| 5081 | do { | ||
| 5082 | idx = WaitForMultipleObjects(pid_nr, proclist, FALSE, blocking); | ||
| 5083 | if (idx < pid_nr) { | ||
| 5084 | GetExitCodeProcess(proclist[idx], &win_status); | ||
| 5085 | *status = exit_code_to_wait_status(win_status); | ||
| 5086 | pid = GetProcessId(proclist[idx]); | ||
| 5087 | break; | ||
| 5088 | } | ||
| 5089 | } while (blocking && !pending_int && waitcmd_int != 1); | ||
| 5090 | } | ||
| 5091 | return pid; | ||
| 5092 | } | ||
| 5093 | #endif | ||
| 5094 | |||
| 4417 | /* Inside dowait(): */ | 5095 | /* Inside dowait(): */ |
| 4418 | #define DOWAIT_NONBLOCK 0 /* waitpid() will use WNOHANG and won't wait for signals */ | 5096 | #define DOWAIT_NONBLOCK 0 /* waitpid() will use WNOHANG and won't wait for signals */ |
| 4419 | #define DOWAIT_BLOCK 1 /* waitpid() will NOT use WNOHANG */ | 5097 | #define DOWAIT_BLOCK 1 /* waitpid() will NOT use WNOHANG */ |
| @@ -4425,6 +5103,7 @@ sprint_status48(char *os, int status, int sigonly) | |||
| 4425 | static int | 5103 | static int |
| 4426 | waitproc(int block, int *status) | 5104 | waitproc(int block, int *status) |
| 4427 | { | 5105 | { |
| 5106 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 4428 | sigset_t oldmask; | 5107 | sigset_t oldmask; |
| 4429 | int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; | 5108 | int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; |
| 4430 | int err; | 5109 | int err; |
| @@ -4464,6 +5143,11 @@ waitproc(int block, int *status) | |||
| 4464 | /* If we fall off the loop, err is 0, which means we got a !SIGCHLD signal */ | 5143 | /* If we fall off the loop, err is 0, which means we got a !SIGCHLD signal */ |
| 4465 | 5144 | ||
| 4466 | return err; | 5145 | return err; |
| 5146 | #else | ||
| 5147 | // Only DOWAIT_NONBLOCK is non-blocking, other values block. | ||
| 5148 | *status = 0; | ||
| 5149 | return waitpid_child(status, block != DOWAIT_NONBLOCK); | ||
| 5150 | #endif | ||
| 4467 | } | 5151 | } |
| 4468 | 5152 | ||
| 4469 | static int waitone(int block, struct job *job) | 5153 | static int waitone(int block, struct job *job) |
| @@ -4517,6 +5201,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)); | 5201 | 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; | 5202 | sp->ps_status = status; |
| 4519 | thisjob = jp; | 5203 | thisjob = jp; |
| 5204 | #if ENABLE_PLATFORM_MINGW32 | ||
| 5205 | CloseHandle(sp->ps_proc); | ||
| 5206 | sp->ps_proc = NULL; | ||
| 5207 | #endif | ||
| 4520 | } | 5208 | } |
| 4521 | if (sp->ps_status == -1) | 5209 | if (sp->ps_status == -1) |
| 4522 | jobstate = JOBRUNNING; | 5210 | jobstate = JOBRUNNING; |
| @@ -4577,6 +5265,7 @@ static int waitone(int block, struct job *job) | |||
| 4577 | 5265 | ||
| 4578 | static int dowait(int block, struct job *jp) | 5266 | static int dowait(int block, struct job *jp) |
| 4579 | { | 5267 | { |
| 5268 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 4580 | smallint gotchld = *(volatile smallint *)&gotsigchld; | 5269 | smallint gotchld = *(volatile smallint *)&gotsigchld; |
| 4581 | int rpid; | 5270 | int rpid; |
| 4582 | int pid; | 5271 | int pid; |
| @@ -4598,9 +5287,17 @@ static int dowait(int block, struct job *jp) | |||
| 4598 | } while (pid >= 0); | 5287 | } while (pid >= 0); |
| 4599 | 5288 | ||
| 4600 | return rpid; | 5289 | return rpid; |
| 5290 | #else | ||
| 5291 | int pid = 1; | ||
| 5292 | |||
| 5293 | while ((jp ? jp->state == JOBRUNNING : pid > 0) && waitcmd_int != 1) | ||
| 5294 | pid = waitone(block, jp); | ||
| 5295 | |||
| 5296 | return pid; | ||
| 5297 | #endif | ||
| 4601 | } | 5298 | } |
| 4602 | 5299 | ||
| 4603 | #if JOBS | 5300 | #if JOBS || JOBS_WIN32 |
| 4604 | static void | 5301 | static void |
| 4605 | showjob(struct job *jp, int mode) | 5302 | showjob(struct job *jp, int mode) |
| 4606 | { | 5303 | { |
| @@ -4615,7 +5312,7 @@ showjob(struct job *jp, int mode) | |||
| 4615 | 5312 | ||
| 4616 | if (mode & SHOW_ONLY_PGID) { /* jobs -p */ | 5313 | if (mode & SHOW_ONLY_PGID) { /* jobs -p */ |
| 4617 | /* just output process (group) id of pipeline */ | 5314 | /* just output process (group) id of pipeline */ |
| 4618 | fprintf(out, "%d\n", ps->ps_pid); | 5315 | fprintf(out, "%"PID_FMT"d\n", ps->ps_pid); |
| 4619 | return; | 5316 | return; |
| 4620 | } | 5317 | } |
| 4621 | 5318 | ||
| @@ -4628,7 +5325,7 @@ showjob(struct job *jp, int mode) | |||
| 4628 | s[col - 3] = '-'; | 5325 | s[col - 3] = '-'; |
| 4629 | 5326 | ||
| 4630 | if (mode & SHOW_PIDS) | 5327 | if (mode & SHOW_PIDS) |
| 4631 | col += fmtstr(s + col, 16, "%d ", ps->ps_pid); | 5328 | col += fmtstr(s + col, 16, "%"PID_FMT"d ", ps->ps_pid); |
| 4632 | 5329 | ||
| 4633 | psend = ps + jp->nprocs; | 5330 | psend = ps + jp->nprocs; |
| 4634 | 5331 | ||
| @@ -4637,8 +5334,10 @@ showjob(struct job *jp, int mode) | |||
| 4637 | col += sizeof("Running") - 1; | 5334 | col += sizeof("Running") - 1; |
| 4638 | } else { | 5335 | } else { |
| 4639 | int status = psend[-1].ps_status; | 5336 | int status = psend[-1].ps_status; |
| 5337 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 4640 | if (jp->state == JOBSTOPPED) | 5338 | if (jp->state == JOBSTOPPED) |
| 4641 | status = jp->stopstatus; | 5339 | status = jp->stopstatus; |
| 5340 | #endif | ||
| 4642 | col += sprint_status48(s + col, status, 0); | 5341 | col += sprint_status48(s + col, status, 0); |
| 4643 | } | 5342 | } |
| 4644 | /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ | 5343 | /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ |
| @@ -4657,14 +5356,18 @@ showjob(struct job *jp, int mode) | |||
| 4657 | s[0] = '\0'; | 5356 | s[0] = '\0'; |
| 4658 | col = 33; | 5357 | col = 33; |
| 4659 | if (mode & SHOW_PIDS) | 5358 | if (mode & SHOW_PIDS) |
| 4660 | col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1; | 5359 | col = fmtstr(s, 48, "\n%*c%"PID_FMT"d ", indent_col, ' ', ps->ps_pid) - 1; |
| 4661 | start: | 5360 | start: |
| 5361 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 4662 | fprintf(out, "%s%*c%s%s", | 5362 | fprintf(out, "%s%*c%s%s", |
| 4663 | s, | 5363 | s, |
| 4664 | 33 - col >= 0 ? 33 - col : 0, ' ', | 5364 | 33 - col >= 0 ? 33 - col : 0, ' ', |
| 4665 | ps == jp->ps ? "" : "| ", | 5365 | ps == jp->ps ? "" : "| ", |
| 4666 | ps->ps_cmd | 5366 | ps->ps_cmd |
| 4667 | ); | 5367 | ); |
| 5368 | #else | ||
| 5369 | fprintf(out, "%s", s); | ||
| 5370 | #endif | ||
| 4668 | } while (++ps != psend); | 5371 | } while (++ps != psend); |
| 4669 | newline_and_flush(out); | 5372 | newline_and_flush(out); |
| 4670 | 5373 | ||
| @@ -4749,7 +5452,7 @@ getstatus(struct job *job) | |||
| 4749 | { | 5452 | { |
| 4750 | /* XXX: limits number of signals */ | 5453 | /* XXX: limits number of signals */ |
| 4751 | retval = WTERMSIG(status); | 5454 | retval = WTERMSIG(status); |
| 4752 | #if JOBS | 5455 | #if JOBS || ENABLE_PLATFORM_MINGW32 |
| 4753 | if (retval == SIGINT) | 5456 | if (retval == SIGINT) |
| 4754 | job->sigint = 1; | 5457 | job->sigint = 1; |
| 4755 | #endif | 5458 | #endif |
| @@ -4800,6 +5503,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
| 4800 | * with an exit status greater than 128, immediately after which | 5503 | * with an exit status greater than 128, immediately after which |
| 4801 | * the trap is executed." | 5504 | * the trap is executed." |
| 4802 | */ | 5505 | */ |
| 5506 | #if ENABLE_PLATFORM_MINGW32 | ||
| 5507 | waitcmd_int = -1; | ||
| 5508 | #endif | ||
| 4803 | #if BASH_WAIT_N | 5509 | #if BASH_WAIT_N |
| 4804 | status = dowait(DOWAIT_CHILD_OR_SIG | DOWAIT_JOBSTATUS, NULL); | 5510 | status = dowait(DOWAIT_CHILD_OR_SIG | DOWAIT_JOBSTATUS, NULL); |
| 4805 | #else | 5511 | #else |
| @@ -4809,8 +5515,14 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
| 4809 | * dowait() returns pid > 0. Check this case, | 5515 | * dowait() returns pid > 0. Check this case, |
| 4810 | * not "if (dowait() < 0)"! | 5516 | * not "if (dowait() < 0)"! |
| 4811 | */ | 5517 | */ |
| 5518 | #if ENABLE_PLATFORM_MINGW32 | ||
| 5519 | if (waitcmd_int == 1) | ||
| 5520 | return 128 | SIGINT; | ||
| 5521 | waitcmd_int = 0; | ||
| 5522 | #else | ||
| 4812 | if (pending_sig) | 5523 | if (pending_sig) |
| 4813 | goto sigout; | 5524 | goto sigout; |
| 5525 | #endif | ||
| 4814 | #if BASH_WAIT_N | 5526 | #if BASH_WAIT_N |
| 4815 | if (one) { | 5527 | if (one) { |
| 4816 | /* wait -n waits for one _job_, not one _process_. | 5528 | /* wait -n waits for one _job_, not one _process_. |
| @@ -4921,7 +5633,7 @@ makejob(int nprocs) | |||
| 4921 | break; | 5633 | break; |
| 4922 | if (jp->state != JOBDONE || !jp->waited) | 5634 | if (jp->state != JOBDONE || !jp->waited) |
| 4923 | continue; | 5635 | continue; |
| 4924 | #if JOBS | 5636 | #if JOBS || JOBS_WIN32 |
| 4925 | if (jobctl) | 5637 | if (jobctl) |
| 4926 | continue; | 5638 | continue; |
| 4927 | #endif | 5639 | #endif |
| @@ -4947,7 +5659,7 @@ makejob(int nprocs) | |||
| 4947 | return jp; | 5659 | return jp; |
| 4948 | } | 5660 | } |
| 4949 | 5661 | ||
| 4950 | #if JOBS | 5662 | #if JOBS || JOBS_WIN32 |
| 4951 | /* | 5663 | /* |
| 4952 | * Return a string identifying a command (to be printed by the | 5664 | * Return a string identifying a command (to be printed by the |
| 4953 | * jobs command). | 5665 | * jobs command). |
| @@ -5287,6 +5999,7 @@ clear_traps(void) | |||
| 5287 | INTON; | 5999 | INTON; |
| 5288 | } | 6000 | } |
| 5289 | 6001 | ||
| 6002 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 5290 | /* Lives far away from here, needed for forkchild */ | 6003 | /* Lives far away from here, needed for forkchild */ |
| 5291 | static void closescript(void); | 6004 | static void closescript(void); |
| 5292 | 6005 | ||
| @@ -5425,14 +6138,22 @@ forkchild(struct job *jp, union node *n, int mode) | |||
| 5425 | for (jp = curjob; jp; jp = jp->prev_job) | 6138 | for (jp = curjob; jp; jp = jp->prev_job) |
| 5426 | freejob(jp); | 6139 | freejob(jp); |
| 5427 | } | 6140 | } |
| 6141 | #endif | ||
| 5428 | 6142 | ||
| 5429 | /* Called after fork(), in parent */ | 6143 | /* Called after fork(), in parent */ |
| 5430 | #if !JOBS | 6144 | #if !JOBS && !JOBS_WIN32 |
| 5431 | #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) | 6145 | #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) |
| 5432 | #endif | 6146 | #endif |
| 5433 | static void | 6147 | static void |
| 6148 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 5434 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 6149 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
| 6150 | #else | ||
| 6151 | forkparent(struct job *jp, union node *n, int mode, HANDLE proc) | ||
| 6152 | #endif | ||
| 5435 | { | 6153 | { |
| 6154 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6155 | pid_t pid = GetProcessId(proc); | ||
| 6156 | #else | ||
| 5436 | if (pid < 0) { | 6157 | if (pid < 0) { |
| 5437 | TRACE(("Fork failed, errno=%d", errno)); | 6158 | TRACE(("Fork failed, errno=%d", errno)); |
| 5438 | if (jp) | 6159 | if (jp) |
| @@ -5440,6 +6161,7 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) | |||
| 5440 | ash_msg_and_raise_perror("can't fork"); | 6161 | ash_msg_and_raise_perror("can't fork"); |
| 5441 | /* NOTREACHED */ | 6162 | /* NOTREACHED */ |
| 5442 | } | 6163 | } |
| 6164 | #endif | ||
| 5443 | 6165 | ||
| 5444 | TRACE(("In parent shell: child = %d\n", pid)); | 6166 | TRACE(("In parent shell: child = %d\n", pid)); |
| 5445 | if (!jp) /* jp is NULL when called by openhere() for heredoc support */ | 6167 | if (!jp) /* jp is NULL when called by openhere() for heredoc support */ |
| @@ -5459,19 +6181,29 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) | |||
| 5459 | if (mode == FORK_BG) { | 6181 | if (mode == FORK_BG) { |
| 5460 | backgndpid = pid; /* set $! */ | 6182 | backgndpid = pid; /* set $! */ |
| 5461 | set_curjob(jp, CUR_RUNNING); | 6183 | set_curjob(jp, CUR_RUNNING); |
| 6184 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6185 | if (iflag && jp && jp->nprocs == 0) | ||
| 6186 | fprintf(stderr, "[%d] %"PID_FMT"d\n", jobno(jp), pid); | ||
| 6187 | #endif | ||
| 5462 | } | 6188 | } |
| 5463 | if (jp) { | 6189 | if (jp) { |
| 5464 | struct procstat *ps = &jp->ps[jp->nprocs++]; | 6190 | struct procstat *ps = &jp->ps[jp->nprocs++]; |
| 5465 | ps->ps_pid = pid; | 6191 | ps->ps_pid = pid; |
| 5466 | ps->ps_status = -1; | 6192 | ps->ps_status = -1; |
| 6193 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 5467 | ps->ps_cmd = nullstr; | 6194 | ps->ps_cmd = nullstr; |
| 5468 | #if JOBS | 6195 | #endif |
| 6196 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6197 | ps->ps_proc = proc; | ||
| 6198 | #endif | ||
| 6199 | #if JOBS || JOBS_WIN32 | ||
| 5469 | if (jobctl && n) | 6200 | if (jobctl && n) |
| 5470 | ps->ps_cmd = commandtext(n); | 6201 | ps->ps_cmd = commandtext(n); |
| 5471 | #endif | 6202 | #endif |
| 5472 | } | 6203 | } |
| 5473 | } | 6204 | } |
| 5474 | 6205 | ||
| 6206 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 5475 | /* jp and n are NULL when called by openhere() for heredoc support */ | 6207 | /* jp and n are NULL when called by openhere() for heredoc support */ |
| 5476 | static int | 6208 | static int |
| 5477 | forkshell(struct job *jp, union node *n, int mode) | 6209 | forkshell(struct job *jp, union node *n, int mode) |
| @@ -5517,6 +6249,7 @@ vforkexec(union node *n, char **argv, const char *path, int idx) | |||
| 5517 | 6249 | ||
| 5518 | return jp; | 6250 | return jp; |
| 5519 | } | 6251 | } |
| 6252 | #endif | ||
| 5520 | 6253 | ||
| 5521 | /* | 6254 | /* |
| 5522 | * Wait for job to finish. | 6255 | * Wait for job to finish. |
| @@ -5580,6 +6313,10 @@ waitforjob(struct job *jp) | |||
| 5580 | return exitstatus; | 6313 | return exitstatus; |
| 5581 | 6314 | ||
| 5582 | st = getstatus(jp); | 6315 | st = getstatus(jp); |
| 6316 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6317 | if (!jp->sigint && iflag && rootshell) | ||
| 6318 | pending_int = 0; | ||
| 6319 | #endif | ||
| 5583 | #if JOBS | 6320 | #if JOBS |
| 5584 | if (jp->jobctl) { | 6321 | if (jp->jobctl) { |
| 5585 | xtcsetpgrp(ttyfd, rootpid); | 6322 | xtcsetpgrp(ttyfd, rootpid); |
| @@ -5605,6 +6342,7 @@ waitforjob(struct job *jp) | |||
| 5605 | /* | 6342 | /* |
| 5606 | * return 1 if there are stopped jobs, otherwise 0 | 6343 | * return 1 if there are stopped jobs, otherwise 0 |
| 5607 | */ | 6344 | */ |
| 6345 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 5608 | static int | 6346 | static int |
| 5609 | stoppedjobs(void) | 6347 | stoppedjobs(void) |
| 5610 | { | 6348 | { |
| @@ -5623,6 +6361,17 @@ stoppedjobs(void) | |||
| 5623 | out: | 6361 | out: |
| 5624 | return retval; | 6362 | return retval; |
| 5625 | } | 6363 | } |
| 6364 | #else | ||
| 6365 | static int | ||
| 6366 | stoppedjobs(void) | ||
| 6367 | { | ||
| 6368 | if (iflag && curjob) { | ||
| 6369 | out2str("You have background jobs.\n"); | ||
| 6370 | return 1; | ||
| 6371 | } | ||
| 6372 | return 0; | ||
| 6373 | } | ||
| 6374 | #endif | ||
| 5626 | 6375 | ||
| 5627 | /* | 6376 | /* |
| 5628 | * Code for dealing with input/output redirection. | 6377 | * Code for dealing with input/output redirection. |
| @@ -5641,11 +6390,21 @@ stoppedjobs(void) | |||
| 5641 | static int | 6390 | static int |
| 5642 | write2pipe(int pip[2], const char *p, size_t len) | 6391 | write2pipe(int pip[2], const char *p, size_t len) |
| 5643 | { | 6392 | { |
| 6393 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
| 6394 | |||
| 5644 | if (len <= PIPE_BUF) { | 6395 | if (len <= PIPE_BUF) { |
| 5645 | xwrite(pip[1], p, len); | 6396 | xwrite(pip[1], p, len); |
| 5646 | goto out; | 6397 | goto out; |
| 5647 | } | 6398 | } |
| 5648 | 6399 | ||
| 6400 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6401 | memset(&fs, 0, sizeof(fs)); | ||
| 6402 | fs.fpid = FS_OPENHERE; | ||
| 6403 | fs.fd[0] = pip[0]; | ||
| 6404 | fs.fd[1] = pip[1]; | ||
| 6405 | fs.path = p; | ||
| 6406 | spawn_forkshell(&fs, NULL, NULL, FORK_NOJOB); | ||
| 6407 | #else | ||
| 5649 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | 6408 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { |
| 5650 | /* child */ | 6409 | /* child */ |
| 5651 | close(pip[0]); | 6410 | close(pip[0]); |
| @@ -5657,6 +6416,7 @@ write2pipe(int pip[2], const char *p, size_t len) | |||
| 5657 | xwrite(pip[1], p, len); | 6416 | xwrite(pip[1], p, len); |
| 5658 | _exit_SUCCESS(); | 6417 | _exit_SUCCESS(); |
| 5659 | } | 6418 | } |
| 6419 | #endif | ||
| 5660 | out: | 6420 | out: |
| 5661 | close(pip[1]); | 6421 | close(pip[1]); |
| 5662 | return pip[0]; | 6422 | return pip[0]; |
| @@ -5711,6 +6471,10 @@ openredirect(union node *redir) | |||
| 5711 | flags = O_RDONLY; | 6471 | flags = O_RDONLY; |
| 5712 | do_open: | 6472 | do_open: |
| 5713 | f = sh_open(redir->nfile.expfname, flags, 0); | 6473 | f = sh_open(redir->nfile.expfname, flags, 0); |
| 6474 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6475 | if (redir->nfile.type == NAPPEND) | ||
| 6476 | lseek(f, 0, SEEK_END); | ||
| 6477 | #endif | ||
| 5714 | break; | 6478 | break; |
| 5715 | case NFROMSTR: | 6479 | case NFROMSTR: |
| 5716 | f = openherestr(redir->nfile.expfname); | 6480 | f = openherestr(redir->nfile.expfname); |
| @@ -5967,6 +6731,12 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq) | |||
| 5967 | if (fd == preverrout_fd) | 6731 | if (fd == preverrout_fd) |
| 5968 | preverrout_fd = new_fd; | 6732 | preverrout_fd = new_fd; |
| 5969 | 6733 | ||
| 6734 | #if ENABLE_PLATFORM_MINGW32 && !defined(_UCRT) | ||
| 6735 | // Workaround for problems with stderr in MSVCRT | ||
| 6736 | if (fd == fileno(stderr)) | ||
| 6737 | setvbuf(stderr, NULL, _IONBF, 0); | ||
| 6738 | #endif | ||
| 6739 | |||
| 5970 | return 0; /* "we did not close fd" */ | 6740 | return 0; /* "we did not close fd" */ |
| 5971 | } | 6741 | } |
| 5972 | 6742 | ||
| @@ -6320,6 +7090,9 @@ ifsbreakup(char *string, struct arglist *arglist) | |||
| 6320 | const char *ifs, *realifs; | 7090 | const char *ifs, *realifs; |
| 6321 | int ifsspc; | 7091 | int ifsspc; |
| 6322 | int nulonly; | 7092 | int nulonly; |
| 7093 | #if ENABLE_PLATFORM_MINGW32 | ||
| 7094 | int lshift = 0; | ||
| 7095 | #endif | ||
| 6323 | 7096 | ||
| 6324 | start = string; | 7097 | start = string; |
| 6325 | if (ifslastp != NULL) { | 7098 | if (ifslastp != NULL) { |
| @@ -6330,7 +7103,33 @@ ifsbreakup(char *string, struct arglist *arglist) | |||
| 6330 | do { | 7103 | do { |
| 6331 | int afternul; | 7104 | int afternul; |
| 6332 | 7105 | ||
| 7106 | #if ENABLE_PLATFORM_MINGW32 | ||
| 7107 | /* Adjust region offsets for left-shifted string. */ | ||
| 7108 | ifsp->begoff -= lshift; | ||
| 7109 | ifsp->endoff -= lshift; | ||
| 7110 | #endif | ||
| 6333 | p = string + ifsp->begoff; | 7111 | p = string + ifsp->begoff; |
| 7112 | #if ENABLE_PLATFORM_MINGW32 | ||
| 7113 | if (ifsp->endoff > ifsp->begoff + 1) { | ||
| 7114 | /* Transform CRLF to LF. Skip regions having zero or | ||
| 7115 | * one characters: they can't contain CRLF. If the | ||
| 7116 | * region shrinks shift the rest of the string left. */ | ||
| 7117 | int oldlen = ifsp->endoff - ifsp->begoff; | ||
| 7118 | int newlen = remove_cr(p, oldlen); | ||
| 7119 | int delta = oldlen - newlen; | ||
| 7120 | |||
| 7121 | if (delta > 0) { | ||
| 7122 | char *t = string + ifsp->endoff; | ||
| 7123 | char *s = string + ifsp->endoff - delta; | ||
| 7124 | |||
| 7125 | while (*t) | ||
| 7126 | *s++ = *t++; | ||
| 7127 | *s = '\0'; | ||
| 7128 | lshift += delta; | ||
| 7129 | ifsp->endoff -= delta; | ||
| 7130 | } | ||
| 7131 | } | ||
| 7132 | #endif | ||
| 6334 | afternul = nulonly; | 7133 | afternul = nulonly; |
| 6335 | nulonly = ifsp->nulonly; | 7134 | nulonly = ifsp->nulonly; |
| 6336 | ifs = nulonly ? nullstr : realifs; | 7135 | ifs = nulonly ? nullstr : realifs; |
| @@ -6775,6 +7574,7 @@ evalbackcmd(union node *n, struct backcmd *result | |||
| 6775 | const int ip = 0; | 7574 | const int ip = 0; |
| 6776 | const int ic = 1; | 7575 | const int ic = 1; |
| 6777 | #endif | 7576 | #endif |
| 7577 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
| 6778 | 7578 | ||
| 6779 | result->fd = -1; | 7579 | result->fd = -1; |
| 6780 | result->buf = NULL; | 7580 | result->buf = NULL; |
| @@ -6788,6 +7588,15 @@ evalbackcmd(union node *n, struct backcmd *result | |||
| 6788 | ash_msg_and_raise_perror("can't create pipe"); | 7588 | ash_msg_and_raise_perror("can't create pipe"); |
| 6789 | /* process substitution uses NULL job, like openhere() */ | 7589 | /* process substitution uses NULL job, like openhere() */ |
| 6790 | jp = (ctl == CTLBACKQ) ? makejob(1) : NULL; | 7590 | jp = (ctl == CTLBACKQ) ? makejob(1) : NULL; |
| 7591 | #if ENABLE_PLATFORM_MINGW32 | ||
| 7592 | memset(&fs, 0, sizeof(fs)); | ||
| 7593 | fs.fpid = FS_EVALBACKCMD; | ||
| 7594 | fs.n = n; | ||
| 7595 | fs.fd[0] = pip[0]; | ||
| 7596 | fs.fd[1] = pip[1]; | ||
| 7597 | fs.fd[2] = ctl; | ||
| 7598 | spawn_forkshell(&fs, jp, n, FORK_NOJOB); | ||
| 7599 | #else | ||
| 6791 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 7600 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
| 6792 | /* child */ | 7601 | /* child */ |
| 6793 | reset_exception_handler(); | 7602 | reset_exception_handler(); |
| @@ -6812,6 +7621,7 @@ evalbackcmd(union node *n, struct backcmd *result | |||
| 6812 | evaltreenr(n, EV_EXIT); | 7621 | evaltreenr(n, EV_EXIT); |
| 6813 | /* NOTREACHED */ | 7622 | /* NOTREACHED */ |
| 6814 | } | 7623 | } |
| 7624 | #endif | ||
| 6815 | /* parent */ | 7625 | /* parent */ |
| 6816 | #if BASH_PROCESS_SUBST | 7626 | #if BASH_PROCESS_SUBST |
| 6817 | if (ctl != CTLBACKQ) { | 7627 | if (ctl != CTLBACKQ) { |
| @@ -6890,8 +7700,14 @@ expbackq(union node *cmd, int flag IF_BASH_PROCESS_SUBST(, int ctl)) | |||
| 6890 | 7700 | ||
| 6891 | /* Eat all trailing newlines */ | 7701 | /* Eat all trailing newlines */ |
| 6892 | dest = expdest; | 7702 | dest = expdest; |
| 6893 | for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';) | 7703 | for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';) { |
| 6894 | STUNPUTC(dest); | 7704 | STUNPUTC(dest); |
| 7705 | #if ENABLE_PLATFORM_MINGW32 | ||
| 7706 | if (dest > ((char *)stackblock() + startloc) && dest[-1] == '\r') { | ||
| 7707 | STUNPUTC(dest); | ||
| 7708 | } | ||
| 7709 | #endif | ||
| 7710 | } | ||
| 6895 | expdest = dest; | 7711 | expdest = dest; |
| 6896 | 7712 | ||
| 6897 | if (!(flag & EXP_QUOTED)) | 7713 | if (!(flag & EXP_QUOTED)) |
| @@ -8038,6 +8854,26 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
| 8038 | #else | 8854 | #else |
| 8039 | /* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */ | 8855 | /* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */ |
| 8040 | 8856 | ||
| 8857 | #if ENABLE_ASH_GLOB_OPTIONS | ||
| 8858 | static int FAST_FUNC | ||
| 8859 | ash_accept_glob(const char *name) | ||
| 8860 | { | ||
| 8861 | struct stat st; | ||
| 8862 | |||
| 8863 | if (nohiddenglob || nohidsysglob) { | ||
| 8864 | if (!lstat(name, &st)) { | ||
| 8865 | if ((st.st_attr & FILE_ATTRIBUTE_HIDDEN)) { | ||
| 8866 | if (nohiddenglob || | ||
| 8867 | (st.st_attr & FILE_ATTRIBUTE_SYSTEM)) { | ||
| 8868 | return FALSE; | ||
| 8869 | } | ||
| 8870 | } | ||
| 8871 | } | ||
| 8872 | } | ||
| 8873 | return TRUE; | ||
| 8874 | } | ||
| 8875 | #endif | ||
| 8876 | |||
| 8041 | /* | 8877 | /* |
| 8042 | * Do metacharacter (i.e. *, ?, [...]) expansion. | 8878 | * Do metacharacter (i.e. *, ?, [...]) expansion. |
| 8043 | */ | 8879 | */ |
| @@ -8065,6 +8901,10 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
| 8065 | 8901 | ||
| 8066 | metaflag = 0; | 8902 | metaflag = 0; |
| 8067 | start = name; | 8903 | start = name; |
| 8904 | #if ENABLE_PLATFORM_MINGW32 | ||
| 8905 | if (expdir_len == 0 && has_dos_drive_prefix(start) && start[2] != '/') | ||
| 8906 | start += 2; | ||
| 8907 | #endif | ||
| 8068 | for (p = name; esc = 0, *p; p += esc + 1) { | 8908 | for (p = name; esc = 0, *p; p += esc + 1) { |
| 8069 | if (*p == '*' || *p == '?') | 8909 | if (*p == '*' || *p == '?') |
| 8070 | metaflag = 1; | 8910 | metaflag = 1; |
| @@ -8139,8 +8979,16 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
| 8139 | while (!pending_int && (dp = readdir(dirp)) != NULL) { | 8979 | while (!pending_int && (dp = readdir(dirp)) != NULL) { |
| 8140 | if (dp->d_name[0] == '.' && !matchdot) | 8980 | if (dp->d_name[0] == '.' && !matchdot) |
| 8141 | continue; | 8981 | continue; |
| 8982 | #if ENABLE_ASH_GLOB_OPTIONS | ||
| 8983 | # undef pmatch | ||
| 8984 | # define pmatch(a, b) !fnmatch((a), (b), nocaseglob ? FNM_CASEFOLD : 0) | ||
| 8985 | #endif | ||
| 8142 | if (pmatch(start, dp->d_name)) { | 8986 | if (pmatch(start, dp->d_name)) { |
| 8143 | if (atend) { | 8987 | if (atend) { |
| 8988 | #if ENABLE_ASH_GLOB_OPTIONS | ||
| 8989 | if (!ash_accept_glob(dp->d_name)) | ||
| 8990 | continue; | ||
| 8991 | #endif | ||
| 8144 | strcpy(enddir, dp->d_name); | 8992 | strcpy(enddir, dp->d_name); |
| 8145 | addfname(expdir); | 8993 | addfname(expdir); |
| 8146 | } else { | 8994 | } else { |
| @@ -8168,6 +9016,10 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
| 8168 | endname[-esc - 1] = esc ? '\\' : '/'; | 9016 | endname[-esc - 1] = esc ? '\\' : '/'; |
| 8169 | #undef expdir | 9017 | #undef expdir |
| 8170 | #undef expdir_max | 9018 | #undef expdir_max |
| 9019 | #if ENABLE_ASH_GLOB_OPTIONS | ||
| 9020 | # undef pmatch | ||
| 9021 | # define pmatch(a, b) !fnmatch((a), (b), 0) | ||
| 9022 | #endif | ||
| 8171 | } | 9023 | } |
| 8172 | 9024 | ||
| 8173 | static struct strlist * | 9025 | static struct strlist * |
| @@ -8440,14 +9292,40 @@ static int builtinloc = -1; /* index in path of %builtin, or -1 */ | |||
| 8440 | 9292 | ||
| 8441 | 9293 | ||
| 8442 | static void | 9294 | static void |
| 9295 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9296 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no, const char *path, int noexec,) | ||
| 9297 | const char *cmd, char **argv, char **envp) | ||
| 9298 | #else | ||
| 8443 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp) | 9299 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp) |
| 9300 | #endif | ||
| 8444 | { | 9301 | { |
| 9302 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
| 9303 | interp_t interp; | ||
| 9304 | #endif | ||
| 8445 | #if ENABLE_FEATURE_SH_STANDALONE | 9305 | #if ENABLE_FEATURE_SH_STANDALONE |
| 8446 | if (applet_no >= 0) { | 9306 | if (applet_no >= 0) { |
| 9307 | # if ENABLE_PLATFORM_MINGW32 | ||
| 9308 | /* Treat all applets as NOEXEC, including the shell itself | ||
| 9309 | * if we were called from forkshell_shellexec(). */ | ||
| 9310 | run_noexec: | ||
| 9311 | if (applet_main[applet_no] != ash_main || noexec) { | ||
| 9312 | /* mingw-w64's getopt() uses __argv[0] as the program name */ | ||
| 9313 | __argv[0] = (char *)cmd; | ||
| 9314 | /* 'which' wants to know if it was invoked from a standalone | ||
| 9315 | * shell. 'Which' in argv[0] indicates this. */ | ||
| 9316 | if (strcmp(argv[0], "which") == 0) { | ||
| 9317 | argv[0] = (char *)"Which"; | ||
| 9318 | } | ||
| 9319 | # else | ||
| 8447 | if (!vforked && APPLET_IS_NOEXEC(applet_no)) { | 9320 | if (!vforked && APPLET_IS_NOEXEC(applet_no)) { |
| 9321 | # endif | ||
| 9322 | #if !ENABLE_PLATFORM_MINGW32 || !defined(_UCRT) | ||
| 9323 | /* If building for UCRT move this up into shellexec() to | ||
| 9324 | * work around a bug. */ | ||
| 8448 | clearenv(); | 9325 | clearenv(); |
| 8449 | while (*envp) | 9326 | while (*envp) |
| 8450 | putenv(*envp++); | 9327 | putenv(*envp++); |
| 9328 | #endif | ||
| 8451 | popredir(/*drop:*/ 1); | 9329 | popredir(/*drop:*/ 1); |
| 8452 | run_noexec_applet_and_exit(applet_no, cmd, argv); | 9330 | run_noexec_applet_and_exit(applet_no, cmd, argv); |
| 8453 | } | 9331 | } |
| @@ -8458,6 +9336,44 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
| 8458 | } | 9336 | } |
| 8459 | #endif | 9337 | #endif |
| 8460 | 9338 | ||
| 9339 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9340 | /* Workaround for libtool, which assumes the host is an MSYS2 | ||
| 9341 | * environment and requires special-case escaping for cmd.exe. | ||
| 9342 | * https://github.com/skeeto/w64devkit/issues/50 */ | ||
| 9343 | if (string_array_len(argv) >= 3 && | ||
| 9344 | strcmp(argv[0], "cmd") == 0 && | ||
| 9345 | strcmp(argv[1], "//c") == 0 && | ||
| 9346 | strcmp(argv[2], "echo") == 0) { | ||
| 9347 | argv[1]++; /* drop extra slash */ | ||
| 9348 | } | ||
| 9349 | |||
| 9350 | /* cmd was allocated on the stack with room for an extension */ | ||
| 9351 | add_win32_extension((char *)cmd); | ||
| 9352 | |||
| 9353 | # if ENABLE_FEATURE_SH_STANDALONE | ||
| 9354 | /* If the command is a script with an interpreter which is an | ||
| 9355 | * applet, we can run it as if it were a noexec applet. */ | ||
| 9356 | if (parse_interpreter(cmd, &interp)) { | ||
| 9357 | applet_no = find_applet_by_name_for_sh(interp.name, path); | ||
| 9358 | if (applet_no >= 0) { | ||
| 9359 | argv[0] = (char *)cmd; | ||
| 9360 | /* evalcommand()/spawn_forkshell() add two elements before argv */ | ||
| 9361 | if (interp.opts) { | ||
| 9362 | argv--; | ||
| 9363 | argv[0] = (char *)interp.opts; | ||
| 9364 | } | ||
| 9365 | argv--; | ||
| 9366 | cmd = argv[0] = (char *)interp.name; | ||
| 9367 | /* Identify the index of the script file in argv */ | ||
| 9368 | set_interp(1 + (interp.opts != NULL)); | ||
| 9369 | goto run_noexec; | ||
| 9370 | } | ||
| 9371 | } | ||
| 9372 | # endif | ||
| 9373 | |||
| 9374 | execve(cmd, argv, envp); | ||
| 9375 | /* skip POSIX-mandated retry on ENOEXEC */ | ||
| 9376 | #else /* !ENABLE_PLATFORM_MINGW32 */ | ||
| 8461 | repeat: | 9377 | repeat: |
| 8462 | #ifdef SYSV | 9378 | #ifdef SYSV |
| 8463 | do { | 9379 | do { |
| @@ -8493,14 +9409,25 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
| 8493 | argv[0] = (char*) "ash"; | 9409 | argv[0] = (char*) "ash"; |
| 8494 | goto repeat; | 9410 | goto repeat; |
| 8495 | } | 9411 | } |
| 9412 | #endif /* !ENABLE_PLATFORM_MINGW32 */ | ||
| 8496 | } | 9413 | } |
| 8497 | 9414 | ||
| 9415 | #if !ENABLE_PLATFORM_MINGW32 || !ENABLE_FEATURE_SH_STANDALONE | ||
| 9416 | # define shellexec(prg, a, pth, i, n) shellexec(prg, a, pth, i) | ||
| 9417 | #endif | ||
| 9418 | |||
| 8498 | /* | 9419 | /* |
| 8499 | * Exec a program. Never returns. If you change this routine, you may | 9420 | * Exec a program. Never returns. If you change this routine, you may |
| 8500 | * have to change the find_command routine as well. | 9421 | * have to change the find_command routine as well. |
| 8501 | * argv[-1] must exist and be writable! See tryexec() for why. | 9422 | * argv[-1] must exist and be writable! See tryexec() for why. |
| 8502 | */ | 9423 | */ |
| 8503 | static void shellexec(char *prog, char **argv, const char *path, int idx) | 9424 | #if ENABLE_PLATFORM_MINGW32 |
| 9425 | static struct builtincmd *find_builtin(const char *name); | ||
| 9426 | static void shellexec(char *prog, char **argv, const char *path, int idx, | ||
| 9427 | int noexec) NORETURN; | ||
| 9428 | #endif | ||
| 9429 | static void shellexec(char *prog, char **argv, const char *path, int idx, | ||
| 9430 | int noexec) | ||
| 8504 | { | 9431 | { |
| 8505 | char *cmdname; | 9432 | char *cmdname; |
| 8506 | int e; | 9433 | int e; |
| @@ -8509,12 +9436,30 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
| 8509 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ | 9436 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ |
| 8510 | 9437 | ||
| 8511 | envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); | 9438 | envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); |
| 9439 | #if ENABLE_FEATURE_SH_STANDALONE && ENABLE_PLATFORM_MINGW32 && defined(_UCRT) | ||
| 9440 | /* Avoid UCRT bug by updating parent's environment and passing a | ||
| 9441 | * NULL environment pointer to execve(). */ | ||
| 9442 | clearenv(); | ||
| 9443 | while (*envp) | ||
| 9444 | putenv(*envp++); | ||
| 9445 | envp = NULL; | ||
| 9446 | #endif | ||
| 9447 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 8512 | if (strchr(prog, '/') != NULL | 9448 | if (strchr(prog, '/') != NULL |
| 9449 | #else | ||
| 9450 | if (has_path(prog) | ||
| 9451 | #endif | ||
| 8513 | #if ENABLE_FEATURE_SH_STANDALONE | 9452 | #if ENABLE_FEATURE_SH_STANDALONE |
| 8514 | || (applet_no = find_applet_by_name(prog)) >= 0 | 9453 | || (applet_no = find_applet_by_name_for_sh(prog, path)) >= 0 |
| 8515 | #endif | 9454 | #endif |
| 8516 | ) { | 9455 | ) { |
| 9456 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9457 | char *progext = stack_add_ext_space(prog); | ||
| 9458 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no, path, noexec,) | ||
| 9459 | progext, argv, envp); | ||
| 9460 | #else | ||
| 8517 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); | 9461 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); |
| 9462 | #endif | ||
| 8518 | if (applet_no >= 0) { | 9463 | if (applet_no >= 0) { |
| 8519 | /* We tried execing ourself, but it didn't work. | 9464 | /* We tried execing ourself, but it didn't work. |
| 8520 | * Maybe /proc/self/exe doesn't exist? | 9465 | * Maybe /proc/self/exe doesn't exist? |
| @@ -8523,13 +9468,33 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
| 8523 | goto try_PATH; | 9468 | goto try_PATH; |
| 8524 | } | 9469 | } |
| 8525 | e = errno; | 9470 | e = errno; |
| 9471 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9472 | if (unix_path(prog)) { | ||
| 9473 | const char *name = bb_basename(prog); | ||
| 9474 | # if ENABLE_FEATURE_SH_STANDALONE | ||
| 9475 | if ((applet_no = find_applet_by_name_for_sh(name, path)) >= 0) { | ||
| 9476 | tryexec(applet_no, path, noexec, name, argv, envp); | ||
| 9477 | e = errno; | ||
| 9478 | } | ||
| 9479 | # endif | ||
| 9480 | if (!find_builtin(name)) { | ||
| 9481 | argv[0] = (char *)name; | ||
| 9482 | goto try_PATH; | ||
| 9483 | } | ||
| 9484 | } | ||
| 9485 | #endif | ||
| 8526 | } else { | 9486 | } else { |
| 8527 | try_PATH: | 9487 | try_PATH: |
| 8528 | e = ENOENT; | 9488 | e = ENOENT; |
| 8529 | while (padvance(&path, argv[0]) >= 0) { | 9489 | while (padvance(&path, argv[0]) >= 0) { |
| 8530 | cmdname = stackblock(); | 9490 | cmdname = stackblock(); |
| 8531 | if (--idx < 0 && pathopt == NULL) { | 9491 | if (--idx < 0 && pathopt == NULL) { |
| 9492 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9493 | tryexec(IF_FEATURE_SH_STANDALONE(-1, path, noexec,) | ||
| 9494 | cmdname, argv, envp); | ||
| 9495 | #else | ||
| 8532 | tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp); | 9496 | tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp); |
| 9497 | #endif | ||
| 8533 | if (errno != ENOENT && errno != ENOTDIR) | 9498 | if (errno != ENOENT && errno != ENOTDIR) |
| 8534 | e = errno; | 9499 | e = errno; |
| 8535 | } | 9500 | } |
| @@ -8568,6 +9533,9 @@ printentry(struct tblentry *cmdp) | |||
| 8568 | padvance(&path, cmdp->cmdname); | 9533 | padvance(&path, cmdp->cmdname); |
| 8569 | } while (--idx >= 0); | 9534 | } while (--idx >= 0); |
| 8570 | name = stackblock(); | 9535 | name = stackblock(); |
| 9536 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9537 | add_win32_extension(name); | ||
| 9538 | #endif | ||
| 8571 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); | 9539 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); |
| 8572 | } | 9540 | } |
| 8573 | 9541 | ||
| @@ -8768,7 +9736,7 @@ changepath(const char *newval) | |||
| 8768 | bltin = idx; | 9736 | bltin = idx; |
| 8769 | break; | 9737 | break; |
| 8770 | } | 9738 | } |
| 8771 | new = strchr(new, ':'); | 9739 | new = strchr(new, PATH_SEP); |
| 8772 | if (!new) | 9740 | if (!new) |
| 8773 | break; | 9741 | break; |
| 8774 | idx++; | 9742 | idx++; |
| @@ -8945,14 +9913,37 @@ describe_command(char *command, const char *path, int describe_command_verbose) | |||
| 8945 | case CMDNORMAL: { | 9913 | case CMDNORMAL: { |
| 8946 | int j = entry.u.index; | 9914 | int j = entry.u.index; |
| 8947 | char *p; | 9915 | char *p; |
| 9916 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
| 9917 | if (j < -1) { | ||
| 9918 | p = (char *)bb_basename(command); | ||
| 9919 | if (describe_command_verbose) { | ||
| 9920 | out1fmt(" is a builtin applet"); | ||
| 9921 | } else { | ||
| 9922 | out1str(applet_to_exe(p)); | ||
| 9923 | } | ||
| 9924 | break; | ||
| 9925 | } | ||
| 9926 | #endif | ||
| 8948 | if (j < 0) { | 9927 | if (j < 0) { |
| 9928 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9929 | p = stack_add_ext_space(command); | ||
| 9930 | #else | ||
| 8949 | p = command; | 9931 | p = command; |
| 9932 | #endif | ||
| 8950 | } else { | 9933 | } else { |
| 9934 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9935 | if (unix_path(command)) | ||
| 9936 | command = (char *)bb_basename(command); | ||
| 9937 | #endif | ||
| 8951 | do { | 9938 | do { |
| 8952 | padvance(&path, command); | 9939 | padvance(&path, command); |
| 8953 | } while (--j >= 0); | 9940 | } while (--j >= 0); |
| 8954 | p = stackblock(); | 9941 | p = stackblock(); |
| 8955 | } | 9942 | } |
| 9943 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9944 | add_win32_extension(p); | ||
| 9945 | bs_to_slash(p); | ||
| 9946 | #endif | ||
| 8956 | if (describe_command_verbose) { | 9947 | if (describe_command_verbose) { |
| 8957 | out1fmt(" is %s", p); | 9948 | out1fmt(" is %s", p); |
| 8958 | } else { | 9949 | } else { |
| @@ -9107,6 +10098,15 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 9107 | /*static int funcstringsize; // size of strings in node */ | 10098 | /*static int funcstringsize; // size of strings in node */ |
| 9108 | static void *funcblock; /* block to allocate function from */ | 10099 | static void *funcblock; /* block to allocate function from */ |
| 9109 | static char *funcstring_end; /* end of block to allocate strings from */ | 10100 | static char *funcstring_end; /* end of block to allocate strings from */ |
| 10101 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10102 | static int fs_size; | ||
| 10103 | static void *fs_start; | ||
| 10104 | # if FORKSHELL_DEBUG | ||
| 10105 | static void *fs_funcstring; | ||
| 10106 | static const char **annot; | ||
| 10107 | static char *annot_free; | ||
| 10108 | # endif | ||
| 10109 | #endif | ||
| 9110 | 10110 | ||
| 9111 | static const uint8_t nodesize[N_NUMBER] ALIGN1 = { | 10111 | static const uint8_t nodesize[N_NUMBER] ALIGN1 = { |
| 9112 | [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), | 10112 | [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), |
| @@ -9240,14 +10240,79 @@ calcsize(int funcblocksize, union node *n) | |||
| 9240 | } | 10240 | } |
| 9241 | 10241 | ||
| 9242 | static char * | 10242 | static char * |
| 9243 | nodeckstrdup(char *s) | 10243 | nodeckstrdup(const char *s) |
| 9244 | { | 10244 | { |
| 10245 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10246 | if(!s) | ||
| 10247 | return NULL; | ||
| 10248 | #endif | ||
| 9245 | funcstring_end -= SHELL_ALIGN(strlen(s) + 1); | 10249 | funcstring_end -= SHELL_ALIGN(strlen(s) + 1); |
| 9246 | return strcpy(funcstring_end, s); | 10250 | return strcpy(funcstring_end, s); |
| 9247 | } | 10251 | } |
| 9248 | 10252 | ||
| 9249 | static union node *copynode(union node *); | 10253 | static union node *copynode(union node *); |
| 9250 | 10254 | ||
| 10255 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10256 | # if FORKSHELL_DEBUG | ||
| 10257 | # define MARK_PTR(dst,note,flag) forkshell_mark_ptr((void *)&dst, note, flag) | ||
| 10258 | # else | ||
| 10259 | # define MARK_PTR(dst,note,flag) forkshell_mark_ptr((void *)&dst) | ||
| 10260 | # endif | ||
| 10261 | |||
| 10262 | #define NO_FREE 0 | ||
| 10263 | #define FREE 1 | ||
| 10264 | |||
| 10265 | #if FORKSHELL_DEBUG | ||
| 10266 | static void forkshell_mark_ptr(void *dst, const char *note, int flag) | ||
| 10267 | #else | ||
| 10268 | static void forkshell_mark_ptr(void *dst) | ||
| 10269 | #endif | ||
| 10270 | { | ||
| 10271 | char *lrelocate = (char *)fs_start + fs_size; | ||
| 10272 | int index = ((char *)dst - (char *)fs_start)/sizeof(char *); | ||
| 10273 | |||
| 10274 | lrelocate[index/8] |= 1 << (index % 8); | ||
| 10275 | |||
| 10276 | #if FORKSHELL_DEBUG | ||
| 10277 | if (dst < fs_start || dst >= fs_funcstring) { | ||
| 10278 | fprintf(stderr, "dst (%p) out of range (%p %p)\n", | ||
| 10279 | dst, fs_start, fs_funcstring); | ||
| 10280 | } | ||
| 10281 | if (annot) { | ||
| 10282 | if (annot[index]) { | ||
| 10283 | fprintf(stderr, "duplicate annotation: %s %s\n", | ||
| 10284 | annot[index], note); | ||
| 10285 | } | ||
| 10286 | annot[index] = note; | ||
| 10287 | annot_free[index] = flag; | ||
| 10288 | } | ||
| 10289 | #endif | ||
| 10290 | } | ||
| 10291 | |||
| 10292 | # define SAVE_PTR(dst,note,flag) { \ | ||
| 10293 | if (fs_size) { \ | ||
| 10294 | MARK_PTR(dst,note,flag); \ | ||
| 10295 | } \ | ||
| 10296 | } | ||
| 10297 | # define SAVE_PTR2(dst1,note1,flag1,dst2,note2,flag2) { \ | ||
| 10298 | if (fs_size) { \ | ||
| 10299 | MARK_PTR(dst1,note1,flag1); \ | ||
| 10300 | MARK_PTR(dst2,note2,flag2); \ | ||
| 10301 | } \ | ||
| 10302 | } | ||
| 10303 | # define SAVE_PTR3(dst1,note1,flag1,dst2,note2,flag2,dst3,note3,flag3) { \ | ||
| 10304 | if (fs_size) { \ | ||
| 10305 | MARK_PTR(dst1,note1,flag1); \ | ||
| 10306 | MARK_PTR(dst2,note2,flag2); \ | ||
| 10307 | MARK_PTR(dst3,note3,flag3); \ | ||
| 10308 | } \ | ||
| 10309 | } | ||
| 10310 | #else | ||
| 10311 | # define SAVE_PTR(dst,note,flag) | ||
| 10312 | # define SAVE_PTR2(dst1,note1,flag1,dst2,note2,flag2) | ||
| 10313 | # define SAVE_PTR3(dst1,note1,flag1,dst2,note2,flag2,dst3,note3,flag3) | ||
| 10314 | #endif | ||
| 10315 | |||
| 9251 | static struct nodelist * | 10316 | static struct nodelist * |
| 9252 | copynodelist(struct nodelist *lp) | 10317 | copynodelist(struct nodelist *lp) |
| 9253 | { | 10318 | { |
| @@ -9259,6 +10324,8 @@ copynodelist(struct nodelist *lp) | |||
| 9259 | *lpp = funcblock; | 10324 | *lpp = funcblock; |
| 9260 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); | 10325 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); |
| 9261 | (*lpp)->n = copynode(lp->n); | 10326 | (*lpp)->n = copynode(lp->n); |
| 10327 | SAVE_PTR2((*lpp)->n, "(*lpp)->next", NO_FREE, | ||
| 10328 | (*lpp)->next, "(*lpp)->next", NO_FREE); | ||
| 9262 | lp = lp->next; | 10329 | lp = lp->next; |
| 9263 | lpp = &(*lpp)->next; | 10330 | lpp = &(*lpp)->next; |
| 9264 | } | 10331 | } |
| @@ -9282,10 +10349,14 @@ copynode(union node *n) | |||
| 9282 | new->ncmd.args = copynode(n->ncmd.args); | 10349 | new->ncmd.args = copynode(n->ncmd.args); |
| 9283 | new->ncmd.assign = copynode(n->ncmd.assign); | 10350 | new->ncmd.assign = copynode(n->ncmd.assign); |
| 9284 | new->ncmd.linno = n->ncmd.linno; | 10351 | new->ncmd.linno = n->ncmd.linno; |
| 10352 | SAVE_PTR3(new->ncmd.redirect, "ncmd.redirect", NO_FREE, | ||
| 10353 | new->ncmd.args, "ncmd.args", NO_FREE, | ||
| 10354 | new->ncmd.assign, "ncmd.assign", NO_FREE); | ||
| 9285 | break; | 10355 | break; |
| 9286 | case NPIPE: | 10356 | case NPIPE: |
| 9287 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | 10357 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); |
| 9288 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; | 10358 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; |
| 10359 | SAVE_PTR(new->npipe.cmdlist, "npipe.cmdlist", NO_FREE); | ||
| 9289 | break; | 10360 | break; |
| 9290 | case NREDIR: | 10361 | case NREDIR: |
| 9291 | case NBACKGND: | 10362 | case NBACKGND: |
| @@ -9293,6 +10364,8 @@ copynode(union node *n) | |||
| 9293 | new->nredir.redirect = copynode(n->nredir.redirect); | 10364 | new->nredir.redirect = copynode(n->nredir.redirect); |
| 9294 | new->nredir.n = copynode(n->nredir.n); | 10365 | new->nredir.n = copynode(n->nredir.n); |
| 9295 | new->nredir.linno = n->nredir.linno; | 10366 | new->nredir.linno = n->nredir.linno; |
| 10367 | SAVE_PTR2(new->nredir.redirect, "nredir.redirect", NO_FREE, | ||
| 10368 | new->nredir.n, "nredir.n", NO_FREE); | ||
| 9296 | break; | 10369 | break; |
| 9297 | case NAND: | 10370 | case NAND: |
| 9298 | case NOR: | 10371 | case NOR: |
| @@ -9301,37 +10374,58 @@ copynode(union node *n) | |||
| 9301 | case NUNTIL: | 10374 | case NUNTIL: |
| 9302 | new->nbinary.ch2 = copynode(n->nbinary.ch2); | 10375 | new->nbinary.ch2 = copynode(n->nbinary.ch2); |
| 9303 | new->nbinary.ch1 = copynode(n->nbinary.ch1); | 10376 | new->nbinary.ch1 = copynode(n->nbinary.ch1); |
| 10377 | SAVE_PTR2(new->nbinary.ch1, "nbinary.ch1", NO_FREE, | ||
| 10378 | new->nbinary.ch2, "nbinary.ch2", NO_FREE); | ||
| 9304 | break; | 10379 | break; |
| 9305 | case NIF: | 10380 | case NIF: |
| 9306 | new->nif.elsepart = copynode(n->nif.elsepart); | 10381 | new->nif.elsepart = copynode(n->nif.elsepart); |
| 9307 | new->nif.ifpart = copynode(n->nif.ifpart); | 10382 | new->nif.ifpart = copynode(n->nif.ifpart); |
| 9308 | new->nif.test = copynode(n->nif.test); | 10383 | new->nif.test = copynode(n->nif.test); |
| 10384 | SAVE_PTR3(new->nif.elsepart, "nif.elsepart", NO_FREE, | ||
| 10385 | new->nif.ifpart, "nif.ifpart", NO_FREE, | ||
| 10386 | new->nif.test, "nif.test", NO_FREE); | ||
| 9309 | break; | 10387 | break; |
| 9310 | case NFOR: | 10388 | case NFOR: |
| 9311 | new->nfor.var = nodeckstrdup(n->nfor.var); | 10389 | new->nfor.var = nodeckstrdup(n->nfor.var); |
| 9312 | new->nfor.body = copynode(n->nfor.body); | 10390 | new->nfor.body = copynode(n->nfor.body); |
| 9313 | new->nfor.args = copynode(n->nfor.args); | 10391 | new->nfor.args = copynode(n->nfor.args); |
| 9314 | new->nfor.linno = n->nfor.linno; | 10392 | new->nfor.linno = n->nfor.linno; |
| 10393 | SAVE_PTR3(new->nfor.var, | ||
| 10394 | xasprintf("nfor.var '%s'", n->nfor.var ?: "NULL"), FREE, | ||
| 10395 | new->nfor.body, "nfor.body", NO_FREE, | ||
| 10396 | new->nfor.args, "nfor.args", NO_FREE); | ||
| 9315 | break; | 10397 | break; |
| 9316 | case NCASE: | 10398 | case NCASE: |
| 9317 | new->ncase.cases = copynode(n->ncase.cases); | 10399 | new->ncase.cases = copynode(n->ncase.cases); |
| 9318 | new->ncase.expr = copynode(n->ncase.expr); | 10400 | new->ncase.expr = copynode(n->ncase.expr); |
| 9319 | new->ncase.linno = n->ncase.linno; | 10401 | new->ncase.linno = n->ncase.linno; |
| 10402 | SAVE_PTR2(new->ncase.cases, "ncase.cases", NO_FREE, | ||
| 10403 | new->ncase.expr, "ncase.expr", NO_FREE); | ||
| 9320 | break; | 10404 | break; |
| 9321 | case NCLIST: | 10405 | case NCLIST: |
| 9322 | new->nclist.body = copynode(n->nclist.body); | 10406 | new->nclist.body = copynode(n->nclist.body); |
| 9323 | new->nclist.pattern = copynode(n->nclist.pattern); | 10407 | new->nclist.pattern = copynode(n->nclist.pattern); |
| 9324 | new->nclist.next = copynode(n->nclist.next); | 10408 | new->nclist.next = copynode(n->nclist.next); |
| 10409 | SAVE_PTR3(new->nclist.body, "nclist.body", NO_FREE, | ||
| 10410 | new->nclist.pattern, "nclist.pattern", NO_FREE, | ||
| 10411 | new->nclist.next, "nclist.next", NO_FREE); | ||
| 9325 | break; | 10412 | break; |
| 9326 | case NDEFUN: | 10413 | case NDEFUN: |
| 9327 | new->ndefun.body = copynode(n->ndefun.body); | 10414 | new->ndefun.body = copynode(n->ndefun.body); |
| 9328 | new->ndefun.text = nodeckstrdup(n->ndefun.text); | 10415 | new->ndefun.text = nodeckstrdup(n->ndefun.text); |
| 9329 | new->ndefun.linno = n->ndefun.linno; | 10416 | new->ndefun.linno = n->ndefun.linno; |
| 10417 | SAVE_PTR2(new->ndefun.body, "ndefun.body", NO_FREE, | ||
| 10418 | new->ndefun.text, | ||
| 10419 | xasprintf("ndefun.text '%s'", n->ndefun.text ?: "NULL"), FREE); | ||
| 9330 | break; | 10420 | break; |
| 9331 | case NARG: | 10421 | case NARG: |
| 9332 | new->narg.backquote = copynodelist(n->narg.backquote); | 10422 | new->narg.backquote = copynodelist(n->narg.backquote); |
| 9333 | new->narg.text = nodeckstrdup(n->narg.text); | 10423 | new->narg.text = nodeckstrdup(n->narg.text); |
| 9334 | new->narg.next = copynode(n->narg.next); | 10424 | new->narg.next = copynode(n->narg.next); |
| 10425 | SAVE_PTR3(new->narg.backquote, "narg.backquote", NO_FREE, | ||
| 10426 | new->narg.text, | ||
| 10427 | xasprintf("narg.text '%s'", n->narg.text ?: "NULL"), FREE, | ||
| 10428 | new->narg.next, "narg.next", NO_FREE); | ||
| 9335 | break; | 10429 | break; |
| 9336 | case NTO: | 10430 | case NTO: |
| 9337 | #if BASH_REDIR_OUTPUT | 10431 | #if BASH_REDIR_OUTPUT |
| @@ -9345,6 +10439,8 @@ copynode(union node *n) | |||
| 9345 | new->nfile.fname = copynode(n->nfile.fname); | 10439 | new->nfile.fname = copynode(n->nfile.fname); |
| 9346 | new->nfile.fd = n->nfile.fd; | 10440 | new->nfile.fd = n->nfile.fd; |
| 9347 | new->nfile.next = copynode(n->nfile.next); | 10441 | new->nfile.next = copynode(n->nfile.next); |
| 10442 | SAVE_PTR2(new->nfile.fname, "nfile.fname", NO_FREE, | ||
| 10443 | new->nfile.next, "nfile.next", NO_FREE); | ||
| 9348 | break; | 10444 | break; |
| 9349 | case NTOFD: | 10445 | case NTOFD: |
| 9350 | case NFROMFD: | 10446 | case NFROMFD: |
| @@ -9352,15 +10448,20 @@ copynode(union node *n) | |||
| 9352 | new->ndup.dupfd = n->ndup.dupfd; | 10448 | new->ndup.dupfd = n->ndup.dupfd; |
| 9353 | new->ndup.fd = n->ndup.fd; | 10449 | new->ndup.fd = n->ndup.fd; |
| 9354 | new->ndup.next = copynode(n->ndup.next); | 10450 | new->ndup.next = copynode(n->ndup.next); |
| 10451 | SAVE_PTR2(new->ndup.vname, "ndup.vname", NO_FREE, | ||
| 10452 | new->ndup.next, "ndup.next", NO_FREE); | ||
| 9355 | break; | 10453 | break; |
| 9356 | case NHERE: | 10454 | case NHERE: |
| 9357 | case NXHERE: | 10455 | case NXHERE: |
| 9358 | new->nhere.doc = copynode(n->nhere.doc); | 10456 | new->nhere.doc = copynode(n->nhere.doc); |
| 9359 | new->nhere.fd = n->nhere.fd; | 10457 | new->nhere.fd = n->nhere.fd; |
| 9360 | new->nhere.next = copynode(n->nhere.next); | 10458 | new->nhere.next = copynode(n->nhere.next); |
| 10459 | SAVE_PTR2(new->nhere.doc, "nhere.doc", NO_FREE, | ||
| 10460 | new->nhere.next, "nhere.next", NO_FREE); | ||
| 9361 | break; | 10461 | break; |
| 9362 | case NNOT: | 10462 | case NNOT: |
| 9363 | new->nnot.com = copynode(n->nnot.com); | 10463 | new->nnot.com = copynode(n->nnot.com); |
| 10464 | SAVE_PTR(new->nnot.com, "nnot.com", NO_FREE); | ||
| 9364 | break; | 10465 | break; |
| 9365 | }; | 10466 | }; |
| 9366 | new->type = n->type; | 10467 | new->type = n->type; |
| @@ -9381,6 +10482,7 @@ copyfunc(union node *n) | |||
| 9381 | f = ckzalloc(blocksize /* + funcstringsize */); | 10482 | f = ckzalloc(blocksize /* + funcstringsize */); |
| 9382 | funcblock = (char *) f + offsetof(struct funcnode, n); | 10483 | funcblock = (char *) f + offsetof(struct funcnode, n); |
| 9383 | funcstring_end = (char *) f + blocksize; | 10484 | funcstring_end = (char *) f + blocksize; |
| 10485 | IF_PLATFORM_MINGW32(fs_size = 0); | ||
| 9384 | copynode(n); | 10486 | copynode(n); |
| 9385 | /* f->count = 0; - ckzalloc did it */ | 10487 | /* f->count = 0; - ckzalloc did it */ |
| 9386 | return f; | 10488 | return f; |
| @@ -9408,12 +10510,15 @@ defun(union node *func) | |||
| 9408 | #define SKIPFUNCDEF (1 << 3) | 10510 | #define SKIPFUNCDEF (1 << 3) |
| 9409 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ | 10511 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ |
| 9410 | static int skipcount; /* number of levels to skip */ | 10512 | static int skipcount; /* number of levels to skip */ |
| 10513 | #if ENABLE_PLATFORM_POSIX | ||
| 9411 | static int loopnest; /* current loop nesting level */ | 10514 | static int loopnest; /* current loop nesting level */ |
| 10515 | #endif | ||
| 9412 | static int funcline; /* starting line number of current function, or 0 if not in a function */ | 10516 | static int funcline; /* starting line number of current function, or 0 if not in a function */ |
| 9413 | 10517 | ||
| 9414 | /* Forward decl way out to parsing code - dotrap needs it */ | 10518 | /* Forward decl way out to parsing code - dotrap needs it */ |
| 9415 | static int evalstring(char *s, int flags); | 10519 | static int evalstring(char *s, int flags); |
| 9416 | 10520 | ||
| 10521 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 9417 | /* Called to execute a trap. | 10522 | /* Called to execute a trap. |
| 9418 | * Single callsite - at the end of evaltree(). | 10523 | * Single callsite - at the end of evaltree(). |
| 9419 | * If we return non-zero, evaltree raises EXEXIT exception. | 10524 | * If we return non-zero, evaltree raises EXEXIT exception. |
| @@ -9472,6 +10577,47 @@ dotrap(void) | |||
| 9472 | savestatus = last_status; | 10577 | savestatus = last_status; |
| 9473 | TRACE(("dotrap returns\n")); | 10578 | TRACE(("dotrap returns\n")); |
| 9474 | } | 10579 | } |
| 10580 | #else | ||
| 10581 | static void | ||
| 10582 | dotrap(void) | ||
| 10583 | { | ||
| 10584 | int status, last_status; | ||
| 10585 | char *p; | ||
| 10586 | |||
| 10587 | if (!pending_int && waitcmd_int != 1) { | ||
| 10588 | waitcmd_int = 0; | ||
| 10589 | return; | ||
| 10590 | } | ||
| 10591 | |||
| 10592 | status = savestatus; | ||
| 10593 | last_status = status; | ||
| 10594 | if (status < 0) { | ||
| 10595 | status = exitstatus; | ||
| 10596 | savestatus = status; | ||
| 10597 | } | ||
| 10598 | pending_int = waitcmd_int = 0; | ||
| 10599 | barrier(); | ||
| 10600 | |||
| 10601 | TRACE(("dotrap entered\n")); | ||
| 10602 | if (evalskip) { | ||
| 10603 | pending_int = 1; | ||
| 10604 | return; | ||
| 10605 | } | ||
| 10606 | |||
| 10607 | p = trap[SIGINT]; | ||
| 10608 | if (p) { | ||
| 10609 | TRACE(("sig %d is active, will run handler '%s'\n", SIGINT, p)); | ||
| 10610 | trap_depth++; | ||
| 10611 | evalstring(p, 0); | ||
| 10612 | trap_depth--; | ||
| 10613 | if (evalskip != SKIPFUNC) | ||
| 10614 | exitstatus = status; | ||
| 10615 | } | ||
| 10616 | |||
| 10617 | savestatus = last_status; | ||
| 10618 | TRACE(("dotrap returns\n")); | ||
| 10619 | } | ||
| 10620 | #endif | ||
| 9475 | 10621 | ||
| 9476 | /* forward declarations - evaluation is fairly recursive business... */ | 10622 | /* forward declarations - evaluation is fairly recursive business... */ |
| 9477 | static int evalloop(union node *, int); | 10623 | static int evalloop(union node *, int); |
| @@ -9758,19 +10904,37 @@ evalcase(union node *n, int flags) | |||
| 9758 | static int | 10904 | static int |
| 9759 | evalsubshell(union node *n, int flags) | 10905 | evalsubshell(union node *n, int flags) |
| 9760 | { | 10906 | { |
| 10907 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
| 9761 | struct job *jp; | 10908 | struct job *jp; |
| 9762 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ | 10909 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ |
| 9763 | int status; | 10910 | int status; |
| 9764 | 10911 | ||
| 9765 | errlinno = lineno = n->nredir.linno; | 10912 | errlinno = lineno = n->nredir.linno; |
| 9766 | 10913 | ||
| 10914 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10915 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) { | ||
| 10916 | reset_exception_handler(); | ||
| 10917 | expredir(n->nredir.redirect); | ||
| 10918 | redirect(n->nredir.redirect, 0); | ||
| 10919 | evaltreenr(n->nredir.n, flags); | ||
| 10920 | /* never returns */ | ||
| 10921 | } | ||
| 10922 | #else | ||
| 9767 | expredir(n->nredir.redirect); | 10923 | expredir(n->nredir.redirect); |
| 9768 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) | 10924 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) |
| 9769 | goto nofork; | 10925 | goto nofork; |
| 10926 | #endif | ||
| 9770 | INTOFF; | 10927 | INTOFF; |
| 9771 | if (backgnd == FORK_FG) | 10928 | if (backgnd == FORK_FG) |
| 9772 | get_tty_state(); | 10929 | get_tty_state(); |
| 9773 | jp = makejob(1); | 10930 | jp = makejob(1); |
| 10931 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10932 | memset(&fs, 0, sizeof(fs)); | ||
| 10933 | fs.fpid = FS_EVALSUBSHELL; | ||
| 10934 | fs.n = n; | ||
| 10935 | fs.flags = flags; | ||
| 10936 | spawn_forkshell(&fs, jp, n, backgnd); | ||
| 10937 | #else | ||
| 9774 | if (forkshell(jp, n, backgnd) == 0) { | 10938 | if (forkshell(jp, n, backgnd) == 0) { |
| 9775 | /* child */ | 10939 | /* child */ |
| 9776 | INTON; | 10940 | INTON; |
| @@ -9783,6 +10947,7 @@ evalsubshell(union node *n, int flags) | |||
| 9783 | evaltreenr(n->nredir.n, flags); | 10947 | evaltreenr(n->nredir.n, flags); |
| 9784 | /* never returns */ | 10948 | /* never returns */ |
| 9785 | } | 10949 | } |
| 10950 | #endif | ||
| 9786 | /* parent */ | 10951 | /* parent */ |
| 9787 | status = 0; | 10952 | status = 0; |
| 9788 | if (backgnd == FORK_FG) | 10953 | if (backgnd == FORK_FG) |
| @@ -9864,6 +11029,7 @@ expredir(union node *n) | |||
| 9864 | static int | 11029 | static int |
| 9865 | evalpipe(union node *n, int flags) | 11030 | evalpipe(union node *n, int flags) |
| 9866 | { | 11031 | { |
| 11032 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
| 9867 | struct job *jp; | 11033 | struct job *jp; |
| 9868 | struct nodelist *lp; | 11034 | struct nodelist *lp; |
| 9869 | int pipelen; | 11035 | int pipelen; |
| @@ -9890,6 +11056,16 @@ evalpipe(union node *n, int flags) | |||
| 9890 | ash_msg_and_raise_perror("can't create pipe"); | 11056 | ash_msg_and_raise_perror("can't create pipe"); |
| 9891 | } | 11057 | } |
| 9892 | } | 11058 | } |
| 11059 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11060 | memset(&fs, 0, sizeof(fs)); | ||
| 11061 | fs.fpid = FS_EVALPIPE; | ||
| 11062 | fs.flags = flags; | ||
| 11063 | fs.n = lp->n; | ||
| 11064 | fs.fd[0] = pip[0]; | ||
| 11065 | fs.fd[1] = pip[1]; | ||
| 11066 | fs.fd[2] = prevfd; | ||
| 11067 | spawn_forkshell(&fs, jp, lp->n, n->npipe.pipe_backgnd); | ||
| 11068 | #else | ||
| 9893 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { | 11069 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { |
| 9894 | /* child */ | 11070 | /* child */ |
| 9895 | reset_exception_handler(); | 11071 | reset_exception_handler(); |
| @@ -9908,6 +11084,7 @@ evalpipe(union node *n, int flags) | |||
| 9908 | evaltreenr(lp->n, flags); | 11084 | evaltreenr(lp->n, flags); |
| 9909 | /* never returns */ | 11085 | /* never returns */ |
| 9910 | } | 11086 | } |
| 11087 | #endif | ||
| 9911 | /* parent */ | 11088 | /* parent */ |
| 9912 | if (prevfd >= 0) | 11089 | if (prevfd >= 0) |
| 9913 | close(prevfd); | 11090 | close(prevfd); |
| @@ -9965,6 +11142,9 @@ setinteractive(int on) | |||
| 9965 | line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); | 11142 | line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); |
| 9966 | # if ENABLE_FEATURE_TAB_COMPLETION | 11143 | # if ENABLE_FEATURE_TAB_COMPLETION |
| 9967 | line_input_state->get_exe_name = ash_command_name; | 11144 | line_input_state->get_exe_name = ash_command_name; |
| 11145 | # if ENABLE_ASH_GLOB_OPTIONS | ||
| 11146 | line_input_state->sh_accept_glob = ash_accept_glob; | ||
| 11147 | # endif | ||
| 9968 | # endif | 11148 | # endif |
| 9969 | # if EDITING_HAS_sh_get_var | 11149 | # if EDITING_HAS_sh_get_var |
| 9970 | line_input_state->sh_get_var = lookupvar; | 11150 | line_input_state->sh_get_var = lookupvar; |
| @@ -9992,6 +11172,12 @@ optschanged(void) | |||
| 9992 | #else | 11172 | #else |
| 9993 | viflag = 0; /* forcibly keep the option off */ | 11173 | viflag = 0; /* forcibly keep the option off */ |
| 9994 | #endif | 11174 | #endif |
| 11175 | #if ENABLE_ASH_NOCONSOLE | ||
| 11176 | hide_console(noconsole); | ||
| 11177 | #endif | ||
| 11178 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11179 | setwinxp(winxp); | ||
| 11180 | #endif | ||
| 9995 | } | 11181 | } |
| 9996 | 11182 | ||
| 9997 | struct localvar_list { | 11183 | struct localvar_list { |
| @@ -10011,6 +11197,9 @@ poplocalvars(int keep) | |||
| 10011 | struct localvar_list *ll; | 11197 | struct localvar_list *ll; |
| 10012 | struct localvar *lvp, *next; | 11198 | struct localvar *lvp, *next; |
| 10013 | struct var *vp; | 11199 | struct var *vp; |
| 11200 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11201 | int var_type; | ||
| 11202 | #endif | ||
| 10014 | 11203 | ||
| 10015 | INTOFF; | 11204 | INTOFF; |
| 10016 | ll = localvar_stack; | 11205 | ll = localvar_stack; |
| @@ -10053,6 +11242,17 @@ poplocalvars(int keep) | |||
| 10053 | free((char*)vp->var_text); | 11242 | free((char*)vp->var_text); |
| 10054 | vp->flags = lvp->flags; | 11243 | vp->flags = lvp->flags; |
| 10055 | vp->var_text = lvp->text; | 11244 | vp->var_text = lvp->text; |
| 11245 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11246 | var_type = is_bb_var(lvp->text); | ||
| 11247 | if (var_type == BB_VAR_ASSIGN && (lvp->flags & VEXPORT)) | ||
| 11248 | putenv(lvp->text); | ||
| 11249 | else if (var_type) { | ||
| 11250 | char *var = xstrdup(lvp->text); | ||
| 11251 | *strchrnul(var, '=') = '\0'; | ||
| 11252 | unsetenv(var); | ||
| 11253 | free(var); | ||
| 11254 | } | ||
| 11255 | #endif | ||
| 10056 | } | 11256 | } |
| 10057 | free(lvp); | 11257 | free(lvp); |
| 10058 | } | 11258 | } |
| @@ -10275,7 +11475,7 @@ execcmd(int argc UNUSED_PARAM, char **argv) | |||
| 10275 | prog = argv[0]; | 11475 | prog = argv[0]; |
| 10276 | if (optionarg) | 11476 | if (optionarg) |
| 10277 | argv[0] = optionarg; | 11477 | argv[0] = optionarg; |
| 10278 | shellexec(prog, argv, pathval(), 0); | 11478 | shellexec(prog, argv, pathval(), 0, FALSE); |
| 10279 | /* NOTREACHED */ | 11479 | /* NOTREACHED */ |
| 10280 | } | 11480 | } |
| 10281 | return 0; | 11481 | return 0; |
| @@ -10328,6 +11528,9 @@ static int readcmd(int, char **) FAST_FUNC; | |||
| 10328 | static int setcmd(int, char **) FAST_FUNC; | 11528 | static int setcmd(int, char **) FAST_FUNC; |
| 10329 | static int shiftcmd(int, char **) FAST_FUNC; | 11529 | static int shiftcmd(int, char **) FAST_FUNC; |
| 10330 | static int timescmd(int, char **) FAST_FUNC; | 11530 | static int timescmd(int, char **) FAST_FUNC; |
| 11531 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11532 | static int titlecmd(int, char **) FAST_FUNC; | ||
| 11533 | #endif | ||
| 10331 | static int trapcmd(int, char **) FAST_FUNC; | 11534 | static int trapcmd(int, char **) FAST_FUNC; |
| 10332 | static int umaskcmd(int, char **) FAST_FUNC; | 11535 | static int umaskcmd(int, char **) FAST_FUNC; |
| 10333 | static int unsetcmd(int, char **) FAST_FUNC; | 11536 | static int unsetcmd(int, char **) FAST_FUNC; |
| @@ -10400,7 +11603,7 @@ static const struct builtincmd builtintab[] = { | |||
| 10400 | #if MAX_HISTORY | 11603 | #if MAX_HISTORY |
| 10401 | { BUILTIN_NOSPEC "history" , historycmd }, | 11604 | { BUILTIN_NOSPEC "history" , historycmd }, |
| 10402 | #endif | 11605 | #endif |
| 10403 | #if JOBS | 11606 | #if JOBS || JOBS_WIN32 |
| 10404 | { BUILTIN_REGULAR "jobs" , jobscmd }, | 11607 | { BUILTIN_REGULAR "jobs" , jobscmd }, |
| 10405 | { BUILTIN_REGULAR "kill" , killcmd }, | 11608 | { BUILTIN_REGULAR "kill" , killcmd }, |
| 10406 | #endif | 11609 | #endif |
| @@ -10427,6 +11630,9 @@ static const struct builtincmd builtintab[] = { | |||
| 10427 | { BUILTIN_REGULAR "test" , testcmd }, | 11630 | { BUILTIN_REGULAR "test" , testcmd }, |
| 10428 | #endif | 11631 | #endif |
| 10429 | { BUILTIN_SPEC_REG "times" , timescmd }, | 11632 | { BUILTIN_SPEC_REG "times" , timescmd }, |
| 11633 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11634 | { BUILTIN_REGULAR "title" , titlecmd }, | ||
| 11635 | #endif | ||
| 10430 | { BUILTIN_SPEC_REG "trap" , trapcmd }, | 11636 | { BUILTIN_SPEC_REG "trap" , trapcmd }, |
| 10431 | { BUILTIN_REGULAR "true" , truecmd }, | 11637 | { BUILTIN_REGULAR "true" , truecmd }, |
| 10432 | { BUILTIN_REGULAR "type" , typecmd }, | 11638 | { BUILTIN_REGULAR "type" , typecmd }, |
| @@ -10445,7 +11651,7 @@ static const struct builtincmd builtintab[] = { | |||
| 10445 | /* [ */ 1 * ENABLE_ASH_TEST + \ | 11651 | /* [ */ 1 * ENABLE_ASH_TEST + \ |
| 10446 | /* [[ */ 1 * BASH_TEST2 + \ | 11652 | /* [[ */ 1 * BASH_TEST2 + \ |
| 10447 | /* alias */ 1 * ENABLE_ASH_ALIAS + \ | 11653 | /* alias */ 1 * ENABLE_ASH_ALIAS + \ |
| 10448 | /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \ | 11654 | /* bg */ 1 * JOBS + \ |
| 10449 | /* break cd cddir */ 3) | 11655 | /* break cd cddir */ 3) |
| 10450 | #define EVALCMD (COMMANDCMD + \ | 11656 | #define EVALCMD (COMMANDCMD + \ |
| 10451 | /* command */ 1 * ENABLE_ASH_CMDCMD + \ | 11657 | /* command */ 1 * ENABLE_ASH_CMDCMD + \ |
| @@ -10526,6 +11732,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 10526 | * as POSIX mandates */ | 11732 | * as POSIX mandates */ |
| 10527 | return back_exitstatus; | 11733 | return back_exitstatus; |
| 10528 | } | 11734 | } |
| 11735 | |||
| 10529 | static int | 11736 | static int |
| 10530 | evalcommand(union node *cmd, int flags) | 11737 | evalcommand(union node *cmd, int flags) |
| 10531 | { | 11738 | { |
| @@ -10625,9 +11832,19 @@ evalcommand(union node *cmd, int flags) | |||
| 10625 | 11832 | ||
| 10626 | localvar_stop = pushlocalvars(vlocal); | 11833 | localvar_stop = pushlocalvars(vlocal); |
| 10627 | 11834 | ||
| 11835 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11836 | # if ENABLE_FEATURE_SH_STANDALONE | ||
| 11837 | /* Reserve two extra spots at the front for shellexec. */ | ||
| 11838 | nargv = stalloc(sizeof(char *) * (argc + 3)); | ||
| 11839 | argv = nargv = nargv + 2; | ||
| 11840 | # else | ||
| 11841 | argv = nargv = stalloc(sizeof(char *) * (argc + 1)); | ||
| 11842 | # endif | ||
| 11843 | #else | ||
| 10628 | /* Reserve one extra spot at the front for shellexec. */ | 11844 | /* Reserve one extra spot at the front for shellexec. */ |
| 10629 | nargv = stalloc(sizeof(char *) * (argc + 2)); | 11845 | nargv = stalloc(sizeof(char *) * (argc + 2)); |
| 10630 | argv = ++nargv; | 11846 | argv = ++nargv; |
| 11847 | #endif | ||
| 10631 | for (sp = arglist.list; sp; sp = sp->next) { | 11848 | for (sp = arglist.list; sp; sp = sp->next) { |
| 10632 | TRACE(("evalcommand arg: %s\n", sp->text)); | 11849 | TRACE(("evalcommand arg: %s\n", sp->text)); |
| 10633 | *nargv++ = sp->text; | 11850 | *nargv++ = sp->text; |
| @@ -10736,9 +11953,11 @@ evalcommand(union node *cmd, int flags) | |||
| 10736 | 11953 | ||
| 10737 | default: { | 11954 | default: { |
| 10738 | 11955 | ||
| 11956 | //TODO: find a better solution for Windows on ARM than ignoring NOFORK | ||
| 10739 | #if ENABLE_FEATURE_SH_STANDALONE \ | 11957 | #if ENABLE_FEATURE_SH_STANDALONE \ |
| 10740 | && ENABLE_FEATURE_SH_NOFORK \ | 11958 | && ENABLE_FEATURE_SH_NOFORK \ |
| 10741 | && NUM_APPLETS > 1 | 11959 | && NUM_APPLETS > 1 \ |
| 11960 | && !(defined(_ARM64_) && !defined(_UCRT) && ENABLE_PLATFORM_MINGW32) | ||
| 10742 | /* (1) BUG: if variables are set, we need to fork, or save/restore them | 11961 | /* (1) BUG: if variables are set, we need to fork, or save/restore them |
| 10743 | * around run_nofork_applet() call. | 11962 | * around run_nofork_applet() call. |
| 10744 | * (2) Should this check also be done in forkshell()? | 11963 | * (2) Should this check also be done in forkshell()? |
| @@ -10748,6 +11967,9 @@ evalcommand(union node *cmd, int flags) | |||
| 10748 | int applet_no = (- cmdentry.u.index - 2); | 11967 | int applet_no = (- cmdentry.u.index - 2); |
| 10749 | if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { | 11968 | if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { |
| 10750 | char **sv_environ; | 11969 | char **sv_environ; |
| 11970 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11971 | char *sv_argv0; | ||
| 11972 | #endif | ||
| 10751 | 11973 | ||
| 10752 | INTOFF; | 11974 | INTOFF; |
| 10753 | sv_environ = environ; | 11975 | sv_environ = environ; |
| @@ -10760,8 +11982,16 @@ evalcommand(union node *cmd, int flags) | |||
| 10760 | * and/or wait for user input ineligible for NOFORK: | 11982 | * and/or wait for user input ineligible for NOFORK: |
| 10761 | * for example, "yes" or "rm" (rm -i waits for input). | 11983 | * for example, "yes" or "rm" (rm -i waits for input). |
| 10762 | */ | 11984 | */ |
| 11985 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11986 | sv_argv0 = __argv[0]; | ||
| 11987 | argv[0] = (char *)bb_basename(argv[0]); | ||
| 11988 | __argv[0] = argv[0]; | ||
| 11989 | #endif | ||
| 10763 | exitstatus = run_nofork_applet(applet_no, argv); | 11990 | exitstatus = run_nofork_applet(applet_no, argv); |
| 10764 | environ = sv_environ; | 11991 | environ = sv_environ; |
| 11992 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11993 | __argv[0] = sv_argv0; | ||
| 11994 | #endif | ||
| 10765 | /* | 11995 | /* |
| 10766 | * Try enabling NOFORK for "yes" applet. | 11996 | * Try enabling NOFORK for "yes" applet. |
| 10767 | * ^C _will_ stop it (write returns EINTR), | 11997 | * ^C _will_ stop it (write returns EINTR), |
| @@ -10780,6 +12010,22 @@ evalcommand(union node *cmd, int flags) | |||
| 10780 | * in a script or a subshell does not need forking, | 12010 | * in a script or a subshell does not need forking, |
| 10781 | * we can just exec it. | 12011 | * we can just exec it. |
| 10782 | */ | 12012 | */ |
| 12013 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12014 | if (!(flags & EV_EXIT) || may_have_traps IF_SUW32(|| delayexit)) { | ||
| 12015 | /* No, forking off a child is necessary */ | ||
| 12016 | struct forkshell fs; | ||
| 12017 | |||
| 12018 | INTOFF; | ||
| 12019 | memset(&fs, 0, sizeof(fs)); | ||
| 12020 | fs.fpid = FS_SHELLEXEC; | ||
| 12021 | fs.argv = argv; | ||
| 12022 | fs.path = (char*)path; | ||
| 12023 | fs.fd[0] = cmdentry.u.index; | ||
| 12024 | jp = makejob(/*cmd,*/ 1); | ||
| 12025 | spawn_forkshell(&fs, jp, cmd, FORK_FG); | ||
| 12026 | break; | ||
| 12027 | } | ||
| 12028 | #else | ||
| 10783 | if (!(flags & EV_EXIT) || may_have_traps) { | 12029 | if (!(flags & EV_EXIT) || may_have_traps) { |
| 10784 | /* No, forking off a child is necessary */ | 12030 | /* No, forking off a child is necessary */ |
| 10785 | INTOFF; | 12031 | INTOFF; |
| @@ -10787,7 +12033,8 @@ evalcommand(union node *cmd, int flags) | |||
| 10787 | jp = vforkexec(cmd, argv, path, cmdentry.u.index); | 12033 | jp = vforkexec(cmd, argv, path, cmdentry.u.index); |
| 10788 | break; | 12034 | break; |
| 10789 | } | 12035 | } |
| 10790 | shellexec(argv[0], argv, path, cmdentry.u.index); | 12036 | #endif |
| 12037 | shellexec(argv[0], argv, path, cmdentry.u.index, FALSE); | ||
| 10791 | /* NOTREACHED */ | 12038 | /* NOTREACHED */ |
| 10792 | } /* default */ | 12039 | } /* default */ |
| 10793 | case CMDBUILTIN: | 12040 | case CMDBUILTIN: |
| @@ -10998,6 +12245,54 @@ static void popstring(void) | |||
| 10998 | INTON; | 12245 | INTON; |
| 10999 | } | 12246 | } |
| 11000 | 12247 | ||
| 12248 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12249 | /* | ||
| 12250 | * Wrapper around nonblock_immune_read() to remove CRs, but only from | ||
| 12251 | * CRLF pairs. The tricky part is handling a CR at the end of the buffer. | ||
| 12252 | */ | ||
| 12253 | static inline ssize_t | ||
| 12254 | nonblock_immune_wrapper(struct parsefile *pf, char *buffer, size_t count) | ||
| 12255 | { | ||
| 12256 | int nr, injected_cr; | ||
| 12257 | |||
| 12258 | // Inject unprocessed CR from previous read into the buffer. | ||
| 12259 | if (pf->cr) | ||
| 12260 | *buffer = '\r'; | ||
| 12261 | retry: | ||
| 12262 | nr = nonblock_immune_read(pf->pf_fd, buffer + pf->cr, count - pf->cr); | ||
| 12263 | if (nr < 0) | ||
| 12264 | return nr; | ||
| 12265 | |||
| 12266 | injected_cr = pf->cr; | ||
| 12267 | nr += pf->cr; | ||
| 12268 | pf->cr = 0; | ||
| 12269 | |||
| 12270 | if (nr > 0) { | ||
| 12271 | nr = remove_cr(buffer, nr); | ||
| 12272 | // remove_cr() won't reduce size to zero, so [nr - 1] is OK. | ||
| 12273 | if (buffer[nr - 1] == '\r') { | ||
| 12274 | if (nr > 1) { | ||
| 12275 | // Ignore trailing CR for now: we'll deal with it later. | ||
| 12276 | pf->cr = 1; | ||
| 12277 | --nr; | ||
| 12278 | } else if (injected_cr) { // nr == 1 | ||
| 12279 | // Buffer only contains an injected CR. This means the | ||
| 12280 | // read returned EOF. Return the buffer as-is. The | ||
| 12281 | // next call will detect EOF. | ||
| 12282 | } else { | ||
| 12283 | // Buffer only contains a CR from the most recent read. | ||
| 12284 | // Try another read, treating the CR as injected. We'll | ||
| 12285 | // either get more characters or EOF. Either way we | ||
| 12286 | // won't end up here again. | ||
| 12287 | pf->cr = 1; | ||
| 12288 | goto retry; | ||
| 12289 | } | ||
| 12290 | } | ||
| 12291 | } | ||
| 12292 | return nr; | ||
| 12293 | } | ||
| 12294 | #endif | ||
| 12295 | |||
| 11001 | static int | 12296 | static int |
| 11002 | preadfd(void) | 12297 | preadfd(void) |
| 11003 | { | 12298 | { |
| @@ -11008,7 +12303,11 @@ preadfd(void) | |||
| 11008 | #if ENABLE_FEATURE_EDITING | 12303 | #if ENABLE_FEATURE_EDITING |
| 11009 | /* retry: */ | 12304 | /* retry: */ |
| 11010 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) | 12305 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) |
| 12306 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12307 | nr = nonblock_immune_wrapper(g_parsefile, buf, IBUFSIZ - 1); | ||
| 12308 | #else | ||
| 11011 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); | 12309 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
| 12310 | #endif | ||
| 11012 | else { | 12311 | else { |
| 11013 | # if ENABLE_ASH_IDLE_TIMEOUT | 12312 | # if ENABLE_ASH_IDLE_TIMEOUT |
| 11014 | int timeout = -1; | 12313 | int timeout = -1; |
| @@ -11047,17 +12346,29 @@ preadfd(void) | |||
| 11047 | INTON; /* here non-blocked SIGINT will longjmp */ | 12346 | INTON; /* here non-blocked SIGINT will longjmp */ |
| 11048 | if (nr == 0) { | 12347 | if (nr == 0) { |
| 11049 | /* ^C pressed, "convert" to SIGINT */ | 12348 | /* ^C pressed, "convert" to SIGINT */ |
| 12349 | # if !ENABLE_PLATFORM_MINGW32 | ||
| 11050 | write(STDOUT_FILENO, "^C\n", 3); | 12350 | write(STDOUT_FILENO, "^C\n", 3); |
| 11051 | raise(SIGINT); /* here non-blocked SIGINT will longjmp */ | 12351 | raise(SIGINT); /* here non-blocked SIGINT will longjmp */ |
| 11052 | /* raise(SIGINT) did not work! (e.g. if SIGINT | 12352 | /* raise(SIGINT) did not work! (e.g. if SIGINT |
| 11053 | * is SIG_IGNed on startup, it stays SIG_IGNed) | 12353 | * is SIG_IGNed on startup, it stays SIG_IGNed) |
| 11054 | */ | 12354 | */ |
| 12355 | # else | ||
| 12356 | write(STDOUT_FILENO, "^C\n", 3); | ||
| 12357 | # endif | ||
| 11055 | if (trap[SIGINT]) { | 12358 | if (trap[SIGINT]) { |
| 12359 | # if ENABLE_PLATFORM_MINGW32 | ||
| 12360 | pending_int = 1; | ||
| 12361 | dotrap(); | ||
| 12362 | # endif | ||
| 11056 | empty_line_input: | 12363 | empty_line_input: |
| 11057 | buf[0] = '\n'; | 12364 | buf[0] = '\n'; |
| 11058 | buf[1] = '\0'; | 12365 | buf[1] = '\0'; |
| 11059 | return 1; | 12366 | return 1; |
| 11060 | } | 12367 | } |
| 12368 | # if ENABLE_PLATFORM_MINGW32 | ||
| 12369 | else | ||
| 12370 | raise_interrupt(); | ||
| 12371 | # endif | ||
| 11061 | exitstatus = 128 + SIGINT; | 12372 | exitstatus = 128 + SIGINT; |
| 11062 | /* bash behavior on ^C + ignored SIGINT: */ | 12373 | /* bash behavior on ^C + ignored SIGINT: */ |
| 11063 | goto again; | 12374 | goto again; |
| @@ -11081,7 +12392,11 @@ preadfd(void) | |||
| 11081 | } | 12392 | } |
| 11082 | } | 12393 | } |
| 11083 | #else | 12394 | #else |
| 12395 | # if ENABLE_PLATFORM_MINGW32 | ||
| 12396 | nr = nonblock_immune_wrapper(g_parsefile, buf, IBUFSIZ - 1); | ||
| 12397 | # else | ||
| 11084 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); | 12398 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
| 12399 | # endif | ||
| 11085 | #endif | 12400 | #endif |
| 11086 | 12401 | ||
| 11087 | #if 0 /* disabled: nonblock_immune_read() handles this problem */ | 12402 | #if 0 /* disabled: nonblock_immune_read() handles this problem */ |
| @@ -11380,6 +12695,7 @@ popallfiles(void) | |||
| 11380 | unwindfiles(&basepf); | 12695 | unwindfiles(&basepf); |
| 11381 | } | 12696 | } |
| 11382 | 12697 | ||
| 12698 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 11383 | /* | 12699 | /* |
| 11384 | * Close the file(s) that the shell is reading commands from. Called | 12700 | * Close the file(s) that the shell is reading commands from. Called |
| 11385 | * after a fork is done. | 12701 | * after a fork is done. |
| @@ -11393,6 +12709,7 @@ closescript(void) | |||
| 11393 | g_parsefile->pf_fd = 0; | 12709 | g_parsefile->pf_fd = 0; |
| 11394 | } | 12710 | } |
| 11395 | } | 12711 | } |
| 12712 | #endif | ||
| 11396 | 12713 | ||
| 11397 | /* | 12714 | /* |
| 11398 | * Like setinputfile, but takes an open file descriptor. Call this with | 12715 | * Like setinputfile, but takes an open file descriptor. Call this with |
| @@ -11625,8 +12942,19 @@ options(int *login_sh) | |||
| 11625 | int val; | 12942 | int val; |
| 11626 | int c; | 12943 | int c; |
| 11627 | 12944 | ||
| 11628 | if (login_sh != NULL) /* if we came from startup code */ | 12945 | #if ENABLE_ASH_NOCONSOLE |
| 12946 | noconsole = console_state(); | ||
| 12947 | #endif | ||
| 12948 | if (login_sh != NULL) { /* if we came from startup code */ | ||
| 11629 | minusc = NULL; | 12949 | minusc = NULL; |
| 12950 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12951 | dirarg = NULL; | ||
| 12952 | title = NULL; | ||
| 12953 | # if ENABLE_SUW32 | ||
| 12954 | delayexit = 0; | ||
| 12955 | # endif | ||
| 12956 | #endif | ||
| 12957 | } | ||
| 11630 | while ((p = *argptr) != NULL) { | 12958 | while ((p = *argptr) != NULL) { |
| 11631 | c = *p++; | 12959 | c = *p++; |
| 11632 | if (c != '-' && c != '+') | 12960 | if (c != '-' && c != '+') |
| @@ -11656,6 +12984,31 @@ options(int *login_sh) | |||
| 11656 | cflag = 1; | 12984 | cflag = 1; |
| 11657 | continue; | 12985 | continue; |
| 11658 | } | 12986 | } |
| 12987 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12988 | /* Undocumented flags; | ||
| 12989 | * -d force current directory | ||
| 12990 | * -t title to display in console window | ||
| 12991 | * -N prompt user before exit | ||
| 12992 | * Must appear before -s or -c. */ | ||
| 12993 | if (c == 'd' && val == 1) { | ||
| 12994 | if (*argptr == NULL) | ||
| 12995 | ash_msg_and_raise_error(bb_msg_requires_arg, "-d"); | ||
| 12996 | dirarg = *argptr++; | ||
| 12997 | continue; | ||
| 12998 | } | ||
| 12999 | if (c == 't' && val == 1) { | ||
| 13000 | if (*argptr == NULL) | ||
| 13001 | ash_msg_and_raise_error(bb_msg_requires_arg, "-t"); | ||
| 13002 | title = *argptr++; | ||
| 13003 | continue; | ||
| 13004 | } | ||
| 13005 | # if ENABLE_SUW32 | ||
| 13006 | if (c == 'N' && val == 1) { | ||
| 13007 | delayexit = 1; | ||
| 13008 | continue; | ||
| 13009 | } | ||
| 13010 | # endif | ||
| 13011 | #endif | ||
| 11659 | if (c == 's') { /* -s, +s */ | 13012 | if (c == 's') { /* -s, +s */ |
| 11660 | sflag = 1; | 13013 | sflag = 1; |
| 11661 | continue; | 13014 | continue; |
| @@ -13699,6 +15052,9 @@ evalstring(char *s, int flags) | |||
| 13699 | int status; | 15052 | int status; |
| 13700 | 15053 | ||
| 13701 | s = sstrdup(s); | 15054 | s = sstrdup(s); |
| 15055 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15056 | remove_cr(s, strlen(s)+1); | ||
| 15057 | #endif | ||
| 13702 | setinputstring(s); | 15058 | setinputstring(s); |
| 13703 | setstackmark(&smark); | 15059 | setstackmark(&smark); |
| 13704 | 15060 | ||
| @@ -13786,7 +15142,7 @@ cmdloop(int top) | |||
| 13786 | int skip; | 15142 | int skip; |
| 13787 | 15143 | ||
| 13788 | setstackmark(&smark); | 15144 | setstackmark(&smark); |
| 13789 | #if JOBS | 15145 | #if JOBS || JOBS_WIN32 |
| 13790 | if (jobctl) | 15146 | if (jobctl) |
| 13791 | showjobs(SHOW_CHANGED|SHOW_STDERR); | 15147 | showjobs(SHOW_CHANGED|SHOW_STDERR); |
| 13792 | #endif | 15148 | #endif |
| @@ -13794,6 +15150,9 @@ cmdloop(int top) | |||
| 13794 | if (iflag && top) { | 15150 | if (iflag && top) { |
| 13795 | inter++; | 15151 | inter++; |
| 13796 | chkmail(); | 15152 | chkmail(); |
| 15153 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15154 | terminal_mode(TRUE); | ||
| 15155 | #endif | ||
| 13797 | } | 15156 | } |
| 13798 | n = parsecmd(inter); | 15157 | n = parsecmd(inter); |
| 13799 | #if DEBUG | 15158 | #if DEBUG |
| @@ -13817,8 +15176,10 @@ cmdloop(int top) | |||
| 13817 | } else { | 15176 | } else { |
| 13818 | int i; | 15177 | int i; |
| 13819 | 15178 | ||
| 15179 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 13820 | /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */ | 15180 | /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */ |
| 13821 | job_warning >>= 1; | 15181 | job_warning >>= 1; |
| 15182 | #endif | ||
| 13822 | numeof = 0; | 15183 | numeof = 0; |
| 13823 | i = evaltree(n, 0); | 15184 | i = evaltree(n, 0); |
| 13824 | if (n) | 15185 | if (n) |
| @@ -13848,7 +15209,7 @@ find_dot_file(char *basename) | |||
| 13848 | int len; | 15209 | int len; |
| 13849 | 15210 | ||
| 13850 | /* don't try this for absolute or relative paths */ | 15211 | /* don't try this for absolute or relative paths */ |
| 13851 | if (strchr(basename, '/')) | 15212 | if (strchr(basename, '/') IF_PLATFORM_MINGW32(|| strchr(basename, '\\'))) |
| 13852 | return basename; | 15213 | return basename; |
| 13853 | 15214 | ||
| 13854 | path = pathval(); | 15215 | path = pathval(); |
| @@ -14013,6 +15374,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
| 14013 | struct builtincmd *bcmd; | 15374 | struct builtincmd *bcmd; |
| 14014 | int len; | 15375 | int len; |
| 14015 | 15376 | ||
| 15377 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14016 | /* If name contains a slash, don't use PATH or hash table */ | 15378 | /* If name contains a slash, don't use PATH or hash table */ |
| 14017 | if (strchr(name, '/') != NULL) { | 15379 | if (strchr(name, '/') != NULL) { |
| 14018 | entry->u.index = -1; | 15380 | entry->u.index = -1; |
| @@ -14032,6 +15394,35 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
| 14032 | entry->cmdtype = CMDNORMAL; | 15394 | entry->cmdtype = CMDNORMAL; |
| 14033 | return; | 15395 | return; |
| 14034 | } | 15396 | } |
| 15397 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
| 15398 | /* If name contains a slash or drive prefix, don't use PATH or hash table */ | ||
| 15399 | if (has_path(name)) { | ||
| 15400 | entry->u.index = -1; | ||
| 15401 | entry->cmdtype = CMDNORMAL; | ||
| 15402 | fullname = stack_add_ext_space(name); | ||
| 15403 | if (add_win32_extension(fullname)) { | ||
| 15404 | return; | ||
| 15405 | } else if (unix_path(name)) { | ||
| 15406 | name = (char *)bb_basename(name); | ||
| 15407 | if ( | ||
| 15408 | # if ENABLE_FEATURE_SH_STANDALONE | ||
| 15409 | find_applet_by_name_for_sh(name, path) >= 0 || | ||
| 15410 | # endif | ||
| 15411 | !find_builtin(bb_basename(name)) | ||
| 15412 | ) { | ||
| 15413 | act |= DO_NOFUNC; | ||
| 15414 | } else if (act & DO_ABS) { | ||
| 15415 | entry->cmdtype = CMDUNKNOWN; | ||
| 15416 | return; | ||
| 15417 | } | ||
| 15418 | } else if (act & DO_ABS) { | ||
| 15419 | entry->cmdtype = CMDUNKNOWN; | ||
| 15420 | return; | ||
| 15421 | } else { | ||
| 15422 | return; | ||
| 15423 | } | ||
| 15424 | } | ||
| 15425 | #endif /* ENABLE_PLATFORM_MINGW32 */ | ||
| 14035 | 15426 | ||
| 14036 | /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ | 15427 | /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ |
| 14037 | 15428 | ||
| @@ -14086,7 +15477,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
| 14086 | 15477 | ||
| 14087 | #if ENABLE_FEATURE_SH_STANDALONE | 15478 | #if ENABLE_FEATURE_SH_STANDALONE |
| 14088 | { | 15479 | { |
| 14089 | int applet_no = find_applet_by_name(name); | 15480 | int applet_no = find_applet_by_name_for_sh(name, path); |
| 14090 | if (applet_no >= 0) { | 15481 | if (applet_no >= 0) { |
| 14091 | entry->cmdtype = CMDNORMAL; | 15482 | entry->cmdtype = CMDNORMAL; |
| 14092 | entry->u.index = -2 - applet_no; | 15483 | entry->u.index = -2 - applet_no; |
| @@ -14125,12 +15516,15 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
| 14125 | } | 15516 | } |
| 14126 | } | 15517 | } |
| 14127 | /* if rehash, don't redo absolute path names */ | 15518 | /* if rehash, don't redo absolute path names */ |
| 14128 | if (fullname[0] == '/' && idx <= prev) { | 15519 | if (!is_relative_path(fullname) && idx <= prev) { |
| 14129 | if (idx < prev) | 15520 | if (idx < prev) |
| 14130 | continue; | 15521 | continue; |
| 14131 | TRACE(("searchexec \"%s\": no change\n", name)); | 15522 | TRACE(("searchexec \"%s\": no change\n", name)); |
| 14132 | goto success; | 15523 | goto success; |
| 14133 | } | 15524 | } |
| 15525 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15526 | add_win32_extension(fullname); | ||
| 15527 | #endif | ||
| 14134 | while (stat(fullname, &statb) < 0) { | 15528 | while (stat(fullname, &statb) < 0) { |
| 14135 | #ifdef SYSV | 15529 | #ifdef SYSV |
| 14136 | if (errno == EINTR) | 15530 | if (errno == EINTR) |
| @@ -14268,19 +15662,45 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14268 | if (LONE_DASH(action)) | 15662 | if (LONE_DASH(action)) |
| 14269 | action = NULL; | 15663 | action = NULL; |
| 14270 | else { | 15664 | else { |
| 15665 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14271 | if (action[0]) /* not NULL and not "" and not "-" */ | 15666 | if (action[0]) /* not NULL and not "" and not "-" */ |
| 14272 | may_have_traps = 1; | 15667 | may_have_traps = 1; |
| 15668 | #endif | ||
| 14273 | action = ckstrdup(action); | 15669 | action = ckstrdup(action); |
| 14274 | } | 15670 | } |
| 14275 | } | 15671 | } |
| 14276 | free(trap[signo]); | 15672 | free(trap[signo]); |
| 14277 | trap[signo] = action; | 15673 | trap[signo] = action; |
| 15674 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15675 | if (signo == SIGINT) { | ||
| 15676 | // trap '' INT disables Ctrl-C, anything else enables it | ||
| 15677 | if (action && action[0] == '\0') { | ||
| 15678 | SetConsoleCtrlHandler(NULL, TRUE); | ||
| 15679 | # if ENABLE_FEATURE_EDITING | ||
| 15680 | if (line_input_state) { | ||
| 15681 | line_input_state->flags |= IGNORE_CTRL_C; | ||
| 15682 | } | ||
| 15683 | # endif | ||
| 15684 | } else { | ||
| 15685 | SetConsoleCtrlHandler(NULL, FALSE); | ||
| 15686 | # if ENABLE_FEATURE_EDITING | ||
| 15687 | if (line_input_state) { | ||
| 15688 | line_input_state->flags &= ~IGNORE_CTRL_C; | ||
| 15689 | } | ||
| 15690 | # endif | ||
| 15691 | } | ||
| 15692 | } | ||
| 15693 | #else | ||
| 14278 | if (signo != 0 && signo < NSIG) | 15694 | if (signo != 0 && signo < NSIG) |
| 14279 | setsignal(signo); | 15695 | setsignal(signo); |
| 15696 | #endif | ||
| 14280 | INTON; | 15697 | INTON; |
| 14281 | next: | 15698 | next: |
| 14282 | ap++; | 15699 | ap++; |
| 14283 | } | 15700 | } |
| 15701 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15702 | may_have_traps = trap[SIGINT] && trap[SIGINT][0] != '\0'; | ||
| 15703 | #endif | ||
| 14284 | return exitcode; | 15704 | return exitcode; |
| 14285 | } | 15705 | } |
| 14286 | 15706 | ||
| @@ -14309,10 +15729,12 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14309 | { | 15729 | { |
| 14310 | const char *a = applet_names; | 15730 | const char *a = applet_names; |
| 14311 | while (*a) { | 15731 | while (*a) { |
| 14312 | col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a); | 15732 | if (prefer_applet(a, pathval())) { |
| 14313 | if (col > 60) { | 15733 | col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a); |
| 14314 | out1fmt("\n"); | 15734 | if (col > 60) { |
| 14315 | col = 0; | 15735 | out1fmt("\n"); |
| 15736 | col = 0; | ||
| 15737 | } | ||
| 14316 | } | 15738 | } |
| 14317 | while (*a++ != '\0') | 15739 | while (*a++ != '\0') |
| 14318 | continue; | 15740 | continue; |
| @@ -14374,7 +15796,24 @@ exportcmd(int argc UNUSED_PARAM, char **argv) | |||
| 14374 | } else { | 15796 | } else { |
| 14375 | vp = *findvar(name); | 15797 | vp = *findvar(name); |
| 14376 | if (vp) { | 15798 | if (vp) { |
| 15799 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15800 | if (is_bb_var(name) == BB_VAR_EXACT) { | ||
| 15801 | if (flag_off == ~VEXPORT) | ||
| 15802 | unsetenv(name); | ||
| 15803 | else if (flag == VEXPORT && !(vp->flags & VUNSET)) | ||
| 15804 | putenv(vp->var_text); | ||
| 15805 | } | ||
| 15806 | #endif | ||
| 14377 | vp->flags = ((vp->flags | flag) & flag_off); | 15807 | vp->flags = ((vp->flags | flag) & flag_off); |
| 15808 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15809 | /* Unexporting a variable imported from the | ||
| 15810 | * environment restores its original value and | ||
| 15811 | * removes the VIMPORT flag. */ | ||
| 15812 | if ((vp->flags & VIMPORT) && (flag_off == ~VEXPORT)) { | ||
| 15813 | vp->flags &= ~VIMPORT; | ||
| 15814 | p = getenv(name); | ||
| 15815 | } else | ||
| 15816 | #endif | ||
| 14378 | continue; | 15817 | continue; |
| 14379 | } | 15818 | } |
| 14380 | } | 15819 | } |
| @@ -14465,6 +15904,21 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14465 | return 0; | 15904 | return 0; |
| 14466 | } | 15905 | } |
| 14467 | 15906 | ||
| 15907 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15908 | static int FAST_FUNC | ||
| 15909 | titlecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | ||
| 15910 | { | ||
| 15911 | if (*argptr == NULL) { | ||
| 15912 | char buffer[256]; | ||
| 15913 | if (get_title(buffer, sizeof(buffer))) | ||
| 15914 | puts(buffer); | ||
| 15915 | } else { | ||
| 15916 | set_title(*argptr); | ||
| 15917 | } | ||
| 15918 | return 0; | ||
| 15919 | } | ||
| 15920 | #endif | ||
| 15921 | |||
| 14468 | #if ENABLE_FEATURE_SH_MATH | 15922 | #if ENABLE_FEATURE_SH_MATH |
| 14469 | /* | 15923 | /* |
| 14470 | * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell. | 15924 | * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell. |
| @@ -14557,6 +16011,7 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14557 | r = shell_builtin_read(¶ms); | 16011 | r = shell_builtin_read(¶ms); |
| 14558 | INTON; | 16012 | INTON; |
| 14559 | 16013 | ||
| 16014 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14560 | if ((uintptr_t)r == 1 && errno == EINTR) { | 16015 | if ((uintptr_t)r == 1 && errno == EINTR) { |
| 14561 | /* To get SIGCHLD: sleep 1 & read x; echo $x | 16016 | /* To get SIGCHLD: sleep 1 & read x; echo $x |
| 14562 | * Correct behavior is to not exit "read" | 16017 | * Correct behavior is to not exit "read" |
| @@ -14569,6 +16024,29 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14569 | /* bash: "The exit status is greater than 128 if the timeout is exceeded." */ | 16024 | /* bash: "The exit status is greater than 128 if the timeout is exceeded." */ |
| 14570 | /* The actual value observed with bash 5.2.15: */ | 16025 | /* The actual value observed with bash 5.2.15: */ |
| 14571 | return 128 + SIGALRM; | 16026 | return 128 + SIGALRM; |
| 16027 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
| 16028 | if ((uintptr_t)r == 2) { | ||
| 16029 | /* Timeout, return 128 + SIGALRM */ | ||
| 16030 | return 142; | ||
| 16031 | } else if ((uintptr_t)r == 3) { | ||
| 16032 | /* ^C pressed, propagate event */ | ||
| 16033 | if (trap[SIGINT]) { | ||
| 16034 | write(STDOUT_FILENO, "^C", 2); | ||
| 16035 | pending_int = 1; | ||
| 16036 | dotrap(); | ||
| 16037 | if (!(rootshell && iflag)) | ||
| 16038 | return (uintptr_t)0; | ||
| 16039 | else | ||
| 16040 | goto again; | ||
| 16041 | } else if (iflag) { | ||
| 16042 | raise_interrupt(); | ||
| 16043 | } else { | ||
| 16044 | GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); | ||
| 16045 | exitshell(); | ||
| 16046 | } | ||
| 16047 | return (uintptr_t)r; | ||
| 16048 | } | ||
| 16049 | #endif | ||
| 14572 | 16050 | ||
| 14573 | if ((uintptr_t)r > 1) | 16051 | if ((uintptr_t)r > 1) |
| 14574 | ash_msg_and_raise_error(r); | 16052 | ash_msg_and_raise_error(r); |
| @@ -14630,6 +16108,9 @@ umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14630 | if (!isdigit(modestr[0])) | 16108 | if (!isdigit(modestr[0])) |
| 14631 | mask ^= 0777; | 16109 | mask ^= 0777; |
| 14632 | umask(mask); | 16110 | umask(mask); |
| 16111 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16112 | setvareq(xasprintf("BB_UMASK=0%o", mask), VEXPORT|VNOSAVE); | ||
| 16113 | #endif | ||
| 14633 | } | 16114 | } |
| 14634 | return 0; | 16115 | return 0; |
| 14635 | } | 16116 | } |
| @@ -14730,6 +16211,13 @@ exitshell(void) | |||
| 14730 | /*free(p); - we'll exit soon */ | 16211 | /*free(p); - we'll exit soon */ |
| 14731 | } | 16212 | } |
| 14732 | out: | 16213 | out: |
| 16214 | #if ENABLE_SUW32 | ||
| 16215 | if (delayexit) { | ||
| 16216 | #define EXIT_MSG "Press any key to exit..." | ||
| 16217 | console_write(EXIT_MSG, sizeof(EXIT_MSG) - 1); | ||
| 16218 | _getch(); | ||
| 16219 | } | ||
| 16220 | #endif | ||
| 14733 | exitreset(); | 16221 | exitreset(); |
| 14734 | /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". | 16222 | /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". |
| 14735 | * our setjobctl(0) does not panic if tcsetpgrp fails inside it. | 16223 | * our setjobctl(0) does not panic if tcsetpgrp fails inside it. |
| @@ -14740,22 +16228,99 @@ exitshell(void) | |||
| 14740 | /* NOTREACHED */ | 16228 | /* NOTREACHED */ |
| 14741 | } | 16229 | } |
| 14742 | 16230 | ||
| 16231 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16232 | /* We need to see if HOME is *really* unset */ | ||
| 16233 | # undef getenv | ||
| 16234 | static void setvar_if_unset(const char *key, const char *value) | ||
| 16235 | { | ||
| 16236 | if (!getenv(key) || getuid() == 0) | ||
| 16237 | setvar(key, value, VEXPORT); | ||
| 16238 | } | ||
| 16239 | #endif | ||
| 16240 | |||
| 14743 | /* Don't inline: conserve stack of caller from having our locals too */ | 16241 | /* Don't inline: conserve stack of caller from having our locals too */ |
| 14744 | static NOINLINE void | 16242 | static NOINLINE void |
| 14745 | init(void) | 16243 | init(void) |
| 14746 | { | 16244 | { |
| 16245 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16246 | int import = 0; | ||
| 16247 | #endif | ||
| 16248 | |||
| 14747 | /* we will never free this */ | 16249 | /* we will never free this */ |
| 14748 | basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ); | 16250 | basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ); |
| 14749 | basepf.linno = 1; | 16251 | basepf.linno = 1; |
| 14750 | 16252 | ||
| 16253 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14751 | sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ | 16254 | sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ |
| 14752 | setsignal(SIGCHLD); | 16255 | setsignal(SIGCHLD); |
| 16256 | #endif | ||
| 14753 | 16257 | ||
| 14754 | { | 16258 | { |
| 14755 | char **envp; | 16259 | char **envp; |
| 14756 | const char *p; | 16260 | const char *p; |
| 14757 | 16261 | ||
| 14758 | initvar(); | 16262 | initvar(); |
| 16263 | |||
| 16264 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16265 | /* | ||
| 16266 | * case insensitive env names from Windows world | ||
| 16267 | * | ||
| 16268 | * Some standard env names such as PATH is named Path and so on | ||
| 16269 | * ash itself is case sensitive, so "Path" will confuse it, as | ||
| 16270 | * MSVC getenv() is case insensitive. | ||
| 16271 | * | ||
| 16272 | * We may end up having both Path and PATH. Then Path will be chosen | ||
| 16273 | * because it appears first. | ||
| 16274 | */ | ||
| 16275 | if (windows_env()) { | ||
| 16276 | /* | ||
| 16277 | * If we get here it's because the environment suggests we | ||
| 16278 | * haven't been invoked from an earlier instance of BusyBox. | ||
| 16279 | */ | ||
| 16280 | char *start, *end; | ||
| 16281 | struct passwd *pw; | ||
| 16282 | |||
| 16283 | /* mintty sets HOME: unset it */ | ||
| 16284 | const char *tty = getenv("TERM_PROGRAM"); | ||
| 16285 | if (tty && strcmp(tty, "mintty") == 0) { | ||
| 16286 | unsetenv("HOME"); | ||
| 16287 | } | ||
| 16288 | |||
| 16289 | import = VIMPORT; | ||
| 16290 | for (envp = environ; envp && *envp; envp++) { | ||
| 16291 | if (!(end=strchr(*envp, '='))) | ||
| 16292 | continue; | ||
| 16293 | |||
| 16294 | /* check for invalid characters in name */ | ||
| 16295 | start = (char *)endofname(*envp); | ||
| 16296 | if (*start != '=') { | ||
| 16297 | /* Make a copy of the original variable */ | ||
| 16298 | setvareq(xstrdup(*envp), VEXPORT|VNOSAVE); | ||
| 16299 | |||
| 16300 | /* Replace invalid characters with underscores */ | ||
| 16301 | for (; start < end; start++) { | ||
| 16302 | if (!isalnum(*start)) { | ||
| 16303 | *start = '_'; | ||
| 16304 | } | ||
| 16305 | } | ||
| 16306 | } | ||
| 16307 | |||
| 16308 | /* make all variable names uppercase */ | ||
| 16309 | for (start = *envp;start < end;start++) | ||
| 16310 | *start = toupper(*start); | ||
| 16311 | } | ||
| 16312 | |||
| 16313 | /* Initialise some variables normally set at login, but | ||
| 16314 | * only if someone hasn't already set them or we're root. */ | ||
| 16315 | pw = getpwuid(getuid()); | ||
| 16316 | if (pw) { | ||
| 16317 | setvar_if_unset("USER", pw->pw_name); | ||
| 16318 | setvar_if_unset("LOGNAME", pw->pw_name); | ||
| 16319 | setvar_if_unset("HOME", pw->pw_dir); | ||
| 16320 | } | ||
| 16321 | setvar_if_unset("SHELL", DEFAULT_SHELL); | ||
| 16322 | } | ||
| 16323 | #endif | ||
| 14759 | for (envp = environ; envp && *envp; envp++) { | 16324 | for (envp = environ; envp && *envp; envp++) { |
| 14760 | /* Used to have | 16325 | /* Used to have |
| 14761 | * p = endofname(*envp); | 16326 | * p = endofname(*envp); |
| @@ -14769,7 +16334,11 @@ init(void) | |||
| 14769 | * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this | 16334 | * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this |
| 14770 | */ | 16335 | */ |
| 14771 | if (strchr(*envp, '=')) { | 16336 | if (strchr(*envp, '=')) { |
| 16337 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14772 | setvareq(*envp, VEXPORT|VTEXTFIXED); | 16338 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
| 16339 | #else | ||
| 16340 | setvareq(*envp, VEXPORT|import); | ||
| 16341 | #endif | ||
| 14773 | } | 16342 | } |
| 14774 | } | 16343 | } |
| 14775 | 16344 | ||
| @@ -14816,7 +16385,11 @@ procargs(char **xargv) | |||
| 14816 | int i; | 16385 | int i; |
| 14817 | int login_sh; | 16386 | int login_sh; |
| 14818 | 16387 | ||
| 16388 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16389 | login_sh = applet_name[0] == 'l'; | ||
| 16390 | #else | ||
| 14819 | login_sh = /*xargv[0] &&*/ xargv[0][0] == '-'; | 16391 | login_sh = /*xargv[0] &&*/ xargv[0][0] == '-'; |
| 16392 | #endif | ||
| 14820 | #if NUM_SCRIPTS > 0 | 16393 | #if NUM_SCRIPTS > 0 |
| 14821 | if (minusc) | 16394 | if (minusc) |
| 14822 | goto setarg0; | 16395 | goto setarg0; |
| @@ -14839,7 +16412,9 @@ procargs(char **xargv) | |||
| 14839 | } | 16412 | } |
| 14840 | if (iflag == 2 /* no explicit -i given */ | 16413 | if (iflag == 2 /* no explicit -i given */ |
| 14841 | && sflag == 1 /* -s given (or implied) */ | 16414 | && sflag == 1 /* -s given (or implied) */ |
| 16415 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14842 | && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */ | 16416 | && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */ |
| 16417 | #endif | ||
| 14843 | && isatty(0) && isatty(1) /* we are on tty */ | 16418 | && isatty(0) && isatty(1) /* we are on tty */ |
| 14844 | ) { | 16419 | ) { |
| 14845 | iflag = 1; | 16420 | iflag = 1; |
| @@ -14859,6 +16434,9 @@ procargs(char **xargv) | |||
| 14859 | goto setarg0; | 16434 | goto setarg0; |
| 14860 | } else if (!sflag) { | 16435 | } else if (!sflag) { |
| 14861 | setinputfile(*xargv, 0); | 16436 | setinputfile(*xargv, 0); |
| 16437 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16438 | bs_to_slash(*xargv); | ||
| 16439 | #endif | ||
| 14862 | setarg0: | 16440 | setarg0: |
| 14863 | arg0 = *xargv++; | 16441 | arg0 = *xargv++; |
| 14864 | } | 16442 | } |
| @@ -14881,8 +16459,10 @@ procargs(char **xargv) | |||
| 14881 | * NB: must do it before setting up signals (in optschanged()) | 16459 | * NB: must do it before setting up signals (in optschanged()) |
| 14882 | * and reading .profile etc (after we return from here): | 16460 | * and reading .profile etc (after we return from here): |
| 14883 | */ | 16461 | */ |
| 16462 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14884 | if (iflag) | 16463 | if (iflag) |
| 14885 | signal(SIGHUP, SIG_DFL); | 16464 | signal(SIGHUP, SIG_DFL); |
| 16465 | #endif | ||
| 14886 | 16466 | ||
| 14887 | optschanged(); | 16467 | optschanged(); |
| 14888 | 16468 | ||
| @@ -14926,9 +16506,21 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14926 | struct stackmark smark; | 16506 | struct stackmark smark; |
| 14927 | int login_sh; | 16507 | int login_sh; |
| 14928 | 16508 | ||
| 16509 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16510 | INIT_G_memstack(); | ||
| 16511 | |||
| 16512 | if (argc == 3 && !strcmp(argv[1], "--fs")) { | ||
| 16513 | forkshell_init(argv[2]); | ||
| 16514 | /* only reached in case of error */ | ||
| 16515 | bb_error_msg_and_die("forkshell failed"); | ||
| 16516 | } | ||
| 16517 | #endif | ||
| 16518 | |||
| 14929 | /* Initialize global data */ | 16519 | /* Initialize global data */ |
| 14930 | INIT_G_misc(); | 16520 | INIT_G_misc(); |
| 16521 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14931 | INIT_G_memstack(); | 16522 | INIT_G_memstack(); |
| 16523 | #endif | ||
| 14932 | INIT_G_var(); | 16524 | INIT_G_var(); |
| 14933 | #if ENABLE_ASH_ALIAS | 16525 | #if ENABLE_ASH_ALIAS |
| 14934 | INIT_G_alias(); | 16526 | INIT_G_alias(); |
| @@ -14974,6 +16566,10 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14974 | init(); | 16566 | init(); |
| 14975 | setstackmark(&smark); | 16567 | setstackmark(&smark); |
| 14976 | 16568 | ||
| 16569 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16570 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
| 16571 | #endif | ||
| 16572 | |||
| 14977 | #if NUM_SCRIPTS > 0 | 16573 | #if NUM_SCRIPTS > 0 |
| 14978 | if (argc < 0) | 16574 | if (argc < 0) |
| 14979 | /* Non-NULL minusc tells procargs that an embedded script is being run */ | 16575 | /* Non-NULL minusc tells procargs that an embedded script is being run */ |
| @@ -14985,11 +16581,45 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14985 | trace_puts_args(argv); | 16581 | trace_puts_args(argv); |
| 14986 | #endif | 16582 | #endif |
| 14987 | 16583 | ||
| 16584 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16585 | if (!dirarg && !login_sh && iflag) { | ||
| 16586 | char *cwd = getcwd(NULL, 0); | ||
| 16587 | if (cwd) { | ||
| 16588 | chdir(cwd); | ||
| 16589 | setpwd(NULL, 0); | ||
| 16590 | free(cwd); | ||
| 16591 | } | ||
| 16592 | } | ||
| 16593 | |||
| 16594 | if (title) | ||
| 16595 | set_title(title); | ||
| 16596 | #endif | ||
| 16597 | |||
| 14988 | if (login_sh) { | 16598 | if (login_sh) { |
| 14989 | const char *hp; | 16599 | const char *hp; |
| 14990 | 16600 | ||
| 16601 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16602 | if (!dirarg) { | ||
| 16603 | hp = lookupvar("HOME"); | ||
| 16604 | if (hp == NULL || *hp == '\0') | ||
| 16605 | hp = xgetpwuid(getuid())->pw_dir; | ||
| 16606 | chdir(hp); | ||
| 16607 | setpwd(NULL, 0); | ||
| 16608 | } | ||
| 16609 | #endif | ||
| 16610 | |||
| 14991 | state = 1; | 16611 | state = 1; |
| 16612 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16613 | hp = concat_path_file(get_system_drive(), "/etc/profile"); | ||
| 16614 | read_profile(hp); | ||
| 16615 | free((void *)hp); | ||
| 16616 | |||
| 16617 | hp = exe_relative_path("/etc/profile"); | ||
| 16618 | read_profile(hp); | ||
| 16619 | free((void *)hp); | ||
| 16620 | #else | ||
| 14992 | read_profile("/etc/profile"); | 16621 | read_profile("/etc/profile"); |
| 16622 | #endif | ||
| 14993 | state1: | 16623 | state1: |
| 14994 | state = 2; | 16624 | state = 2; |
| 14995 | hp = lookupvar("HOME"); | 16625 | hp = lookupvar("HOME"); |
| @@ -14998,10 +16628,18 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14998 | } | 16628 | } |
| 14999 | state2: | 16629 | state2: |
| 15000 | state = 3; | 16630 | state = 3; |
| 16631 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16632 | if (dirarg) { | ||
| 16633 | chdir(dirarg); | ||
| 16634 | setpwd(NULL, 0); | ||
| 16635 | } | ||
| 16636 | #endif | ||
| 15001 | if (iflag | 16637 | if (iflag |
| 16638 | #if ENABLE_PLATFORM_POSIX | ||
| 15002 | #ifndef linux | 16639 | #ifndef linux |
| 15003 | && getuid() == geteuid() && getgid() == getegid() | 16640 | && getuid() == geteuid() && getgid() == getegid() |
| 15004 | #endif | 16641 | #endif |
| 16642 | #endif | ||
| 15005 | ) { | 16643 | ) { |
| 15006 | const char *shinit = lookupvar("ENV"); | 16644 | const char *shinit = lookupvar("ENV"); |
| 15007 | if (shinit != NULL && *shinit != '\0') | 16645 | if (shinit != NULL && *shinit != '\0') |
| @@ -15026,7 +16664,11 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 15026 | // ash -sc 'echo $-' | 16664 | // ash -sc 'echo $-' |
| 15027 | // continue reading input from stdin after running 'echo'. | 16665 | // continue reading input from stdin after running 'echo'. |
| 15028 | // bash does not do this: it prints "hBcs" and exits. | 16666 | // bash does not do this: it prints "hBcs" and exits. |
| 16667 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 15029 | evalstring(minusc, EV_EXIT); | 16668 | evalstring(minusc, EV_EXIT); |
| 16669 | #else | ||
| 16670 | evalstring(minusc, sflag ? 0 : EV_EXIT); | ||
| 16671 | #endif | ||
| 15030 | } | 16672 | } |
| 15031 | 16673 | ||
| 15032 | if (sflag || minusc == NULL) { | 16674 | if (sflag || minusc == NULL) { |
| @@ -15074,6 +16716,1110 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 15074 | /* NOTREACHED */ | 16716 | /* NOTREACHED */ |
| 15075 | } | 16717 | } |
| 15076 | 16718 | ||
| 16719 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16720 | static void | ||
| 16721 | forkshell_openhere(struct forkshell *fs) | ||
| 16722 | { | ||
| 16723 | const char *p = fs->path; | ||
| 16724 | size_t len = strlen(p); | ||
| 16725 | int pip[2]; | ||
| 16726 | |||
| 16727 | pip[0] = fs->fd[0]; | ||
| 16728 | pip[1] = fs->fd[1]; | ||
| 16729 | |||
| 16730 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
| 16731 | |||
| 16732 | close(pip[0]); | ||
| 16733 | ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); | ||
| 16734 | ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); | ||
| 16735 | ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); | ||
| 16736 | ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); | ||
| 16737 | signal(SIGPIPE, SIG_DFL); | ||
| 16738 | xwrite(pip[1], p, len); | ||
| 16739 | _exit_SUCCESS(); | ||
| 16740 | } | ||
| 16741 | |||
| 16742 | static void | ||
| 16743 | forkshell_evalbackcmd(struct forkshell *fs) | ||
| 16744 | { | ||
| 16745 | #if BASH_PROCESS_SUBST | ||
| 16746 | /* determine end of pipe used by parent (ip) and child (ic) */ | ||
| 16747 | const int ctl = fs->fd[2]; | ||
| 16748 | const int ip = (ctl == CTLTOPROC); | ||
| 16749 | const int ic = !(ctl == CTLTOPROC); | ||
| 16750 | #else | ||
| 16751 | const int ip = 0; | ||
| 16752 | const int ic = 1; | ||
| 16753 | #endif | ||
| 16754 | union node *n = fs->n; | ||
| 16755 | int pip[2]; | ||
| 16756 | |||
| 16757 | pip[ip] = fs->fd[ip]; | ||
| 16758 | pip[ic] = fs->fd[ic]; | ||
| 16759 | |||
| 16760 | FORCEINTON; | ||
| 16761 | close(pip[ip]); | ||
| 16762 | if (pip[ic] != ic) { | ||
| 16763 | /*close(ic);*/ | ||
| 16764 | dup2_or_raise(pip[ic], ic); | ||
| 16765 | close(pip[ic]); | ||
| 16766 | } | ||
| 16767 | eflag = 0; | ||
| 16768 | ifsfree(); | ||
| 16769 | evaltreenr(n, EV_EXIT); | ||
| 16770 | /* NOTREACHED */ | ||
| 16771 | } | ||
| 16772 | |||
| 16773 | static void | ||
| 16774 | forkshell_evalsubshell(struct forkshell *fs) | ||
| 16775 | { | ||
| 16776 | union node *n = fs->n; | ||
| 16777 | int flags = fs->flags; | ||
| 16778 | |||
| 16779 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
| 16780 | INTON; | ||
| 16781 | flags |= EV_EXIT; | ||
| 16782 | if (fs->mode) | ||
| 16783 | flags &= ~EV_TESTED; | ||
| 16784 | expredir(n->nredir.redirect); | ||
| 16785 | redirect(n->nredir.redirect, 0); | ||
| 16786 | evaltreenr(n->nredir.n, flags); | ||
| 16787 | /* never returns */ | ||
| 16788 | } | ||
| 16789 | |||
| 16790 | static void | ||
| 16791 | forkshell_evalpipe(struct forkshell *fs) | ||
| 16792 | { | ||
| 16793 | union node *n = fs->n; | ||
| 16794 | int flags = fs->flags; | ||
| 16795 | int prevfd = fs->fd[2]; | ||
| 16796 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
| 16797 | |||
| 16798 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
| 16799 | INTON; | ||
| 16800 | if (pip[1] >= 0) { | ||
| 16801 | close(pip[0]); | ||
| 16802 | } | ||
| 16803 | if (prevfd > 0) { | ||
| 16804 | dup2(prevfd, 0); | ||
| 16805 | close(prevfd); | ||
| 16806 | } | ||
| 16807 | if (pip[1] > 1) { | ||
| 16808 | dup2(pip[1], 1); | ||
| 16809 | close(pip[1]); | ||
| 16810 | } | ||
| 16811 | evaltreenr(n, flags); | ||
| 16812 | } | ||
| 16813 | |||
| 16814 | static void | ||
| 16815 | forkshell_shellexec(struct forkshell *fs) | ||
| 16816 | { | ||
| 16817 | int idx = fs->fd[0]; | ||
| 16818 | char **argv = fs->argv; | ||
| 16819 | const char *path = fs->path; | ||
| 16820 | |||
| 16821 | FORCEINTON; | ||
| 16822 | shellexec(argv[0], argv, path, idx, TRUE); | ||
| 16823 | } | ||
| 16824 | |||
| 16825 | static void | ||
| 16826 | forkshell_child(struct forkshell *fs) | ||
| 16827 | { | ||
| 16828 | switch ( fs->fpid ) { | ||
| 16829 | case FS_OPENHERE: | ||
| 16830 | forkshell_openhere(fs); | ||
| 16831 | break; | ||
| 16832 | case FS_EVALBACKCMD: | ||
| 16833 | forkshell_evalbackcmd(fs); | ||
| 16834 | break; | ||
| 16835 | case FS_EVALSUBSHELL: | ||
| 16836 | forkshell_evalsubshell(fs); | ||
| 16837 | break; | ||
| 16838 | case FS_EVALPIPE: | ||
| 16839 | forkshell_evalpipe(fs); | ||
| 16840 | break; | ||
| 16841 | case FS_SHELLEXEC: | ||
| 16842 | forkshell_shellexec(fs); | ||
| 16843 | break; | ||
| 16844 | } | ||
| 16845 | } | ||
| 16846 | |||
| 16847 | /* | ||
| 16848 | * Reinitialise the builtin environment variables in varinit. Their | ||
| 16849 | * current settings have been copied from the parent in vartab. Look | ||
| 16850 | * these up using the names from varinit_data, copy the details from | ||
| 16851 | * vartab to varinit and replace the old copy in vartab with the new | ||
| 16852 | * one in varinit. | ||
| 16853 | * | ||
| 16854 | * Also reinitialise the function pointers and line number variable. | ||
| 16855 | */ | ||
| 16856 | static void | ||
| 16857 | reinitvar(void) | ||
| 16858 | { | ||
| 16859 | int i; | ||
| 16860 | const char *name; | ||
| 16861 | struct var **old; | ||
| 16862 | |||
| 16863 | for (i=0; i<ARRAY_SIZE(varinit); ++i) { | ||
| 16864 | if (i == LINENO_INDEX) | ||
| 16865 | name = "LINENO="; | ||
| 16866 | else if (i == FUNCNAME_INDEX) | ||
| 16867 | name = "FUNCNAME="; | ||
| 16868 | else | ||
| 16869 | name = varinit_data[i].var_text; | ||
| 16870 | if ((old = findvar(name)) != NULL) { | ||
| 16871 | varinit[i] = **old; | ||
| 16872 | *old = varinit+i; | ||
| 16873 | } | ||
| 16874 | varinit[i].var_func = varinit_data[i].var_func; | ||
| 16875 | } | ||
| 16876 | vlineno.var_text = linenovar; | ||
| 16877 | vfuncname.var_text = funcnamevar; | ||
| 16878 | } | ||
| 16879 | |||
| 16880 | static void | ||
| 16881 | spawn_forkshell(struct forkshell *fs, struct job *jp, union node *n, int mode) | ||
| 16882 | { | ||
| 16883 | struct forkshell *new; | ||
| 16884 | char buf[32]; | ||
| 16885 | const char *argv[] = { "sh", "--fs", NULL, NULL }; | ||
| 16886 | intptr_t ret; | ||
| 16887 | |||
| 16888 | new = forkshell_prepare(fs); | ||
| 16889 | if (new == NULL) | ||
| 16890 | goto fail; | ||
| 16891 | |||
| 16892 | new->mode = mode; | ||
| 16893 | new->nprocs = jp == NULL ? 0 : jp->nprocs; | ||
| 16894 | #if JOBS_WIN32 | ||
| 16895 | new->jpnull = jp == NULL; | ||
| 16896 | #endif | ||
| 16897 | sprintf(buf, "%p", new->hMapFile); | ||
| 16898 | argv[2] = buf; | ||
| 16899 | ret = spawnve(P_NOWAIT, bb_busybox_exec_path, (char *const *)argv, NULL); | ||
| 16900 | CloseHandle(new->hMapFile); | ||
| 16901 | UnmapViewOfFile(new); | ||
| 16902 | if (ret == -1) { | ||
| 16903 | fail: | ||
| 16904 | if (jp) | ||
| 16905 | freejob(jp); | ||
| 16906 | ash_msg_and_raise_error("unable to spawn shell"); | ||
| 16907 | } | ||
| 16908 | forkparent(jp, n, mode, (HANDLE)ret); | ||
| 16909 | } | ||
| 16910 | |||
| 16911 | /* | ||
| 16912 | * forkshell_prepare() and friends | ||
| 16913 | * | ||
| 16914 | * The sequence is as follows: | ||
| 16915 | * - funcblocksize is initialized | ||
| 16916 | * - forkshell_size(fs) is called to calculate the exact memory needed | ||
| 16917 | * - a new struct is allocated | ||
| 16918 | * - funcblock, funcstring, relocate are initialized from the new block | ||
| 16919 | * - forkshell_copy(fs) is called to copy recursively everything over | ||
| 16920 | * it will record all relocations along the way | ||
| 16921 | * | ||
| 16922 | * When this memory is mapped elsewhere, pointer fixup will be needed | ||
| 16923 | */ | ||
| 16924 | |||
| 16925 | /* redefine without test that fs_size is nonzero */ | ||
| 16926 | #undef SAVE_PTR | ||
| 16927 | #undef SAVE_PTR2 | ||
| 16928 | #undef SAVE_PTR3 | ||
| 16929 | #define SAVE_PTR(dst,note,flag) {MARK_PTR(dst,note,flag);} | ||
| 16930 | |||
| 16931 | static int align_len(const char *s) | ||
| 16932 | { | ||
| 16933 | return s ? SHELL_ALIGN(strlen(s)+1) : 0; | ||
| 16934 | } | ||
| 16935 | |||
| 16936 | struct datasize { | ||
| 16937 | int funcblocksize; | ||
| 16938 | int funcstringsize; | ||
| 16939 | }; | ||
| 16940 | |||
| 16941 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
| 16942 | static struct datasize \ | ||
| 16943 | name(struct datasize ds, type *p) \ | ||
| 16944 | { \ | ||
| 16945 | while (p) { \ | ||
| 16946 | ds.funcblocksize += sizeof(type); | ||
| 16947 | /* do something here with p */ | ||
| 16948 | #define SLIST_SIZE_END() \ | ||
| 16949 | p = p->next; \ | ||
| 16950 | } \ | ||
| 16951 | return ds; \ | ||
| 16952 | } | ||
| 16953 | |||
| 16954 | #define SLIST_COPY_BEGIN(name,type) \ | ||
| 16955 | static type * \ | ||
| 16956 | name(type *vp) \ | ||
| 16957 | { \ | ||
| 16958 | type *start; \ | ||
| 16959 | type **vpp; \ | ||
| 16960 | vpp = &start; \ | ||
| 16961 | while (vp) { \ | ||
| 16962 | *vpp = funcblock; \ | ||
| 16963 | funcblock = (char *) funcblock + sizeof(type); | ||
| 16964 | /* do something here with vpp and vp */ | ||
| 16965 | #define SLIST_COPY_END() \ | ||
| 16966 | SAVE_PTR((*vpp)->next, "(*vpp)->next", NO_FREE); \ | ||
| 16967 | vp = vp->next; \ | ||
| 16968 | vpp = &(*vpp)->next; \ | ||
| 16969 | } \ | ||
| 16970 | *vpp = NULL; \ | ||
| 16971 | return start; \ | ||
| 16972 | } | ||
| 16973 | |||
| 16974 | /* | ||
| 16975 | * struct var | ||
| 16976 | */ | ||
| 16977 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
| 16978 | ds.funcstringsize += align_len(p->var_text); | ||
| 16979 | SLIST_SIZE_END() | ||
| 16980 | |||
| 16981 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
| 16982 | (*vpp)->var_text = nodeckstrdup(vp->var_text); | ||
| 16983 | (*vpp)->flags = vp->flags; | ||
| 16984 | (*vpp)->var_func = NULL; | ||
| 16985 | SAVE_PTR((*vpp)->var_text, xasprintf("(*vpp)->var_text '%s'", vp->var_text ?: "NULL"), FREE); | ||
| 16986 | SLIST_COPY_END() | ||
| 16987 | |||
| 16988 | /* | ||
| 16989 | * struct tblentry | ||
| 16990 | */ | ||
| 16991 | static struct datasize | ||
| 16992 | tblentry_size(struct datasize ds, struct tblentry *tep) | ||
| 16993 | { | ||
| 16994 | while (tep) { | ||
| 16995 | ds.funcblocksize += sizeof(struct tblentry) + align_len(tep->cmdname); | ||
| 16996 | /* CMDBUILTIN, e->param.cmd needs no pointer relocation */ | ||
| 16997 | if (tep->cmdtype == CMDFUNCTION) { | ||
| 16998 | ds.funcblocksize += offsetof(struct funcnode, n); | ||
| 16999 | ds.funcblocksize = calcsize(ds.funcblocksize, &tep->param.func->n); | ||
| 17000 | } | ||
| 17001 | tep = tep->next; | ||
| 17002 | } | ||
| 17003 | return ds; | ||
| 17004 | } | ||
| 17005 | |||
| 17006 | static struct tblentry * | ||
| 17007 | tblentry_copy(struct tblentry *tep) | ||
| 17008 | { | ||
| 17009 | struct tblentry *start; | ||
| 17010 | struct tblentry **newp; | ||
| 17011 | int size; | ||
| 17012 | |||
| 17013 | newp = &start; | ||
| 17014 | while (tep) { | ||
| 17015 | *newp = funcblock; | ||
| 17016 | size = sizeof(struct tblentry) + align_len(tep->cmdname); | ||
| 17017 | |||
| 17018 | funcblock = (char *) funcblock + size; | ||
| 17019 | memcpy(*newp, tep, sizeof(struct tblentry)+strlen(tep->cmdname)); | ||
| 17020 | switch (tep->cmdtype) { | ||
| 17021 | case CMDBUILTIN: | ||
| 17022 | /* Save index of builtin, not pointer; fixed by forkshell_init() */ | ||
| 17023 | (*newp)->param.index = tep->param.cmd - builtintab; | ||
| 17024 | break; | ||
| 17025 | case CMDFUNCTION: | ||
| 17026 | (*newp)->param.func = funcblock; | ||
| 17027 | funcblock = (char *) funcblock + offsetof(struct funcnode, n); | ||
| 17028 | copynode(&tep->param.func->n); | ||
| 17029 | SAVE_PTR((*newp)->param.func, "param.func", NO_FREE); | ||
| 17030 | break; | ||
| 17031 | default: | ||
| 17032 | break; | ||
| 17033 | } | ||
| 17034 | SAVE_PTR((*newp)->next, xasprintf("cmdname '%s'", tep->cmdname), FREE); | ||
| 17035 | tep = tep->next; | ||
| 17036 | newp = &(*newp)->next; | ||
| 17037 | } | ||
| 17038 | *newp = NULL; | ||
| 17039 | return start; | ||
| 17040 | } | ||
| 17041 | |||
| 17042 | static struct datasize | ||
| 17043 | cmdtable_size(struct datasize ds) | ||
| 17044 | { | ||
| 17045 | int i; | ||
| 17046 | ds.funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE; | ||
| 17047 | for (i = 0; i < CMDTABLESIZE; i++) | ||
| 17048 | ds = tblentry_size(ds, cmdtable[i]); | ||
| 17049 | return ds; | ||
| 17050 | } | ||
| 17051 | |||
| 17052 | static struct tblentry ** | ||
| 17053 | cmdtable_copy(void) | ||
| 17054 | { | ||
| 17055 | struct tblentry **new = funcblock; | ||
| 17056 | int i; | ||
| 17057 | |||
| 17058 | funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE; | ||
| 17059 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
| 17060 | new[i] = tblentry_copy(cmdtable[i]); | ||
| 17061 | SAVE_PTR(new[i], xasprintf("cmdtable[%d]", i), FREE); | ||
| 17062 | } | ||
| 17063 | return new; | ||
| 17064 | } | ||
| 17065 | |||
| 17066 | #if ENABLE_ASH_ALIAS | ||
| 17067 | /* | ||
| 17068 | * struct alias | ||
| 17069 | */ | ||
| 17070 | SLIST_SIZE_BEGIN(alias_size,struct alias) | ||
| 17071 | ds.funcstringsize += align_len(p->name); | ||
| 17072 | ds.funcstringsize += align_len(p->val); | ||
| 17073 | SLIST_SIZE_END() | ||
| 17074 | |||
| 17075 | SLIST_COPY_BEGIN(alias_copy,struct alias) | ||
| 17076 | (*vpp)->name = nodeckstrdup(vp->name); | ||
| 17077 | (*vpp)->val = nodeckstrdup(vp->val); | ||
| 17078 | (*vpp)->flag = vp->flag; | ||
| 17079 | SAVE_PTR((*vpp)->name, xasprintf("(*vpp)->name '%s'", vp->name ?: "NULL"), FREE); | ||
| 17080 | SAVE_PTR((*vpp)->val, xasprintf("(*vpp)->val '%s'", vp->val ?: "NULL"), FREE); | ||
| 17081 | SLIST_COPY_END() | ||
| 17082 | |||
| 17083 | static struct datasize | ||
| 17084 | atab_size(struct datasize ds) | ||
| 17085 | { | ||
| 17086 | int i; | ||
| 17087 | ds.funcblocksize += sizeof(struct alias *)*ATABSIZE; | ||
| 17088 | for (i = 0; i < ATABSIZE; i++) | ||
| 17089 | ds = alias_size(ds, atab[i]); | ||
| 17090 | return ds; | ||
| 17091 | } | ||
| 17092 | |||
| 17093 | static struct alias ** | ||
| 17094 | atab_copy(void) | ||
| 17095 | { | ||
| 17096 | struct alias **new = funcblock; | ||
| 17097 | int i; | ||
| 17098 | |||
| 17099 | funcblock = (char *) funcblock + sizeof(struct alias *)*ATABSIZE; | ||
| 17100 | for (i = 0; i < ATABSIZE; i++) { | ||
| 17101 | new[i] = alias_copy(atab[i]); | ||
| 17102 | SAVE_PTR(new[i], xasprintf("atab[%d]", i), FREE); | ||
| 17103 | } | ||
| 17104 | return new; | ||
| 17105 | } | ||
| 17106 | #endif | ||
| 17107 | |||
| 17108 | /* | ||
| 17109 | * char ** | ||
| 17110 | */ | ||
| 17111 | static struct datasize | ||
| 17112 | argv_size(struct datasize ds, char **p) | ||
| 17113 | { | ||
| 17114 | if (p) { | ||
| 17115 | while (*p) { | ||
| 17116 | ds.funcblocksize += sizeof(char *); | ||
| 17117 | ds.funcstringsize += align_len(*p); | ||
| 17118 | p++; | ||
| 17119 | } | ||
| 17120 | // Allow two extra elements for tryexec(). | ||
| 17121 | ds.funcblocksize += 3 * sizeof(char *); | ||
| 17122 | } | ||
| 17123 | return ds; | ||
| 17124 | } | ||
| 17125 | |||
| 17126 | static char ** | ||
| 17127 | argv_copy(char **p) | ||
| 17128 | { | ||
| 17129 | char **new, **start = funcblock; | ||
| 17130 | #if FORKSHELL_DEBUG | ||
| 17131 | int i = 0; | ||
| 17132 | #endif | ||
| 17133 | |||
| 17134 | if (p) { | ||
| 17135 | // Allow two extra elements for tryexec(). | ||
| 17136 | funcblock = (char *) funcblock + 2 * sizeof(char *); | ||
| 17137 | while (*p) { | ||
| 17138 | new = funcblock; | ||
| 17139 | funcblock = (char *) funcblock + sizeof(char *); | ||
| 17140 | *new = nodeckstrdup(*p); | ||
| 17141 | SAVE_PTR(*new, xasprintf("argv[%d] '%s'", i++, *p), FREE); | ||
| 17142 | p++; | ||
| 17143 | } | ||
| 17144 | new = funcblock; | ||
| 17145 | funcblock = (char *) funcblock + sizeof(char *); | ||
| 17146 | *new = NULL; | ||
| 17147 | return start + 2; | ||
| 17148 | } | ||
| 17149 | return NULL; | ||
| 17150 | } | ||
| 17151 | |||
| 17152 | #if MAX_HISTORY | ||
| 17153 | static struct datasize | ||
| 17154 | history_size(struct datasize ds) | ||
| 17155 | { | ||
| 17156 | int i; | ||
| 17157 | line_input_t *st = line_input_state; | ||
| 17158 | |||
| 17159 | ds.funcblocksize += sizeof(char *) * st->cnt_history; | ||
| 17160 | for (i = 0; i < st->cnt_history; i++) { | ||
| 17161 | ds.funcstringsize += align_len(st->history[i]); | ||
| 17162 | } | ||
| 17163 | return ds; | ||
| 17164 | } | ||
| 17165 | |||
| 17166 | static char ** | ||
| 17167 | history_copy(void) | ||
| 17168 | { | ||
| 17169 | line_input_t *st = line_input_state; | ||
| 17170 | char **new = funcblock; | ||
| 17171 | int i; | ||
| 17172 | |||
| 17173 | funcblock = (char *)funcblock + sizeof(char *) * st->cnt_history; | ||
| 17174 | for (i = 0; i < st->cnt_history; i++) { | ||
| 17175 | new[i] = nodeckstrdup(st->history[i]); | ||
| 17176 | SAVE_PTR(new[i], | ||
| 17177 | xasprintf("history[%d] '%s'", i, st->history[i]), FREE); | ||
| 17178 | } | ||
| 17179 | return new; | ||
| 17180 | } | ||
| 17181 | #endif | ||
| 17182 | |||
| 17183 | #if JOBS_WIN32 | ||
| 17184 | /* | ||
| 17185 | * struct procstat | ||
| 17186 | */ | ||
| 17187 | static struct datasize | ||
| 17188 | procstat_size(struct datasize ds, int nj) | ||
| 17189 | { | ||
| 17190 | struct job *jp = jobtab + nj; | ||
| 17191 | |||
| 17192 | if (jp->ps != &jp->ps0) | ||
| 17193 | ds.funcblocksize += sizeof(struct procstat) * jp->nprocs; | ||
| 17194 | |||
| 17195 | for (int i = 0; i < jp->nprocs; i++) | ||
| 17196 | ds.funcstringsize += align_len(jp->ps[i].ps_cmd); | ||
| 17197 | |||
| 17198 | return ds; | ||
| 17199 | } | ||
| 17200 | |||
| 17201 | static struct procstat * | ||
| 17202 | procstat_copy(int nj) | ||
| 17203 | { | ||
| 17204 | struct job *jp = jobtab + nj; | ||
| 17205 | struct procstat *new = funcblock; | ||
| 17206 | |||
| 17207 | funcblock = (char *)funcblock + sizeof(struct procstat) * jp->nprocs; | ||
| 17208 | memcpy(new, jp->ps, sizeof(struct procstat) * jp->nprocs); | ||
| 17209 | |||
| 17210 | for (int i = 0; i < jp->nprocs; i++) { | ||
| 17211 | new[i].ps_cmd = nodeckstrdup(jp->ps[i].ps_cmd); | ||
| 17212 | SAVE_PTR(new[i].ps_cmd, | ||
| 17213 | xasprintf("jobtab[%d].ps[%d].ps_cmd '%s'", | ||
| 17214 | nj, i, jp->ps[i].ps_cmd), FREE); | ||
| 17215 | } | ||
| 17216 | return new; | ||
| 17217 | } | ||
| 17218 | |||
| 17219 | /* | ||
| 17220 | * struct jobs | ||
| 17221 | */ | ||
| 17222 | static struct datasize | ||
| 17223 | jobtab_size(struct datasize ds) | ||
| 17224 | { | ||
| 17225 | ds.funcblocksize += sizeof(struct job) * njobs; | ||
| 17226 | for (int i = 0; i < njobs; i++) { | ||
| 17227 | if (jobtab[i].used) | ||
| 17228 | ds = procstat_size(ds, i); | ||
| 17229 | } | ||
| 17230 | return ds; | ||
| 17231 | } | ||
| 17232 | |||
| 17233 | static struct job * | ||
| 17234 | jobtab_copy(void) | ||
| 17235 | { | ||
| 17236 | struct job *new = funcblock; | ||
| 17237 | int i; | ||
| 17238 | |||
| 17239 | funcblock = (char *)funcblock + sizeof(struct job) * njobs; | ||
| 17240 | memcpy(new, jobtab, sizeof(struct job) * njobs); | ||
| 17241 | |||
| 17242 | for (i = 0; i < njobs; i++) { | ||
| 17243 | if (!jobtab[i].used) | ||
| 17244 | continue; | ||
| 17245 | |||
| 17246 | if (jobtab[i].ps == &jobtab[i].ps0) { | ||
| 17247 | new[i].ps0.ps_cmd = nodeckstrdup(jobtab[i].ps0.ps_cmd); | ||
| 17248 | SAVE_PTR(new[i].ps0.ps_cmd, | ||
| 17249 | xasprintf("jobtab[%d].ps0.ps_cmd '%s'", | ||
| 17250 | i, jobtab[i].ps0.ps_cmd), FREE); | ||
| 17251 | new[i].ps = &new[i].ps0; | ||
| 17252 | } else if (jobtab[i].nprocs) { | ||
| 17253 | new[i].ps = procstat_copy(i); | ||
| 17254 | } else { | ||
| 17255 | new[i].ps = NULL; | ||
| 17256 | } | ||
| 17257 | SAVE_PTR(new[i].ps, xasprintf("jobtab[%d].ps", i), FREE); | ||
| 17258 | |||
| 17259 | if (jobtab[i].prev_job) { | ||
| 17260 | new[i].prev_job = new + (jobtab[i].prev_job - jobtab); | ||
| 17261 | SAVE_PTR(new[i].prev_job, | ||
| 17262 | xasprintf("jobtab[%d].prev_job", i), FREE); | ||
| 17263 | } | ||
| 17264 | } | ||
| 17265 | return new; | ||
| 17266 | } | ||
| 17267 | #endif | ||
| 17268 | |||
| 17269 | /* | ||
| 17270 | * struct redirtab | ||
| 17271 | */ | ||
| 17272 | static int | ||
| 17273 | redirtab_size(int funcblocksize, struct redirtab *rdtp) | ||
| 17274 | { | ||
| 17275 | while (rdtp) { | ||
| 17276 | funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
| 17277 | rdtp = rdtp->next; | ||
| 17278 | } | ||
| 17279 | return funcblocksize; | ||
| 17280 | } | ||
| 17281 | |||
| 17282 | static struct redirtab * | ||
| 17283 | redirtab_copy(struct redirtab *rdtp) | ||
| 17284 | { | ||
| 17285 | struct redirtab *start; | ||
| 17286 | struct redirtab **vpp; | ||
| 17287 | |||
| 17288 | vpp = &start; | ||
| 17289 | while (rdtp) { | ||
| 17290 | int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
| 17291 | *vpp = funcblock; | ||
| 17292 | funcblock = (char *) funcblock + size; | ||
| 17293 | memcpy(*vpp, rdtp, size); | ||
| 17294 | SAVE_PTR((*vpp)->next, "(*vpp)->next", NO_FREE); | ||
| 17295 | rdtp = rdtp->next; | ||
| 17296 | vpp = &(*vpp)->next; | ||
| 17297 | } | ||
| 17298 | *vpp = NULL; | ||
| 17299 | return start; | ||
| 17300 | } | ||
| 17301 | |||
| 17302 | static struct datasize | ||
| 17303 | globals_var_size(struct datasize ds) | ||
| 17304 | { | ||
| 17305 | int i; | ||
| 17306 | |||
| 17307 | ds.funcblocksize += sizeof(struct globals_var); | ||
| 17308 | ds.funcstringsize += align_len(funcname); | ||
| 17309 | ds = argv_size(ds, shellparam.p); | ||
| 17310 | ds.funcblocksize = redirtab_size(ds.funcblocksize, redirlist); | ||
| 17311 | for (i = 0; i < VTABSIZE; i++) | ||
| 17312 | ds = var_size(ds, vartab[i]); | ||
| 17313 | return ds; | ||
| 17314 | } | ||
| 17315 | |||
| 17316 | #undef funcname | ||
| 17317 | #undef shellparam | ||
| 17318 | #undef redirlist | ||
| 17319 | #undef vartab | ||
| 17320 | static struct globals_var * | ||
| 17321 | globals_var_copy(void) | ||
| 17322 | { | ||
| 17323 | int i; | ||
| 17324 | struct globals_var *gvp, *new; | ||
| 17325 | |||
| 17326 | gvp = ash_ptr_to_globals_var; | ||
| 17327 | new = funcblock; | ||
| 17328 | funcblock = (char *) funcblock + sizeof(struct globals_var); | ||
| 17329 | memcpy(new, gvp, sizeof(struct globals_var)); | ||
| 17330 | |||
| 17331 | new->funcname = nodeckstrdup(gvp->funcname); | ||
| 17332 | SAVE_PTR(new->funcname, xasprintf("funcname '%s'", gvp->funcname ?: "NULL"), FREE); | ||
| 17333 | |||
| 17334 | /* shparam */ | ||
| 17335 | new->shellparam.malloced = 0; | ||
| 17336 | new->shellparam.p = argv_copy(gvp->shellparam.p); | ||
| 17337 | SAVE_PTR(new->shellparam.p, "shellparam.p", NO_FREE); | ||
| 17338 | |||
| 17339 | new->redirlist = redirtab_copy(gvp->redirlist); | ||
| 17340 | SAVE_PTR(new->redirlist, "redirlist", NO_FREE); | ||
| 17341 | |||
| 17342 | for (i = 0; i < VTABSIZE; i++) { | ||
| 17343 | new->vartab[i] = var_copy(gvp->vartab[i]); | ||
| 17344 | SAVE_PTR(new->vartab[i], xasprintf("vartab[%d]", i), FREE); | ||
| 17345 | } | ||
| 17346 | |||
| 17347 | return new; | ||
| 17348 | } | ||
| 17349 | |||
| 17350 | static struct datasize | ||
| 17351 | globals_misc_size(struct datasize ds) | ||
| 17352 | { | ||
| 17353 | ds.funcblocksize += sizeof(struct globals_misc); | ||
| 17354 | ds.funcstringsize += align_len(minusc); | ||
| 17355 | if (curdir != nullstr) | ||
| 17356 | ds.funcstringsize += align_len(curdir); | ||
| 17357 | if (physdir != nullstr) | ||
| 17358 | ds.funcstringsize += align_len(physdir); | ||
| 17359 | ds.funcstringsize += align_len(arg0); | ||
| 17360 | ds.funcstringsize += align_len(commandname); | ||
| 17361 | for (int i = 0; i < ARRAY_SIZE(trap); i++) | ||
| 17362 | ds.funcstringsize += align_len(trap[i]); | ||
| 17363 | return ds; | ||
| 17364 | } | ||
| 17365 | |||
| 17366 | #undef minusc | ||
| 17367 | #undef curdir | ||
| 17368 | #undef physdir | ||
| 17369 | #undef arg0 | ||
| 17370 | #undef commandname | ||
| 17371 | #undef g_parsefile | ||
| 17372 | #undef basepf | ||
| 17373 | #undef nullstr | ||
| 17374 | #undef trap | ||
| 17375 | static struct globals_misc * | ||
| 17376 | globals_misc_copy(void) | ||
| 17377 | { | ||
| 17378 | struct globals_misc *p = ash_ptr_to_globals_misc; | ||
| 17379 | struct globals_misc *new = funcblock; | ||
| 17380 | |||
| 17381 | funcblock = (char *) funcblock + sizeof(struct globals_misc); | ||
| 17382 | memcpy(new, p, sizeof(struct globals_misc)); | ||
| 17383 | |||
| 17384 | new->minusc = nodeckstrdup(p->minusc); | ||
| 17385 | new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr; | ||
| 17386 | new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr; | ||
| 17387 | new->arg0 = nodeckstrdup(p->arg0); | ||
| 17388 | new->commandname = nodeckstrdup(p->commandname); | ||
| 17389 | SAVE_PTR(new->minusc, xasprintf("minusc '%s'", p->minusc ?: "NULL"), FREE); | ||
| 17390 | SAVE_PTR(new->curdir, | ||
| 17391 | xasprintf("curdir '%s'", new->curdir ?: "NULL"), FREE); | ||
| 17392 | SAVE_PTR(new->physdir, | ||
| 17393 | xasprintf("physdir '%s'", new->physdir ?: "NULL"), FREE); | ||
| 17394 | SAVE_PTR(new->arg0, xasprintf("arg0 '%s'", p->arg0 ?: "NULL"), FREE); | ||
| 17395 | SAVE_PTR(new->commandname, | ||
| 17396 | xasprintf("commandname '%s'", p->commandname ?: "NULL"), FREE); | ||
| 17397 | for (int i = 0; i < ARRAY_SIZE(p->trap); i++) { | ||
| 17398 | new->trap[i] = nodeckstrdup(p->trap[i]); | ||
| 17399 | SAVE_PTR(new->trap[i], xasprintf("trap[%d]", i), FREE); | ||
| 17400 | } | ||
| 17401 | new->g_parsefile = NULL; | ||
| 17402 | memset(&new->basepf, 0, sizeof(struct parsefile)); | ||
| 17403 | return new; | ||
| 17404 | } | ||
| 17405 | |||
| 17406 | static struct datasize | ||
| 17407 | forkshell_size(struct forkshell *fs) | ||
| 17408 | { | ||
| 17409 | struct datasize ds = {0, 0}; | ||
| 17410 | |||
| 17411 | ds.funcstringsize += align_len(fs->path); | ||
| 17412 | if (fs->fpid == FS_OPENHERE) | ||
| 17413 | return ds; | ||
| 17414 | |||
| 17415 | ds = globals_misc_size(ds); | ||
| 17416 | ds = globals_var_size(ds); | ||
| 17417 | ds = cmdtable_size(ds); | ||
| 17418 | |||
| 17419 | ds.funcblocksize = calcsize(ds.funcblocksize, fs->n); | ||
| 17420 | ds = argv_size(ds, fs->argv); | ||
| 17421 | |||
| 17422 | if ((ENABLE_ASH_ALIAS || MAX_HISTORY || JOBS_WIN32) && | ||
| 17423 | fs->fpid != FS_SHELLEXEC) { | ||
| 17424 | #if ENABLE_ASH_ALIAS | ||
| 17425 | ds = atab_size(ds); | ||
| 17426 | #endif | ||
| 17427 | #if MAX_HISTORY | ||
| 17428 | if (line_input_state) | ||
| 17429 | ds = history_size(ds); | ||
| 17430 | #endif | ||
| 17431 | #if JOBS_WIN32 | ||
| 17432 | ds = jobtab_size(ds); | ||
| 17433 | #endif | ||
| 17434 | } | ||
| 17435 | return ds; | ||
| 17436 | } | ||
| 17437 | |||
| 17438 | static void | ||
| 17439 | forkshell_copy(struct forkshell *fs, struct forkshell *new) | ||
| 17440 | { | ||
| 17441 | memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */ | ||
| 17442 | |||
| 17443 | new->path = nodeckstrdup(fs->path); | ||
| 17444 | SAVE_PTR(new->path, xasprintf("path '%s'", fs->path ?: "NULL"), FREE); | ||
| 17445 | if (fs->fpid == FS_OPENHERE) | ||
| 17446 | return; | ||
| 17447 | |||
| 17448 | new->gmp = globals_misc_copy(); | ||
| 17449 | new->gvp = globals_var_copy(); | ||
| 17450 | new->cmdtable = cmdtable_copy(); | ||
| 17451 | SAVE_PTR(new->gmp, "gmp", NO_FREE); | ||
| 17452 | SAVE_PTR(new->gvp, "gvp", NO_FREE); | ||
| 17453 | SAVE_PTR(new->cmdtable, "cmdtable", NO_FREE); | ||
| 17454 | |||
| 17455 | new->n = copynode(fs->n); | ||
| 17456 | new->argv = argv_copy(fs->argv); | ||
| 17457 | SAVE_PTR(new->n, "n", NO_FREE); | ||
| 17458 | SAVE_PTR(new->argv, "argv", NO_FREE); | ||
| 17459 | |||
| 17460 | if ((ENABLE_ASH_ALIAS || MAX_HISTORY || JOBS_WIN32) && | ||
| 17461 | fs->fpid != FS_SHELLEXEC) { | ||
| 17462 | #if ENABLE_ASH_ALIAS | ||
| 17463 | new->atab = atab_copy(); | ||
| 17464 | SAVE_PTR(new->atab, "atab", NO_FREE); | ||
| 17465 | #endif | ||
| 17466 | #if MAX_HISTORY | ||
| 17467 | if (line_input_state) { | ||
| 17468 | new->history = history_copy(); | ||
| 17469 | SAVE_PTR(new->history, "history", NO_FREE); | ||
| 17470 | new->cnt_history = line_input_state->cnt_history; | ||
| 17471 | } | ||
| 17472 | #endif | ||
| 17473 | #if JOBS_WIN32 | ||
| 17474 | if (njobs) { | ||
| 17475 | new->jobtab = jobtab_copy(); | ||
| 17476 | SAVE_PTR(new->jobtab, "jobtab", NO_FREE); | ||
| 17477 | new->njobs = njobs; | ||
| 17478 | if (curjob) { | ||
| 17479 | new->curjob = new->jobtab + (curjob - jobtab); | ||
| 17480 | SAVE_PTR(new->curjob, "curjob", NO_FREE); | ||
| 17481 | } | ||
| 17482 | } | ||
| 17483 | #endif | ||
| 17484 | } | ||
| 17485 | } | ||
| 17486 | |||
| 17487 | #if FORKSHELL_DEBUG | ||
| 17488 | #define NUM_BLOCKS FUNCSTRING | ||
| 17489 | enum {GMP, GVP, CMDTABLE, NODE, ARGV, ATAB, HISTORY, JOBTAB, FUNCSTRING}; | ||
| 17490 | |||
| 17491 | /* fp0 and notes can each be NULL */ | ||
| 17492 | static void | ||
| 17493 | forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes) | ||
| 17494 | { | ||
| 17495 | FILE *fp; | ||
| 17496 | void *lfuncblock; | ||
| 17497 | char *lfuncstring; | ||
| 17498 | char *lrelocate; | ||
| 17499 | char *s; | ||
| 17500 | int count, i, total, bitmapsize; | ||
| 17501 | int size[NUM_BLOCKS]; | ||
| 17502 | char *lptr[NUM_BLOCKS+1]; | ||
| 17503 | const char *fsname[] = { | ||
| 17504 | "FS_OPENHERE", | ||
| 17505 | "FS_EVALBACKCMD", | ||
| 17506 | "FS_EVALSUBSHELL", | ||
| 17507 | "FS_EVALPIPE", | ||
| 17508 | "FS_SHELLEXEC" | ||
| 17509 | }; | ||
| 17510 | |||
| 17511 | if (fp0 != NULL) { | ||
| 17512 | fp = fp0; | ||
| 17513 | } | ||
| 17514 | else { | ||
| 17515 | char name[64]; | ||
| 17516 | static int num = 0; | ||
| 17517 | |||
| 17518 | sprintf(name, "fs_%d_%03d.out", getpid(), ++num % 100); | ||
| 17519 | if ((fp=fopen(name, "w")) == NULL) | ||
| 17520 | return; | ||
| 17521 | } | ||
| 17522 | |||
| 17523 | bitmapsize = (fs->relocatesize + 7)/8; | ||
| 17524 | total = sizeof(struct forkshell) + fs->funcblocksize + | ||
| 17525 | fs->funcstringsize + bitmapsize; | ||
| 17526 | fprintf(fp, "total size %6d = %d + %d + %d + %d = %d\n", | ||
| 17527 | fs->size + bitmapsize, | ||
| 17528 | (int)sizeof(struct forkshell), fs->funcblocksize, | ||
| 17529 | fs->funcstringsize, bitmapsize, total); | ||
| 17530 | |||
| 17531 | lfuncblock = (char *)(fs + 1); | ||
| 17532 | lfuncstring = (char *)lfuncblock + fs->funcblocksize; | ||
| 17533 | lrelocate = (char *)lfuncstring + fs->funcstringsize; | ||
| 17534 | |||
| 17535 | /* funcblocksize is zero for FS_OPENHERE */ | ||
| 17536 | if (fs->funcblocksize != 0) { | ||
| 17537 | /* Depending on the configuration and the type of forkshell | ||
| 17538 | * some items may not be present. */ | ||
| 17539 | lptr[FUNCSTRING] = lfuncstring; | ||
| 17540 | #if JOBS_WIN32 | ||
| 17541 | lptr[JOBTAB] = fs->jobtab ? (char *)fs->jobtab : lptr[FUNCSTRING]; | ||
| 17542 | #else | ||
| 17543 | lptr[JOBTAB] = lptr[FUNCSTRING]; | ||
| 17544 | #endif | ||
| 17545 | #if MAX_HISTORY | ||
| 17546 | lptr[HISTORY] = fs->history ? (char *)fs->history : lptr[JOBTAB]; | ||
| 17547 | #else | ||
| 17548 | lptr[HISTORY] = lptr[JOBTAB]; | ||
| 17549 | #endif | ||
| 17550 | lptr[ATAB] = IF_ASH_ALIAS(fs->atab ? (char *)fs->atab :) lptr[HISTORY]; | ||
| 17551 | lptr[ARGV] = fs->argv ? (char *)fs->argv : lptr[ATAB]; | ||
| 17552 | lptr[NODE] = fs->n ? (char *)fs->n : lptr[ARGV]; | ||
| 17553 | lptr[CMDTABLE] = (char *)fs->cmdtable; | ||
| 17554 | lptr[GVP] = (char *)fs->gvp; | ||
| 17555 | lptr[GMP] = (char *)fs->gmp; | ||
| 17556 | |||
| 17557 | fprintf(fp, "funcblocksize %6d = ", fs->funcblocksize); | ||
| 17558 | total = 0; | ||
| 17559 | for (i=0; i<NUM_BLOCKS; ++i) { | ||
| 17560 | size[i] = (int)(lptr[i+1] - lptr[i]); | ||
| 17561 | total += size[i]; | ||
| 17562 | fprintf(fp, "%d %c ", size[i], i == NUM_BLOCKS - 1 ? '=' : '+'); | ||
| 17563 | } | ||
| 17564 | fprintf(fp, "%d\n\n", total); | ||
| 17565 | } | ||
| 17566 | else { | ||
| 17567 | fprintf(fp, "\n"); | ||
| 17568 | } | ||
| 17569 | |||
| 17570 | fprintf(fp, "%s\n\n", fsname[fs->fpid]); | ||
| 17571 | fprintf(fp, "--- relocate ---\n"); | ||
| 17572 | count = 0; | ||
| 17573 | for (i = 0; i < fs->relocatesize; ++i) { | ||
| 17574 | if (lrelocate[i/8] & (1 << i % 8)) { | ||
| 17575 | char **ptr = (char **)((char *)fs + i * sizeof(char *)); | ||
| 17576 | fprintf(fp, "%p %p %s\n", ptr, *ptr, | ||
| 17577 | notes && notes[i] ? notes[i] : ""); | ||
| 17578 | ++count; | ||
| 17579 | } | ||
| 17580 | } | ||
| 17581 | fprintf(fp, "--- %d relocations ---\n\n", count); | ||
| 17582 | |||
| 17583 | fprintf(fp, "--- funcstring ---\n"); | ||
| 17584 | count = 0; | ||
| 17585 | s = lfuncstring; | ||
| 17586 | while (s-lfuncstring < fs->funcstringsize) { | ||
| 17587 | if (!*s) { | ||
| 17588 | ++s; | ||
| 17589 | continue; | ||
| 17590 | } | ||
| 17591 | fprintf(fp, "%p '%s'\n", s, s); | ||
| 17592 | s += strlen(s)+1; | ||
| 17593 | ++count; | ||
| 17594 | } | ||
| 17595 | fprintf(fp, "--- %d strings ---\n", count); | ||
| 17596 | |||
| 17597 | if (fp0 == NULL) | ||
| 17598 | fclose(fp); | ||
| 17599 | } | ||
| 17600 | #endif | ||
| 17601 | |||
| 17602 | static struct forkshell * | ||
| 17603 | forkshell_prepare(struct forkshell *fs) | ||
| 17604 | { | ||
| 17605 | struct forkshell *new; | ||
| 17606 | struct datasize ds; | ||
| 17607 | int size, relocatesize, bitmapsize; | ||
| 17608 | HANDLE h; | ||
| 17609 | SECURITY_ATTRIBUTES sa; | ||
| 17610 | #if FORKSHELL_DEBUG | ||
| 17611 | char *relocate; | ||
| 17612 | char name[64]; | ||
| 17613 | FILE *fp; | ||
| 17614 | static int num = 0; | ||
| 17615 | #endif | ||
| 17616 | |||
| 17617 | /* calculate size of structure, funcblock and funcstring */ | ||
| 17618 | ds = forkshell_size(fs); | ||
| 17619 | size = sizeof(struct forkshell) + ds.funcblocksize + ds.funcstringsize; | ||
| 17620 | relocatesize = (sizeof(struct forkshell) + ds.funcblocksize)/sizeof(char *); | ||
| 17621 | bitmapsize = (relocatesize + 7)/8; | ||
| 17622 | |||
| 17623 | /* Allocate shared memory region */ | ||
| 17624 | memset(&sa, 0, sizeof(sa)); | ||
| 17625 | sa.nLength = sizeof(sa); | ||
| 17626 | sa.lpSecurityDescriptor = NULL; | ||
| 17627 | sa.bInheritHandle = TRUE; | ||
| 17628 | h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, | ||
| 17629 | size+bitmapsize, NULL); | ||
| 17630 | |||
| 17631 | /* Initialise pointers */ | ||
| 17632 | new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
| 17633 | if (new == NULL) | ||
| 17634 | return NULL; | ||
| 17635 | fs_size = size; | ||
| 17636 | fs_start = new; | ||
| 17637 | funcblock = (char *)(new + 1); | ||
| 17638 | funcstring_end = (char *)new + size; | ||
| 17639 | #if FORKSHELL_DEBUG | ||
| 17640 | fs_funcstring = (char *)new + sizeof(struct forkshell) + ds.funcblocksize; | ||
| 17641 | relocate = (char *)new + size; | ||
| 17642 | annot = (const char **)xzalloc(sizeof(char *)*relocatesize); | ||
| 17643 | annot_free = xzalloc(relocatesize); | ||
| 17644 | #endif | ||
| 17645 | |||
| 17646 | /* Now pack them all */ | ||
| 17647 | forkshell_copy(fs, new); | ||
| 17648 | |||
| 17649 | /* Finish it up */ | ||
| 17650 | new->size = size; | ||
| 17651 | new->relocatesize = relocatesize; | ||
| 17652 | new->old_base = (char *)new; | ||
| 17653 | new->hMapFile = h; | ||
| 17654 | #if FORKSHELL_DEBUG | ||
| 17655 | sprintf(name, "fs_%d_%03d.out", getpid(), ++num % 100); | ||
| 17656 | if ((fp=fopen(name, "w")) != NULL) { | ||
| 17657 | int i; | ||
| 17658 | |||
| 17659 | new->funcblocksize = (char *)funcblock - (char *)(new + 1); | ||
| 17660 | new->funcstringsize = (char *)new + size - funcstring_end; | ||
| 17661 | |||
| 17662 | /* perform some sanity checks on pointers */ | ||
| 17663 | fprintf(fp, "forkshell %p %6d\n", new, (int)sizeof(*new)); | ||
| 17664 | fprintf(fp, "funcblock %p %6d\n", new+1, new->funcblocksize); | ||
| 17665 | fprintf(fp, "funcstring %p %6d\n", funcstring_end, | ||
| 17666 | new->funcstringsize); | ||
| 17667 | if ((char *)funcblock != funcstring_end) | ||
| 17668 | fprintf(fp, " funcstring != end funcblock + 1 %p\n", funcblock); | ||
| 17669 | fprintf(fp, "relocate %p %6d\n\n", relocate, bitmapsize); | ||
| 17670 | |||
| 17671 | forkshell_print(fp, new, annot); | ||
| 17672 | |||
| 17673 | for (i = 0; i < relocatesize; ++i) { | ||
| 17674 | if (annot_free[i]) { | ||
| 17675 | free((void *)annot[i]); | ||
| 17676 | } | ||
| 17677 | } | ||
| 17678 | free(annot); | ||
| 17679 | free(annot_free); | ||
| 17680 | annot = NULL; | ||
| 17681 | fclose(fp); | ||
| 17682 | } | ||
| 17683 | #endif | ||
| 17684 | return new; | ||
| 17685 | } | ||
| 17686 | |||
| 17687 | #undef trap_ptr | ||
| 17688 | static void | ||
| 17689 | forkshell_init(const char *idstr) | ||
| 17690 | { | ||
| 17691 | struct forkshell *fs; | ||
| 17692 | void *map_handle; | ||
| 17693 | HANDLE h; | ||
| 17694 | int i; | ||
| 17695 | char **ptr; | ||
| 17696 | char *lrelocate; | ||
| 17697 | |||
| 17698 | if (sscanf(idstr, "%p", &map_handle) != 1) | ||
| 17699 | return; | ||
| 17700 | |||
| 17701 | h = (HANDLE)map_handle; | ||
| 17702 | fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
| 17703 | if (!fs) | ||
| 17704 | return; | ||
| 17705 | |||
| 17706 | /* this memory can't be freed */ | ||
| 17707 | sticky_mem_start = fs; | ||
| 17708 | sticky_mem_end = (char *) fs + fs->size; | ||
| 17709 | |||
| 17710 | /* pointer fixup */ | ||
| 17711 | lrelocate = (char *)fs + fs->size; | ||
| 17712 | for (i = 0; i < fs->relocatesize; i++) { | ||
| 17713 | if (lrelocate[i/8] & (1 << i % 8)) { | ||
| 17714 | ptr = (char **)((char *)fs + i * sizeof(char *)); | ||
| 17715 | if (*ptr) | ||
| 17716 | *ptr = (char *)fs + (*ptr - fs->old_base); | ||
| 17717 | } | ||
| 17718 | } | ||
| 17719 | |||
| 17720 | if (fs->fpid == FS_OPENHERE) | ||
| 17721 | goto end; | ||
| 17722 | |||
| 17723 | /* Now fix up stuff that can't be transferred */ | ||
| 17724 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
| 17725 | struct tblentry *e = fs->cmdtable[i]; | ||
| 17726 | while (e) { | ||
| 17727 | if (e->cmdtype == CMDBUILTIN) | ||
| 17728 | e->param.cmd = builtintab + e->param.index; | ||
| 17729 | e = e->next; | ||
| 17730 | } | ||
| 17731 | } | ||
| 17732 | fs->gmp->trap_ptr = fs->gmp->trap; | ||
| 17733 | |||
| 17734 | /* from init() */ | ||
| 17735 | fs->gmp->basepf.next_to_pgetc = fs->gmp->basepf.buf = ckzalloc(IBUFSIZ); | ||
| 17736 | fs->gmp->basepf.linno = 1; | ||
| 17737 | fs->gmp->g_parsefile = &fs->gmp->basepf; | ||
| 17738 | |||
| 17739 | /* Set global variables */ | ||
| 17740 | ASSIGN_CONST_PTR(&ash_ptr_to_globals_misc, fs->gmp); | ||
| 17741 | ASSIGN_CONST_PTR(&ash_ptr_to_globals_var, fs->gvp); | ||
| 17742 | cmdtable = fs->cmdtable; | ||
| 17743 | #if ENABLE_ASH_ALIAS | ||
| 17744 | atab = fs->atab; /* will be NULL for FS_SHELLEXEC */ | ||
| 17745 | #endif | ||
| 17746 | #if MAX_HISTORY | ||
| 17747 | if (fs->cnt_history) { | ||
| 17748 | line_input_state = new_line_input_t(FOR_SHELL); | ||
| 17749 | line_input_state->cnt_history = fs->cnt_history; | ||
| 17750 | for (i = 0; i < line_input_state->cnt_history; i++) | ||
| 17751 | line_input_state->history[i] = fs->history[i]; | ||
| 17752 | } | ||
| 17753 | #endif | ||
| 17754 | #if JOBS_WIN32 | ||
| 17755 | jobtab = fs->jobtab; | ||
| 17756 | njobs = fs->njobs; | ||
| 17757 | curjob = fs->curjob; | ||
| 17758 | #endif | ||
| 17759 | |||
| 17760 | CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */ | ||
| 17761 | |||
| 17762 | reinitvar(); | ||
| 17763 | |||
| 17764 | if (setjmp(main_handler.loc)) { | ||
| 17765 | exitreset(); | ||
| 17766 | exitshell(); | ||
| 17767 | } | ||
| 17768 | exception_handler = &main_handler; | ||
| 17769 | |||
| 17770 | shlvl++; | ||
| 17771 | if (fs->mode == FORK_BG) { | ||
| 17772 | SetConsoleCtrlHandler(NULL, TRUE); | ||
| 17773 | if (fs->nprocs == 0) { | ||
| 17774 | close(0); | ||
| 17775 | if (open(bb_dev_null, O_RDONLY) != 0) | ||
| 17776 | ash_msg_and_raise_perror("can't open '%s'", bb_dev_null); | ||
| 17777 | } | ||
| 17778 | } | ||
| 17779 | else { | ||
| 17780 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
| 17781 | } | ||
| 17782 | |||
| 17783 | if (fs->n && fs->n->type == NCMD /* is it single cmd? */ | ||
| 17784 | /* && n->ncmd.args->type == NARG - always true? */ | ||
| 17785 | && fs->n->ncmd.args && strcmp(fs->n->ncmd.args->narg.text, "trap") == 0 | ||
| 17786 | && fs->n->ncmd.args->narg.next == NULL /* "trap" with no arguments */ | ||
| 17787 | /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */ | ||
| 17788 | ) { | ||
| 17789 | TRACE(("Trap hack\n")); | ||
| 17790 | /* Save trap handler strings for trap builtin to print */ | ||
| 17791 | fs->gmp->trap_ptr = xmemdup(fs->gmp->trap, sizeof(fs->gmp->trap)); | ||
| 17792 | /* Fall through into clearing traps */ | ||
| 17793 | } | ||
| 17794 | clear_traps(); | ||
| 17795 | #if JOBS_WIN32 | ||
| 17796 | /* do job control only in root shell */ | ||
| 17797 | jobctl = 0; | ||
| 17798 | |||
| 17799 | if (fs->n && fs->n->type == NCMD && fs->n->ncmd.args && | ||
| 17800 | strcmp(fs->n->ncmd.args->narg.text, "jobs") == 0) { | ||
| 17801 | TRACE(("Job hack\n")); | ||
| 17802 | if (!fs->jpnull) | ||
| 17803 | freejob(curjob); | ||
| 17804 | goto end; | ||
| 17805 | } | ||
| 17806 | for (struct job *jp = curjob; jp; jp = jp->prev_job) | ||
| 17807 | freejob(jp); | ||
| 17808 | #endif | ||
| 17809 | end: | ||
| 17810 | forkshell_child(fs); | ||
| 17811 | } | ||
| 17812 | |||
| 17813 | #undef free | ||
| 17814 | static void | ||
| 17815 | sticky_free(void *base) | ||
| 17816 | { | ||
| 17817 | if (base >= sticky_mem_start && base < sticky_mem_end) | ||
| 17818 | return; | ||
| 17819 | free(base); | ||
| 17820 | } | ||
| 17821 | #endif | ||
| 17822 | |||
| 15077 | /*- | 17823 | /*- |
| 15078 | * Copyright (c) 1989, 1991, 1993, 1994 | 17824 | * Copyright (c) 1989, 1991, 1993, 1994 |
| 15079 | * The Regents of the University of California. All rights reserved. | 17825 | * The Regents of the University of California. All rights reserved. |
