diff options
Diffstat (limited to 'shell/ash.c')
| -rw-r--r-- | shell/ash.c | 2740 |
1 files changed, 2703 insertions, 37 deletions
diff --git a/shell/ash.c b/shell/ash.c index 094a87390..719f722a2 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
| @@ -15,6 +15,21 @@ | |||
| 15 | * | 15 | * |
| 16 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | 16 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
| 17 | */ | 17 | */ |
| 18 | |||
| 19 | /* | ||
| 20 | * MinGW notes | ||
| 21 | * | ||
| 22 | * - Environment variables from Windows will all be turned to uppercase. | ||
| 23 | * - PATH accepts both ; and : as separator, but can't be mixed | ||
| 24 | * - command without ".exe" extension is still understood as executable | ||
| 25 | * - shell scripts on the path are detected by the presence of '#!' | ||
| 26 | * - both / and \ are supported in PATH. Usually you must use / | ||
| 27 | * - job control doesn't work, though the jobs builtin is available | ||
| 28 | * - trap doesn't work for signals, only EXIT | ||
| 29 | * - /dev/null is supported for redirection | ||
| 30 | * - fake $PPID | ||
| 31 | */ | ||
| 32 | |||
| 18 | //config:config SHELL_ASH | 33 | //config:config SHELL_ASH |
| 19 | //config: bool #hidden option | 34 | //config: bool #hidden option |
| 20 | //config: depends on !NOMMU | 35 | //config: depends on !NOMMU |
| @@ -170,11 +185,36 @@ | |||
| 170 | //config: you to run the specified command or builtin, | 185 | //config: you to run the specified command or builtin, |
| 171 | //config: even when there is a function with the same name. | 186 | //config: even when there is a function with the same name. |
| 172 | //config: | 187 | //config: |
| 188 | //config: | ||
| 189 | //config:config ASH_NOCONSOLE | ||
| 190 | //config: bool "'noconsole' option" | ||
| 191 | //config: default y | ||
| 192 | //config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32 | ||
| 193 | //config: help | ||
| 194 | //config: Enable support for the 'noconsole' option, which attempts to | ||
| 195 | //config: conceal the console normally associated with a command line | ||
| 196 | //config: application. This may be useful when running a shell script | ||
| 197 | //config: from a GUI application. Also the 'noiconify' option, which | ||
| 198 | //config: controls whether the console is iconified or hidden. | ||
| 199 | //config: | ||
| 200 | //config:config ASH_GLOB_OPTIONS | ||
| 201 | //config: bool "Globbing options" | ||
| 202 | //config: default y | ||
| 203 | //config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32 | ||
| 204 | //config: help | ||
| 205 | //config: Enable support for options to control globbing: | ||
| 206 | //config: - 'nocaseglob' allows case-insensitive filename globbing | ||
| 207 | //config: - 'nohiddenglob' allows hidden files to be omitted from globbing | ||
| 208 | //config: - 'nohidsysglob' allows hidden system files to be omitted | ||
| 209 | //config: | ||
| 173 | //config:endif # ash options | 210 | //config:endif # ash options |
| 174 | 211 | ||
| 175 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) | 212 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) |
| 176 | // APPLET_ODDNAME:name main location suid_type help | 213 | // 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)) | 214 | //applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) |
| 215 | //applet:IF_PLATFORM_MINGW32( | ||
| 216 | //applet:IF_SH_IS_ASH( APPLET_ODDNAME(lash, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) | ||
| 217 | //applet:) | ||
| 178 | //applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) | 218 | //applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) |
| 179 | 219 | ||
| 180 | //kbuild:lib-$(CONFIG_SHELL_ASH) += ash.o ash_ptr_hack.o shell_common.o | 220 | //kbuild:lib-$(CONFIG_SHELL_ASH) += ash.o ash_ptr_hack.o shell_common.o |
| @@ -195,7 +235,17 @@ | |||
| 195 | 235 | ||
| 196 | #define PROFILE 0 | 236 | #define PROFILE 0 |
| 197 | 237 | ||
| 238 | /* | ||
| 239 | * Only one of JOBS or JOBS_WIN32 is enabled at a time (or neither). | ||
| 240 | * JOBS_WIN32 doesn't enable job control, just some job-related features. | ||
| 241 | */ | ||
| 242 | #if ENABLE_PLATFORM_MINGW32 | ||
| 243 | #define JOBS_WIN32 ENABLE_ASH_JOB_CONTROL | ||
| 244 | #define JOBS 0 | ||
| 245 | #else | ||
| 246 | #define JOBS_WIN32 0 | ||
| 198 | #define JOBS ENABLE_ASH_JOB_CONTROL | 247 | #define JOBS ENABLE_ASH_JOB_CONTROL |
| 248 | #endif | ||
| 199 | 249 | ||
| 200 | #include <fnmatch.h> | 250 | #include <fnmatch.h> |
| 201 | #include <sys/times.h> | 251 | #include <sys/times.h> |
| @@ -206,6 +256,10 @@ | |||
| 206 | #else | 256 | #else |
| 207 | # define NUM_SCRIPTS 0 | 257 | # define NUM_SCRIPTS 0 |
| 208 | #endif | 258 | #endif |
| 259 | #if ENABLE_PLATFORM_MINGW32 | ||
| 260 | # include <conio.h> | ||
| 261 | # include "lazyload.h" | ||
| 262 | #endif | ||
| 209 | 263 | ||
| 210 | /* So far, all bash compat is controlled by one config option */ | 264 | /* So far, all bash compat is controlled by one config option */ |
| 211 | /* Separate defines document which part of code implements what */ | 265 | /* Separate defines document which part of code implements what */ |
| @@ -316,10 +370,89 @@ typedef long arith_t; | |||
| 316 | # define unlikely(cond) (cond) | 370 | # define unlikely(cond) (cond) |
| 317 | #endif | 371 | #endif |
| 318 | 372 | ||
| 373 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 374 | # define is_relative_path(path) ((path)[0] != '/') | ||
| 375 | #endif | ||
| 376 | |||
| 319 | #if !BB_MMU | 377 | #if !BB_MMU |
| 320 | # error "Do not even bother, ash will not run on NOMMU machine" | 378 | # error "Do not even bother, ash will not run on NOMMU machine" |
| 321 | #endif | 379 | #endif |
| 322 | 380 | ||
| 381 | #if ENABLE_PLATFORM_MINGW32 | ||
| 382 | # define FORKSHELL_DEBUG 0 | ||
| 383 | |||
| 384 | union node; | ||
| 385 | struct strlist; | ||
| 386 | struct job; | ||
| 387 | |||
| 388 | struct forkshell { | ||
| 389 | /* filled by forkshell_copy() */ | ||
| 390 | struct globals_var *gvp; | ||
| 391 | struct globals_misc *gmp; | ||
| 392 | struct tblentry **cmdtable; | ||
| 393 | #if ENABLE_ASH_ALIAS | ||
| 394 | struct alias **atab; | ||
| 395 | #endif | ||
| 396 | #if MAX_HISTORY | ||
| 397 | char **history; | ||
| 398 | int cnt_history; | ||
| 399 | #endif | ||
| 400 | #if JOBS_WIN32 | ||
| 401 | struct job *jobtab; | ||
| 402 | unsigned njobs; | ||
| 403 | struct job *curjob; | ||
| 404 | #endif | ||
| 405 | /* struct parsefile *g_parsefile; */ | ||
| 406 | HANDLE hMapFile; | ||
| 407 | char *old_base; | ||
| 408 | int size; | ||
| 409 | # if FORKSHELL_DEBUG | ||
| 410 | int funcblocksize; | ||
| 411 | int funcstringsize; | ||
| 412 | # endif | ||
| 413 | int relocatesize; | ||
| 414 | |||
| 415 | /* type of forkshell */ | ||
| 416 | int fpid; | ||
| 417 | |||
| 418 | /* generic data, used by forkshell_child */ | ||
| 419 | int mode; | ||
| 420 | int nprocs; | ||
| 421 | #if JOBS_WIN32 | ||
| 422 | int jpnull; | ||
| 423 | #endif | ||
| 424 | |||
| 425 | /* optional data, used by forkshell_child */ | ||
| 426 | int flags; | ||
| 427 | int fd[3]; | ||
| 428 | union node *n; | ||
| 429 | char **argv; | ||
| 430 | char *path; | ||
| 431 | }; | ||
| 432 | |||
| 433 | enum { | ||
| 434 | FS_OPENHERE, | ||
| 435 | FS_EVALBACKCMD, | ||
| 436 | FS_EVALSUBSHELL, | ||
| 437 | FS_EVALPIPE, | ||
| 438 | FS_SHELLEXEC | ||
| 439 | }; | ||
| 440 | |||
| 441 | static struct forkshell* forkshell_prepare(struct forkshell *fs); | ||
| 442 | static void forkshell_init(const char *idstr); | ||
| 443 | static void *sticky_mem_start, *sticky_mem_end; | ||
| 444 | static void sticky_free(void *p); | ||
| 445 | # define free(p) sticky_free(p) | ||
| 446 | #if !JOBS && !JOBS_WIN32 | ||
| 447 | #define spawn_forkshell(fs, jp, n, mode) spawn_forkshell(fs, jp, mode) | ||
| 448 | #endif | ||
| 449 | static void spawn_forkshell(struct forkshell *fs, struct job *jp, | ||
| 450 | union node *n, int mode); | ||
| 451 | # if FORKSHELL_DEBUG | ||
| 452 | static void forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes); | ||
| 453 | # endif | ||
| 454 | #endif | ||
| 455 | |||
| 323 | /* ============ Hash table sizes. Configurable. */ | 456 | /* ============ Hash table sizes. Configurable. */ |
| 324 | 457 | ||
| 325 | #define VTABSIZE 39 | 458 | #define VTABSIZE 39 |
| @@ -347,7 +480,11 @@ static const char *const optletters_optnames[] ALIGN_PTR = { | |||
| 347 | "m" "monitor", | 480 | "m" "monitor", |
| 348 | "n" "noexec", | 481 | "n" "noexec", |
| 349 | /* Ditto: bash has no "set -s", "set -c" */ | 482 | /* Ditto: bash has no "set -s", "set -c" */ |
| 483 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 350 | "s" "", | 484 | "s" "", |
| 485 | #else | ||
| 486 | "s" "stdin", | ||
| 487 | #endif | ||
| 351 | "c" "", | 488 | "c" "", |
| 352 | "x" "xtrace", | 489 | "x" "xtrace", |
| 353 | "v" "verbose", | 490 | "v" "verbose", |
| @@ -364,6 +501,18 @@ static const char *const optletters_optnames[] ALIGN_PTR = { | |||
| 364 | ,"\0" "nolog" | 501 | ,"\0" "nolog" |
| 365 | ,"\0" "debug" | 502 | ,"\0" "debug" |
| 366 | #endif | 503 | #endif |
| 504 | #if ENABLE_PLATFORM_MINGW32 | ||
| 505 | ,"X" "winxp" | ||
| 506 | #endif | ||
| 507 | #if ENABLE_ASH_NOCONSOLE | ||
| 508 | ,"\0" "noconsole" | ||
| 509 | ,"\0" "noiconify" | ||
| 510 | #endif | ||
| 511 | #if ENABLE_ASH_GLOB_OPTIONS | ||
| 512 | ,"\0" "nocaseglob" | ||
| 513 | ,"\0" "nohiddenglob" | ||
| 514 | ,"\0" "nohidsysglob" | ||
| 515 | #endif | ||
| 367 | }; | 516 | }; |
| 368 | //bash 4.4.23 also has these opts (with these defaults): | 517 | //bash 4.4.23 also has these opts (with these defaults): |
| 369 | //braceexpand on | 518 | //braceexpand on |
| @@ -406,21 +555,36 @@ struct jmploc { | |||
| 406 | struct globals_misc { | 555 | struct globals_misc { |
| 407 | uint8_t exitstatus; /* exit status of last command */ | 556 | uint8_t exitstatus; /* exit status of last command */ |
| 408 | uint8_t back_exitstatus;/* exit status of backquoted command */ | 557 | uint8_t back_exitstatus;/* exit status of backquoted command */ |
| 558 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 409 | smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ | 559 | smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ |
| 560 | #endif | ||
| 410 | smallint inps4; /* Prevent PS4 nesting. */ | 561 | smallint inps4; /* Prevent PS4 nesting. */ |
| 411 | int savestatus; /* exit status of last command outside traps */ | 562 | int savestatus; /* exit status of last command outside traps */ |
| 412 | int rootpid; /* pid of main shell */ | 563 | int rootpid; /* pid of main shell */ |
| 413 | /* shell level: 0 for the main shell, 1 for its children, and so on */ | 564 | /* shell level: 0 for the main shell, 1 for its children, and so on */ |
| 414 | int shlvl; | 565 | int shlvl; |
| 566 | #if ENABLE_PLATFORM_MINGW32 | ||
| 567 | int loopnest; /* current loop nesting level */ | ||
| 568 | #endif | ||
| 415 | #define rootshell (!shlvl) | 569 | #define rootshell (!shlvl) |
| 416 | int errlinno; | 570 | int errlinno; |
| 417 | 571 | ||
| 418 | char *minusc; /* argument to -c option */ | 572 | char *minusc; /* argument to -c option */ |
| 573 | #if ENABLE_PLATFORM_MINGW32 | ||
| 574 | char *dirarg; /* argument to -d option */ | ||
| 575 | char *title; /* argument to -t option */ | ||
| 576 | #if ENABLE_SUW32 | ||
| 577 | int delayexit; /* set by -N option */ | ||
| 578 | # endif | ||
| 579 | #endif | ||
| 419 | 580 | ||
| 420 | char *curdir; // = nullstr; /* current working directory */ | 581 | char *curdir; // = nullstr; /* current working directory */ |
| 421 | char *physdir; // = nullstr; /* physical working directory */ | 582 | char *physdir; // = nullstr; /* physical working directory */ |
| 422 | 583 | ||
| 423 | char *arg0; /* value of $0 */ | 584 | char *arg0; /* value of $0 */ |
| 585 | #if ENABLE_PLATFORM_MINGW32 | ||
| 586 | char *commandname; | ||
| 587 | #endif | ||
| 424 | 588 | ||
| 425 | struct jmploc *exception_handler; | 589 | struct jmploc *exception_handler; |
| 426 | 590 | ||
| @@ -431,8 +595,10 @@ struct globals_misc { | |||
| 431 | * but we do read it async. | 595 | * but we do read it async. |
| 432 | */ | 596 | */ |
| 433 | volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ | 597 | volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ |
| 598 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 434 | volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */ | 599 | volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */ |
| 435 | volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */ | 600 | volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */ |
| 601 | #endif | ||
| 436 | smallint exception_type; /* kind of exception: */ | 602 | smallint exception_type; /* kind of exception: */ |
| 437 | #define EXINT 0 /* SIGINT received */ | 603 | #define EXINT 0 /* SIGINT received */ |
| 438 | #define EXERROR 1 /* a generic error */ | 604 | #define EXERROR 1 /* a generic error */ |
| @@ -467,8 +633,21 @@ struct globals_misc { | |||
| 467 | # define nolog optlist[16 + BASH_PIPEFAIL] | 633 | # define nolog optlist[16 + BASH_PIPEFAIL] |
| 468 | # define debug optlist[17 + BASH_PIPEFAIL] | 634 | # define debug optlist[17 + BASH_PIPEFAIL] |
| 469 | #endif | 635 | #endif |
| 636 | #if ENABLE_PLATFORM_MINGW32 | ||
| 637 | # define winxp optlist[16 + BASH_PIPEFAIL + 2*(DEBUG != 0)] | ||
| 638 | # if ENABLE_ASH_NOCONSOLE | ||
| 639 | # define noconsole optlist[17 + BASH_PIPEFAIL + 2*(DEBUG != 0)] | ||
| 640 | # define noiconify optlist[18 + BASH_PIPEFAIL + 2*(DEBUG != 0)] | ||
| 641 | # endif | ||
| 642 | # if ENABLE_ASH_GLOB_OPTIONS | ||
| 643 | # define nocaseglob optlist[17 + BASH_PIPEFAIL + 2*(DEBUG != 0) + 2*ENABLE_ASH_NOCONSOLE] | ||
| 644 | # define nohiddenglob optlist[18 + BASH_PIPEFAIL + 2*(DEBUG != 0) + 2*ENABLE_ASH_NOCONSOLE] | ||
| 645 | # define nohidsysglob optlist[19 + BASH_PIPEFAIL + 2*(DEBUG != 0) + 2*ENABLE_ASH_NOCONSOLE] | ||
| 646 | # endif | ||
| 647 | #endif | ||
| 470 | 648 | ||
| 471 | /* trap handler commands */ | 649 | /* trap handler commands */ |
| 650 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 472 | /* | 651 | /* |
| 473 | * Sigmode records the current value of the signal handlers for the various | 652 | * Sigmode records the current value of the signal handlers for the various |
| 474 | * modes. A value of zero means that the current handler is not known. | 653 | * modes. A value of zero means that the current handler is not known. |
| @@ -482,6 +661,7 @@ struct globals_misc { | |||
| 482 | 661 | ||
| 483 | /* indicates specified signal received */ | 662 | /* indicates specified signal received */ |
| 484 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ | 663 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ |
| 664 | #endif | ||
| 485 | uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ | 665 | uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ |
| 486 | char *trap[NSIG + 1]; | 666 | char *trap[NSIG + 1]; |
| 487 | /* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */ | 667 | /* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */ |
| @@ -506,10 +686,21 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
| 506 | #define rootpid (G_misc.rootpid ) | 686 | #define rootpid (G_misc.rootpid ) |
| 507 | #define shlvl (G_misc.shlvl ) | 687 | #define shlvl (G_misc.shlvl ) |
| 508 | #define errlinno (G_misc.errlinno ) | 688 | #define errlinno (G_misc.errlinno ) |
| 689 | #if ENABLE_PLATFORM_MINGW32 | ||
| 690 | #define loopnest (G_misc.loopnest ) | ||
| 691 | #endif | ||
| 509 | #define minusc (G_misc.minusc ) | 692 | #define minusc (G_misc.minusc ) |
| 693 | #if ENABLE_PLATFORM_MINGW32 | ||
| 694 | #define dirarg (G_misc.dirarg ) | ||
| 695 | #define title (G_misc.title ) | ||
| 696 | #define delayexit (G_misc.delayexit ) | ||
| 697 | #endif | ||
| 510 | #define curdir (G_misc.curdir ) | 698 | #define curdir (G_misc.curdir ) |
| 511 | #define physdir (G_misc.physdir ) | 699 | #define physdir (G_misc.physdir ) |
| 512 | #define arg0 (G_misc.arg0 ) | 700 | #define arg0 (G_misc.arg0 ) |
| 701 | #if ENABLE_PLATFORM_MINGW32 | ||
| 702 | #define commandname (G_misc.commandname) | ||
| 703 | #endif | ||
| 513 | #define exception_handler (G_misc.exception_handler) | 704 | #define exception_handler (G_misc.exception_handler) |
| 514 | #define exception_type (G_misc.exception_type ) | 705 | #define exception_type (G_misc.exception_type ) |
| 515 | #define suppress_int (G_misc.suppress_int ) | 706 | #define suppress_int (G_misc.suppress_int ) |
| @@ -525,6 +716,13 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
| 525 | #define trap_ptr (G_misc.trap_ptr ) | 716 | #define trap_ptr (G_misc.trap_ptr ) |
| 526 | #define random_gen (G_misc.random_gen ) | 717 | #define random_gen (G_misc.random_gen ) |
| 527 | #define backgndpid (G_misc.backgndpid ) | 718 | #define backgndpid (G_misc.backgndpid ) |
| 719 | |||
| 720 | #if ENABLE_PLATFORM_MINGW32 | ||
| 721 | #undef got_sigchld | ||
| 722 | #undef pending_sig | ||
| 723 | #define pending_sig (0) | ||
| 724 | #endif | ||
| 725 | |||
| 528 | #define INIT_G_misc() do { \ | 726 | #define INIT_G_misc() do { \ |
| 529 | XZALLOC_CONST_PTR(&ash_ptr_to_globals_misc, sizeof(G_misc)); \ | 727 | XZALLOC_CONST_PTR(&ash_ptr_to_globals_misc, sizeof(G_misc)); \ |
| 530 | savestatus = -1; \ | 728 | savestatus = -1; \ |
| @@ -540,6 +738,9 @@ static void trace_printf(const char *fmt, ...); | |||
| 540 | static void trace_vprintf(const char *fmt, va_list va); | 738 | static void trace_vprintf(const char *fmt, va_list va); |
| 541 | # define TRACE(param) trace_printf param | 739 | # define TRACE(param) trace_printf param |
| 542 | # define TRACEV(param) trace_vprintf param | 740 | # define TRACEV(param) trace_vprintf param |
| 741 | # if ENABLE_PLATFORM_MINGW32 && defined(close) | ||
| 742 | # undef close | ||
| 743 | # endif | ||
| 543 | # define close(fd) do { \ | 744 | # define close(fd) do { \ |
| 544 | int dfd = (fd); \ | 745 | int dfd = (fd); \ |
| 545 | if (close(dfd) < 0) \ | 746 | if (close(dfd) < 0) \ |
| @@ -629,11 +830,18 @@ struct parsefile { | |||
| 629 | 830 | ||
| 630 | /* Number of outstanding calls to pungetc. */ | 831 | /* Number of outstanding calls to pungetc. */ |
| 631 | int unget; | 832 | int unget; |
| 833 | |||
| 834 | #if ENABLE_PLATFORM_MINGW32 | ||
| 835 | /* True if a trailing CR from a previous read was left unprocessed. */ | ||
| 836 | int cr; | ||
| 837 | #endif | ||
| 632 | }; | 838 | }; |
| 633 | 839 | ||
| 634 | static struct parsefile basepf; /* top level input file */ | 840 | static struct parsefile basepf; /* top level input file */ |
| 635 | static struct parsefile *g_parsefile = &basepf; /* current input file */ | 841 | static struct parsefile *g_parsefile = &basepf; /* current input file */ |
| 842 | #if ENABLE_PLATFORM_POSIX | ||
| 636 | static char *commandname; /* currently executing command */ | 843 | static char *commandname; /* currently executing command */ |
| 844 | #endif | ||
| 637 | 845 | ||
| 638 | 846 | ||
| 639 | /* ============ Interrupts / exceptions */ | 847 | /* ============ Interrupts / exceptions */ |
| @@ -690,21 +898,39 @@ raise_exception(int e) | |||
| 690 | * are held using the INT_OFF macro. (The test for iflag is just | 898 | * are held using the INT_OFF macro. (The test for iflag is just |
| 691 | * defensive programming.) | 899 | * defensive programming.) |
| 692 | */ | 900 | */ |
| 693 | static void raise_interrupt(void) NORETURN; | 901 | static void raise_interrupt(void) IF_NOT_PLATFORM_MINGW32(NORETURN); |
| 694 | static void | 902 | static void |
| 695 | raise_interrupt(void) | 903 | raise_interrupt(void) |
| 696 | { | 904 | { |
| 905 | #if ENABLE_PLATFORM_MINGW32 | ||
| 906 | /* Contrary to the comment above on Windows raise_interrupt() is | ||
| 907 | * called when SIGINT is trapped or ignored. We detect this here | ||
| 908 | * and return without doing anything. */ | ||
| 909 | if (trap[SIGINT]) | ||
| 910 | return; | ||
| 911 | #endif | ||
| 697 | pending_int = 0; | 912 | pending_int = 0; |
| 913 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 698 | /* Signal is not automatically unmasked after it is raised, | 914 | /* Signal is not automatically unmasked after it is raised, |
| 699 | * do it ourself - unmask all signals */ | 915 | * do it ourself - unmask all signals */ |
| 700 | sigprocmask_allsigs(SIG_UNBLOCK); | 916 | sigprocmask_allsigs(SIG_UNBLOCK); |
| 917 | #endif | ||
| 701 | /* pending_sig = 0; - now done in signal_handler() */ | 918 | /* pending_sig = 0; - now done in signal_handler() */ |
| 702 | 919 | ||
| 703 | if (!(rootshell && iflag)) { | 920 | if (!(rootshell && iflag)) { |
| 921 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 704 | /* Kill ourself with SIGINT */ | 922 | /* Kill ourself with SIGINT */ |
| 705 | signal(SIGINT, SIG_DFL); | 923 | signal(SIGINT, SIG_DFL); |
| 706 | raise(SIGINT); | 924 | raise(SIGINT); |
| 925 | #else | ||
| 926 | fflush_all(); | ||
| 927 | _exit(SIGINT << 24); | ||
| 928 | #endif | ||
| 707 | } | 929 | } |
| 930 | #if ENABLE_PLATFORM_MINGW32 | ||
| 931 | if (iflag) | ||
| 932 | write(STDOUT_FILENO, "^C", 2); | ||
| 933 | #endif | ||
| 708 | /* bash: ^C even on empty command line sets $? */ | 934 | /* bash: ^C even on empty command line sets $? */ |
| 709 | exitstatus = SIGINT + 128; | 935 | exitstatus = SIGINT + 128; |
| 710 | raise_exception(EXINT); | 936 | raise_exception(EXINT); |
| @@ -1992,6 +2218,18 @@ maybe_single_quote(const char *s) | |||
| 1992 | return single_quote(s); | 2218 | return single_quote(s); |
| 1993 | } | 2219 | } |
| 1994 | 2220 | ||
| 2221 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2222 | /* Copy path to a string on the stack long enough to allow a file extension | ||
| 2223 | * to be added. */ | ||
| 2224 | static char * | ||
| 2225 | stack_add_ext_space(const char *path) | ||
| 2226 | { | ||
| 2227 | char *p = growstackto(strlen(path) + 5); | ||
| 2228 | strcpy(p, path); | ||
| 2229 | return p; | ||
| 2230 | } | ||
| 2231 | #endif | ||
| 2232 | |||
| 1995 | 2233 | ||
| 1996 | /* ============ nextopt */ | 2234 | /* ============ nextopt */ |
| 1997 | 2235 | ||
| @@ -2114,6 +2352,9 @@ struct localvar { | |||
| 2114 | #else | 2352 | #else |
| 2115 | # define VDYNAMIC 0 | 2353 | # define VDYNAMIC 0 |
| 2116 | #endif | 2354 | #endif |
| 2355 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2356 | # define VIMPORT 0x400 /* variable was imported from environment */ | ||
| 2357 | #endif | ||
| 2117 | 2358 | ||
| 2118 | 2359 | ||
| 2119 | /* Need to be before varinit_data[] */ | 2360 | /* Need to be before varinit_data[] */ |
| @@ -2143,6 +2384,24 @@ static void change_seconds(const char *) FAST_FUNC; | |||
| 2143 | static void change_realtime(const char *) FAST_FUNC; | 2384 | static void change_realtime(const char *) FAST_FUNC; |
| 2144 | #endif | 2385 | #endif |
| 2145 | 2386 | ||
| 2387 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2388 | static void FAST_FUNC | ||
| 2389 | change_terminal_mode(const char *newval UNUSED_PARAM) | ||
| 2390 | { | ||
| 2391 | terminal_mode(TRUE); | ||
| 2392 | } | ||
| 2393 | |||
| 2394 | static void clearcmdentry(void); | ||
| 2395 | static void FAST_FUNC | ||
| 2396 | change_override_applets(const char *newval UNUSED_PARAM) | ||
| 2397 | { | ||
| 2398 | clearcmdentry(); | ||
| 2399 | } | ||
| 2400 | |||
| 2401 | # define LINENO_INDEX (5 + 2 * ENABLE_ASH_MAIL + ENABLE_ASH_GETOPTS) | ||
| 2402 | # define FUNCNAME_INDEX (LINENO_INDEX + 1) | ||
| 2403 | #endif | ||
| 2404 | |||
| 2146 | static const struct { | 2405 | static const struct { |
| 2147 | int flags; | 2406 | int flags; |
| 2148 | const char *var_text; | 2407 | const char *var_text; |
| @@ -2180,6 +2439,12 @@ static const struct { | |||
| 2180 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 2439 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY |
| 2181 | { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL }, | 2440 | { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL }, |
| 2182 | #endif | 2441 | #endif |
| 2442 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2443 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_SKIP_ANSI_EMULATION, change_terminal_mode }, | ||
| 2444 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_TERMINAL_MODE, change_terminal_mode }, | ||
| 2445 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_OVERRIDE_APPLETS, change_override_applets }, | ||
| 2446 | { VSTRFIXED|VTEXTFIXED|VUNSET, BB_CRITICAL_ERROR_DIALOGS, change_critical_error_dialogs }, | ||
| 2447 | #endif | ||
| 2183 | }; | 2448 | }; |
| 2184 | 2449 | ||
| 2185 | struct redirtab; | 2450 | struct redirtab; |
| @@ -2401,6 +2666,65 @@ bltinlookup(const char *name) | |||
| 2401 | return lookupvar(name); | 2666 | return lookupvar(name); |
| 2402 | } | 2667 | } |
| 2403 | 2668 | ||
| 2669 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2670 | static char * | ||
| 2671 | fix_pathvar(const char *path, int len) | ||
| 2672 | { | ||
| 2673 | char *newpath = xstrdup(path); | ||
| 2674 | char *p; | ||
| 2675 | int modified = FALSE; | ||
| 2676 | |||
| 2677 | p = newpath + len; | ||
| 2678 | while (*p) { | ||
| 2679 | if (*p != ':' && *p != ';') { | ||
| 2680 | /* skip drive */ | ||
| 2681 | if (isalpha(*p) && p[1] == ':') | ||
| 2682 | p += 2; | ||
| 2683 | /* skip through path component */ | ||
| 2684 | for (; *p != '\0' && *p != ':' && *p != ';'; ++p) | ||
| 2685 | continue; | ||
| 2686 | } | ||
| 2687 | /* *p is ':', ';' or '\0' here */ | ||
| 2688 | if (*p == ':') { | ||
| 2689 | *p++ = ';'; | ||
| 2690 | modified = TRUE; | ||
| 2691 | } | ||
| 2692 | else if (*p == ';') { | ||
| 2693 | ++p; | ||
| 2694 | } | ||
| 2695 | } | ||
| 2696 | |||
| 2697 | if (!modified) { | ||
| 2698 | free(newpath); | ||
| 2699 | newpath = NULL; | ||
| 2700 | } | ||
| 2701 | return newpath; | ||
| 2702 | } | ||
| 2703 | |||
| 2704 | #define BB_VAR_EXACT 1 /* exact match for name */ | ||
| 2705 | #define BB_VAR_ASSIGN -1 /* matches name followed by '=' */ | ||
| 2706 | |||
| 2707 | /* Match variables that should be placed in the environment immediately | ||
| 2708 | * they're exported and removed immediately they're no longer exported */ | ||
| 2709 | static int | ||
| 2710 | is_bb_var(const char *s) | ||
| 2711 | { | ||
| 2712 | const char *p; | ||
| 2713 | int len; | ||
| 2714 | |||
| 2715 | for (p = bbvar; *p; p += len + 1) { | ||
| 2716 | len = strlen(p); | ||
| 2717 | if (strncmp(s, p, len) == 0) { | ||
| 2718 | if (s[len] == '\0') | ||
| 2719 | return BB_VAR_EXACT; | ||
| 2720 | else if (s[len] == '=') | ||
| 2721 | return BB_VAR_ASSIGN; | ||
| 2722 | } | ||
| 2723 | } | ||
| 2724 | return FALSE; | ||
| 2725 | } | ||
| 2726 | #endif | ||
| 2727 | |||
| 2404 | /* | 2728 | /* |
| 2405 | * Same as setvar except that the variable and value are passed in | 2729 | * Same as setvar except that the variable and value are passed in |
| 2406 | * the first argument as name=value. Since the first argument will | 2730 | * the first argument as name=value. Since the first argument will |
| @@ -2412,6 +2736,26 @@ static struct var * | |||
| 2412 | setvareq(char *s, int flags) | 2736 | setvareq(char *s, int flags) |
| 2413 | { | 2737 | { |
| 2414 | struct var *vp, **vpp; | 2738 | struct var *vp, **vpp; |
| 2739 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2740 | const char *paths = "PATH=\0""CDPATH=\0""MANPATH=\0"; | ||
| 2741 | const char *p; | ||
| 2742 | int len; | ||
| 2743 | |||
| 2744 | for (p = paths; *p; p += len + 1) { | ||
| 2745 | len = strlen(p); | ||
| 2746 | if (strncmp(s, p, len) == 0) { | ||
| 2747 | char *newpath = fix_pathvar(s, len); | ||
| 2748 | if (newpath) { | ||
| 2749 | if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE) | ||
| 2750 | free(s); | ||
| 2751 | flags |= VNOSAVE; | ||
| 2752 | flags &= ~(VTEXTFIXED|VSTACK); | ||
| 2753 | s = newpath; | ||
| 2754 | } | ||
| 2755 | break; | ||
| 2756 | } | ||
| 2757 | } | ||
| 2758 | #endif | ||
| 2415 | 2759 | ||
| 2416 | vpp = hashvar(s); | 2760 | vpp = hashvar(s); |
| 2417 | flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); | 2761 | flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); |
| @@ -2437,6 +2781,11 @@ setvareq(char *s, int flags) | |||
| 2437 | if (!(vp->flags & (VTEXTFIXED|VSTACK))) | 2781 | if (!(vp->flags & (VTEXTFIXED|VSTACK))) |
| 2438 | free((char*)vp->var_text); | 2782 | free((char*)vp->var_text); |
| 2439 | 2783 | ||
| 2784 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2785 | if ((flags & VUNSET) && (vp->flags & VEXPORT) && | ||
| 2786 | is_bb_var(s) == BB_VAR_EXACT) | ||
| 2787 | unsetenv(s); | ||
| 2788 | #endif | ||
| 2440 | if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) { | 2789 | if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) { |
| 2441 | *vpp = vp->next; | 2790 | *vpp = vp->next; |
| 2442 | free(vp); | 2791 | free(vp); |
| @@ -2466,6 +2815,10 @@ setvareq(char *s, int flags) | |||
| 2466 | s = ckstrdup(s); | 2815 | s = ckstrdup(s); |
| 2467 | vp->var_text = s; | 2816 | vp->var_text = s; |
| 2468 | vp->flags = flags; | 2817 | vp->flags = flags; |
| 2818 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2819 | if ((flags & VEXPORT) && is_bb_var(s) == BB_VAR_ASSIGN) | ||
| 2820 | putenv(s); | ||
| 2821 | #endif | ||
| 2469 | 2822 | ||
| 2470 | out: | 2823 | out: |
| 2471 | return vp; | 2824 | return vp; |
| @@ -2587,6 +2940,72 @@ listvars(int on, int off, struct strlist *lp, char ***end) | |||
| 2587 | return grabstackstr(ep); | 2940 | return grabstackstr(ep); |
| 2588 | } | 2941 | } |
| 2589 | 2942 | ||
| 2943 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2944 | /* Adjust directory separator in variables imported from the environment */ | ||
| 2945 | static void | ||
| 2946 | setwinxp(int on) | ||
| 2947 | { | ||
| 2948 | static smallint is_winxp = 1; | ||
| 2949 | struct var **vpp; | ||
| 2950 | struct var *vp; | ||
| 2951 | |||
| 2952 | if (on == is_winxp) | ||
| 2953 | return; | ||
| 2954 | is_winxp = on; | ||
| 2955 | |||
| 2956 | for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) { | ||
| 2957 | for (vp = *vpp; vp; vp = vp->next) { | ||
| 2958 | if ((vp->flags & VIMPORT)) { | ||
| 2959 | char *end = strchr(vp->var_text, '='); | ||
| 2960 | if (!end || is_prefixed_with(vp->var_text, "COMSPEC=") || | ||
| 2961 | is_prefixed_with(vp->var_text, "SYSTEMROOT=")) | ||
| 2962 | continue; | ||
| 2963 | if (!on) | ||
| 2964 | bs_to_slash(end + 1); | ||
| 2965 | else | ||
| 2966 | slash_to_bs(end + 1); | ||
| 2967 | } | ||
| 2968 | } | ||
| 2969 | } | ||
| 2970 | } | ||
| 2971 | |||
| 2972 | # if ENABLE_ASH_NOCONSOLE | ||
| 2973 | /* | ||
| 2974 | * Console state is either: | ||
| 2975 | * 0 normal | ||
| 2976 | * 1 iconified/hidden | ||
| 2977 | * 2 unknown | ||
| 2978 | */ | ||
| 2979 | static int console_state(void) | ||
| 2980 | { | ||
| 2981 | DECLARE_PROC_ADDR(BOOL, ShowWindow, HWND, int); | ||
| 2982 | |||
| 2983 | if (INIT_PROC_ADDR(user32.dll, ShowWindow)) { | ||
| 2984 | BOOL state; | ||
| 2985 | |||
| 2986 | if (noiconify) { | ||
| 2987 | state = IsWindowVisible(GetConsoleWindow()); | ||
| 2988 | if (state >= 0) | ||
| 2989 | return state == 0; | ||
| 2990 | } else { | ||
| 2991 | state = IsIconic(GetConsoleWindow()); | ||
| 2992 | if (state >= 0) | ||
| 2993 | return state != 0; | ||
| 2994 | } | ||
| 2995 | } | ||
| 2996 | return 2; | ||
| 2997 | } | ||
| 2998 | |||
| 2999 | static void hide_console(int hide) | ||
| 3000 | { | ||
| 3001 | // Switch console state if it's known and isn't the required state | ||
| 3002 | if (console_state() == !hide) | ||
| 3003 | ShowWindow(GetConsoleWindow(), hide ? | ||
| 3004 | (noiconify ? SW_HIDE : SW_MINIMIZE) : SW_NORMAL); | ||
| 3005 | } | ||
| 3006 | # endif | ||
| 3007 | #endif | ||
| 3008 | |||
| 2590 | 3009 | ||
| 2591 | /* ============ Path search helper */ | 3010 | /* ============ Path search helper */ |
| 2592 | static const char * | 3011 | static const char * |
| @@ -2630,7 +3049,7 @@ static const char *pathopt; /* set by padvance */ | |||
| 2630 | static int | 3049 | static int |
| 2631 | padvance_magic(const char **path, const char *name, int magic) | 3050 | padvance_magic(const char **path, const char *name, int magic) |
| 2632 | { | 3051 | { |
| 2633 | const char *term = "%:"; | 3052 | const char *term = "%"PATH_SEP_STR; |
| 2634 | const char *lpathopt; | 3053 | const char *lpathopt; |
| 2635 | const char *p; | 3054 | const char *p; |
| 2636 | char *q; | 3055 | char *q; |
| @@ -2647,14 +3066,14 @@ padvance_magic(const char **path, const char *name, int magic) | |||
| 2647 | if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) { | 3066 | if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) { |
| 2648 | lpathopt = start + 1; | 3067 | lpathopt = start + 1; |
| 2649 | start = p; | 3068 | start = p; |
| 2650 | term = ":"; | 3069 | term = PATH_SEP_STR; |
| 2651 | } | 3070 | } |
| 2652 | 3071 | ||
| 2653 | len = strcspn(start, term); | 3072 | len = strcspn(start, term); |
| 2654 | p = start + len; | 3073 | p = start + len; |
| 2655 | 3074 | ||
| 2656 | if (*p == '%') { | 3075 | if (*p == '%') { |
| 2657 | size_t extra = strchrnul(p, ':') - p; | 3076 | size_t extra = strchrnul(p, PATH_SEP) - p; |
| 2658 | 3077 | ||
| 2659 | if (legal_pathopt(p + 1, term, magic)) | 3078 | if (legal_pathopt(p + 1, term, magic)) |
| 2660 | lpathopt = p + 1; | 3079 | lpathopt = p + 1; |
| @@ -2665,14 +3084,18 @@ padvance_magic(const char **path, const char *name, int magic) | |||
| 2665 | } | 3084 | } |
| 2666 | 3085 | ||
| 2667 | pathopt = lpathopt; | 3086 | pathopt = lpathopt; |
| 2668 | *path = *p == ':' ? p + 1 : NULL; | 3087 | *path = *p == PATH_SEP ? p + 1 : NULL; |
| 2669 | 3088 | ||
| 2670 | /* "2" is for '/' and '\0' */ | 3089 | /* "2" is for '/' and '\0' */ |
| 2671 | qlen = len + strlen(name) + 2; | 3090 | /* reserve space for suffix on WIN32 */ |
| 3091 | qlen = len + strlen(name) + 2 IF_PLATFORM_MINGW32(+ 4); | ||
| 2672 | q = growstackto(qlen); | 3092 | q = growstackto(qlen); |
| 2673 | 3093 | ||
| 2674 | if (len) { | 3094 | if (len) { |
| 2675 | q = mempcpy(q, start, len); | 3095 | q = mempcpy(q, start, len); |
| 3096 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3097 | if (q[-1] != '/' && q[-1] != '\\') | ||
| 3098 | #endif | ||
| 2676 | *q++ = '/'; | 3099 | *q++ = '/'; |
| 2677 | } | 3100 | } |
| 2678 | strcpy(q, name); | 3101 | strcpy(q, name); |
| @@ -2763,6 +3186,7 @@ setprompt_if(smallint do_set, int whichprompt) | |||
| 2763 | 3186 | ||
| 2764 | #define CD_PHYSICAL 1 | 3187 | #define CD_PHYSICAL 1 |
| 2765 | #define CD_PRINT 2 | 3188 | #define CD_PRINT 2 |
| 3189 | #define CD_PRINT_ALL 4 | ||
| 2766 | 3190 | ||
| 2767 | static int | 3191 | static int |
| 2768 | cdopt(void) | 3192 | cdopt(void) |
| @@ -2771,7 +3195,14 @@ cdopt(void) | |||
| 2771 | int i, j; | 3195 | int i, j; |
| 2772 | 3196 | ||
| 2773 | j = 'L'; | 3197 | j = 'L'; |
| 3198 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3199 | while ((i = nextopt("LPa")) != '\0') { | ||
| 3200 | if (i == 'a') | ||
| 3201 | flags |= CD_PRINT_ALL; | ||
| 3202 | else | ||
| 3203 | #else | ||
| 2774 | while ((i = nextopt("LP")) != '\0') { | 3204 | while ((i = nextopt("LP")) != '\0') { |
| 3205 | #endif | ||
| 2775 | if (i != j) { | 3206 | if (i != j) { |
| 2776 | flags ^= CD_PHYSICAL; | 3207 | flags ^= CD_PHYSICAL; |
| 2777 | j = i; | 3208 | j = i; |
| @@ -2788,6 +3219,129 @@ cdopt(void) | |||
| 2788 | static const char * | 3219 | static const char * |
| 2789 | updatepwd(const char *dir) | 3220 | updatepwd(const char *dir) |
| 2790 | { | 3221 | { |
| 3222 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3223 | /* | ||
| 3224 | * Due to Windows drive notion, getting pwd is a completely | ||
| 3225 | * different thing. Handle it in a separate routine | ||
| 3226 | */ | ||
| 3227 | |||
| 3228 | char *new; | ||
| 3229 | char *p; | ||
| 3230 | char *cdcomppath; | ||
| 3231 | const char *lim; | ||
| 3232 | int len; | ||
| 3233 | char buffer[PATH_MAX]; | ||
| 3234 | /* | ||
| 3235 | * There are five cases that make some kind of sense | ||
| 3236 | * | ||
| 3237 | * Absolute paths: | ||
| 3238 | * c:/path | ||
| 3239 | * //host/share | ||
| 3240 | * | ||
| 3241 | * Relative to current working directory of other drive: | ||
| 3242 | * c:path | ||
| 3243 | * | ||
| 3244 | * Relative to current root (drive/share): | ||
| 3245 | * /path | ||
| 3246 | * | ||
| 3247 | * Relative to current working directory of current root (drive/share): | ||
| 3248 | * path | ||
| 3249 | */ | ||
| 3250 | enum {ABS_DRIVE, ABS_SHARE, REL_OTHER, REL_ROOT, REL_CWD} target; | ||
| 3251 | |||
| 3252 | /* skip multiple leading separators unless dir is a UNC path */ | ||
| 3253 | if (is_dir_sep(*dir) && unc_root_len(dir) == 0) { | ||
| 3254 | while (is_dir_sep(dir[1])) | ||
| 3255 | ++dir; | ||
| 3256 | } | ||
| 3257 | |||
| 3258 | len = strlen(dir); | ||
| 3259 | if (len >= 2 && has_dos_drive_prefix(dir)) | ||
| 3260 | target = len >= 3 && is_dir_sep(dir[2]) ? ABS_DRIVE : REL_OTHER; | ||
| 3261 | else if (unc_root_len(dir) != 0) | ||
| 3262 | target = ABS_SHARE; | ||
| 3263 | else if (is_dir_sep(*dir)) | ||
| 3264 | target = REL_ROOT; | ||
| 3265 | else | ||
| 3266 | target = REL_CWD; | ||
| 3267 | |||
| 3268 | cdcomppath = sstrdup(dir); | ||
| 3269 | STARTSTACKSTR(new); | ||
| 3270 | |||
| 3271 | switch (target) { | ||
| 3272 | case REL_OTHER: | ||
| 3273 | /* c:path */ | ||
| 3274 | if (get_drive_cwd(dir, buffer, PATH_MAX) == NULL) | ||
| 3275 | return 0; | ||
| 3276 | new = stack_putstr(buffer, new); | ||
| 3277 | len = 2; | ||
| 3278 | cdcomppath += len; | ||
| 3279 | dir += len; | ||
| 3280 | break; | ||
| 3281 | case REL_CWD: | ||
| 3282 | case REL_ROOT: | ||
| 3283 | /* path or /path */ | ||
| 3284 | len = root_len(curdir); | ||
| 3285 | if (len == 0) | ||
| 3286 | return 0; | ||
| 3287 | new = target == REL_CWD ? stack_putstr(curdir, new) : | ||
| 3288 | stnputs(curdir, len, new); | ||
| 3289 | break; | ||
| 3290 | default: | ||
| 3291 | /* //host/share or c:/path */ | ||
| 3292 | len = root_len(dir); | ||
| 3293 | if (len == 0) | ||
| 3294 | return 0; | ||
| 3295 | new = stnputs(dir, len, new); | ||
| 3296 | cdcomppath += len; | ||
| 3297 | dir += len; | ||
| 3298 | break; | ||
| 3299 | } | ||
| 3300 | |||
| 3301 | new = makestrspace(strlen(dir) + 2, new); | ||
| 3302 | lim = (char *)stackblock() + len + 1; | ||
| 3303 | |||
| 3304 | if (!is_dir_sep(*dir)) { | ||
| 3305 | if (!is_dir_sep(new[-1])) | ||
| 3306 | USTPUTC('/', new); | ||
| 3307 | if (new > lim && is_dir_sep(*lim)) | ||
| 3308 | lim++; | ||
| 3309 | } else { | ||
| 3310 | USTPUTC('/', new); | ||
| 3311 | cdcomppath++; | ||
| 3312 | if (is_dir_sep(dir[1]) && !is_dir_sep(dir[2])) { | ||
| 3313 | USTPUTC('/', new); | ||
| 3314 | cdcomppath++; | ||
| 3315 | lim++; | ||
| 3316 | } | ||
| 3317 | } | ||
| 3318 | p = strtok(cdcomppath, "/\\"); | ||
| 3319 | while (p) { | ||
| 3320 | switch (*p) { | ||
| 3321 | case '.': | ||
| 3322 | if (p[1] == '.' && p[2] == '\0') { | ||
| 3323 | while (new > lim) { | ||
| 3324 | STUNPUTC(new); | ||
| 3325 | if (is_dir_sep(new[-1])) | ||
| 3326 | break; | ||
| 3327 | } | ||
| 3328 | break; | ||
| 3329 | } | ||
| 3330 | if (p[1] == '\0') | ||
| 3331 | break; | ||
| 3332 | /* fall through */ | ||
| 3333 | default: | ||
| 3334 | new = stack_putstr(p, new); | ||
| 3335 | USTPUTC('/', new); | ||
| 3336 | } | ||
| 3337 | p = strtok(NULL, "/\\"); | ||
| 3338 | } | ||
| 3339 | if (new > lim) | ||
| 3340 | STUNPUTC(new); | ||
| 3341 | *new = 0; | ||
| 3342 | fix_path_case((char *)stackblock()); | ||
| 3343 | return bs_to_slash((char *)stackblock()); | ||
| 3344 | #else | ||
| 2791 | char *new; | 3345 | char *new; |
| 2792 | char *p; | 3346 | char *p; |
| 2793 | char *cdcomppath; | 3347 | char *cdcomppath; |
| @@ -2841,6 +3395,7 @@ updatepwd(const char *dir) | |||
| 2841 | STUNPUTC(new); | 3395 | STUNPUTC(new); |
| 2842 | *new = 0; | 3396 | *new = 0; |
| 2843 | return stackblock(); | 3397 | return stackblock(); |
| 3398 | #endif | ||
| 2844 | } | 3399 | } |
| 2845 | 3400 | ||
| 2846 | /* | 3401 | /* |
| @@ -2936,7 +3491,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 2936 | } | 3491 | } |
| 2937 | if (!dest) | 3492 | if (!dest) |
| 2938 | dest = nullstr; | 3493 | dest = nullstr; |
| 2939 | if (*dest == '/') | 3494 | if (!is_relative_path(dest)) |
| 2940 | goto step6; | 3495 | goto step6; |
| 2941 | if (*dest == '.') { | 3496 | if (*dest == '.') { |
| 2942 | c = dest[1]; | 3497 | c = dest[1]; |
| @@ -2959,7 +3514,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 2959 | p = stalloc(len); | 3514 | p = stalloc(len); |
| 2960 | 3515 | ||
| 2961 | if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { | 3516 | if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { |
| 2962 | if (c && c != ':') | 3517 | if (c && c != PATH_SEP) |
| 2963 | flags |= CD_PRINT; | 3518 | flags |= CD_PRINT; |
| 2964 | docd: | 3519 | docd: |
| 2965 | if (!docd(p, flags)) | 3520 | if (!docd(p, flags)) |
| @@ -2981,6 +3536,26 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 2981 | return 0; | 3536 | return 0; |
| 2982 | } | 3537 | } |
| 2983 | 3538 | ||
| 3539 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3540 | static void | ||
| 3541 | print_all_cwd(void) | ||
| 3542 | { | ||
| 3543 | FILE *mnt; | ||
| 3544 | struct mntent *entry; | ||
| 3545 | char buffer[PATH_MAX]; | ||
| 3546 | |||
| 3547 | mnt = setmntent(bb_path_mtab_file, "r"); | ||
| 3548 | if (mnt) { | ||
| 3549 | while ((entry=getmntent(mnt)) != NULL) { | ||
| 3550 | entry->mnt_dir[2] = '\0'; | ||
| 3551 | if (get_drive_cwd(entry->mnt_dir, buffer, PATH_MAX) != NULL) | ||
| 3552 | out1fmt("%s\n", buffer); | ||
| 3553 | } | ||
| 3554 | endmntent(mnt); | ||
| 3555 | } | ||
| 3556 | } | ||
| 3557 | #endif | ||
| 3558 | |||
| 2984 | static int FAST_FUNC | 3559 | static int FAST_FUNC |
| 2985 | pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 3560 | pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) |
| 2986 | { | 3561 | { |
| @@ -2988,6 +3563,12 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 2988 | const char *dir = curdir; | 3563 | const char *dir = curdir; |
| 2989 | 3564 | ||
| 2990 | flags = cdopt(); | 3565 | flags = cdopt(); |
| 3566 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3567 | if (flags & CD_PRINT_ALL) { | ||
| 3568 | print_all_cwd(); | ||
| 3569 | return 0; | ||
| 3570 | } | ||
| 3571 | #endif | ||
| 2991 | if (flags) { | 3572 | if (flags) { |
| 2992 | if (physdir == nullstr) | 3573 | if (physdir == nullstr) |
| 2993 | setpwd(dir, 0); | 3574 | setpwd(dir, 0); |
| @@ -3616,7 +4197,12 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 3616 | struct procstat { | 4197 | struct procstat { |
| 3617 | pid_t ps_pid; /* process id */ | 4198 | pid_t ps_pid; /* process id */ |
| 3618 | int ps_status; /* last process status from wait() */ | 4199 | int ps_status; /* last process status from wait() */ |
| 4200 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 3619 | char *ps_cmd; /* text of command being run */ | 4201 | char *ps_cmd; /* text of command being run */ |
| 4202 | #endif | ||
| 4203 | #if ENABLE_PLATFORM_MINGW32 | ||
| 4204 | HANDLE ps_proc; | ||
| 4205 | #endif | ||
| 3620 | }; | 4206 | }; |
| 3621 | 4207 | ||
| 3622 | struct job { | 4208 | struct job { |
| @@ -3632,8 +4218,10 @@ struct job { | |||
| 3632 | #define JOBDONE 2 /* all procs are completed */ | 4218 | #define JOBDONE 2 /* all procs are completed */ |
| 3633 | unsigned | 4219 | unsigned |
| 3634 | state: 8, | 4220 | state: 8, |
| 3635 | #if JOBS | 4221 | #if JOBS || ENABLE_PLATFORM_MINGW32 |
| 3636 | sigint: 1, /* job was killed by SIGINT */ | 4222 | sigint: 1, /* job was killed by SIGINT */ |
| 4223 | #endif | ||
| 4224 | #if JOBS | ||
| 3637 | jobctl: 1, /* job running under job control */ | 4225 | jobctl: 1, /* job running under job control */ |
| 3638 | #endif | 4226 | #endif |
| 3639 | waited: 1, /* true if this entry has been waited for */ | 4227 | waited: 1, /* true if this entry has been waited for */ |
| @@ -3643,17 +4231,23 @@ struct job { | |||
| 3643 | }; | 4231 | }; |
| 3644 | 4232 | ||
| 3645 | static struct job *makejob(/*union node *,*/ int); | 4233 | static struct job *makejob(/*union node *,*/ int); |
| 4234 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 3646 | static int forkshell(struct job *, union node *, int); | 4235 | static int forkshell(struct job *, union node *, int); |
| 4236 | #endif | ||
| 3647 | static int waitforjob(struct job *); | 4237 | static int waitforjob(struct job *); |
| 3648 | 4238 | ||
| 3649 | #if !JOBS | 4239 | #if !JOBS && !JOBS_WIN32 |
| 3650 | enum { doing_jobctl = 0 }; | 4240 | enum { doing_jobctl = 0 }; |
| 3651 | #define setjobctl(on) do {} while (0) | 4241 | #define setjobctl(on) do {} while (0) |
| 3652 | #else | 4242 | #elif JOBS_WIN32 |
| 4243 | static smallint doing_jobctl; //references:8 | ||
| 4244 | #define setjobctl(on) do { if (rootshell) doing_jobctl = on; } while (0) | ||
| 4245 | #else /* JOBS */ | ||
| 3653 | static smallint doing_jobctl; //references:8 | 4246 | static smallint doing_jobctl; //references:8 |
| 3654 | static void setjobctl(int); | 4247 | static void setjobctl(int); |
| 3655 | #endif | 4248 | #endif |
| 3656 | 4249 | ||
| 4250 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 3657 | /* | 4251 | /* |
| 3658 | * Ignore a signal. | 4252 | * Ignore a signal. |
| 3659 | */ | 4253 | */ |
| @@ -3802,6 +4396,10 @@ setsignal(int signo) | |||
| 3802 | 4396 | ||
| 3803 | sigaction_set(signo, &act); | 4397 | sigaction_set(signo, &act); |
| 3804 | } | 4398 | } |
| 4399 | #else | ||
| 4400 | #define setsignal(s) | ||
| 4401 | #define ignoresig(s) | ||
| 4402 | #endif | ||
| 3805 | 4403 | ||
| 3806 | /* mode flags for set_curjob */ | 4404 | /* mode flags for set_curjob */ |
| 3807 | #define CUR_DELETE 2 | 4405 | #define CUR_DELETE 2 |
| @@ -3935,7 +4533,7 @@ set_curjob(struct job *jp, unsigned mode) | |||
| 3935 | } | 4533 | } |
| 3936 | } | 4534 | } |
| 3937 | 4535 | ||
| 3938 | #if JOBS || DEBUG | 4536 | #if JOBS || ENABLE_PLATFORM_MINGW32 || DEBUG |
| 3939 | static int | 4537 | static int |
| 3940 | jobno(const struct job *jp) | 4538 | jobno(const struct job *jp) |
| 3941 | { | 4539 | { |
| @@ -3953,7 +4551,9 @@ static struct job * | |||
| 3953 | getjob(const char *name, int getctl) | 4551 | getjob(const char *name, int getctl) |
| 3954 | { | 4552 | { |
| 3955 | struct job *jp; | 4553 | struct job *jp; |
| 4554 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 3956 | struct job *found; | 4555 | struct job *found; |
| 4556 | #endif | ||
| 3957 | const char *err_msg = "%s: no such job"; | 4557 | const char *err_msg = "%s: no such job"; |
| 3958 | unsigned num; | 4558 | unsigned num; |
| 3959 | int c; | 4559 | int c; |
| @@ -3998,6 +4598,7 @@ getjob(const char *name, int getctl) | |||
| 3998 | } | 4598 | } |
| 3999 | } | 4599 | } |
| 4000 | 4600 | ||
| 4601 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 4001 | found = NULL; | 4602 | found = NULL; |
| 4002 | while (jp) { | 4603 | while (jp) { |
| 4003 | if (*p == '?' | 4604 | if (*p == '?' |
| @@ -4014,6 +4615,9 @@ getjob(const char *name, int getctl) | |||
| 4014 | if (!found) | 4615 | if (!found) |
| 4015 | goto err; | 4616 | goto err; |
| 4016 | jp = found; | 4617 | jp = found; |
| 4618 | #else | ||
| 4619 | goto err; | ||
| 4620 | #endif | ||
| 4017 | 4621 | ||
| 4018 | gotit: | 4622 | gotit: |
| 4019 | #if JOBS | 4623 | #if JOBS |
| @@ -4032,14 +4636,18 @@ getjob(const char *name, int getctl) | |||
| 4032 | static void | 4636 | static void |
| 4033 | freejob(struct job *jp) | 4637 | freejob(struct job *jp) |
| 4034 | { | 4638 | { |
| 4639 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 4035 | struct procstat *ps; | 4640 | struct procstat *ps; |
| 4036 | int i; | 4641 | int i; |
| 4642 | #endif | ||
| 4037 | 4643 | ||
| 4038 | INT_OFF; | 4644 | INT_OFF; |
| 4645 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 4039 | for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { | 4646 | for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { |
| 4040 | if (ps->ps_cmd != nullstr) | 4647 | if (ps->ps_cmd != nullstr) |
| 4041 | free(ps->ps_cmd); | 4648 | free(ps->ps_cmd); |
| 4042 | } | 4649 | } |
| 4650 | #endif | ||
| 4043 | if (jp->ps != &jp->ps0) | 4651 | if (jp->ps != &jp->ps0) |
| 4044 | free(jp->ps); | 4652 | free(jp->ps); |
| 4045 | jp->used = 0; | 4653 | jp->used = 0; |
| @@ -4132,7 +4740,9 @@ setjobctl(int on) | |||
| 4132 | ttyfd = fd; | 4740 | ttyfd = fd; |
| 4133 | doing_jobctl = on; | 4741 | doing_jobctl = on; |
| 4134 | } | 4742 | } |
| 4743 | #endif | ||
| 4135 | 4744 | ||
| 4745 | #if JOBS || JOBS_WIN32 | ||
| 4136 | static int FAST_FUNC | 4746 | static int FAST_FUNC |
| 4137 | killcmd(int argc, char **argv) | 4747 | killcmd(int argc, char **argv) |
| 4138 | { | 4748 | { |
| @@ -4162,8 +4772,10 @@ killcmd(int argc, char **argv) | |||
| 4162 | * sh -c 'true|sleep 1 & sleep 2; kill %1' | 4772 | * sh -c 'true|sleep 1 & sleep 2; kill %1' |
| 4163 | */ | 4773 | */ |
| 4164 | n = jp->nprocs; /* can't be 0 (I hope) */ | 4774 | n = jp->nprocs; /* can't be 0 (I hope) */ |
| 4775 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 4165 | if (jp->jobctl) | 4776 | if (jp->jobctl) |
| 4166 | n = 1; | 4777 | n = 1; |
| 4778 | #endif | ||
| 4167 | dst = alloca(n * sizeof(int)*4); | 4779 | dst = alloca(n * sizeof(int)*4); |
| 4168 | argv[i] = dst; | 4780 | argv[i] = dst; |
| 4169 | for (j = 0; j < n; j++) { | 4781 | for (j = 0; j < n; j++) { |
| @@ -4178,7 +4790,11 @@ killcmd(int argc, char **argv) | |||
| 4178 | * leading space. Needed to not confuse | 4790 | * leading space. Needed to not confuse |
| 4179 | * negative pids with "kill -SIGNAL_NO" syntax | 4791 | * negative pids with "kill -SIGNAL_NO" syntax |
| 4180 | */ | 4792 | */ |
| 4793 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 4181 | dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); | 4794 | dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); |
| 4795 | #else | ||
| 4796 | dst += sprintf(dst, " -%u", (int)ps->ps_pid); | ||
| 4797 | #endif | ||
| 4182 | } | 4798 | } |
| 4183 | *dst = '\0'; | 4799 | *dst = '\0'; |
| 4184 | } | 4800 | } |
| @@ -4186,7 +4802,9 @@ killcmd(int argc, char **argv) | |||
| 4186 | } | 4802 | } |
| 4187 | return kill_main(argc, argv); | 4803 | return kill_main(argc, argv); |
| 4188 | } | 4804 | } |
| 4805 | #endif | ||
| 4189 | 4806 | ||
| 4807 | #if JOBS | ||
| 4190 | static void | 4808 | static void |
| 4191 | showpipe(struct job *jp /*, FILE *out*/) | 4809 | showpipe(struct job *jp /*, FILE *out*/) |
| 4192 | { | 4810 | { |
| @@ -4291,6 +4909,78 @@ sprint_status48(char *os, int status, int sigonly) | |||
| 4291 | return s - os; | 4909 | return s - os; |
| 4292 | } | 4910 | } |
| 4293 | 4911 | ||
| 4912 | #if ENABLE_PLATFORM_MINGW32 | ||
| 4913 | static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) | ||
| 4914 | { | ||
| 4915 | if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { | ||
| 4916 | # if ENABLE_FEATURE_EDITING | ||
| 4917 | bb_got_signal = SIGINT; /* for read_line_input: "we got a signal" */ | ||
| 4918 | # endif | ||
| 4919 | if (!suppress_int && !(rootshell && iflag)) | ||
| 4920 | raise_interrupt(); | ||
| 4921 | pending_int = 1; | ||
| 4922 | return TRUE; | ||
| 4923 | } | ||
| 4924 | return FALSE; | ||
| 4925 | } | ||
| 4926 | |||
| 4927 | /* | ||
| 4928 | * Windows does not know about parent-child relationship | ||
| 4929 | * They don't support waitpid(-1) | ||
| 4930 | */ | ||
| 4931 | static pid_t | ||
| 4932 | waitpid_child(int *status, int wait_flags) | ||
| 4933 | { | ||
| 4934 | struct job *jb; | ||
| 4935 | struct procstat *ps; | ||
| 4936 | int pid_nr = 0; | ||
| 4937 | pid_t *pidlist; | ||
| 4938 | HANDLE *proclist; | ||
| 4939 | pid_t pid = -1; | ||
| 4940 | DWORD win_status, idx; | ||
| 4941 | int i; | ||
| 4942 | |||
| 4943 | for (jb = curjob; jb; jb = jb->prev_job) { | ||
| 4944 | if (jb->state != JOBDONE) | ||
| 4945 | pid_nr += jb->nprocs; | ||
| 4946 | } | ||
| 4947 | if (pid_nr == 0) | ||
| 4948 | return -1; | ||
| 4949 | |||
| 4950 | pidlist = ckmalloc(sizeof(*pidlist)*pid_nr); | ||
| 4951 | proclist = ckmalloc(sizeof(*proclist)*pid_nr); | ||
| 4952 | |||
| 4953 | pid_nr = 0; | ||
| 4954 | for (jb = curjob; jb; jb = jb->prev_job) { | ||
| 4955 | if (jb->state == JOBDONE) | ||
| 4956 | continue; | ||
| 4957 | ps = jb->ps; | ||
| 4958 | for (i = 0; i < jb->nprocs; ++i) { | ||
| 4959 | if (ps[i].ps_proc) { | ||
| 4960 | pidlist[pid_nr] = ps[i].ps_pid; | ||
| 4961 | proclist[pid_nr++] = ps[i].ps_proc; | ||
| 4962 | } | ||
| 4963 | } | ||
| 4964 | } | ||
| 4965 | |||
| 4966 | if (pid_nr == 0) | ||
| 4967 | goto done; | ||
| 4968 | |||
| 4969 | idx = WaitForMultipleObjects(pid_nr, proclist, FALSE, | ||
| 4970 | wait_flags&WNOHANG ? 1 : INFINITE); | ||
| 4971 | if (idx < pid_nr) { | ||
| 4972 | GetExitCodeProcess(proclist[idx], &win_status); | ||
| 4973 | *status = exit_code_to_wait_status(win_status); | ||
| 4974 | pid = pidlist[idx]; | ||
| 4975 | } | ||
| 4976 | done: | ||
| 4977 | free(pidlist); | ||
| 4978 | free(proclist); | ||
| 4979 | return pid; | ||
| 4980 | } | ||
| 4981 | #define waitpid(p, s, f) waitpid_child(s, f) | ||
| 4982 | #endif | ||
| 4983 | |||
| 4294 | #define DOWAIT_NONBLOCK 0 | 4984 | #define DOWAIT_NONBLOCK 0 |
| 4295 | #define DOWAIT_BLOCK 1 | 4985 | #define DOWAIT_BLOCK 1 |
| 4296 | #define DOWAIT_BLOCK_OR_SIG 2 | 4986 | #define DOWAIT_BLOCK_OR_SIG 2 |
| @@ -4301,6 +4991,7 @@ sprint_status48(char *os, int status, int sigonly) | |||
| 4301 | static int | 4991 | static int |
| 4302 | waitproc(int block, int *status) | 4992 | waitproc(int block, int *status) |
| 4303 | { | 4993 | { |
| 4994 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 4304 | sigset_t oldmask; | 4995 | sigset_t oldmask; |
| 4305 | int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; | 4996 | int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; |
| 4306 | int err; | 4997 | int err; |
| @@ -4331,6 +5022,11 @@ waitproc(int block, int *status) | |||
| 4331 | } while (got_sigchld); | 5022 | } while (got_sigchld); |
| 4332 | 5023 | ||
| 4333 | return err; | 5024 | return err; |
| 5025 | #else | ||
| 5026 | int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; | ||
| 5027 | *status = 0; | ||
| 5028 | return waitpid(-1, status, flags); | ||
| 5029 | #endif | ||
| 4334 | } | 5030 | } |
| 4335 | 5031 | ||
| 4336 | static int | 5032 | static int |
| @@ -4387,6 +5083,11 @@ waitone(int block, struct job *job) | |||
| 4387 | jobno(jp), pid, ps->ps_status, status)); | 5083 | jobno(jp), pid, ps->ps_status, status)); |
| 4388 | ps->ps_status = status; | 5084 | ps->ps_status = status; |
| 4389 | thisjob = jp; | 5085 | thisjob = jp; |
| 5086 | #if ENABLE_PLATFORM_MINGW32 | ||
| 5087 | ps->ps_pid = -1; | ||
| 5088 | CloseHandle(ps->ps_proc); | ||
| 5089 | ps->ps_proc = NULL; | ||
| 5090 | #endif | ||
| 4390 | } | 5091 | } |
| 4391 | if (ps->ps_status == -1) | 5092 | if (ps->ps_status == -1) |
| 4392 | jobstate = JOBRUNNING; | 5093 | jobstate = JOBRUNNING; |
| @@ -4449,6 +5150,7 @@ waitone(int block, struct job *job) | |||
| 4449 | static int | 5150 | static int |
| 4450 | dowait(int block, struct job *jp) | 5151 | dowait(int block, struct job *jp) |
| 4451 | { | 5152 | { |
| 5153 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 4452 | smallint gotchld = *(volatile smallint *)&got_sigchld; | 5154 | smallint gotchld = *(volatile smallint *)&got_sigchld; |
| 4453 | int rpid; | 5155 | int rpid; |
| 4454 | int pid; | 5156 | int pid; |
| @@ -4470,9 +5172,17 @@ dowait(int block, struct job *jp) | |||
| 4470 | } while (pid >= 0); | 5172 | } while (pid >= 0); |
| 4471 | 5173 | ||
| 4472 | return rpid; | 5174 | return rpid; |
| 5175 | #else | ||
| 5176 | int pid = 1; | ||
| 5177 | |||
| 5178 | while (jp ? jp->state == JOBRUNNING : pid > 0) | ||
| 5179 | pid = waitone(block, jp); | ||
| 5180 | |||
| 5181 | return pid; | ||
| 5182 | #endif | ||
| 4473 | } | 5183 | } |
| 4474 | 5184 | ||
| 4475 | #if JOBS | 5185 | #if JOBS || JOBS_WIN32 |
| 4476 | static void | 5186 | static void |
| 4477 | showjob(struct job *jp, int mode) | 5187 | showjob(struct job *jp, int mode) |
| 4478 | { | 5188 | { |
| @@ -4487,7 +5197,7 @@ showjob(struct job *jp, int mode) | |||
| 4487 | 5197 | ||
| 4488 | if (mode & SHOW_ONLY_PGID) { /* jobs -p */ | 5198 | if (mode & SHOW_ONLY_PGID) { /* jobs -p */ |
| 4489 | /* just output process (group) id of pipeline */ | 5199 | /* just output process (group) id of pipeline */ |
| 4490 | fprintf(out, "%d\n", ps->ps_pid); | 5200 | fprintf(out, "%"PID_FMT"d\n", ps->ps_pid); |
| 4491 | return; | 5201 | return; |
| 4492 | } | 5202 | } |
| 4493 | 5203 | ||
| @@ -4500,7 +5210,7 @@ showjob(struct job *jp, int mode) | |||
| 4500 | s[col - 3] = '-'; | 5210 | s[col - 3] = '-'; |
| 4501 | 5211 | ||
| 4502 | if (mode & SHOW_PIDS) | 5212 | if (mode & SHOW_PIDS) |
| 4503 | col += fmtstr(s + col, 16, "%d ", ps->ps_pid); | 5213 | col += fmtstr(s + col, 16, "%"PID_FMT"d ", ps->ps_pid); |
| 4504 | 5214 | ||
| 4505 | psend = ps + jp->nprocs; | 5215 | psend = ps + jp->nprocs; |
| 4506 | 5216 | ||
| @@ -4509,8 +5219,10 @@ showjob(struct job *jp, int mode) | |||
| 4509 | col += sizeof("Running") - 1; | 5219 | col += sizeof("Running") - 1; |
| 4510 | } else { | 5220 | } else { |
| 4511 | int status = psend[-1].ps_status; | 5221 | int status = psend[-1].ps_status; |
| 5222 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 4512 | if (jp->state == JOBSTOPPED) | 5223 | if (jp->state == JOBSTOPPED) |
| 4513 | status = jp->stopstatus; | 5224 | status = jp->stopstatus; |
| 5225 | #endif | ||
| 4514 | col += sprint_status48(s + col, status, 0); | 5226 | col += sprint_status48(s + col, status, 0); |
| 4515 | } | 5227 | } |
| 4516 | /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ | 5228 | /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ |
| @@ -4529,14 +5241,18 @@ showjob(struct job *jp, int mode) | |||
| 4529 | s[0] = '\0'; | 5241 | s[0] = '\0'; |
| 4530 | col = 33; | 5242 | col = 33; |
| 4531 | if (mode & SHOW_PIDS) | 5243 | if (mode & SHOW_PIDS) |
| 4532 | col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1; | 5244 | col = fmtstr(s, 48, "\n%*c%"PID_FMT"d ", indent_col, ' ', ps->ps_pid) - 1; |
| 4533 | start: | 5245 | start: |
| 5246 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 4534 | fprintf(out, "%s%*c%s%s", | 5247 | fprintf(out, "%s%*c%s%s", |
| 4535 | s, | 5248 | s, |
| 4536 | 33 - col >= 0 ? 33 - col : 0, ' ', | 5249 | 33 - col >= 0 ? 33 - col : 0, ' ', |
| 4537 | ps == jp->ps ? "" : "| ", | 5250 | ps == jp->ps ? "" : "| ", |
| 4538 | ps->ps_cmd | 5251 | ps->ps_cmd |
| 4539 | ); | 5252 | ); |
| 5253 | #else | ||
| 5254 | fprintf(out, "%s", s); | ||
| 5255 | #endif | ||
| 4540 | } while (++ps != psend); | 5256 | } while (++ps != psend); |
| 4541 | newline_and_flush(out); | 5257 | newline_and_flush(out); |
| 4542 | 5258 | ||
| @@ -4621,7 +5337,7 @@ getstatus(struct job *job) | |||
| 4621 | { | 5337 | { |
| 4622 | /* XXX: limits number of signals */ | 5338 | /* XXX: limits number of signals */ |
| 4623 | retval = WTERMSIG(status); | 5339 | retval = WTERMSIG(status); |
| 4624 | #if JOBS | 5340 | #if JOBS || ENABLE_PLATFORM_MINGW32 |
| 4625 | if (retval == SIGINT) | 5341 | if (retval == SIGINT) |
| 4626 | job->sigint = 1; | 5342 | job->sigint = 1; |
| 4627 | #endif | 5343 | #endif |
| @@ -4793,7 +5509,7 @@ makejob(/*union node *node,*/ int nprocs) | |||
| 4793 | break; | 5509 | break; |
| 4794 | if (jp->state != JOBDONE || !jp->waited) | 5510 | if (jp->state != JOBDONE || !jp->waited) |
| 4795 | continue; | 5511 | continue; |
| 4796 | #if JOBS | 5512 | #if JOBS || JOBS_WIN32 |
| 4797 | if (doing_jobctl) | 5513 | if (doing_jobctl) |
| 4798 | continue; | 5514 | continue; |
| 4799 | #endif | 5515 | #endif |
| @@ -4819,7 +5535,7 @@ makejob(/*union node *node,*/ int nprocs) | |||
| 4819 | return jp; | 5535 | return jp; |
| 4820 | } | 5536 | } |
| 4821 | 5537 | ||
| 4822 | #if JOBS | 5538 | #if JOBS || JOBS_WIN32 |
| 4823 | /* | 5539 | /* |
| 4824 | * Return a string identifying a command (to be printed by the | 5540 | * Return a string identifying a command (to be printed by the |
| 4825 | * jobs command). | 5541 | * jobs command). |
| @@ -5161,6 +5877,7 @@ clear_traps(void) | |||
| 5161 | INT_ON; | 5877 | INT_ON; |
| 5162 | } | 5878 | } |
| 5163 | 5879 | ||
| 5880 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 5164 | /* Lives far away from here, needed for forkchild */ | 5881 | /* Lives far away from here, needed for forkchild */ |
| 5165 | static void closescript(void); | 5882 | static void closescript(void); |
| 5166 | 5883 | ||
| @@ -5287,14 +6004,22 @@ forkchild(struct job *jp, union node *n, int mode) | |||
| 5287 | for (jp = curjob; jp; jp = jp->prev_job) | 6004 | for (jp = curjob; jp; jp = jp->prev_job) |
| 5288 | freejob(jp); | 6005 | freejob(jp); |
| 5289 | } | 6006 | } |
| 6007 | #endif | ||
| 5290 | 6008 | ||
| 5291 | /* Called after fork(), in parent */ | 6009 | /* Called after fork(), in parent */ |
| 5292 | #if !JOBS | 6010 | #if !JOBS && !JOBS_WIN32 |
| 5293 | #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) | 6011 | #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) |
| 5294 | #endif | 6012 | #endif |
| 5295 | static void | 6013 | static void |
| 6014 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 5296 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 6015 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
| 6016 | #else | ||
| 6017 | forkparent(struct job *jp, union node *n, int mode, HANDLE proc) | ||
| 6018 | #endif | ||
| 5297 | { | 6019 | { |
| 6020 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6021 | pid_t pid = GetProcessId(proc); | ||
| 6022 | #endif | ||
| 5298 | TRACE(("In parent shell: child = %d\n", pid)); | 6023 | TRACE(("In parent shell: child = %d\n", pid)); |
| 5299 | if (!jp) /* jp is NULL when called by openhere() for heredoc support */ | 6024 | if (!jp) /* jp is NULL when called by openhere() for heredoc support */ |
| 5300 | return; | 6025 | return; |
| @@ -5313,19 +6038,29 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) | |||
| 5313 | if (mode == FORK_BG) { | 6038 | if (mode == FORK_BG) { |
| 5314 | backgndpid = pid; /* set $! */ | 6039 | backgndpid = pid; /* set $! */ |
| 5315 | set_curjob(jp, CUR_RUNNING); | 6040 | set_curjob(jp, CUR_RUNNING); |
| 6041 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6042 | if (iflag && jp && jp->nprocs == 0) | ||
| 6043 | fprintf(stderr, "[%d] %"PID_FMT"d\n", jobno(jp), pid); | ||
| 6044 | #endif | ||
| 5316 | } | 6045 | } |
| 5317 | if (jp) { | 6046 | if (jp) { |
| 5318 | struct procstat *ps = &jp->ps[jp->nprocs++]; | 6047 | struct procstat *ps = &jp->ps[jp->nprocs++]; |
| 5319 | ps->ps_pid = pid; | 6048 | ps->ps_pid = pid; |
| 5320 | ps->ps_status = -1; | 6049 | ps->ps_status = -1; |
| 6050 | #if ENABLE_PLATFORM_POSIX || JOBS_WIN32 | ||
| 5321 | ps->ps_cmd = nullstr; | 6051 | ps->ps_cmd = nullstr; |
| 5322 | #if JOBS | 6052 | #endif |
| 6053 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6054 | ps->ps_proc = proc; | ||
| 6055 | #endif | ||
| 6056 | #if JOBS || JOBS_WIN32 | ||
| 5323 | if (doing_jobctl && n) | 6057 | if (doing_jobctl && n) |
| 5324 | ps->ps_cmd = commandtext(n); | 6058 | ps->ps_cmd = commandtext(n); |
| 5325 | #endif | 6059 | #endif |
| 5326 | } | 6060 | } |
| 5327 | } | 6061 | } |
| 5328 | 6062 | ||
| 6063 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 5329 | /* jp and n are NULL when called by openhere() for heredoc support */ | 6064 | /* jp and n are NULL when called by openhere() for heredoc support */ |
| 5330 | static int | 6065 | static int |
| 5331 | forkshell(struct job *jp, union node *n, int mode) | 6066 | forkshell(struct job *jp, union node *n, int mode) |
| @@ -5348,6 +6083,7 @@ forkshell(struct job *jp, union node *n, int mode) | |||
| 5348 | } | 6083 | } |
| 5349 | return pid; | 6084 | return pid; |
| 5350 | } | 6085 | } |
| 6086 | #endif | ||
| 5351 | 6087 | ||
| 5352 | /* | 6088 | /* |
| 5353 | * Wait for job to finish. | 6089 | * Wait for job to finish. |
| @@ -5411,6 +6147,10 @@ waitforjob(struct job *jp) | |||
| 5411 | return exitstatus; | 6147 | return exitstatus; |
| 5412 | 6148 | ||
| 5413 | st = getstatus(jp); | 6149 | st = getstatus(jp); |
| 6150 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6151 | if (!jp->sigint && iflag && rootshell) | ||
| 6152 | pending_int = 0; | ||
| 6153 | #endif | ||
| 5414 | #if JOBS | 6154 | #if JOBS |
| 5415 | if (jp->jobctl) { | 6155 | if (jp->jobctl) { |
| 5416 | xtcsetpgrp(ttyfd, rootpid); | 6156 | xtcsetpgrp(ttyfd, rootpid); |
| @@ -5436,6 +6176,7 @@ waitforjob(struct job *jp) | |||
| 5436 | /* | 6176 | /* |
| 5437 | * return 1 if there are stopped jobs, otherwise 0 | 6177 | * return 1 if there are stopped jobs, otherwise 0 |
| 5438 | */ | 6178 | */ |
| 6179 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 5439 | static int | 6180 | static int |
| 5440 | stoppedjobs(void) | 6181 | stoppedjobs(void) |
| 5441 | { | 6182 | { |
| @@ -5454,6 +6195,17 @@ stoppedjobs(void) | |||
| 5454 | out: | 6195 | out: |
| 5455 | return retval; | 6196 | return retval; |
| 5456 | } | 6197 | } |
| 6198 | #else | ||
| 6199 | static int | ||
| 6200 | stoppedjobs(void) | ||
| 6201 | { | ||
| 6202 | if (iflag && curjob) { | ||
| 6203 | out2str("You have background jobs.\n"); | ||
| 6204 | return 1; | ||
| 6205 | } | ||
| 6206 | return 0; | ||
| 6207 | } | ||
| 6208 | #endif | ||
| 5457 | 6209 | ||
| 5458 | 6210 | ||
| 5459 | /* | 6211 | /* |
| @@ -5478,6 +6230,7 @@ openhere(union node *redir) | |||
| 5478 | char *p; | 6230 | char *p; |
| 5479 | int pip[2]; | 6231 | int pip[2]; |
| 5480 | size_t len = 0; | 6232 | size_t len = 0; |
| 6233 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
| 5481 | 6234 | ||
| 5482 | if (pipe(pip) < 0) | 6235 | if (pipe(pip) < 0) |
| 5483 | ash_msg_and_raise_perror("can't create pipe"); | 6236 | ash_msg_and_raise_perror("can't create pipe"); |
| @@ -5494,6 +6247,14 @@ openhere(union node *redir) | |||
| 5494 | goto out; | 6247 | goto out; |
| 5495 | } | 6248 | } |
| 5496 | 6249 | ||
| 6250 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6251 | memset(&fs, 0, sizeof(fs)); | ||
| 6252 | fs.fpid = FS_OPENHERE; | ||
| 6253 | fs.fd[0] = pip[0]; | ||
| 6254 | fs.fd[1] = pip[1]; | ||
| 6255 | fs.path = p; | ||
| 6256 | spawn_forkshell(&fs, NULL, NULL, FORK_NOJOB); | ||
| 6257 | #else | ||
| 5497 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | 6258 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { |
| 5498 | /* child */ | 6259 | /* child */ |
| 5499 | close(pip[0]); | 6260 | close(pip[0]); |
| @@ -5505,6 +6266,7 @@ openhere(union node *redir) | |||
| 5505 | xwrite(pip[1], p, len); | 6266 | xwrite(pip[1], p, len); |
| 5506 | _exit_SUCCESS(); | 6267 | _exit_SUCCESS(); |
| 5507 | } | 6268 | } |
| 6269 | #endif | ||
| 5508 | out: | 6270 | out: |
| 5509 | close(pip[1]); | 6271 | close(pip[1]); |
| 5510 | return pip[0]; | 6272 | return pip[0]; |
| @@ -5582,6 +6344,9 @@ openredirect(union node *redir) | |||
| 5582 | f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); | 6344 | f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); |
| 5583 | if (f < 0) | 6345 | if (f < 0) |
| 5584 | goto ecreate; | 6346 | goto ecreate; |
| 6347 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6348 | lseek(f, 0, SEEK_END); | ||
| 6349 | #endif | ||
| 5585 | break; | 6350 | break; |
| 5586 | } | 6351 | } |
| 5587 | 6352 | ||
| @@ -6133,6 +6898,9 @@ ifsbreakup(char *string, struct arglist *arglist) | |||
| 6133 | const char *ifs, *realifs; | 6898 | const char *ifs, *realifs; |
| 6134 | int ifsspc; | 6899 | int ifsspc; |
| 6135 | int nulonly; | 6900 | int nulonly; |
| 6901 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6902 | int lshift = 0; | ||
| 6903 | #endif | ||
| 6136 | 6904 | ||
| 6137 | start = string; | 6905 | start = string; |
| 6138 | if (ifslastp != NULL) { | 6906 | if (ifslastp != NULL) { |
| @@ -6143,7 +6911,33 @@ ifsbreakup(char *string, struct arglist *arglist) | |||
| 6143 | do { | 6911 | do { |
| 6144 | int afternul; | 6912 | int afternul; |
| 6145 | 6913 | ||
| 6914 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6915 | /* Adjust region offsets for left-shifted string. */ | ||
| 6916 | ifsp->begoff -= lshift; | ||
| 6917 | ifsp->endoff -= lshift; | ||
| 6918 | #endif | ||
| 6146 | p = string + ifsp->begoff; | 6919 | p = string + ifsp->begoff; |
| 6920 | #if ENABLE_PLATFORM_MINGW32 | ||
| 6921 | if (ifsp->endoff > ifsp->begoff + 1) { | ||
| 6922 | /* Transform CRLF to LF. Skip regions having zero or | ||
| 6923 | * one characters: they can't contain CRLF. If the | ||
| 6924 | * region shrinks shift the rest of the string left. */ | ||
| 6925 | int oldlen = ifsp->endoff - ifsp->begoff; | ||
| 6926 | int newlen = remove_cr(p, oldlen); | ||
| 6927 | int delta = oldlen - newlen; | ||
| 6928 | |||
| 6929 | if (delta > 0) { | ||
| 6930 | char *t = string + ifsp->endoff; | ||
| 6931 | char *s = string + ifsp->endoff - delta; | ||
| 6932 | |||
| 6933 | while (*t) | ||
| 6934 | *s++ = *t++; | ||
| 6935 | *s = '\0'; | ||
| 6936 | lshift += delta; | ||
| 6937 | ifsp->endoff -= delta; | ||
| 6938 | } | ||
| 6939 | } | ||
| 6940 | #endif | ||
| 6147 | afternul = nulonly; | 6941 | afternul = nulonly; |
| 6148 | nulonly = ifsp->nulonly; | 6942 | nulonly = ifsp->nulonly; |
| 6149 | ifs = nulonly ? nullstr : realifs; | 6943 | ifs = nulonly ? nullstr : realifs; |
| @@ -6588,6 +7382,7 @@ evalbackcmd(union node *n, struct backcmd *result | |||
| 6588 | const int ip = 0; | 7382 | const int ip = 0; |
| 6589 | const int ic = 1; | 7383 | const int ic = 1; |
| 6590 | #endif | 7384 | #endif |
| 7385 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
| 6591 | 7386 | ||
| 6592 | result->fd = -1; | 7387 | result->fd = -1; |
| 6593 | result->buf = NULL; | 7388 | result->buf = NULL; |
| @@ -6601,6 +7396,15 @@ evalbackcmd(union node *n, struct backcmd *result | |||
| 6601 | ash_msg_and_raise_perror("can't create pipe"); | 7396 | ash_msg_and_raise_perror("can't create pipe"); |
| 6602 | /* process substitution uses NULL job, like openhere() */ | 7397 | /* process substitution uses NULL job, like openhere() */ |
| 6603 | jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL; | 7398 | jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL; |
| 7399 | #if ENABLE_PLATFORM_MINGW32 | ||
| 7400 | memset(&fs, 0, sizeof(fs)); | ||
| 7401 | fs.fpid = FS_EVALBACKCMD; | ||
| 7402 | fs.n = n; | ||
| 7403 | fs.fd[0] = pip[0]; | ||
| 7404 | fs.fd[1] = pip[1]; | ||
| 7405 | fs.fd[2] = ctl; | ||
| 7406 | spawn_forkshell(&fs, jp, n, FORK_NOJOB); | ||
| 7407 | #else | ||
| 6604 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 7408 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
| 6605 | /* child */ | 7409 | /* child */ |
| 6606 | FORCE_INT_ON; | 7410 | FORCE_INT_ON; |
| @@ -6624,6 +7428,7 @@ evalbackcmd(union node *n, struct backcmd *result | |||
| 6624 | evaltreenr(n, EV_EXIT); | 7428 | evaltreenr(n, EV_EXIT); |
| 6625 | /* NOTREACHED */ | 7429 | /* NOTREACHED */ |
| 6626 | } | 7430 | } |
| 7431 | #endif | ||
| 6627 | /* parent */ | 7432 | /* parent */ |
| 6628 | #if BASH_PROCESS_SUBST | 7433 | #if BASH_PROCESS_SUBST |
| 6629 | if (ctl != CTLBACKQ) { | 7434 | if (ctl != CTLBACKQ) { |
| @@ -6702,8 +7507,14 @@ expbackq(union node *cmd, int flag IF_BASH_PROCESS_SUBST(, int ctl)) | |||
| 6702 | 7507 | ||
| 6703 | /* Eat all trailing newlines */ | 7508 | /* Eat all trailing newlines */ |
| 6704 | dest = expdest; | 7509 | dest = expdest; |
| 6705 | for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';) | 7510 | for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';) { |
| 6706 | STUNPUTC(dest); | 7511 | STUNPUTC(dest); |
| 7512 | #if ENABLE_PLATFORM_MINGW32 | ||
| 7513 | if (dest > ((char *)stackblock() + startloc) && dest[-1] == '\r') { | ||
| 7514 | STUNPUTC(dest); | ||
| 7515 | } | ||
| 7516 | #endif | ||
| 7517 | } | ||
| 6707 | expdest = dest; | 7518 | expdest = dest; |
| 6708 | 7519 | ||
| 6709 | if (!(flag & EXP_QUOTED)) | 7520 | if (!(flag & EXP_QUOTED)) |
| @@ -7850,6 +8661,26 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
| 7850 | #else | 8661 | #else |
| 7851 | /* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */ | 8662 | /* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */ |
| 7852 | 8663 | ||
| 8664 | #if ENABLE_ASH_GLOB_OPTIONS | ||
| 8665 | static int FAST_FUNC | ||
| 8666 | ash_accept_glob(const char *name) | ||
| 8667 | { | ||
| 8668 | struct stat st; | ||
| 8669 | |||
| 8670 | if (nohiddenglob || nohidsysglob) { | ||
| 8671 | if (!lstat(name, &st)) { | ||
| 8672 | if ((st.st_attr & FILE_ATTRIBUTE_HIDDEN)) { | ||
| 8673 | if (nohiddenglob || | ||
| 8674 | (st.st_attr & FILE_ATTRIBUTE_SYSTEM)) { | ||
| 8675 | return FALSE; | ||
| 8676 | } | ||
| 8677 | } | ||
| 8678 | } | ||
| 8679 | } | ||
| 8680 | return TRUE; | ||
| 8681 | } | ||
| 8682 | #endif | ||
| 8683 | |||
| 7853 | /* | 8684 | /* |
| 7854 | * Do metacharacter (i.e. *, ?, [...]) expansion. | 8685 | * Do metacharacter (i.e. *, ?, [...]) expansion. |
| 7855 | */ | 8686 | */ |
| @@ -7877,6 +8708,10 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
| 7877 | 8708 | ||
| 7878 | metaflag = 0; | 8709 | metaflag = 0; |
| 7879 | start = name; | 8710 | start = name; |
| 8711 | #if ENABLE_PLATFORM_MINGW32 | ||
| 8712 | if (expdir_len == 0 && has_dos_drive_prefix(start) && start[2] != '/') | ||
| 8713 | start += 2; | ||
| 8714 | #endif | ||
| 7880 | for (p = name; esc = 0, *p; p += esc + 1) { | 8715 | for (p = name; esc = 0, *p; p += esc + 1) { |
| 7881 | if (*p == '*' || *p == '?') | 8716 | if (*p == '*' || *p == '?') |
| 7882 | metaflag = 1; | 8717 | metaflag = 1; |
| @@ -7951,8 +8786,16 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
| 7951 | while (!pending_int && (dp = readdir(dirp)) != NULL) { | 8786 | while (!pending_int && (dp = readdir(dirp)) != NULL) { |
| 7952 | if (dp->d_name[0] == '.' && !matchdot) | 8787 | if (dp->d_name[0] == '.' && !matchdot) |
| 7953 | continue; | 8788 | continue; |
| 8789 | #if ENABLE_ASH_GLOB_OPTIONS | ||
| 8790 | # undef pmatch | ||
| 8791 | # define pmatch(a, b) !fnmatch((a), (b), nocaseglob ? FNM_CASEFOLD : 0) | ||
| 8792 | #endif | ||
| 7954 | if (pmatch(start, dp->d_name)) { | 8793 | if (pmatch(start, dp->d_name)) { |
| 7955 | if (atend) { | 8794 | if (atend) { |
| 8795 | #if ENABLE_ASH_GLOB_OPTIONS | ||
| 8796 | if (!ash_accept_glob(dp->d_name)) | ||
| 8797 | continue; | ||
| 8798 | #endif | ||
| 7956 | strcpy(enddir, dp->d_name); | 8799 | strcpy(enddir, dp->d_name); |
| 7957 | addfname(expdir); | 8800 | addfname(expdir); |
| 7958 | } else { | 8801 | } else { |
| @@ -7980,6 +8823,10 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
| 7980 | endname[-esc - 1] = esc ? '\\' : '/'; | 8823 | endname[-esc - 1] = esc ? '\\' : '/'; |
| 7981 | #undef expdir | 8824 | #undef expdir |
| 7982 | #undef expdir_max | 8825 | #undef expdir_max |
| 8826 | #if ENABLE_ASH_GLOB_OPTIONS | ||
| 8827 | # undef pmatch | ||
| 8828 | # define pmatch(a, b) !fnmatch((a), (b), 0) | ||
| 8829 | #endif | ||
| 7983 | } | 8830 | } |
| 7984 | 8831 | ||
| 7985 | static struct strlist * | 8832 | static struct strlist * |
| @@ -8256,10 +9103,34 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
| 8256 | { | 9103 | { |
| 8257 | #if ENABLE_FEATURE_SH_STANDALONE | 9104 | #if ENABLE_FEATURE_SH_STANDALONE |
| 8258 | if (applet_no >= 0) { | 9105 | if (applet_no >= 0) { |
| 9106 | # if ENABLE_PLATFORM_MINGW32 | ||
| 9107 | /* Treat all applets as NOEXEC, including the shell itself if | ||
| 9108 | * this is a FS_SHELLEXEC shell. */ | ||
| 9109 | struct forkshell *fs = (struct forkshell *)sticky_mem_start; | ||
| 9110 | if (applet_main[applet_no] != ash_main || | ||
| 9111 | (fs && fs->fpid == FS_SHELLEXEC)) { | ||
| 9112 | /* mingw-w64's getopt() uses __argv[0] as the program name */ | ||
| 9113 | __argv[0] = (char *)cmd; | ||
| 9114 | /* 'which' wants to know if it was invoked from a standalone | ||
| 9115 | * shell. Use the spare element of argv to add a flag, but | ||
| 9116 | * not if the first argument is '--help', that's a special | ||
| 9117 | * case. */ | ||
| 9118 | if (strcmp(argv[0], "which") == 0 && | ||
| 9119 | (argv[1] == NULL || strcmp(argv[1], "--help") != 0)) { | ||
| 9120 | --argv; | ||
| 9121 | argv[0] = argv[1]; | ||
| 9122 | argv[1] = (char *)"-s"; | ||
| 9123 | } | ||
| 9124 | # else | ||
| 8259 | if (APPLET_IS_NOEXEC(applet_no)) { | 9125 | if (APPLET_IS_NOEXEC(applet_no)) { |
| 9126 | # endif | ||
| 9127 | #if !ENABLE_PLATFORM_MINGW32 || !defined(_UCRT) | ||
| 9128 | /* If building for UCRT move this up into shellexec() to | ||
| 9129 | * work around a bug. */ | ||
| 8260 | clearenv(); | 9130 | clearenv(); |
| 8261 | while (*envp) | 9131 | while (*envp) |
| 8262 | putenv(*envp++); | 9132 | putenv(*envp++); |
| 9133 | #endif | ||
| 8263 | popredir(/*drop:*/ 1); | 9134 | popredir(/*drop:*/ 1); |
| 8264 | run_noexec_applet_and_exit(applet_no, cmd, argv); | 9135 | run_noexec_applet_and_exit(applet_no, cmd, argv); |
| 8265 | } | 9136 | } |
| @@ -8270,6 +9141,22 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
| 8270 | } | 9141 | } |
| 8271 | #endif | 9142 | #endif |
| 8272 | 9143 | ||
| 9144 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9145 | /* Workaround for libtool, which assumes the host is an MSYS2 | ||
| 9146 | * environment and requires special-case escaping for cmd.exe. | ||
| 9147 | * https://github.com/skeeto/w64devkit/issues/50 */ | ||
| 9148 | if (string_array_len(argv) >= 3 && | ||
| 9149 | strcmp(argv[0], "cmd") == 0 && | ||
| 9150 | strcmp(argv[1], "//c") == 0 && | ||
| 9151 | strcmp(argv[2], "echo") == 0) { | ||
| 9152 | argv[1]++; /* drop extra slash */ | ||
| 9153 | } | ||
| 9154 | |||
| 9155 | /* cmd was allocated on the stack with room for an extension */ | ||
| 9156 | add_win32_extension((char *)cmd); | ||
| 9157 | execve(cmd, argv, envp); | ||
| 9158 | /* skip POSIX-mandated retry on ENOEXEC */ | ||
| 9159 | #else /* !ENABLE_PLATFORM_MINGW32 */ | ||
| 8273 | repeat: | 9160 | repeat: |
| 8274 | #ifdef SYSV | 9161 | #ifdef SYSV |
| 8275 | do { | 9162 | do { |
| @@ -8305,6 +9192,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
| 8305 | argv[0] = (char*) "ash"; | 9192 | argv[0] = (char*) "ash"; |
| 8306 | goto repeat; | 9193 | goto repeat; |
| 8307 | } | 9194 | } |
| 9195 | #endif /* !ENABLE_PLATFORM_MINGW32 */ | ||
| 8308 | } | 9196 | } |
| 8309 | 9197 | ||
| 8310 | /* | 9198 | /* |
| @@ -8312,6 +9200,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
| 8312 | * have to change the find_command routine as well. | 9200 | * have to change the find_command routine as well. |
| 8313 | * argv[-1] must exist and be writable! See tryexec() for why. | 9201 | * argv[-1] must exist and be writable! See tryexec() for why. |
| 8314 | */ | 9202 | */ |
| 9203 | static struct builtincmd *find_builtin(const char *name); | ||
| 8315 | static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN; | 9204 | static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN; |
| 8316 | static void shellexec(char *prog, char **argv, const char *path, int idx) | 9205 | static void shellexec(char *prog, char **argv, const char *path, int idx) |
| 8317 | { | 9206 | { |
| @@ -8322,12 +9211,29 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
| 8322 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ | 9211 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ |
| 8323 | 9212 | ||
| 8324 | envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); | 9213 | envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); |
| 9214 | #if ENABLE_FEATURE_SH_STANDALONE && ENABLE_PLATFORM_MINGW32 && defined(_UCRT) | ||
| 9215 | /* Avoid UCRT bug by updating parent's environment and passing a | ||
| 9216 | * NULL environment pointer to execve(). */ | ||
| 9217 | clearenv(); | ||
| 9218 | while (*envp) | ||
| 9219 | putenv(*envp++); | ||
| 9220 | envp = NULL; | ||
| 9221 | #endif | ||
| 9222 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 8325 | if (strchr(prog, '/') != NULL | 9223 | if (strchr(prog, '/') != NULL |
| 9224 | #else | ||
| 9225 | if (has_path(prog) | ||
| 9226 | #endif | ||
| 8326 | #if ENABLE_FEATURE_SH_STANDALONE | 9227 | #if ENABLE_FEATURE_SH_STANDALONE |
| 8327 | || (applet_no = find_applet_by_name(prog)) >= 0 | 9228 | || (applet_no = find_applet_by_name_for_sh(prog, path)) >= 0 |
| 8328 | #endif | 9229 | #endif |
| 8329 | ) { | 9230 | ) { |
| 9231 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9232 | char *progext = stack_add_ext_space(prog); | ||
| 9233 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) progext, argv, envp); | ||
| 9234 | #else | ||
| 8330 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); | 9235 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); |
| 9236 | #endif | ||
| 8331 | if (applet_no >= 0) { | 9237 | if (applet_no >= 0) { |
| 8332 | /* We tried execing ourself, but it didn't work. | 9238 | /* We tried execing ourself, but it didn't work. |
| 8333 | * Maybe /proc/self/exe doesn't exist? | 9239 | * Maybe /proc/self/exe doesn't exist? |
| @@ -8336,6 +9242,21 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
| 8336 | goto try_PATH; | 9242 | goto try_PATH; |
| 8337 | } | 9243 | } |
| 8338 | e = errno; | 9244 | e = errno; |
| 9245 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9246 | if (unix_path(prog)) { | ||
| 9247 | const char *name = bb_basename(prog); | ||
| 9248 | # if ENABLE_FEATURE_SH_STANDALONE | ||
| 9249 | if ((applet_no = find_applet_by_name_for_sh(name, path)) >= 0) { | ||
| 9250 | tryexec(applet_no, name, argv, envp); | ||
| 9251 | e = errno; | ||
| 9252 | } | ||
| 9253 | # endif | ||
| 9254 | if (!find_builtin(name)) { | ||
| 9255 | argv[0] = (char *)name; | ||
| 9256 | goto try_PATH; | ||
| 9257 | } | ||
| 9258 | } | ||
| 9259 | #endif | ||
| 8339 | } else { | 9260 | } else { |
| 8340 | try_PATH: | 9261 | try_PATH: |
| 8341 | e = ENOENT; | 9262 | e = ENOENT; |
| @@ -8381,6 +9302,9 @@ printentry(struct tblentry *cmdp) | |||
| 8381 | padvance(&path, cmdp->cmdname); | 9302 | padvance(&path, cmdp->cmdname); |
| 8382 | } while (--idx >= 0); | 9303 | } while (--idx >= 0); |
| 8383 | name = stackblock(); | 9304 | name = stackblock(); |
| 9305 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9306 | add_win32_extension(name); | ||
| 9307 | #endif | ||
| 8384 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); | 9308 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); |
| 8385 | } | 9309 | } |
| 8386 | 9310 | ||
| @@ -8581,7 +9505,7 @@ changepath(const char *newval) | |||
| 8581 | bltin = idx; | 9505 | bltin = idx; |
| 8582 | break; | 9506 | break; |
| 8583 | } | 9507 | } |
| 8584 | new = strchr(new, ':'); | 9508 | new = strchr(new, PATH_SEP); |
| 8585 | if (!new) | 9509 | if (!new) |
| 8586 | break; | 9510 | break; |
| 8587 | idx++; | 9511 | idx++; |
| @@ -8758,14 +9682,37 @@ describe_command(char *command, const char *path, int describe_command_verbose) | |||
| 8758 | case CMDNORMAL: { | 9682 | case CMDNORMAL: { |
| 8759 | int j = entry.u.index; | 9683 | int j = entry.u.index; |
| 8760 | char *p; | 9684 | char *p; |
| 9685 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
| 9686 | if (j < -1) { | ||
| 9687 | p = (char *)bb_basename(command); | ||
| 9688 | if (describe_command_verbose) { | ||
| 9689 | out1fmt(" is a builtin applet"); | ||
| 9690 | } else { | ||
| 9691 | out1str(applet_to_exe(p)); | ||
| 9692 | } | ||
| 9693 | break; | ||
| 9694 | } | ||
| 9695 | #endif | ||
| 8761 | if (j < 0) { | 9696 | if (j < 0) { |
| 9697 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9698 | p = stack_add_ext_space(command); | ||
| 9699 | #else | ||
| 8762 | p = command; | 9700 | p = command; |
| 9701 | #endif | ||
| 8763 | } else { | 9702 | } else { |
| 9703 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9704 | if (unix_path(command)) | ||
| 9705 | command = (char *)bb_basename(command); | ||
| 9706 | #endif | ||
| 8764 | do { | 9707 | do { |
| 8765 | padvance(&path, command); | 9708 | padvance(&path, command); |
| 8766 | } while (--j >= 0); | 9709 | } while (--j >= 0); |
| 8767 | p = stackblock(); | 9710 | p = stackblock(); |
| 8768 | } | 9711 | } |
| 9712 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9713 | add_win32_extension(p); | ||
| 9714 | bs_to_slash(p); | ||
| 9715 | #endif | ||
| 8769 | if (describe_command_verbose) { | 9716 | if (describe_command_verbose) { |
| 8770 | out1fmt(" is %s", p); | 9717 | out1fmt(" is %s", p); |
| 8771 | } else { | 9718 | } else { |
| @@ -8921,6 +9868,15 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 8921 | /*static int funcstringsize; // size of strings in node */ | 9868 | /*static int funcstringsize; // size of strings in node */ |
| 8922 | static void *funcblock; /* block to allocate function from */ | 9869 | static void *funcblock; /* block to allocate function from */ |
| 8923 | static char *funcstring_end; /* end of block to allocate strings from */ | 9870 | static char *funcstring_end; /* end of block to allocate strings from */ |
| 9871 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9872 | static int fs_size; | ||
| 9873 | static void *fs_start; | ||
| 9874 | # if FORKSHELL_DEBUG | ||
| 9875 | static void *fs_funcstring; | ||
| 9876 | static const char **annot; | ||
| 9877 | static char *annot_free; | ||
| 9878 | # endif | ||
| 9879 | #endif | ||
| 8924 | 9880 | ||
| 8925 | static const uint8_t nodesize[N_NUMBER] ALIGN1 = { | 9881 | static const uint8_t nodesize[N_NUMBER] ALIGN1 = { |
| 8926 | [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), | 9882 | [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), |
| @@ -9053,14 +10009,79 @@ calcsize(int funcblocksize, union node *n) | |||
| 9053 | } | 10009 | } |
| 9054 | 10010 | ||
| 9055 | static char * | 10011 | static char * |
| 9056 | nodeckstrdup(char *s) | 10012 | nodeckstrdup(const char *s) |
| 9057 | { | 10013 | { |
| 10014 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10015 | if(!s) | ||
| 10016 | return NULL; | ||
| 10017 | #endif | ||
| 9058 | funcstring_end -= SHELL_ALIGN(strlen(s) + 1); | 10018 | funcstring_end -= SHELL_ALIGN(strlen(s) + 1); |
| 9059 | return strcpy(funcstring_end, s); | 10019 | return strcpy(funcstring_end, s); |
| 9060 | } | 10020 | } |
| 9061 | 10021 | ||
| 9062 | static union node *copynode(union node *); | 10022 | static union node *copynode(union node *); |
| 9063 | 10023 | ||
| 10024 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10025 | # if FORKSHELL_DEBUG | ||
| 10026 | # define MARK_PTR(dst,note,flag) forkshell_mark_ptr((void *)&dst, note, flag) | ||
| 10027 | # else | ||
| 10028 | # define MARK_PTR(dst,note,flag) forkshell_mark_ptr((void *)&dst) | ||
| 10029 | # endif | ||
| 10030 | |||
| 10031 | #define NO_FREE 0 | ||
| 10032 | #define FREE 1 | ||
| 10033 | |||
| 10034 | #if FORKSHELL_DEBUG | ||
| 10035 | static void forkshell_mark_ptr(void *dst, const char *note, int flag) | ||
| 10036 | #else | ||
| 10037 | static void forkshell_mark_ptr(void *dst) | ||
| 10038 | #endif | ||
| 10039 | { | ||
| 10040 | char *lrelocate = (char *)fs_start + fs_size; | ||
| 10041 | int index = ((char *)dst - (char *)fs_start)/sizeof(char *); | ||
| 10042 | |||
| 10043 | lrelocate[index/8] |= 1 << (index % 8); | ||
| 10044 | |||
| 10045 | #if FORKSHELL_DEBUG | ||
| 10046 | if (dst < fs_start || dst >= fs_funcstring) { | ||
| 10047 | fprintf(stderr, "dst (%p) out of range (%p %p)\n", | ||
| 10048 | dst, fs_start, fs_funcstring); | ||
| 10049 | } | ||
| 10050 | if (annot) { | ||
| 10051 | if (annot[index]) { | ||
| 10052 | fprintf(stderr, "duplicate annotation: %s %s\n", | ||
| 10053 | annot[index], note); | ||
| 10054 | } | ||
| 10055 | annot[index] = note; | ||
| 10056 | annot_free[index] = flag; | ||
| 10057 | } | ||
| 10058 | #endif | ||
| 10059 | } | ||
| 10060 | |||
| 10061 | # define SAVE_PTR(dst,note,flag) { \ | ||
| 10062 | if (fs_size) { \ | ||
| 10063 | MARK_PTR(dst,note,flag); \ | ||
| 10064 | } \ | ||
| 10065 | } | ||
| 10066 | # define SAVE_PTR2(dst1,note1,flag1,dst2,note2,flag2) { \ | ||
| 10067 | if (fs_size) { \ | ||
| 10068 | MARK_PTR(dst1,note1,flag1); \ | ||
| 10069 | MARK_PTR(dst2,note2,flag2); \ | ||
| 10070 | } \ | ||
| 10071 | } | ||
| 10072 | # define SAVE_PTR3(dst1,note1,flag1,dst2,note2,flag2,dst3,note3,flag3) { \ | ||
| 10073 | if (fs_size) { \ | ||
| 10074 | MARK_PTR(dst1,note1,flag1); \ | ||
| 10075 | MARK_PTR(dst2,note2,flag2); \ | ||
| 10076 | MARK_PTR(dst3,note3,flag3); \ | ||
| 10077 | } \ | ||
| 10078 | } | ||
| 10079 | #else | ||
| 10080 | # define SAVE_PTR(dst,note,flag) | ||
| 10081 | # define SAVE_PTR2(dst1,note1,flag1,dst2,note2,flag2) | ||
| 10082 | # define SAVE_PTR3(dst1,note1,flag1,dst2,note2,flag2,dst3,note3,flag3) | ||
| 10083 | #endif | ||
| 10084 | |||
| 9064 | static struct nodelist * | 10085 | static struct nodelist * |
| 9065 | copynodelist(struct nodelist *lp) | 10086 | copynodelist(struct nodelist *lp) |
| 9066 | { | 10087 | { |
| @@ -9072,6 +10093,8 @@ copynodelist(struct nodelist *lp) | |||
| 9072 | *lpp = funcblock; | 10093 | *lpp = funcblock; |
| 9073 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); | 10094 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); |
| 9074 | (*lpp)->n = copynode(lp->n); | 10095 | (*lpp)->n = copynode(lp->n); |
| 10096 | SAVE_PTR2((*lpp)->n, "(*lpp)->next", NO_FREE, | ||
| 10097 | (*lpp)->next, "(*lpp)->next", NO_FREE); | ||
| 9075 | lp = lp->next; | 10098 | lp = lp->next; |
| 9076 | lpp = &(*lpp)->next; | 10099 | lpp = &(*lpp)->next; |
| 9077 | } | 10100 | } |
| @@ -9095,10 +10118,14 @@ copynode(union node *n) | |||
| 9095 | new->ncmd.args = copynode(n->ncmd.args); | 10118 | new->ncmd.args = copynode(n->ncmd.args); |
| 9096 | new->ncmd.assign = copynode(n->ncmd.assign); | 10119 | new->ncmd.assign = copynode(n->ncmd.assign); |
| 9097 | new->ncmd.linno = n->ncmd.linno; | 10120 | new->ncmd.linno = n->ncmd.linno; |
| 10121 | SAVE_PTR3(new->ncmd.redirect, "ncmd.redirect", NO_FREE, | ||
| 10122 | new->ncmd.args, "ncmd.args", NO_FREE, | ||
| 10123 | new->ncmd.assign, "ncmd.assign", NO_FREE); | ||
| 9098 | break; | 10124 | break; |
| 9099 | case NPIPE: | 10125 | case NPIPE: |
| 9100 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | 10126 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); |
| 9101 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; | 10127 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; |
| 10128 | SAVE_PTR(new->npipe.cmdlist, "npipe.cmdlist", NO_FREE); | ||
| 9102 | break; | 10129 | break; |
| 9103 | case NREDIR: | 10130 | case NREDIR: |
| 9104 | case NBACKGND: | 10131 | case NBACKGND: |
| @@ -9106,6 +10133,8 @@ copynode(union node *n) | |||
| 9106 | new->nredir.redirect = copynode(n->nredir.redirect); | 10133 | new->nredir.redirect = copynode(n->nredir.redirect); |
| 9107 | new->nredir.n = copynode(n->nredir.n); | 10134 | new->nredir.n = copynode(n->nredir.n); |
| 9108 | new->nredir.linno = n->nredir.linno; | 10135 | new->nredir.linno = n->nredir.linno; |
| 10136 | SAVE_PTR2(new->nredir.redirect, "nredir.redirect", NO_FREE, | ||
| 10137 | new->nredir.n, "nredir.n", NO_FREE); | ||
| 9109 | break; | 10138 | break; |
| 9110 | case NAND: | 10139 | case NAND: |
| 9111 | case NOR: | 10140 | case NOR: |
| @@ -9114,37 +10143,58 @@ copynode(union node *n) | |||
| 9114 | case NUNTIL: | 10143 | case NUNTIL: |
| 9115 | new->nbinary.ch2 = copynode(n->nbinary.ch2); | 10144 | new->nbinary.ch2 = copynode(n->nbinary.ch2); |
| 9116 | new->nbinary.ch1 = copynode(n->nbinary.ch1); | 10145 | new->nbinary.ch1 = copynode(n->nbinary.ch1); |
| 10146 | SAVE_PTR2(new->nbinary.ch1, "nbinary.ch1", NO_FREE, | ||
| 10147 | new->nbinary.ch2, "nbinary.ch2", NO_FREE); | ||
| 9117 | break; | 10148 | break; |
| 9118 | case NIF: | 10149 | case NIF: |
| 9119 | new->nif.elsepart = copynode(n->nif.elsepart); | 10150 | new->nif.elsepart = copynode(n->nif.elsepart); |
| 9120 | new->nif.ifpart = copynode(n->nif.ifpart); | 10151 | new->nif.ifpart = copynode(n->nif.ifpart); |
| 9121 | new->nif.test = copynode(n->nif.test); | 10152 | new->nif.test = copynode(n->nif.test); |
| 10153 | SAVE_PTR3(new->nif.elsepart, "nif.elsepart", NO_FREE, | ||
| 10154 | new->nif.ifpart, "nif.ifpart", NO_FREE, | ||
| 10155 | new->nif.test, "nif.test", NO_FREE); | ||
| 9122 | break; | 10156 | break; |
| 9123 | case NFOR: | 10157 | case NFOR: |
| 9124 | new->nfor.var = nodeckstrdup(n->nfor.var); | 10158 | new->nfor.var = nodeckstrdup(n->nfor.var); |
| 9125 | new->nfor.body = copynode(n->nfor.body); | 10159 | new->nfor.body = copynode(n->nfor.body); |
| 9126 | new->nfor.args = copynode(n->nfor.args); | 10160 | new->nfor.args = copynode(n->nfor.args); |
| 9127 | new->nfor.linno = n->nfor.linno; | 10161 | new->nfor.linno = n->nfor.linno; |
| 10162 | SAVE_PTR3(new->nfor.var, | ||
| 10163 | xasprintf("nfor.var '%s'", n->nfor.var ?: "NULL"), FREE, | ||
| 10164 | new->nfor.body, "nfor.body", NO_FREE, | ||
| 10165 | new->nfor.args, "nfor.args", NO_FREE); | ||
| 9128 | break; | 10166 | break; |
| 9129 | case NCASE: | 10167 | case NCASE: |
| 9130 | new->ncase.cases = copynode(n->ncase.cases); | 10168 | new->ncase.cases = copynode(n->ncase.cases); |
| 9131 | new->ncase.expr = copynode(n->ncase.expr); | 10169 | new->ncase.expr = copynode(n->ncase.expr); |
| 9132 | new->ncase.linno = n->ncase.linno; | 10170 | new->ncase.linno = n->ncase.linno; |
| 10171 | SAVE_PTR2(new->ncase.cases, "ncase.cases", NO_FREE, | ||
| 10172 | new->ncase.expr, "ncase.expr", NO_FREE); | ||
| 9133 | break; | 10173 | break; |
| 9134 | case NCLIST: | 10174 | case NCLIST: |
| 9135 | new->nclist.body = copynode(n->nclist.body); | 10175 | new->nclist.body = copynode(n->nclist.body); |
| 9136 | new->nclist.pattern = copynode(n->nclist.pattern); | 10176 | new->nclist.pattern = copynode(n->nclist.pattern); |
| 9137 | new->nclist.next = copynode(n->nclist.next); | 10177 | new->nclist.next = copynode(n->nclist.next); |
| 10178 | SAVE_PTR3(new->nclist.body, "nclist.body", NO_FREE, | ||
| 10179 | new->nclist.pattern, "nclist.pattern", NO_FREE, | ||
| 10180 | new->nclist.next, "nclist.next", NO_FREE); | ||
| 9138 | break; | 10181 | break; |
| 9139 | case NDEFUN: | 10182 | case NDEFUN: |
| 9140 | new->ndefun.body = copynode(n->ndefun.body); | 10183 | new->ndefun.body = copynode(n->ndefun.body); |
| 9141 | new->ndefun.text = nodeckstrdup(n->ndefun.text); | 10184 | new->ndefun.text = nodeckstrdup(n->ndefun.text); |
| 9142 | new->ndefun.linno = n->ndefun.linno; | 10185 | new->ndefun.linno = n->ndefun.linno; |
| 10186 | SAVE_PTR2(new->ndefun.body, "ndefun.body", NO_FREE, | ||
| 10187 | new->ndefun.text, | ||
| 10188 | xasprintf("ndefun.text '%s'", n->ndefun.text ?: "NULL"), FREE); | ||
| 9143 | break; | 10189 | break; |
| 9144 | case NARG: | 10190 | case NARG: |
| 9145 | new->narg.backquote = copynodelist(n->narg.backquote); | 10191 | new->narg.backquote = copynodelist(n->narg.backquote); |
| 9146 | new->narg.text = nodeckstrdup(n->narg.text); | 10192 | new->narg.text = nodeckstrdup(n->narg.text); |
| 9147 | new->narg.next = copynode(n->narg.next); | 10193 | new->narg.next = copynode(n->narg.next); |
| 10194 | SAVE_PTR3(new->narg.backquote, "narg.backquote", NO_FREE, | ||
| 10195 | new->narg.text, | ||
| 10196 | xasprintf("narg.text '%s'", n->narg.text ?: "NULL"), FREE, | ||
| 10197 | new->narg.next, "narg.next", NO_FREE); | ||
| 9148 | break; | 10198 | break; |
| 9149 | case NTO: | 10199 | case NTO: |
| 9150 | #if BASH_REDIR_OUTPUT | 10200 | #if BASH_REDIR_OUTPUT |
| @@ -9157,6 +10207,8 @@ copynode(union node *n) | |||
| 9157 | new->nfile.fname = copynode(n->nfile.fname); | 10207 | new->nfile.fname = copynode(n->nfile.fname); |
| 9158 | new->nfile.fd = n->nfile.fd; | 10208 | new->nfile.fd = n->nfile.fd; |
| 9159 | new->nfile.next = copynode(n->nfile.next); | 10209 | new->nfile.next = copynode(n->nfile.next); |
| 10210 | SAVE_PTR2(new->nfile.fname, "nfile.fname", NO_FREE, | ||
| 10211 | new->nfile.next, "nfile.next", NO_FREE); | ||
| 9160 | break; | 10212 | break; |
| 9161 | case NTOFD: | 10213 | case NTOFD: |
| 9162 | case NFROMFD: | 10214 | case NFROMFD: |
| @@ -9164,15 +10216,20 @@ copynode(union node *n) | |||
| 9164 | new->ndup.dupfd = n->ndup.dupfd; | 10216 | new->ndup.dupfd = n->ndup.dupfd; |
| 9165 | new->ndup.fd = n->ndup.fd; | 10217 | new->ndup.fd = n->ndup.fd; |
| 9166 | new->ndup.next = copynode(n->ndup.next); | 10218 | new->ndup.next = copynode(n->ndup.next); |
| 10219 | SAVE_PTR2(new->ndup.vname, "ndup.vname", NO_FREE, | ||
| 10220 | new->ndup.next, "ndup.next", NO_FREE); | ||
| 9167 | break; | 10221 | break; |
| 9168 | case NHERE: | 10222 | case NHERE: |
| 9169 | case NXHERE: | 10223 | case NXHERE: |
| 9170 | new->nhere.doc = copynode(n->nhere.doc); | 10224 | new->nhere.doc = copynode(n->nhere.doc); |
| 9171 | new->nhere.fd = n->nhere.fd; | 10225 | new->nhere.fd = n->nhere.fd; |
| 9172 | new->nhere.next = copynode(n->nhere.next); | 10226 | new->nhere.next = copynode(n->nhere.next); |
| 10227 | SAVE_PTR2(new->nhere.doc, "nhere.doc", NO_FREE, | ||
| 10228 | new->nhere.next, "nhere.next", NO_FREE); | ||
| 9173 | break; | 10229 | break; |
| 9174 | case NNOT: | 10230 | case NNOT: |
| 9175 | new->nnot.com = copynode(n->nnot.com); | 10231 | new->nnot.com = copynode(n->nnot.com); |
| 10232 | SAVE_PTR(new->nnot.com, "nnot.com", NO_FREE); | ||
| 9176 | break; | 10233 | break; |
| 9177 | }; | 10234 | }; |
| 9178 | new->type = n->type; | 10235 | new->type = n->type; |
| @@ -9193,6 +10250,7 @@ copyfunc(union node *n) | |||
| 9193 | f = ckzalloc(blocksize /* + funcstringsize */); | 10250 | f = ckzalloc(blocksize /* + funcstringsize */); |
| 9194 | funcblock = (char *) f + offsetof(struct funcnode, n); | 10251 | funcblock = (char *) f + offsetof(struct funcnode, n); |
| 9195 | funcstring_end = (char *) f + blocksize; | 10252 | funcstring_end = (char *) f + blocksize; |
| 10253 | IF_PLATFORM_MINGW32(fs_size = 0); | ||
| 9196 | copynode(n); | 10254 | copynode(n); |
| 9197 | /* f->count = 0; - ckzalloc did it */ | 10255 | /* f->count = 0; - ckzalloc did it */ |
| 9198 | return f; | 10256 | return f; |
| @@ -9220,12 +10278,15 @@ defun(union node *func) | |||
| 9220 | #define SKIPFUNCDEF (1 << 3) | 10278 | #define SKIPFUNCDEF (1 << 3) |
| 9221 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ | 10279 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ |
| 9222 | static int skipcount; /* number of levels to skip */ | 10280 | static int skipcount; /* number of levels to skip */ |
| 10281 | #if ENABLE_PLATFORM_POSIX | ||
| 9223 | static int loopnest; /* current loop nesting level */ | 10282 | static int loopnest; /* current loop nesting level */ |
| 10283 | #endif | ||
| 9224 | static int funcline; /* starting line number of current function, or 0 if not in a function */ | 10284 | static int funcline; /* starting line number of current function, or 0 if not in a function */ |
| 9225 | 10285 | ||
| 9226 | /* Forward decl way out to parsing code - dotrap needs it */ | 10286 | /* Forward decl way out to parsing code - dotrap needs it */ |
| 9227 | static int evalstring(char *s, int flags); | 10287 | static int evalstring(char *s, int flags); |
| 9228 | 10288 | ||
| 10289 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 9229 | /* Called to execute a trap. | 10290 | /* Called to execute a trap. |
| 9230 | * Single callsite - at the end of evaltree(). | 10291 | * Single callsite - at the end of evaltree(). |
| 9231 | * If we return non-zero, evaltree raises EXEXIT exception. | 10292 | * If we return non-zero, evaltree raises EXEXIT exception. |
| @@ -9284,6 +10345,45 @@ dotrap(void) | |||
| 9284 | savestatus = last_status; | 10345 | savestatus = last_status; |
| 9285 | TRACE(("dotrap returns\n")); | 10346 | TRACE(("dotrap returns\n")); |
| 9286 | } | 10347 | } |
| 10348 | #else | ||
| 10349 | static void | ||
| 10350 | dotrap(void) | ||
| 10351 | { | ||
| 10352 | int status, last_status; | ||
| 10353 | char *p; | ||
| 10354 | |||
| 10355 | if (!pending_int) | ||
| 10356 | return; | ||
| 10357 | |||
| 10358 | status = savestatus; | ||
| 10359 | last_status = status; | ||
| 10360 | if (status < 0) { | ||
| 10361 | status = exitstatus; | ||
| 10362 | savestatus = status; | ||
| 10363 | } | ||
| 10364 | pending_int = 0; | ||
| 10365 | barrier(); | ||
| 10366 | |||
| 10367 | TRACE(("dotrap entered\n")); | ||
| 10368 | if (evalskip) { | ||
| 10369 | pending_int = 1; | ||
| 10370 | return; | ||
| 10371 | } | ||
| 10372 | |||
| 10373 | p = trap[SIGINT]; | ||
| 10374 | if (p) { | ||
| 10375 | TRACE(("sig %d is active, will run handler '%s'\n", SIGINT, p)); | ||
| 10376 | trap_depth++; | ||
| 10377 | evalstring(p, 0); | ||
| 10378 | trap_depth--; | ||
| 10379 | if (evalskip != SKIPFUNC) | ||
| 10380 | exitstatus = status; | ||
| 10381 | } | ||
| 10382 | |||
| 10383 | savestatus = last_status; | ||
| 10384 | TRACE(("dotrap returns\n")); | ||
| 10385 | } | ||
| 10386 | #endif | ||
| 9287 | 10387 | ||
| 9288 | /* forward declarations - evaluation is fairly recursive business... */ | 10388 | /* forward declarations - evaluation is fairly recursive business... */ |
| 9289 | static int evalloop(union node *, int); | 10389 | static int evalloop(union node *, int); |
| @@ -9569,19 +10669,36 @@ evalcase(union node *n, int flags) | |||
| 9569 | static int | 10669 | static int |
| 9570 | evalsubshell(union node *n, int flags) | 10670 | evalsubshell(union node *n, int flags) |
| 9571 | { | 10671 | { |
| 10672 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
| 9572 | struct job *jp; | 10673 | struct job *jp; |
| 9573 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ | 10674 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ |
| 9574 | int status; | 10675 | int status; |
| 9575 | 10676 | ||
| 9576 | errlinno = lineno = n->nredir.linno; | 10677 | errlinno = lineno = n->nredir.linno; |
| 9577 | 10678 | ||
| 10679 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10680 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) { | ||
| 10681 | expredir(n->nredir.redirect); | ||
| 10682 | redirect(n->nredir.redirect, 0); | ||
| 10683 | evaltreenr(n->nredir.n, flags); | ||
| 10684 | /* never returns */ | ||
| 10685 | } | ||
| 10686 | #else | ||
| 9578 | expredir(n->nredir.redirect); | 10687 | expredir(n->nredir.redirect); |
| 9579 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) | 10688 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) |
| 9580 | goto nofork; | 10689 | goto nofork; |
| 10690 | #endif | ||
| 9581 | INT_OFF; | 10691 | INT_OFF; |
| 9582 | if (backgnd == FORK_FG) | 10692 | if (backgnd == FORK_FG) |
| 9583 | get_tty_state(); | 10693 | get_tty_state(); |
| 9584 | jp = makejob(/*n,*/ 1); | 10694 | jp = makejob(/*n,*/ 1); |
| 10695 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10696 | memset(&fs, 0, sizeof(fs)); | ||
| 10697 | fs.fpid = FS_EVALSUBSHELL; | ||
| 10698 | fs.n = n; | ||
| 10699 | fs.flags = flags; | ||
| 10700 | spawn_forkshell(&fs, jp, n, backgnd); | ||
| 10701 | #else | ||
| 9585 | if (forkshell(jp, n, backgnd) == 0) { | 10702 | if (forkshell(jp, n, backgnd) == 0) { |
| 9586 | /* child */ | 10703 | /* child */ |
| 9587 | INT_ON; | 10704 | INT_ON; |
| @@ -9593,6 +10710,7 @@ evalsubshell(union node *n, int flags) | |||
| 9593 | evaltreenr(n->nredir.n, flags); | 10710 | evaltreenr(n->nredir.n, flags); |
| 9594 | /* never returns */ | 10711 | /* never returns */ |
| 9595 | } | 10712 | } |
| 10713 | #endif | ||
| 9596 | /* parent */ | 10714 | /* parent */ |
| 9597 | status = 0; | 10715 | status = 0; |
| 9598 | if (backgnd == FORK_FG) | 10716 | if (backgnd == FORK_FG) |
| @@ -9673,6 +10791,7 @@ expredir(union node *n) | |||
| 9673 | static int | 10791 | static int |
| 9674 | evalpipe(union node *n, int flags) | 10792 | evalpipe(union node *n, int flags) |
| 9675 | { | 10793 | { |
| 10794 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
| 9676 | struct job *jp; | 10795 | struct job *jp; |
| 9677 | struct nodelist *lp; | 10796 | struct nodelist *lp; |
| 9678 | int pipelen; | 10797 | int pipelen; |
| @@ -9699,6 +10818,16 @@ evalpipe(union node *n, int flags) | |||
| 9699 | ash_msg_and_raise_perror("can't create pipe"); | 10818 | ash_msg_and_raise_perror("can't create pipe"); |
| 9700 | } | 10819 | } |
| 9701 | } | 10820 | } |
| 10821 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10822 | memset(&fs, 0, sizeof(fs)); | ||
| 10823 | fs.fpid = FS_EVALPIPE; | ||
| 10824 | fs.flags = flags; | ||
| 10825 | fs.n = lp->n; | ||
| 10826 | fs.fd[0] = pip[0]; | ||
| 10827 | fs.fd[1] = pip[1]; | ||
| 10828 | fs.fd[2] = prevfd; | ||
| 10829 | spawn_forkshell(&fs, jp, lp->n, n->npipe.pipe_backgnd); | ||
| 10830 | #else | ||
| 9702 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { | 10831 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { |
| 9703 | /* child */ | 10832 | /* child */ |
| 9704 | INT_ON; | 10833 | INT_ON; |
| @@ -9716,6 +10845,7 @@ evalpipe(union node *n, int flags) | |||
| 9716 | evaltreenr(lp->n, flags); | 10845 | evaltreenr(lp->n, flags); |
| 9717 | /* never returns */ | 10846 | /* never returns */ |
| 9718 | } | 10847 | } |
| 10848 | #endif | ||
| 9719 | /* parent */ | 10849 | /* parent */ |
| 9720 | if (prevfd >= 0) | 10850 | if (prevfd >= 0) |
| 9721 | close(prevfd); | 10851 | close(prevfd); |
| @@ -9773,6 +10903,9 @@ setinteractive(int on) | |||
| 9773 | line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); | 10903 | line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); |
| 9774 | # if ENABLE_FEATURE_TAB_COMPLETION | 10904 | # if ENABLE_FEATURE_TAB_COMPLETION |
| 9775 | line_input_state->get_exe_name = ash_command_name; | 10905 | line_input_state->get_exe_name = ash_command_name; |
| 10906 | # if ENABLE_ASH_GLOB_OPTIONS | ||
| 10907 | line_input_state->sh_accept_glob = ash_accept_glob; | ||
| 10908 | # endif | ||
| 9776 | # endif | 10909 | # endif |
| 9777 | # if EDITING_HAS_sh_get_var | 10910 | # if EDITING_HAS_sh_get_var |
| 9778 | line_input_state->sh_get_var = lookupvar; | 10911 | line_input_state->sh_get_var = lookupvar; |
| @@ -9800,6 +10933,12 @@ optschanged(void) | |||
| 9800 | #else | 10933 | #else |
| 9801 | viflag = 0; /* forcibly keep the option off */ | 10934 | viflag = 0; /* forcibly keep the option off */ |
| 9802 | #endif | 10935 | #endif |
| 10936 | #if ENABLE_ASH_NOCONSOLE | ||
| 10937 | hide_console(noconsole); | ||
| 10938 | #endif | ||
| 10939 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10940 | setwinxp(winxp); | ||
| 10941 | #endif | ||
| 9803 | } | 10942 | } |
| 9804 | 10943 | ||
| 9805 | struct localvar_list { | 10944 | struct localvar_list { |
| @@ -9819,6 +10958,9 @@ poplocalvars(int keep) | |||
| 9819 | struct localvar_list *ll; | 10958 | struct localvar_list *ll; |
| 9820 | struct localvar *lvp, *next; | 10959 | struct localvar *lvp, *next; |
| 9821 | struct var *vp; | 10960 | struct var *vp; |
| 10961 | #if ENABLE_PLATFORM_MINGW32 | ||
| 10962 | int var_type; | ||
| 10963 | #endif | ||
| 9822 | 10964 | ||
| 9823 | INT_OFF; | 10965 | INT_OFF; |
| 9824 | ll = localvar_stack; | 10966 | ll = localvar_stack; |
| @@ -9861,6 +11003,17 @@ poplocalvars(int keep) | |||
| 9861 | free((char*)vp->var_text); | 11003 | free((char*)vp->var_text); |
| 9862 | vp->flags = lvp->flags; | 11004 | vp->flags = lvp->flags; |
| 9863 | vp->var_text = lvp->text; | 11005 | vp->var_text = lvp->text; |
| 11006 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11007 | var_type = is_bb_var(lvp->text); | ||
| 11008 | if (var_type == BB_VAR_ASSIGN && (lvp->flags & VEXPORT)) | ||
| 11009 | putenv(lvp->text); | ||
| 11010 | else if (var_type) { | ||
| 11011 | char *var = xstrdup(lvp->text); | ||
| 11012 | *strchrnul(var, '=') = '\0'; | ||
| 11013 | unsetenv(var); | ||
| 11014 | free(var); | ||
| 11015 | } | ||
| 11016 | #endif | ||
| 9864 | } | 11017 | } |
| 9865 | free(lvp); | 11018 | free(lvp); |
| 9866 | } | 11019 | } |
| @@ -10138,6 +11291,9 @@ static int readcmd(int, char **) FAST_FUNC; | |||
| 10138 | static int setcmd(int, char **) FAST_FUNC; | 11291 | static int setcmd(int, char **) FAST_FUNC; |
| 10139 | static int shiftcmd(int, char **) FAST_FUNC; | 11292 | static int shiftcmd(int, char **) FAST_FUNC; |
| 10140 | static int timescmd(int, char **) FAST_FUNC; | 11293 | static int timescmd(int, char **) FAST_FUNC; |
| 11294 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11295 | static int titlecmd(int, char **) FAST_FUNC; | ||
| 11296 | #endif | ||
| 10141 | static int trapcmd(int, char **) FAST_FUNC; | 11297 | static int trapcmd(int, char **) FAST_FUNC; |
| 10142 | static int umaskcmd(int, char **) FAST_FUNC; | 11298 | static int umaskcmd(int, char **) FAST_FUNC; |
| 10143 | static int unsetcmd(int, char **) FAST_FUNC; | 11299 | static int unsetcmd(int, char **) FAST_FUNC; |
| @@ -10210,7 +11366,7 @@ static const struct builtincmd builtintab[] = { | |||
| 10210 | #if MAX_HISTORY | 11366 | #if MAX_HISTORY |
| 10211 | { BUILTIN_NOSPEC "history" , historycmd }, | 11367 | { BUILTIN_NOSPEC "history" , historycmd }, |
| 10212 | #endif | 11368 | #endif |
| 10213 | #if JOBS | 11369 | #if JOBS || JOBS_WIN32 |
| 10214 | { BUILTIN_REGULAR "jobs" , jobscmd }, | 11370 | { BUILTIN_REGULAR "jobs" , jobscmd }, |
| 10215 | { BUILTIN_REGULAR "kill" , killcmd }, | 11371 | { BUILTIN_REGULAR "kill" , killcmd }, |
| 10216 | #endif | 11372 | #endif |
| @@ -10237,6 +11393,9 @@ static const struct builtincmd builtintab[] = { | |||
| 10237 | { BUILTIN_REGULAR "test" , testcmd }, | 11393 | { BUILTIN_REGULAR "test" , testcmd }, |
| 10238 | #endif | 11394 | #endif |
| 10239 | { BUILTIN_SPEC_REG "times" , timescmd }, | 11395 | { BUILTIN_SPEC_REG "times" , timescmd }, |
| 11396 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11397 | { BUILTIN_REGULAR "title" , titlecmd }, | ||
| 11398 | #endif | ||
| 10240 | { BUILTIN_SPEC_REG "trap" , trapcmd }, | 11399 | { BUILTIN_SPEC_REG "trap" , trapcmd }, |
| 10241 | { BUILTIN_REGULAR "true" , truecmd }, | 11400 | { BUILTIN_REGULAR "true" , truecmd }, |
| 10242 | { BUILTIN_REGULAR "type" , typecmd }, | 11401 | { BUILTIN_REGULAR "type" , typecmd }, |
| @@ -10255,7 +11414,7 @@ static const struct builtincmd builtintab[] = { | |||
| 10255 | /* [ */ 1 * ENABLE_ASH_TEST + \ | 11414 | /* [ */ 1 * ENABLE_ASH_TEST + \ |
| 10256 | /* [[ */ 1 * BASH_TEST2 + \ | 11415 | /* [[ */ 1 * BASH_TEST2 + \ |
| 10257 | /* alias */ 1 * ENABLE_ASH_ALIAS + \ | 11416 | /* alias */ 1 * ENABLE_ASH_ALIAS + \ |
| 10258 | /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \ | 11417 | /* bg */ 1 * JOBS + \ |
| 10259 | /* break cd cddir */ 3) | 11418 | /* break cd cddir */ 3) |
| 10260 | #define EVALCMD (COMMANDCMD + \ | 11419 | #define EVALCMD (COMMANDCMD + \ |
| 10261 | /* command */ 1 * ENABLE_ASH_CMDCMD + \ | 11420 | /* command */ 1 * ENABLE_ASH_CMDCMD + \ |
| @@ -10336,6 +11495,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 10336 | * as POSIX mandates */ | 11495 | * as POSIX mandates */ |
| 10337 | return back_exitstatus; | 11496 | return back_exitstatus; |
| 10338 | } | 11497 | } |
| 11498 | |||
| 10339 | static int | 11499 | static int |
| 10340 | evalcommand(union node *cmd, int flags) | 11500 | evalcommand(union node *cmd, int flags) |
| 10341 | { | 11501 | { |
| @@ -10546,9 +11706,11 @@ evalcommand(union node *cmd, int flags) | |||
| 10546 | 11706 | ||
| 10547 | default: { | 11707 | default: { |
| 10548 | 11708 | ||
| 11709 | //TODO: find a better solution for Windows on ARM than ignoring NOFORK | ||
| 10549 | #if ENABLE_FEATURE_SH_STANDALONE \ | 11710 | #if ENABLE_FEATURE_SH_STANDALONE \ |
| 10550 | && ENABLE_FEATURE_SH_NOFORK \ | 11711 | && ENABLE_FEATURE_SH_NOFORK \ |
| 10551 | && NUM_APPLETS > 1 | 11712 | && NUM_APPLETS > 1 \ |
| 11713 | && !(defined(_ARM64_) && !defined(_UCRT) && ENABLE_PLATFORM_MINGW32) | ||
| 10552 | /* (1) BUG: if variables are set, we need to fork, or save/restore them | 11714 | /* (1) BUG: if variables are set, we need to fork, or save/restore them |
| 10553 | * around run_nofork_applet() call. | 11715 | * around run_nofork_applet() call. |
| 10554 | * (2) Should this check also be done in forkshell()? | 11716 | * (2) Should this check also be done in forkshell()? |
| @@ -10570,6 +11732,9 @@ evalcommand(union node *cmd, int flags) | |||
| 10570 | * and/or wait for user input ineligible for NOFORK: | 11732 | * and/or wait for user input ineligible for NOFORK: |
| 10571 | * for example, "yes" or "rm" (rm -i waits for input). | 11733 | * for example, "yes" or "rm" (rm -i waits for input). |
| 10572 | */ | 11734 | */ |
| 11735 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11736 | argv[0] = (char *)bb_basename(argv[0]); | ||
| 11737 | #endif | ||
| 10573 | exitstatus = run_nofork_applet(applet_no, argv); | 11738 | exitstatus = run_nofork_applet(applet_no, argv); |
| 10574 | environ = sv_environ; | 11739 | environ = sv_environ; |
| 10575 | /* | 11740 | /* |
| @@ -10589,6 +11754,22 @@ evalcommand(union node *cmd, int flags) | |||
| 10589 | * in a script or a subshell does not need forking, | 11754 | * in a script or a subshell does not need forking, |
| 10590 | * we can just exec it. | 11755 | * we can just exec it. |
| 10591 | */ | 11756 | */ |
| 11757 | #if ENABLE_PLATFORM_MINGW32 | ||
| 11758 | if (!(flags & EV_EXIT) || may_have_traps IF_SUW32(|| delayexit)) { | ||
| 11759 | /* No, forking off a child is necessary */ | ||
| 11760 | struct forkshell fs; | ||
| 11761 | |||
| 11762 | INT_OFF; | ||
| 11763 | memset(&fs, 0, sizeof(fs)); | ||
| 11764 | fs.fpid = FS_SHELLEXEC; | ||
| 11765 | fs.argv = argv; | ||
| 11766 | fs.path = (char*)path; | ||
| 11767 | fs.fd[0] = cmdentry.u.index; | ||
| 11768 | jp = makejob(/*cmd,*/ 1); | ||
| 11769 | spawn_forkshell(&fs, jp, cmd, FORK_FG); | ||
| 11770 | break; | ||
| 11771 | } | ||
| 11772 | #else | ||
| 10592 | if (!(flags & EV_EXIT) || may_have_traps) { | 11773 | if (!(flags & EV_EXIT) || may_have_traps) { |
| 10593 | /* No, forking off a child is necessary */ | 11774 | /* No, forking off a child is necessary */ |
| 10594 | INT_OFF; | 11775 | INT_OFF; |
| @@ -10602,6 +11783,7 @@ evalcommand(union node *cmd, int flags) | |||
| 10602 | FORCE_INT_ON; | 11783 | FORCE_INT_ON; |
| 10603 | /* fall through to exec'ing external program */ | 11784 | /* fall through to exec'ing external program */ |
| 10604 | } | 11785 | } |
| 11786 | #endif | ||
| 10605 | shellexec(argv[0], argv, path, cmdentry.u.index); | 11787 | shellexec(argv[0], argv, path, cmdentry.u.index); |
| 10606 | /* NOTREACHED */ | 11788 | /* NOTREACHED */ |
| 10607 | } /* default */ | 11789 | } /* default */ |
| @@ -10814,6 +11996,54 @@ static void popstring(void) | |||
| 10814 | INT_ON; | 11996 | INT_ON; |
| 10815 | } | 11997 | } |
| 10816 | 11998 | ||
| 11999 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12000 | /* | ||
| 12001 | * Wrapper around nonblock_immune_read() to remove CRs, but only from | ||
| 12002 | * CRLF pairs. The tricky part is handling a CR at the end of the buffer. | ||
| 12003 | */ | ||
| 12004 | static inline ssize_t | ||
| 12005 | nonblock_immune_wrapper(struct parsefile *pf, char *buffer, size_t count) | ||
| 12006 | { | ||
| 12007 | int nr, injected_cr; | ||
| 12008 | |||
| 12009 | // Inject unprocessed CR from previous read into the buffer. | ||
| 12010 | if (pf->cr) | ||
| 12011 | *buffer = '\r'; | ||
| 12012 | retry: | ||
| 12013 | nr = nonblock_immune_read(pf->pf_fd, buffer + pf->cr, count - pf->cr); | ||
| 12014 | if (nr < 0) | ||
| 12015 | return nr; | ||
| 12016 | |||
| 12017 | injected_cr = pf->cr; | ||
| 12018 | nr += pf->cr; | ||
| 12019 | pf->cr = 0; | ||
| 12020 | |||
| 12021 | if (nr > 0) { | ||
| 12022 | nr = remove_cr(buffer, nr); | ||
| 12023 | // remove_cr() won't reduce size to zero, so [nr - 1] is OK. | ||
| 12024 | if (buffer[nr - 1] == '\r') { | ||
| 12025 | if (nr > 1) { | ||
| 12026 | // Ignore trailing CR for now: we'll deal with it later. | ||
| 12027 | pf->cr = 1; | ||
| 12028 | --nr; | ||
| 12029 | } else if (injected_cr) { // nr == 1 | ||
| 12030 | // Buffer only contains an injected CR. This means the | ||
| 12031 | // read returned EOF. Return the buffer as-is. The | ||
| 12032 | // next call will detect EOF. | ||
| 12033 | } else { | ||
| 12034 | // Buffer only contains a CR from the most recent read. | ||
| 12035 | // Try another read, treating the CR as injected. We'll | ||
| 12036 | // either get more characters or EOF. Either way we | ||
| 12037 | // won't end up here again. | ||
| 12038 | pf->cr = 1; | ||
| 12039 | goto retry; | ||
| 12040 | } | ||
| 12041 | } | ||
| 12042 | } | ||
| 12043 | return nr; | ||
| 12044 | } | ||
| 12045 | #endif | ||
| 12046 | |||
| 10817 | static int | 12047 | static int |
| 10818 | preadfd(void) | 12048 | preadfd(void) |
| 10819 | { | 12049 | { |
| @@ -10824,7 +12054,11 @@ preadfd(void) | |||
| 10824 | #if ENABLE_FEATURE_EDITING | 12054 | #if ENABLE_FEATURE_EDITING |
| 10825 | /* retry: */ | 12055 | /* retry: */ |
| 10826 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) | 12056 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) |
| 12057 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12058 | nr = nonblock_immune_wrapper(g_parsefile, buf, IBUFSIZ - 1); | ||
| 12059 | #else | ||
| 10827 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); | 12060 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
| 12061 | #endif | ||
| 10828 | else { | 12062 | else { |
| 10829 | # if ENABLE_ASH_IDLE_TIMEOUT | 12063 | # if ENABLE_ASH_IDLE_TIMEOUT |
| 10830 | int timeout = -1; | 12064 | int timeout = -1; |
| @@ -10863,12 +12097,21 @@ preadfd(void) | |||
| 10863 | INT_ON; /* here non-blocked SIGINT will longjmp */ | 12097 | INT_ON; /* here non-blocked SIGINT will longjmp */ |
| 10864 | if (nr == 0) { | 12098 | if (nr == 0) { |
| 10865 | /* ^C pressed, "convert" to SIGINT */ | 12099 | /* ^C pressed, "convert" to SIGINT */ |
| 12100 | # if !ENABLE_PLATFORM_MINGW32 | ||
| 10866 | write(STDOUT_FILENO, "^C\n", 3); | 12101 | write(STDOUT_FILENO, "^C\n", 3); |
| 10867 | raise(SIGINT); /* here non-blocked SIGINT will longjmp */ | 12102 | raise(SIGINT); /* here non-blocked SIGINT will longjmp */ |
| 10868 | /* raise(SIGINT) did not work! (e.g. if SIGINT | 12103 | /* raise(SIGINT) did not work! (e.g. if SIGINT |
| 10869 | * is SIG_IGNed on startup, it stays SIG_IGNed) | 12104 | * is SIG_IGNed on startup, it stays SIG_IGNed) |
| 10870 | */ | 12105 | */ |
| 12106 | # else | ||
| 12107 | raise_interrupt(); | ||
| 12108 | write(STDOUT_FILENO, "^C\n", 3); | ||
| 12109 | # endif | ||
| 10871 | if (trap[SIGINT]) { | 12110 | if (trap[SIGINT]) { |
| 12111 | # if ENABLE_PLATFORM_MINGW32 | ||
| 12112 | pending_int = 1; | ||
| 12113 | dotrap(); | ||
| 12114 | # endif | ||
| 10872 | empty_line_input: | 12115 | empty_line_input: |
| 10873 | buf[0] = '\n'; | 12116 | buf[0] = '\n'; |
| 10874 | buf[1] = '\0'; | 12117 | buf[1] = '\0'; |
| @@ -10897,7 +12140,11 @@ preadfd(void) | |||
| 10897 | } | 12140 | } |
| 10898 | } | 12141 | } |
| 10899 | #else | 12142 | #else |
| 12143 | # if ENABLE_PLATFORM_MINGW32 | ||
| 12144 | nr = nonblock_immune_wrapper(g_parsefile, buf, IBUFSIZ - 1); | ||
| 12145 | # else | ||
| 10900 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); | 12146 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
| 12147 | # endif | ||
| 10901 | #endif | 12148 | #endif |
| 10902 | 12149 | ||
| 10903 | #if 0 /* disabled: nonblock_immune_read() handles this problem */ | 12150 | #if 0 /* disabled: nonblock_immune_read() handles this problem */ |
| @@ -11196,6 +12443,7 @@ popallfiles(void) | |||
| 11196 | unwindfiles(&basepf); | 12443 | unwindfiles(&basepf); |
| 11197 | } | 12444 | } |
| 11198 | 12445 | ||
| 12446 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 11199 | /* | 12447 | /* |
| 11200 | * Close the file(s) that the shell is reading commands from. Called | 12448 | * Close the file(s) that the shell is reading commands from. Called |
| 11201 | * after a fork is done. | 12449 | * after a fork is done. |
| @@ -11209,6 +12457,7 @@ closescript(void) | |||
| 11209 | g_parsefile->pf_fd = 0; | 12457 | g_parsefile->pf_fd = 0; |
| 11210 | } | 12458 | } |
| 11211 | } | 12459 | } |
| 12460 | #endif | ||
| 11212 | 12461 | ||
| 11213 | /* | 12462 | /* |
| 11214 | * Like setinputfile, but takes an open file descriptor. Call this with | 12463 | * Like setinputfile, but takes an open file descriptor. Call this with |
| @@ -11445,8 +12694,19 @@ options(int *login_sh) | |||
| 11445 | int val; | 12694 | int val; |
| 11446 | int c; | 12695 | int c; |
| 11447 | 12696 | ||
| 11448 | if (login_sh != NULL) /* if we came from startup code */ | 12697 | #if ENABLE_ASH_NOCONSOLE |
| 12698 | noconsole = console_state(); | ||
| 12699 | #endif | ||
| 12700 | if (login_sh != NULL) { /* if we came from startup code */ | ||
| 11449 | minusc = NULL; | 12701 | minusc = NULL; |
| 12702 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12703 | dirarg = NULL; | ||
| 12704 | title = NULL; | ||
| 12705 | # if ENABLE_SUW32 | ||
| 12706 | delayexit = 0; | ||
| 12707 | # endif | ||
| 12708 | #endif | ||
| 12709 | } | ||
| 11450 | while ((p = *argptr) != NULL) { | 12710 | while ((p = *argptr) != NULL) { |
| 11451 | c = *p++; | 12711 | c = *p++; |
| 11452 | if (c != '-' && c != '+') | 12712 | if (c != '-' && c != '+') |
| @@ -11476,6 +12736,31 @@ options(int *login_sh) | |||
| 11476 | cflag = 1; | 12736 | cflag = 1; |
| 11477 | continue; | 12737 | continue; |
| 11478 | } | 12738 | } |
| 12739 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12740 | /* Undocumented flags; | ||
| 12741 | * -d force current directory | ||
| 12742 | * -t title to display in console window | ||
| 12743 | * -N prompt user before exit | ||
| 12744 | * Must appear before -s or -c. */ | ||
| 12745 | if (c == 'd' && val == 1) { | ||
| 12746 | if (*argptr == NULL) | ||
| 12747 | ash_msg_and_raise_error(bb_msg_requires_arg, "-d"); | ||
| 12748 | dirarg = *argptr++; | ||
| 12749 | continue; | ||
| 12750 | } | ||
| 12751 | if (c == 't' && val == 1) { | ||
| 12752 | if (*argptr == NULL) | ||
| 12753 | ash_msg_and_raise_error(bb_msg_requires_arg, "-t"); | ||
| 12754 | title = *argptr++; | ||
| 12755 | continue; | ||
| 12756 | } | ||
| 12757 | # if ENABLE_SUW32 | ||
| 12758 | if (c == 'N' && val == 1) { | ||
| 12759 | delayexit = 1; | ||
| 12760 | continue; | ||
| 12761 | } | ||
| 12762 | # endif | ||
| 12763 | #endif | ||
| 11479 | if (c == 's') { /* -s, +s */ | 12764 | if (c == 's') { /* -s, +s */ |
| 11480 | sflag = 1; | 12765 | sflag = 1; |
| 11481 | continue; | 12766 | continue; |
| @@ -13503,6 +14788,9 @@ evalstring(char *s, int flags) | |||
| 13503 | int status; | 14788 | int status; |
| 13504 | 14789 | ||
| 13505 | s = sstrdup(s); | 14790 | s = sstrdup(s); |
| 14791 | #if ENABLE_PLATFORM_MINGW32 | ||
| 14792 | remove_cr(s, strlen(s)+1); | ||
| 14793 | #endif | ||
| 13506 | setinputstring(s); | 14794 | setinputstring(s); |
| 13507 | setstackmark(&smark); | 14795 | setstackmark(&smark); |
| 13508 | 14796 | ||
| @@ -13590,7 +14878,7 @@ cmdloop(int top) | |||
| 13590 | int skip; | 14878 | int skip; |
| 13591 | 14879 | ||
| 13592 | setstackmark(&smark); | 14880 | setstackmark(&smark); |
| 13593 | #if JOBS | 14881 | #if JOBS || JOBS_WIN32 |
| 13594 | if (doing_jobctl) | 14882 | if (doing_jobctl) |
| 13595 | showjobs(SHOW_CHANGED|SHOW_STDERR); | 14883 | showjobs(SHOW_CHANGED|SHOW_STDERR); |
| 13596 | #endif | 14884 | #endif |
| @@ -13598,6 +14886,9 @@ cmdloop(int top) | |||
| 13598 | if (iflag && top) { | 14886 | if (iflag && top) { |
| 13599 | inter++; | 14887 | inter++; |
| 13600 | chkmail(); | 14888 | chkmail(); |
| 14889 | #if ENABLE_PLATFORM_MINGW32 | ||
| 14890 | terminal_mode(TRUE); | ||
| 14891 | #endif | ||
| 13601 | } | 14892 | } |
| 13602 | n = parsecmd(inter); | 14893 | n = parsecmd(inter); |
| 13603 | #if DEBUG | 14894 | #if DEBUG |
| @@ -13621,8 +14912,10 @@ cmdloop(int top) | |||
| 13621 | } else { | 14912 | } else { |
| 13622 | int i; | 14913 | int i; |
| 13623 | 14914 | ||
| 14915 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 13624 | /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */ | 14916 | /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */ |
| 13625 | job_warning >>= 1; | 14917 | job_warning >>= 1; |
| 14918 | #endif | ||
| 13626 | numeof = 0; | 14919 | numeof = 0; |
| 13627 | i = evaltree(n, 0); | 14920 | i = evaltree(n, 0); |
| 13628 | if (n) | 14921 | if (n) |
| @@ -13652,7 +14945,7 @@ find_dot_file(char *basename) | |||
| 13652 | int len; | 14945 | int len; |
| 13653 | 14946 | ||
| 13654 | /* don't try this for absolute or relative paths */ | 14947 | /* don't try this for absolute or relative paths */ |
| 13655 | if (strchr(basename, '/')) | 14948 | if (strchr(basename, '/') IF_PLATFORM_MINGW32(|| strchr(basename, '\\'))) |
| 13656 | return basename; | 14949 | return basename; |
| 13657 | 14950 | ||
| 13658 | path = pathval(); | 14951 | path = pathval(); |
| @@ -13781,6 +15074,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
| 13781 | struct builtincmd *bcmd; | 15074 | struct builtincmd *bcmd; |
| 13782 | int len; | 15075 | int len; |
| 13783 | 15076 | ||
| 15077 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 13784 | /* If name contains a slash, don't use PATH or hash table */ | 15078 | /* If name contains a slash, don't use PATH or hash table */ |
| 13785 | if (strchr(name, '/') != NULL) { | 15079 | if (strchr(name, '/') != NULL) { |
| 13786 | entry->u.index = -1; | 15080 | entry->u.index = -1; |
| @@ -13797,6 +15091,35 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
| 13797 | entry->cmdtype = CMDNORMAL; | 15091 | entry->cmdtype = CMDNORMAL; |
| 13798 | return; | 15092 | return; |
| 13799 | } | 15093 | } |
| 15094 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
| 15095 | /* If name contains a slash or drive prefix, don't use PATH or hash table */ | ||
| 15096 | if (has_path(name)) { | ||
| 15097 | entry->u.index = -1; | ||
| 15098 | entry->cmdtype = CMDNORMAL; | ||
| 15099 | fullname = stack_add_ext_space(name); | ||
| 15100 | if (add_win32_extension(fullname)) { | ||
| 15101 | return; | ||
| 15102 | } else if (unix_path(name)) { | ||
| 15103 | name = (char *)bb_basename(name); | ||
| 15104 | if ( | ||
| 15105 | # if ENABLE_FEATURE_SH_STANDALONE | ||
| 15106 | find_applet_by_name_for_sh(name, path) >= 0 || | ||
| 15107 | # endif | ||
| 15108 | !find_builtin(bb_basename(name)) | ||
| 15109 | ) { | ||
| 15110 | act |= DO_NOFUNC; | ||
| 15111 | } else if (act & DO_ABS) { | ||
| 15112 | entry->cmdtype = CMDUNKNOWN; | ||
| 15113 | return; | ||
| 15114 | } | ||
| 15115 | } else if (act & DO_ABS) { | ||
| 15116 | entry->cmdtype = CMDUNKNOWN; | ||
| 15117 | return; | ||
| 15118 | } else { | ||
| 15119 | return; | ||
| 15120 | } | ||
| 15121 | } | ||
| 15122 | #endif /* ENABLE_PLATFORM_MINGW32 */ | ||
| 13800 | 15123 | ||
| 13801 | /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ | 15124 | /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ |
| 13802 | 15125 | ||
| @@ -13851,7 +15174,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
| 13851 | 15174 | ||
| 13852 | #if ENABLE_FEATURE_SH_STANDALONE | 15175 | #if ENABLE_FEATURE_SH_STANDALONE |
| 13853 | { | 15176 | { |
| 13854 | int applet_no = find_applet_by_name(name); | 15177 | int applet_no = find_applet_by_name_for_sh(name, path); |
| 13855 | if (applet_no >= 0) { | 15178 | if (applet_no >= 0) { |
| 13856 | entry->cmdtype = CMDNORMAL; | 15179 | entry->cmdtype = CMDNORMAL; |
| 13857 | entry->u.index = -2 - applet_no; | 15180 | entry->u.index = -2 - applet_no; |
| @@ -13890,12 +15213,15 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
| 13890 | } | 15213 | } |
| 13891 | } | 15214 | } |
| 13892 | /* if rehash, don't redo absolute path names */ | 15215 | /* if rehash, don't redo absolute path names */ |
| 13893 | if (fullname[0] == '/' && idx <= prev) { | 15216 | if (!is_relative_path(fullname) && idx <= prev) { |
| 13894 | if (idx < prev) | 15217 | if (idx < prev) |
| 13895 | continue; | 15218 | continue; |
| 13896 | TRACE(("searchexec \"%s\": no change\n", name)); | 15219 | TRACE(("searchexec \"%s\": no change\n", name)); |
| 13897 | goto success; | 15220 | goto success; |
| 13898 | } | 15221 | } |
| 15222 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15223 | add_win32_extension(fullname); | ||
| 15224 | #endif | ||
| 13899 | while (stat(fullname, &statb) < 0) { | 15225 | while (stat(fullname, &statb) < 0) { |
| 13900 | #ifdef SYSV | 15226 | #ifdef SYSV |
| 13901 | if (errno == EINTR) | 15227 | if (errno == EINTR) |
| @@ -14034,19 +15360,45 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14034 | if (LONE_DASH(action)) | 15360 | if (LONE_DASH(action)) |
| 14035 | action = NULL; | 15361 | action = NULL; |
| 14036 | else { | 15362 | else { |
| 15363 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14037 | if (action[0]) /* not NULL and not "" and not "-" */ | 15364 | if (action[0]) /* not NULL and not "" and not "-" */ |
| 14038 | may_have_traps = 1; | 15365 | may_have_traps = 1; |
| 15366 | #endif | ||
| 14039 | action = ckstrdup(action); | 15367 | action = ckstrdup(action); |
| 14040 | } | 15368 | } |
| 14041 | } | 15369 | } |
| 14042 | free(trap[signo]); | 15370 | free(trap[signo]); |
| 14043 | trap[signo] = action; | 15371 | trap[signo] = action; |
| 15372 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15373 | if (signo == SIGINT) { | ||
| 15374 | // trap '' INT disables Ctrl-C, anything else enables it | ||
| 15375 | if (action && action[0] == '\0') { | ||
| 15376 | SetConsoleCtrlHandler(NULL, TRUE); | ||
| 15377 | # if ENABLE_FEATURE_EDITING | ||
| 15378 | if (line_input_state) { | ||
| 15379 | line_input_state->flags |= IGNORE_CTRL_C; | ||
| 15380 | } | ||
| 15381 | # endif | ||
| 15382 | } else { | ||
| 15383 | SetConsoleCtrlHandler(NULL, FALSE); | ||
| 15384 | # if ENABLE_FEATURE_EDITING | ||
| 15385 | if (line_input_state) { | ||
| 15386 | line_input_state->flags &= ~IGNORE_CTRL_C; | ||
| 15387 | } | ||
| 15388 | # endif | ||
| 15389 | } | ||
| 15390 | } | ||
| 15391 | #else | ||
| 14044 | if (signo != 0 && signo < NSIG) | 15392 | if (signo != 0 && signo < NSIG) |
| 14045 | setsignal(signo); | 15393 | setsignal(signo); |
| 15394 | #endif | ||
| 14046 | INT_ON; | 15395 | INT_ON; |
| 14047 | next: | 15396 | next: |
| 14048 | ap++; | 15397 | ap++; |
| 14049 | } | 15398 | } |
| 15399 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15400 | may_have_traps = trap[SIGINT] && trap[SIGINT][0] != '\0'; | ||
| 15401 | #endif | ||
| 14050 | return exitcode; | 15402 | return exitcode; |
| 14051 | } | 15403 | } |
| 14052 | 15404 | ||
| @@ -14075,10 +15427,12 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14075 | { | 15427 | { |
| 14076 | const char *a = applet_names; | 15428 | const char *a = applet_names; |
| 14077 | while (*a) { | 15429 | while (*a) { |
| 14078 | col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a); | 15430 | if (prefer_applet(a, pathval())) { |
| 14079 | if (col > 60) { | 15431 | col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a); |
| 14080 | out1fmt("\n"); | 15432 | if (col > 60) { |
| 14081 | col = 0; | 15433 | out1fmt("\n"); |
| 15434 | col = 0; | ||
| 15435 | } | ||
| 14082 | } | 15436 | } |
| 14083 | while (*a++ != '\0') | 15437 | while (*a++ != '\0') |
| 14084 | continue; | 15438 | continue; |
| @@ -14140,7 +15494,24 @@ exportcmd(int argc UNUSED_PARAM, char **argv) | |||
| 14140 | } else { | 15494 | } else { |
| 14141 | vp = *findvar(hashvar(name), name); | 15495 | vp = *findvar(hashvar(name), name); |
| 14142 | if (vp) { | 15496 | if (vp) { |
| 15497 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15498 | if (is_bb_var(name) == BB_VAR_EXACT) { | ||
| 15499 | if (flag_off == ~VEXPORT) | ||
| 15500 | unsetenv(name); | ||
| 15501 | else if (flag == VEXPORT && !(vp->flags & VUNSET)) | ||
| 15502 | putenv(vp->var_text); | ||
| 15503 | } | ||
| 15504 | #endif | ||
| 14143 | vp->flags = ((vp->flags | flag) & flag_off); | 15505 | vp->flags = ((vp->flags | flag) & flag_off); |
| 15506 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15507 | /* Unexporting a variable imported from the | ||
| 15508 | * environment restores its original value and | ||
| 15509 | * removes the VIMPORT flag. */ | ||
| 15510 | if ((vp->flags & VIMPORT) && (flag_off == ~VEXPORT)) { | ||
| 15511 | vp->flags &= ~VIMPORT; | ||
| 15512 | p = getenv(name); | ||
| 15513 | } else | ||
| 15514 | #endif | ||
| 14144 | continue; | 15515 | continue; |
| 14145 | } | 15516 | } |
| 14146 | } | 15517 | } |
| @@ -14231,6 +15602,21 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14231 | return 0; | 15602 | return 0; |
| 14232 | } | 15603 | } |
| 14233 | 15604 | ||
| 15605 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15606 | static int FAST_FUNC | ||
| 15607 | titlecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | ||
| 15608 | { | ||
| 15609 | if (*argptr == NULL) { | ||
| 15610 | char buffer[256]; | ||
| 15611 | if (get_title(buffer, sizeof(buffer))) | ||
| 15612 | puts(buffer); | ||
| 15613 | } else { | ||
| 15614 | set_title(*argptr); | ||
| 15615 | } | ||
| 15616 | return 0; | ||
| 15617 | } | ||
| 15618 | #endif | ||
| 15619 | |||
| 14234 | #if ENABLE_FEATURE_SH_MATH | 15620 | #if ENABLE_FEATURE_SH_MATH |
| 14235 | /* | 15621 | /* |
| 14236 | * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell. | 15622 | * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell. |
| @@ -14331,6 +15717,27 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14331 | goto again; | 15717 | goto again; |
| 14332 | } | 15718 | } |
| 14333 | 15719 | ||
| 15720 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15721 | if ((uintptr_t)r == 2) { | ||
| 15722 | /* ^C pressed, propagate event */ | ||
| 15723 | if (trap[SIGINT]) { | ||
| 15724 | write(STDOUT_FILENO, "^C", 2); | ||
| 15725 | pending_int = 1; | ||
| 15726 | dotrap(); | ||
| 15727 | if (!(rootshell && iflag)) | ||
| 15728 | return (uintptr_t)0; | ||
| 15729 | else | ||
| 15730 | goto again; | ||
| 15731 | } else if (iflag) { | ||
| 15732 | raise_interrupt(); | ||
| 15733 | } else { | ||
| 15734 | GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); | ||
| 15735 | exitshell(); | ||
| 15736 | } | ||
| 15737 | return (uintptr_t)r; | ||
| 15738 | } | ||
| 15739 | #endif | ||
| 15740 | |||
| 14334 | if ((uintptr_t)r > 1) | 15741 | if ((uintptr_t)r > 1) |
| 14335 | ash_msg_and_raise_error(r); | 15742 | ash_msg_and_raise_error(r); |
| 14336 | 15743 | ||
| @@ -14391,6 +15798,9 @@ umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 14391 | if (!isdigit(modestr[0])) | 15798 | if (!isdigit(modestr[0])) |
| 14392 | mask ^= 0777; | 15799 | mask ^= 0777; |
| 14393 | umask(mask); | 15800 | umask(mask); |
| 15801 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15802 | setvareq(xasprintf("BB_UMASK=0%o", mask), VEXPORT|VNOSAVE); | ||
| 15803 | #endif | ||
| 14394 | } | 15804 | } |
| 14395 | return 0; | 15805 | return 0; |
| 14396 | } | 15806 | } |
| @@ -14474,6 +15884,13 @@ exitshell(void) | |||
| 14474 | /*free(p); - we'll exit soon */ | 15884 | /*free(p); - we'll exit soon */ |
| 14475 | } | 15885 | } |
| 14476 | out: | 15886 | out: |
| 15887 | #if ENABLE_SUW32 | ||
| 15888 | if (delayexit) { | ||
| 15889 | #define EXIT_MSG "Press any key to exit..." | ||
| 15890 | console_write(EXIT_MSG, sizeof(EXIT_MSG) - 1); | ||
| 15891 | _getch(); | ||
| 15892 | } | ||
| 15893 | #endif | ||
| 14477 | exitreset(); | 15894 | exitreset(); |
| 14478 | /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". | 15895 | /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". |
| 14479 | * our setjobctl(0) does not panic if tcsetpgrp fails inside it. | 15896 | * our setjobctl(0) does not panic if tcsetpgrp fails inside it. |
| @@ -14484,22 +15901,97 @@ exitshell(void) | |||
| 14484 | /* NOTREACHED */ | 15901 | /* NOTREACHED */ |
| 14485 | } | 15902 | } |
| 14486 | 15903 | ||
| 15904 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15905 | /* We need to see if HOME is *really* unset */ | ||
| 15906 | # undef getenv | ||
| 15907 | static void setvar_if_unset(const char *key, const char *value) | ||
| 15908 | { | ||
| 15909 | if (!getenv(key) || getuid() == 0) | ||
| 15910 | setvar(key, value, VEXPORT); | ||
| 15911 | } | ||
| 15912 | #endif | ||
| 15913 | |||
| 14487 | /* Don't inline: conserve stack of caller from having our locals too */ | 15914 | /* Don't inline: conserve stack of caller from having our locals too */ |
| 14488 | static NOINLINE void | 15915 | static NOINLINE void |
| 14489 | init(void) | 15916 | init(void) |
| 14490 | { | 15917 | { |
| 15918 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15919 | int import = 0; | ||
| 15920 | #else | ||
| 14491 | /* we will never free this */ | 15921 | /* we will never free this */ |
| 14492 | basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ); | 15922 | basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ); |
| 14493 | basepf.linno = 1; | 15923 | basepf.linno = 1; |
| 14494 | 15924 | ||
| 14495 | sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ | 15925 | sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ |
| 14496 | setsignal(SIGCHLD); | 15926 | setsignal(SIGCHLD); |
| 15927 | #endif | ||
| 14497 | 15928 | ||
| 14498 | { | 15929 | { |
| 14499 | char **envp; | 15930 | char **envp; |
| 14500 | const char *p; | 15931 | const char *p; |
| 14501 | 15932 | ||
| 14502 | initvar(); | 15933 | initvar(); |
| 15934 | |||
| 15935 | #if ENABLE_PLATFORM_MINGW32 | ||
| 15936 | /* | ||
| 15937 | * case insensitive env names from Windows world | ||
| 15938 | * | ||
| 15939 | * Some standard env names such as PATH is named Path and so on | ||
| 15940 | * ash itself is case sensitive, so "Path" will confuse it, as | ||
| 15941 | * MSVC getenv() is case insensitive. | ||
| 15942 | * | ||
| 15943 | * We may end up having both Path and PATH. Then Path will be chosen | ||
| 15944 | * because it appears first. | ||
| 15945 | */ | ||
| 15946 | if (windows_env()) { | ||
| 15947 | /* | ||
| 15948 | * If we get here it's because the environment suggests we | ||
| 15949 | * haven't been invoked from an earlier instance of BusyBox. | ||
| 15950 | */ | ||
| 15951 | char *start, *end; | ||
| 15952 | struct passwd *pw; | ||
| 15953 | |||
| 15954 | /* mintty sets HOME: unset it */ | ||
| 15955 | const char *tty = getenv("TERM_PROGRAM"); | ||
| 15956 | if (tty && strcmp(tty, "mintty") == 0) { | ||
| 15957 | unsetenv("HOME"); | ||
| 15958 | } | ||
| 15959 | |||
| 15960 | import = VIMPORT; | ||
| 15961 | for (envp = environ; envp && *envp; envp++) { | ||
| 15962 | if (!(end=strchr(*envp, '='))) | ||
| 15963 | continue; | ||
| 15964 | |||
| 15965 | /* check for invalid characters in name */ | ||
| 15966 | start = (char *)endofname(*envp); | ||
| 15967 | if (*start != '=') { | ||
| 15968 | /* Make a copy of the original variable */ | ||
| 15969 | setvareq(xstrdup(*envp), VEXPORT|VNOSAVE); | ||
| 15970 | |||
| 15971 | /* Replace invalid characters with underscores */ | ||
| 15972 | for (; start < end; start++) { | ||
| 15973 | if (!isalnum(*start)) { | ||
| 15974 | *start = '_'; | ||
| 15975 | } | ||
| 15976 | } | ||
| 15977 | } | ||
| 15978 | |||
| 15979 | /* make all variable names uppercase */ | ||
| 15980 | for (start = *envp;start < end;start++) | ||
| 15981 | *start = toupper(*start); | ||
| 15982 | } | ||
| 15983 | |||
| 15984 | /* Initialise some variables normally set at login, but | ||
| 15985 | * only if someone hasn't already set them or we're root. */ | ||
| 15986 | pw = getpwuid(getuid()); | ||
| 15987 | if (pw) { | ||
| 15988 | setvar_if_unset("USER", pw->pw_name); | ||
| 15989 | setvar_if_unset("LOGNAME", pw->pw_name); | ||
| 15990 | setvar_if_unset("HOME", pw->pw_dir); | ||
| 15991 | } | ||
| 15992 | setvar_if_unset("SHELL", DEFAULT_SHELL); | ||
| 15993 | } | ||
| 15994 | #endif | ||
| 14503 | for (envp = environ; envp && *envp; envp++) { | 15995 | for (envp = environ; envp && *envp; envp++) { |
| 14504 | /* Used to have | 15996 | /* Used to have |
| 14505 | * p = endofname(*envp); | 15997 | * p = endofname(*envp); |
| @@ -14513,7 +16005,11 @@ init(void) | |||
| 14513 | * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this | 16005 | * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this |
| 14514 | */ | 16006 | */ |
| 14515 | if (strchr(*envp, '=')) { | 16007 | if (strchr(*envp, '=')) { |
| 16008 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14516 | setvareq(*envp, VEXPORT|VTEXTFIXED); | 16009 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
| 16010 | #else | ||
| 16011 | setvareq(*envp, VEXPORT|import); | ||
| 16012 | #endif | ||
| 14517 | } | 16013 | } |
| 14518 | } | 16014 | } |
| 14519 | 16015 | ||
| @@ -14564,7 +16060,11 @@ procargs(char **argv) | |||
| 14564 | int login_sh; | 16060 | int login_sh; |
| 14565 | 16061 | ||
| 14566 | xargv = argv; | 16062 | xargv = argv; |
| 16063 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16064 | login_sh = applet_name[0] == 'l'; | ||
| 16065 | #else | ||
| 14567 | login_sh = xargv[0] && xargv[0][0] == '-'; | 16066 | login_sh = xargv[0] && xargv[0][0] == '-'; |
| 16067 | #endif | ||
| 14568 | #if NUM_SCRIPTS > 0 | 16068 | #if NUM_SCRIPTS > 0 |
| 14569 | if (minusc) | 16069 | if (minusc) |
| 14570 | goto setarg0; | 16070 | goto setarg0; |
| @@ -14588,7 +16088,9 @@ procargs(char **argv) | |||
| 14588 | } | 16088 | } |
| 14589 | if (iflag == 2 /* no explicit -i given */ | 16089 | if (iflag == 2 /* no explicit -i given */ |
| 14590 | && sflag == 1 /* -s given (or implied) */ | 16090 | && sflag == 1 /* -s given (or implied) */ |
| 16091 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14591 | && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */ | 16092 | && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */ |
| 16093 | #endif | ||
| 14592 | && isatty(0) && isatty(1) /* we are on tty */ | 16094 | && isatty(0) && isatty(1) /* we are on tty */ |
| 14593 | ) { | 16095 | ) { |
| 14594 | iflag = 1; | 16096 | iflag = 1; |
| @@ -14608,6 +16110,9 @@ procargs(char **argv) | |||
| 14608 | goto setarg0; | 16110 | goto setarg0; |
| 14609 | } else if (!sflag) { | 16111 | } else if (!sflag) { |
| 14610 | setinputfile(*xargv, 0); | 16112 | setinputfile(*xargv, 0); |
| 16113 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16114 | bs_to_slash(*xargv); | ||
| 16115 | #endif | ||
| 14611 | setarg0: | 16116 | setarg0: |
| 14612 | arg0 = *xargv++; | 16117 | arg0 = *xargv++; |
| 14613 | commandname = arg0; | 16118 | commandname = arg0; |
| @@ -14631,8 +16136,10 @@ procargs(char **argv) | |||
| 14631 | * NB: must do it before setting up signals (in optschanged()) | 16136 | * NB: must do it before setting up signals (in optschanged()) |
| 14632 | * and reading .profile etc (after we return from here): | 16137 | * and reading .profile etc (after we return from here): |
| 14633 | */ | 16138 | */ |
| 16139 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14634 | if (iflag) | 16140 | if (iflag) |
| 14635 | signal(SIGHUP, SIG_DFL); | 16141 | signal(SIGHUP, SIG_DFL); |
| 16142 | #endif | ||
| 14636 | 16143 | ||
| 14637 | optschanged(); | 16144 | optschanged(); |
| 14638 | 16145 | ||
| @@ -14677,9 +16184,25 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14677 | struct stackmark smark; | 16184 | struct stackmark smark; |
| 14678 | int login_sh; | 16185 | int login_sh; |
| 14679 | 16186 | ||
| 16187 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16188 | INIT_G_memstack(); | ||
| 16189 | |||
| 16190 | /* from init() */ | ||
| 16191 | basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ); | ||
| 16192 | basepf.linno = 1; | ||
| 16193 | |||
| 16194 | if (argc == 3 && !strcmp(argv[1], "--fs")) { | ||
| 16195 | forkshell_init(argv[2]); | ||
| 16196 | /* only reached in case of error */ | ||
| 16197 | bb_error_msg_and_die("forkshell failed"); | ||
| 16198 | } | ||
| 16199 | #endif | ||
| 16200 | |||
| 14680 | /* Initialize global data */ | 16201 | /* Initialize global data */ |
| 14681 | INIT_G_misc(); | 16202 | INIT_G_misc(); |
| 16203 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14682 | INIT_G_memstack(); | 16204 | INIT_G_memstack(); |
| 16205 | #endif | ||
| 14683 | INIT_G_var(); | 16206 | INIT_G_var(); |
| 14684 | #if ENABLE_ASH_ALIAS | 16207 | #if ENABLE_ASH_ALIAS |
| 14685 | INIT_G_alias(); | 16208 | INIT_G_alias(); |
| @@ -14725,6 +16248,10 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14725 | init(); | 16248 | init(); |
| 14726 | setstackmark(&smark); | 16249 | setstackmark(&smark); |
| 14727 | 16250 | ||
| 16251 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16252 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
| 16253 | #endif | ||
| 16254 | |||
| 14728 | #if NUM_SCRIPTS > 0 | 16255 | #if NUM_SCRIPTS > 0 |
| 14729 | if (argc < 0) | 16256 | if (argc < 0) |
| 14730 | /* Non-NULL minusc tells procargs that an embedded script is being run */ | 16257 | /* Non-NULL minusc tells procargs that an embedded script is being run */ |
| @@ -14736,11 +16263,45 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14736 | trace_puts_args(argv); | 16263 | trace_puts_args(argv); |
| 14737 | #endif | 16264 | #endif |
| 14738 | 16265 | ||
| 16266 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16267 | if (!dirarg && !login_sh && iflag) { | ||
| 16268 | char *cwd = getcwd(NULL, 0); | ||
| 16269 | if (cwd) { | ||
| 16270 | chdir(cwd); | ||
| 16271 | setpwd(NULL, 0); | ||
| 16272 | free(cwd); | ||
| 16273 | } | ||
| 16274 | } | ||
| 16275 | |||
| 16276 | if (title) | ||
| 16277 | set_title(title); | ||
| 16278 | #endif | ||
| 16279 | |||
| 14739 | if (login_sh) { | 16280 | if (login_sh) { |
| 14740 | const char *hp; | 16281 | const char *hp; |
| 14741 | 16282 | ||
| 16283 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16284 | if (!dirarg) { | ||
| 16285 | hp = lookupvar("HOME"); | ||
| 16286 | if (hp == NULL || *hp == '\0') | ||
| 16287 | hp = xgetpwuid(getuid())->pw_dir; | ||
| 16288 | chdir(hp); | ||
| 16289 | setpwd(NULL, 0); | ||
| 16290 | } | ||
| 16291 | #endif | ||
| 16292 | |||
| 14742 | state = 1; | 16293 | state = 1; |
| 16294 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16295 | hp = concat_path_file(get_system_drive(), "/etc/profile"); | ||
| 16296 | read_profile(hp); | ||
| 16297 | free((void *)hp); | ||
| 16298 | |||
| 16299 | hp = exe_relative_path("/etc/profile"); | ||
| 16300 | read_profile(hp); | ||
| 16301 | free((void *)hp); | ||
| 16302 | #else | ||
| 14743 | read_profile("/etc/profile"); | 16303 | read_profile("/etc/profile"); |
| 16304 | #endif | ||
| 14744 | state1: | 16305 | state1: |
| 14745 | state = 2; | 16306 | state = 2; |
| 14746 | hp = lookupvar("HOME"); | 16307 | hp = lookupvar("HOME"); |
| @@ -14749,10 +16310,18 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14749 | } | 16310 | } |
| 14750 | state2: | 16311 | state2: |
| 14751 | state = 3; | 16312 | state = 3; |
| 16313 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16314 | if (dirarg) { | ||
| 16315 | chdir(dirarg); | ||
| 16316 | setpwd(NULL, 0); | ||
| 16317 | } | ||
| 16318 | #endif | ||
| 14752 | if (iflag | 16319 | if (iflag |
| 16320 | #if ENABLE_PLATFORM_POSIX | ||
| 14753 | #ifndef linux | 16321 | #ifndef linux |
| 14754 | && getuid() == geteuid() && getgid() == getegid() | 16322 | && getuid() == geteuid() && getgid() == getegid() |
| 14755 | #endif | 16323 | #endif |
| 16324 | #endif | ||
| 14756 | ) { | 16325 | ) { |
| 14757 | const char *shinit = lookupvar("ENV"); | 16326 | const char *shinit = lookupvar("ENV"); |
| 14758 | if (shinit != NULL && *shinit != '\0') | 16327 | if (shinit != NULL && *shinit != '\0') |
| @@ -14777,7 +16346,11 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14777 | // ash -sc 'echo $-' | 16346 | // ash -sc 'echo $-' |
| 14778 | // continue reading input from stdin after running 'echo'. | 16347 | // continue reading input from stdin after running 'echo'. |
| 14779 | // bash does not do this: it prints "hBcs" and exits. | 16348 | // bash does not do this: it prints "hBcs" and exits. |
| 16349 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 14780 | evalstring(minusc, EV_EXIT); | 16350 | evalstring(minusc, EV_EXIT); |
| 16351 | #else | ||
| 16352 | evalstring(minusc, sflag ? 0 : EV_EXIT); | ||
| 16353 | #endif | ||
| 14781 | } | 16354 | } |
| 14782 | 16355 | ||
| 14783 | if (sflag || minusc == NULL) { | 16356 | if (sflag || minusc == NULL) { |
| @@ -14820,6 +16393,1099 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14820 | /* NOTREACHED */ | 16393 | /* NOTREACHED */ |
| 14821 | } | 16394 | } |
| 14822 | 16395 | ||
| 16396 | #if ENABLE_PLATFORM_MINGW32 | ||
| 16397 | static void | ||
| 16398 | forkshell_openhere(struct forkshell *fs) | ||
| 16399 | { | ||
| 16400 | const char *p = fs->path; | ||
| 16401 | size_t len = strlen(p); | ||
| 16402 | int pip[2]; | ||
| 16403 | |||
| 16404 | pip[0] = fs->fd[0]; | ||
| 16405 | pip[1] = fs->fd[1]; | ||
| 16406 | |||
| 16407 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
| 16408 | |||
| 16409 | close(pip[0]); | ||
| 16410 | ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); | ||
| 16411 | ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); | ||
| 16412 | ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); | ||
| 16413 | ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); | ||
| 16414 | signal(SIGPIPE, SIG_DFL); | ||
| 16415 | xwrite(pip[1], p, len); | ||
| 16416 | _exit_SUCCESS(); | ||
| 16417 | } | ||
| 16418 | |||
| 16419 | static void | ||
| 16420 | forkshell_evalbackcmd(struct forkshell *fs) | ||
| 16421 | { | ||
| 16422 | #if BASH_PROCESS_SUBST | ||
| 16423 | /* determine end of pipe used by parent (ip) and child (ic) */ | ||
| 16424 | const int ctl = fs->fd[2]; | ||
| 16425 | const int ip = (ctl == CTLTOPROC); | ||
| 16426 | const int ic = !(ctl == CTLTOPROC); | ||
| 16427 | #else | ||
| 16428 | const int ip = 0; | ||
| 16429 | const int ic = 1; | ||
| 16430 | #endif | ||
| 16431 | union node *n = fs->n; | ||
| 16432 | int pip[2]; | ||
| 16433 | |||
| 16434 | pip[ip] = fs->fd[ip]; | ||
| 16435 | pip[ic] = fs->fd[ic]; | ||
| 16436 | |||
| 16437 | FORCE_INT_ON; | ||
| 16438 | close(pip[ip]); | ||
| 16439 | if (pip[ic] != ic) { | ||
| 16440 | /*close(ic);*/ | ||
| 16441 | dup2_or_raise(pip[ic], ic); | ||
| 16442 | close(pip[ic]); | ||
| 16443 | } | ||
| 16444 | eflag = 0; | ||
| 16445 | ifsfree(); | ||
| 16446 | evaltreenr(n, EV_EXIT); | ||
| 16447 | /* NOTREACHED */ | ||
| 16448 | } | ||
| 16449 | |||
| 16450 | static void | ||
| 16451 | forkshell_evalsubshell(struct forkshell *fs) | ||
| 16452 | { | ||
| 16453 | union node *n = fs->n; | ||
| 16454 | int flags = fs->flags; | ||
| 16455 | |||
| 16456 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
| 16457 | INT_ON; | ||
| 16458 | flags |= EV_EXIT; | ||
| 16459 | if (fs->mode) | ||
| 16460 | flags &= ~EV_TESTED; | ||
| 16461 | expredir(n->nredir.redirect); | ||
| 16462 | redirect(n->nredir.redirect, 0); | ||
| 16463 | evaltreenr(n->nredir.n, flags); | ||
| 16464 | /* never returns */ | ||
| 16465 | } | ||
| 16466 | |||
| 16467 | static void | ||
| 16468 | forkshell_evalpipe(struct forkshell *fs) | ||
| 16469 | { | ||
| 16470 | union node *n = fs->n; | ||
| 16471 | int flags = fs->flags; | ||
| 16472 | int prevfd = fs->fd[2]; | ||
| 16473 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
| 16474 | |||
| 16475 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
| 16476 | INT_ON; | ||
| 16477 | if (pip[1] >= 0) { | ||
| 16478 | close(pip[0]); | ||
| 16479 | } | ||
| 16480 | if (prevfd > 0) { | ||
| 16481 | dup2(prevfd, 0); | ||
| 16482 | close(prevfd); | ||
| 16483 | } | ||
| 16484 | if (pip[1] > 1) { | ||
| 16485 | dup2(pip[1], 1); | ||
| 16486 | close(pip[1]); | ||
| 16487 | } | ||
| 16488 | evaltreenr(n, flags); | ||
| 16489 | } | ||
| 16490 | |||
| 16491 | static void | ||
| 16492 | forkshell_shellexec(struct forkshell *fs) | ||
| 16493 | { | ||
| 16494 | int idx = fs->fd[0]; | ||
| 16495 | char **argv = fs->argv; | ||
| 16496 | char *path = fs->path; | ||
| 16497 | |||
| 16498 | FORCE_INT_ON; | ||
| 16499 | shellexec(argv[0], argv, path, idx); | ||
| 16500 | } | ||
| 16501 | |||
| 16502 | static void | ||
| 16503 | forkshell_child(struct forkshell *fs) | ||
| 16504 | { | ||
| 16505 | switch ( fs->fpid ) { | ||
| 16506 | case FS_OPENHERE: | ||
| 16507 | forkshell_openhere(fs); | ||
| 16508 | break; | ||
| 16509 | case FS_EVALBACKCMD: | ||
| 16510 | forkshell_evalbackcmd(fs); | ||
| 16511 | break; | ||
| 16512 | case FS_EVALSUBSHELL: | ||
| 16513 | forkshell_evalsubshell(fs); | ||
| 16514 | break; | ||
| 16515 | case FS_EVALPIPE: | ||
| 16516 | forkshell_evalpipe(fs); | ||
| 16517 | break; | ||
| 16518 | case FS_SHELLEXEC: | ||
| 16519 | forkshell_shellexec(fs); | ||
| 16520 | break; | ||
| 16521 | } | ||
| 16522 | } | ||
| 16523 | |||
| 16524 | /* | ||
| 16525 | * Reinitialise the builtin environment variables in varinit. Their | ||
| 16526 | * current settings have been copied from the parent in vartab. Look | ||
| 16527 | * these up using the names from varinit_data, copy the details from | ||
| 16528 | * vartab to varinit and replace the old copy in vartab with the new | ||
| 16529 | * one in varinit. | ||
| 16530 | * | ||
| 16531 | * Also reinitialise the function pointers and line number variable. | ||
| 16532 | */ | ||
| 16533 | static void | ||
| 16534 | reinitvar(void) | ||
| 16535 | { | ||
| 16536 | int i; | ||
| 16537 | const char *name; | ||
| 16538 | struct var **vpp, **old; | ||
| 16539 | |||
| 16540 | for (i=0; i<ARRAY_SIZE(varinit); ++i) { | ||
| 16541 | if (i == LINENO_INDEX) | ||
| 16542 | name = "LINENO="; | ||
| 16543 | else if (i == FUNCNAME_INDEX) | ||
| 16544 | name = "FUNCNAME="; | ||
| 16545 | else | ||
| 16546 | name = varinit_data[i].var_text; | ||
| 16547 | vpp = hashvar(name); | ||
| 16548 | if ( (old=findvar(vpp, name)) != NULL ) { | ||
| 16549 | varinit[i] = **old; | ||
| 16550 | *old = varinit+i; | ||
| 16551 | } | ||
| 16552 | varinit[i].var_func = varinit_data[i].var_func; | ||
| 16553 | } | ||
| 16554 | vlineno.var_text = linenovar; | ||
| 16555 | vfuncname.var_text = funcnamevar; | ||
| 16556 | } | ||
| 16557 | |||
| 16558 | static void | ||
| 16559 | spawn_forkshell(struct forkshell *fs, struct job *jp, union node *n, int mode) | ||
| 16560 | { | ||
| 16561 | struct forkshell *new; | ||
| 16562 | char buf[32]; | ||
| 16563 | const char *argv[] = { "sh", "--fs", NULL, NULL }; | ||
| 16564 | intptr_t ret; | ||
| 16565 | |||
| 16566 | new = forkshell_prepare(fs); | ||
| 16567 | if (new == NULL) | ||
| 16568 | goto fail; | ||
| 16569 | |||
| 16570 | new->mode = mode; | ||
| 16571 | new->nprocs = jp == NULL ? 0 : jp->nprocs; | ||
| 16572 | #if JOBS_WIN32 | ||
| 16573 | new->jpnull = jp == NULL; | ||
| 16574 | #endif | ||
| 16575 | sprintf(buf, "%p", new->hMapFile); | ||
| 16576 | argv[2] = buf; | ||
| 16577 | ret = spawnve(P_NOWAIT, bb_busybox_exec_path, (char *const *)argv, NULL); | ||
| 16578 | CloseHandle(new->hMapFile); | ||
| 16579 | UnmapViewOfFile(new); | ||
| 16580 | if (ret == -1) { | ||
| 16581 | fail: | ||
| 16582 | if (jp) | ||
| 16583 | freejob(jp); | ||
| 16584 | ash_msg_and_raise_error("unable to spawn shell"); | ||
| 16585 | } | ||
| 16586 | forkparent(jp, n, mode, (HANDLE)ret); | ||
| 16587 | } | ||
| 16588 | |||
| 16589 | /* | ||
| 16590 | * forkshell_prepare() and friends | ||
| 16591 | * | ||
| 16592 | * The sequence is as follows: | ||
| 16593 | * - funcblocksize is initialized | ||
| 16594 | * - forkshell_size(fs) is called to calculate the exact memory needed | ||
| 16595 | * - a new struct is allocated | ||
| 16596 | * - funcblock, funcstring, relocate are initialized from the new block | ||
| 16597 | * - forkshell_copy(fs) is called to copy recursively everything over | ||
| 16598 | * it will record all relocations along the way | ||
| 16599 | * | ||
| 16600 | * When this memory is mapped elsewhere, pointer fixup will be needed | ||
| 16601 | */ | ||
| 16602 | |||
| 16603 | /* redefine without test that fs_size is nonzero */ | ||
| 16604 | #undef SAVE_PTR | ||
| 16605 | #undef SAVE_PTR2 | ||
| 16606 | #undef SAVE_PTR3 | ||
| 16607 | #define SAVE_PTR(dst,note,flag) {MARK_PTR(dst,note,flag);} | ||
| 16608 | |||
| 16609 | static int align_len(const char *s) | ||
| 16610 | { | ||
| 16611 | return s ? SHELL_ALIGN(strlen(s)+1) : 0; | ||
| 16612 | } | ||
| 16613 | |||
| 16614 | struct datasize { | ||
| 16615 | int funcblocksize; | ||
| 16616 | int funcstringsize; | ||
| 16617 | }; | ||
| 16618 | |||
| 16619 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
| 16620 | static struct datasize \ | ||
| 16621 | name(struct datasize ds, type *p) \ | ||
| 16622 | { \ | ||
| 16623 | while (p) { \ | ||
| 16624 | ds.funcblocksize += sizeof(type); | ||
| 16625 | /* do something here with p */ | ||
| 16626 | #define SLIST_SIZE_END() \ | ||
| 16627 | p = p->next; \ | ||
| 16628 | } \ | ||
| 16629 | return ds; \ | ||
| 16630 | } | ||
| 16631 | |||
| 16632 | #define SLIST_COPY_BEGIN(name,type) \ | ||
| 16633 | static type * \ | ||
| 16634 | name(type *vp) \ | ||
| 16635 | { \ | ||
| 16636 | type *start; \ | ||
| 16637 | type **vpp; \ | ||
| 16638 | vpp = &start; \ | ||
| 16639 | while (vp) { \ | ||
| 16640 | *vpp = funcblock; \ | ||
| 16641 | funcblock = (char *) funcblock + sizeof(type); | ||
| 16642 | /* do something here with vpp and vp */ | ||
| 16643 | #define SLIST_COPY_END() \ | ||
| 16644 | SAVE_PTR((*vpp)->next, "(*vpp)->next", NO_FREE); \ | ||
| 16645 | vp = vp->next; \ | ||
| 16646 | vpp = &(*vpp)->next; \ | ||
| 16647 | } \ | ||
| 16648 | *vpp = NULL; \ | ||
| 16649 | return start; \ | ||
| 16650 | } | ||
| 16651 | |||
| 16652 | /* | ||
| 16653 | * struct var | ||
| 16654 | */ | ||
| 16655 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
| 16656 | ds.funcstringsize += align_len(p->var_text); | ||
| 16657 | SLIST_SIZE_END() | ||
| 16658 | |||
| 16659 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
| 16660 | (*vpp)->var_text = nodeckstrdup(vp->var_text); | ||
| 16661 | (*vpp)->flags = vp->flags; | ||
| 16662 | (*vpp)->var_func = NULL; | ||
| 16663 | SAVE_PTR((*vpp)->var_text, xasprintf("(*vpp)->var_text '%s'", vp->var_text ?: "NULL"), FREE); | ||
| 16664 | SLIST_COPY_END() | ||
| 16665 | |||
| 16666 | /* | ||
| 16667 | * struct tblentry | ||
| 16668 | */ | ||
| 16669 | static struct datasize | ||
| 16670 | tblentry_size(struct datasize ds, struct tblentry *tep) | ||
| 16671 | { | ||
| 16672 | while (tep) { | ||
| 16673 | ds.funcblocksize += sizeof(struct tblentry) + align_len(tep->cmdname); | ||
| 16674 | /* CMDBUILTIN, e->param.cmd needs no pointer relocation */ | ||
| 16675 | if (tep->cmdtype == CMDFUNCTION) { | ||
| 16676 | ds.funcblocksize += offsetof(struct funcnode, n); | ||
| 16677 | ds.funcblocksize = calcsize(ds.funcblocksize, &tep->param.func->n); | ||
| 16678 | } | ||
| 16679 | tep = tep->next; | ||
| 16680 | } | ||
| 16681 | return ds; | ||
| 16682 | } | ||
| 16683 | |||
| 16684 | static struct tblentry * | ||
| 16685 | tblentry_copy(struct tblentry *tep) | ||
| 16686 | { | ||
| 16687 | struct tblentry *start; | ||
| 16688 | struct tblentry **newp; | ||
| 16689 | int size; | ||
| 16690 | |||
| 16691 | newp = &start; | ||
| 16692 | while (tep) { | ||
| 16693 | *newp = funcblock; | ||
| 16694 | size = sizeof(struct tblentry) + align_len(tep->cmdname); | ||
| 16695 | |||
| 16696 | funcblock = (char *) funcblock + size; | ||
| 16697 | memcpy(*newp, tep, sizeof(struct tblentry)+strlen(tep->cmdname)); | ||
| 16698 | switch (tep->cmdtype) { | ||
| 16699 | case CMDBUILTIN: | ||
| 16700 | /* Save index of builtin, not pointer; fixed by forkshell_init() */ | ||
| 16701 | (*newp)->param.index = tep->param.cmd - builtintab; | ||
| 16702 | break; | ||
| 16703 | case CMDFUNCTION: | ||
| 16704 | (*newp)->param.func = funcblock; | ||
| 16705 | funcblock = (char *) funcblock + offsetof(struct funcnode, n); | ||
| 16706 | copynode(&tep->param.func->n); | ||
| 16707 | SAVE_PTR((*newp)->param.func, "param.func", NO_FREE); | ||
| 16708 | break; | ||
| 16709 | default: | ||
| 16710 | break; | ||
| 16711 | } | ||
| 16712 | SAVE_PTR((*newp)->next, xasprintf("cmdname '%s'", tep->cmdname), FREE); | ||
| 16713 | tep = tep->next; | ||
| 16714 | newp = &(*newp)->next; | ||
| 16715 | } | ||
| 16716 | *newp = NULL; | ||
| 16717 | return start; | ||
| 16718 | } | ||
| 16719 | |||
| 16720 | static struct datasize | ||
| 16721 | cmdtable_size(struct datasize ds) | ||
| 16722 | { | ||
| 16723 | int i; | ||
| 16724 | ds.funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE; | ||
| 16725 | for (i = 0; i < CMDTABLESIZE; i++) | ||
| 16726 | ds = tblentry_size(ds, cmdtable[i]); | ||
| 16727 | return ds; | ||
| 16728 | } | ||
| 16729 | |||
| 16730 | static struct tblentry ** | ||
| 16731 | cmdtable_copy(void) | ||
| 16732 | { | ||
| 16733 | struct tblentry **new = funcblock; | ||
| 16734 | int i; | ||
| 16735 | |||
| 16736 | funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE; | ||
| 16737 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
| 16738 | new[i] = tblentry_copy(cmdtable[i]); | ||
| 16739 | SAVE_PTR(new[i], xasprintf("cmdtable[%d]", i), FREE); | ||
| 16740 | } | ||
| 16741 | return new; | ||
| 16742 | } | ||
| 16743 | |||
| 16744 | #if ENABLE_ASH_ALIAS | ||
| 16745 | /* | ||
| 16746 | * struct alias | ||
| 16747 | */ | ||
| 16748 | SLIST_SIZE_BEGIN(alias_size,struct alias) | ||
| 16749 | ds.funcstringsize += align_len(p->name); | ||
| 16750 | ds.funcstringsize += align_len(p->val); | ||
| 16751 | SLIST_SIZE_END() | ||
| 16752 | |||
| 16753 | SLIST_COPY_BEGIN(alias_copy,struct alias) | ||
| 16754 | (*vpp)->name = nodeckstrdup(vp->name); | ||
| 16755 | (*vpp)->val = nodeckstrdup(vp->val); | ||
| 16756 | (*vpp)->flag = vp->flag; | ||
| 16757 | SAVE_PTR((*vpp)->name, xasprintf("(*vpp)->name '%s'", vp->name ?: "NULL"), FREE); | ||
| 16758 | SAVE_PTR((*vpp)->val, xasprintf("(*vpp)->val '%s'", vp->val ?: "NULL"), FREE); | ||
| 16759 | SLIST_COPY_END() | ||
| 16760 | |||
| 16761 | static struct datasize | ||
| 16762 | atab_size(struct datasize ds) | ||
| 16763 | { | ||
| 16764 | int i; | ||
| 16765 | ds.funcblocksize += sizeof(struct alias *)*ATABSIZE; | ||
| 16766 | for (i = 0; i < ATABSIZE; i++) | ||
| 16767 | ds = alias_size(ds, atab[i]); | ||
| 16768 | return ds; | ||
| 16769 | } | ||
| 16770 | |||
| 16771 | static struct alias ** | ||
| 16772 | atab_copy(void) | ||
| 16773 | { | ||
| 16774 | struct alias **new = funcblock; | ||
| 16775 | int i; | ||
| 16776 | |||
| 16777 | funcblock = (char *) funcblock + sizeof(struct alias *)*ATABSIZE; | ||
| 16778 | for (i = 0; i < ATABSIZE; i++) { | ||
| 16779 | new[i] = alias_copy(atab[i]); | ||
| 16780 | SAVE_PTR(new[i], xasprintf("atab[%d]", i), FREE); | ||
| 16781 | } | ||
| 16782 | return new; | ||
| 16783 | } | ||
| 16784 | #endif | ||
| 16785 | |||
| 16786 | /* | ||
| 16787 | * char ** | ||
| 16788 | */ | ||
| 16789 | static struct datasize | ||
| 16790 | argv_size(struct datasize ds, char **p) | ||
| 16791 | { | ||
| 16792 | if (p) { | ||
| 16793 | while (*p) { | ||
| 16794 | ds.funcblocksize += sizeof(char *); | ||
| 16795 | ds.funcstringsize += align_len(*p); | ||
| 16796 | p++; | ||
| 16797 | } | ||
| 16798 | ds.funcblocksize += sizeof(char *); | ||
| 16799 | } | ||
| 16800 | return ds; | ||
| 16801 | } | ||
| 16802 | |||
| 16803 | static char ** | ||
| 16804 | argv_copy(char **p) | ||
| 16805 | { | ||
| 16806 | char **new, **start = funcblock; | ||
| 16807 | #if FORKSHELL_DEBUG | ||
| 16808 | int i = 0; | ||
| 16809 | #endif | ||
| 16810 | |||
| 16811 | if (p) { | ||
| 16812 | while (*p) { | ||
| 16813 | new = funcblock; | ||
| 16814 | funcblock = (char *) funcblock + sizeof(char *); | ||
| 16815 | *new = nodeckstrdup(*p); | ||
| 16816 | SAVE_PTR(*new, xasprintf("argv[%d] '%s'", i++, *p), FREE); | ||
| 16817 | p++; | ||
| 16818 | } | ||
| 16819 | new = funcblock; | ||
| 16820 | funcblock = (char *) funcblock + sizeof(char *); | ||
| 16821 | *new = NULL; | ||
| 16822 | return start; | ||
| 16823 | } | ||
| 16824 | return NULL; | ||
| 16825 | } | ||
| 16826 | |||
| 16827 | #if MAX_HISTORY | ||
| 16828 | static struct datasize | ||
| 16829 | history_size(struct datasize ds) | ||
| 16830 | { | ||
| 16831 | int i; | ||
| 16832 | line_input_t *st = line_input_state; | ||
| 16833 | |||
| 16834 | ds.funcblocksize += sizeof(char *) * st->cnt_history; | ||
| 16835 | for (i = 0; i < st->cnt_history; i++) { | ||
| 16836 | ds.funcstringsize += align_len(st->history[i]); | ||
| 16837 | } | ||
| 16838 | return ds; | ||
| 16839 | } | ||
| 16840 | |||
| 16841 | static char ** | ||
| 16842 | history_copy(void) | ||
| 16843 | { | ||
| 16844 | line_input_t *st = line_input_state; | ||
| 16845 | char **new = funcblock; | ||
| 16846 | int i; | ||
| 16847 | |||
| 16848 | funcblock = (char *)funcblock + sizeof(char *) * st->cnt_history; | ||
| 16849 | for (i = 0; i < st->cnt_history; i++) { | ||
| 16850 | new[i] = nodeckstrdup(st->history[i]); | ||
| 16851 | SAVE_PTR(new[i], | ||
| 16852 | xasprintf("history[%d] '%s'", i, st->history[i]), FREE); | ||
| 16853 | } | ||
| 16854 | return new; | ||
| 16855 | } | ||
| 16856 | #endif | ||
| 16857 | |||
| 16858 | #if JOBS_WIN32 | ||
| 16859 | /* | ||
| 16860 | * struct procstat | ||
| 16861 | */ | ||
| 16862 | static struct datasize | ||
| 16863 | procstat_size(struct datasize ds, int nj) | ||
| 16864 | { | ||
| 16865 | struct job *jp = jobtab + nj; | ||
| 16866 | |||
| 16867 | if (jp->ps != &jp->ps0) | ||
| 16868 | ds.funcblocksize += sizeof(struct procstat) * jp->nprocs; | ||
| 16869 | |||
| 16870 | for (int i = 0; i < jp->nprocs; i++) | ||
| 16871 | ds.funcstringsize += align_len(jp->ps[i].ps_cmd); | ||
| 16872 | |||
| 16873 | return ds; | ||
| 16874 | } | ||
| 16875 | |||
| 16876 | static struct procstat * | ||
| 16877 | procstat_copy(int nj) | ||
| 16878 | { | ||
| 16879 | struct job *jp = jobtab + nj; | ||
| 16880 | struct procstat *new = funcblock; | ||
| 16881 | |||
| 16882 | funcblock = (char *)funcblock + sizeof(struct procstat) * jp->nprocs; | ||
| 16883 | memcpy(new, jp->ps, sizeof(struct procstat) * jp->nprocs); | ||
| 16884 | |||
| 16885 | for (int i = 0; i < jp->nprocs; i++) { | ||
| 16886 | new[i].ps_cmd = nodeckstrdup(jp->ps[i].ps_cmd); | ||
| 16887 | SAVE_PTR(new[i].ps_cmd, | ||
| 16888 | xasprintf("jobtab[%d].ps[%d].ps_cmd '%s'", | ||
| 16889 | nj, i, jp->ps[i].ps_cmd), FREE); | ||
| 16890 | } | ||
| 16891 | return new; | ||
| 16892 | } | ||
| 16893 | |||
| 16894 | /* | ||
| 16895 | * struct jobs | ||
| 16896 | */ | ||
| 16897 | static struct datasize | ||
| 16898 | jobtab_size(struct datasize ds) | ||
| 16899 | { | ||
| 16900 | ds.funcblocksize += sizeof(struct job) * njobs; | ||
| 16901 | for (int i = 0; i < njobs; i++) { | ||
| 16902 | if (jobtab[i].used) | ||
| 16903 | ds = procstat_size(ds, i); | ||
| 16904 | } | ||
| 16905 | return ds; | ||
| 16906 | } | ||
| 16907 | |||
| 16908 | static struct job * | ||
| 16909 | jobtab_copy(void) | ||
| 16910 | { | ||
| 16911 | struct job *new = funcblock; | ||
| 16912 | int i; | ||
| 16913 | |||
| 16914 | funcblock = (char *)funcblock + sizeof(struct job) * njobs; | ||
| 16915 | memcpy(new, jobtab, sizeof(struct job) * njobs); | ||
| 16916 | |||
| 16917 | for (i = 0; i < njobs; i++) { | ||
| 16918 | if (!jobtab[i].used) | ||
| 16919 | continue; | ||
| 16920 | |||
| 16921 | if (jobtab[i].ps == &jobtab[i].ps0) { | ||
| 16922 | new[i].ps0.ps_cmd = nodeckstrdup(jobtab[i].ps0.ps_cmd); | ||
| 16923 | SAVE_PTR(new[i].ps0.ps_cmd, | ||
| 16924 | xasprintf("jobtab[%d].ps0.ps_cmd '%s'", | ||
| 16925 | i, jobtab[i].ps0.ps_cmd), FREE); | ||
| 16926 | new[i].ps = &new[i].ps0; | ||
| 16927 | } else if (jobtab[i].nprocs) { | ||
| 16928 | new[i].ps = procstat_copy(i); | ||
| 16929 | } else { | ||
| 16930 | new[i].ps = NULL; | ||
| 16931 | } | ||
| 16932 | SAVE_PTR(new[i].ps, xasprintf("jobtab[%d].ps", i), FREE); | ||
| 16933 | |||
| 16934 | if (jobtab[i].prev_job) { | ||
| 16935 | new[i].prev_job = new + (jobtab[i].prev_job - jobtab); | ||
| 16936 | SAVE_PTR(new[i].prev_job, | ||
| 16937 | xasprintf("jobtab[%d].prev_job", i), FREE); | ||
| 16938 | } | ||
| 16939 | } | ||
| 16940 | return new; | ||
| 16941 | } | ||
| 16942 | #endif | ||
| 16943 | |||
| 16944 | /* | ||
| 16945 | * struct redirtab | ||
| 16946 | */ | ||
| 16947 | static int | ||
| 16948 | redirtab_size(int funcblocksize, struct redirtab *rdtp) | ||
| 16949 | { | ||
| 16950 | while (rdtp) { | ||
| 16951 | funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
| 16952 | rdtp = rdtp->next; | ||
| 16953 | } | ||
| 16954 | return funcblocksize; | ||
| 16955 | } | ||
| 16956 | |||
| 16957 | static struct redirtab * | ||
| 16958 | redirtab_copy(struct redirtab *rdtp) | ||
| 16959 | { | ||
| 16960 | struct redirtab *start; | ||
| 16961 | struct redirtab **vpp; | ||
| 16962 | |||
| 16963 | vpp = &start; | ||
| 16964 | while (rdtp) { | ||
| 16965 | int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
| 16966 | *vpp = funcblock; | ||
| 16967 | funcblock = (char *) funcblock + size; | ||
| 16968 | memcpy(*vpp, rdtp, size); | ||
| 16969 | SAVE_PTR((*vpp)->next, "(*vpp)->next", NO_FREE); | ||
| 16970 | rdtp = rdtp->next; | ||
| 16971 | vpp = &(*vpp)->next; | ||
| 16972 | } | ||
| 16973 | *vpp = NULL; | ||
| 16974 | return start; | ||
| 16975 | } | ||
| 16976 | |||
| 16977 | static struct datasize | ||
| 16978 | globals_var_size(struct datasize ds) | ||
| 16979 | { | ||
| 16980 | int i; | ||
| 16981 | |||
| 16982 | ds.funcblocksize += sizeof(struct globals_var); | ||
| 16983 | ds.funcstringsize += align_len(funcname); | ||
| 16984 | ds = argv_size(ds, shellparam.p); | ||
| 16985 | ds.funcblocksize = redirtab_size(ds.funcblocksize, redirlist); | ||
| 16986 | for (i = 0; i < VTABSIZE; i++) | ||
| 16987 | ds = var_size(ds, vartab[i]); | ||
| 16988 | return ds; | ||
| 16989 | } | ||
| 16990 | |||
| 16991 | #undef funcname | ||
| 16992 | #undef shellparam | ||
| 16993 | #undef redirlist | ||
| 16994 | #undef vartab | ||
| 16995 | static struct globals_var * | ||
| 16996 | globals_var_copy(void) | ||
| 16997 | { | ||
| 16998 | int i; | ||
| 16999 | struct globals_var *gvp, *new; | ||
| 17000 | |||
| 17001 | gvp = ash_ptr_to_globals_var; | ||
| 17002 | new = funcblock; | ||
| 17003 | funcblock = (char *) funcblock + sizeof(struct globals_var); | ||
| 17004 | memcpy(new, gvp, sizeof(struct globals_var)); | ||
| 17005 | |||
| 17006 | new->funcname = nodeckstrdup(gvp->funcname); | ||
| 17007 | SAVE_PTR(new->funcname, xasprintf("funcname '%s'", gvp->funcname ?: "NULL"), FREE); | ||
| 17008 | |||
| 17009 | /* shparam */ | ||
| 17010 | new->shellparam.malloced = 0; | ||
| 17011 | new->shellparam.p = argv_copy(gvp->shellparam.p); | ||
| 17012 | SAVE_PTR(new->shellparam.p, "shellparam.p", NO_FREE); | ||
| 17013 | |||
| 17014 | new->redirlist = redirtab_copy(gvp->redirlist); | ||
| 17015 | SAVE_PTR(new->redirlist, "redirlist", NO_FREE); | ||
| 17016 | |||
| 17017 | for (i = 0; i < VTABSIZE; i++) { | ||
| 17018 | new->vartab[i] = var_copy(gvp->vartab[i]); | ||
| 17019 | SAVE_PTR(new->vartab[i], xasprintf("vartab[%d]", i), FREE); | ||
| 17020 | } | ||
| 17021 | |||
| 17022 | return new; | ||
| 17023 | } | ||
| 17024 | |||
| 17025 | static struct datasize | ||
| 17026 | globals_misc_size(struct datasize ds) | ||
| 17027 | { | ||
| 17028 | ds.funcblocksize += sizeof(struct globals_misc); | ||
| 17029 | ds.funcstringsize += align_len(minusc); | ||
| 17030 | if (curdir != nullstr) | ||
| 17031 | ds.funcstringsize += align_len(curdir); | ||
| 17032 | if (physdir != nullstr) | ||
| 17033 | ds.funcstringsize += align_len(physdir); | ||
| 17034 | ds.funcstringsize += align_len(arg0); | ||
| 17035 | ds.funcstringsize += align_len(commandname); | ||
| 17036 | for (int i = 0; i < ARRAY_SIZE(trap); i++) | ||
| 17037 | ds.funcstringsize += align_len(trap[i]); | ||
| 17038 | return ds; | ||
| 17039 | } | ||
| 17040 | |||
| 17041 | #undef minusc | ||
| 17042 | #undef curdir | ||
| 17043 | #undef physdir | ||
| 17044 | #undef arg0 | ||
| 17045 | #undef commandname | ||
| 17046 | #undef nullstr | ||
| 17047 | #undef trap | ||
| 17048 | static struct globals_misc * | ||
| 17049 | globals_misc_copy(void) | ||
| 17050 | { | ||
| 17051 | struct globals_misc *p = ash_ptr_to_globals_misc; | ||
| 17052 | struct globals_misc *new = funcblock; | ||
| 17053 | |||
| 17054 | funcblock = (char *) funcblock + sizeof(struct globals_misc); | ||
| 17055 | memcpy(new, p, sizeof(struct globals_misc)); | ||
| 17056 | |||
| 17057 | new->minusc = nodeckstrdup(p->minusc); | ||
| 17058 | new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr; | ||
| 17059 | new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr; | ||
| 17060 | new->arg0 = nodeckstrdup(p->arg0); | ||
| 17061 | new->commandname = nodeckstrdup(p->commandname); | ||
| 17062 | SAVE_PTR(new->minusc, xasprintf("minusc '%s'", p->minusc ?: "NULL"), FREE); | ||
| 17063 | SAVE_PTR(new->curdir, | ||
| 17064 | xasprintf("curdir '%s'", new->curdir ?: "NULL"), FREE); | ||
| 17065 | SAVE_PTR(new->physdir, | ||
| 17066 | xasprintf("physdir '%s'", new->physdir ?: "NULL"), FREE); | ||
| 17067 | SAVE_PTR(new->arg0, xasprintf("arg0 '%s'", p->arg0 ?: "NULL"), FREE); | ||
| 17068 | SAVE_PTR(new->commandname, | ||
| 17069 | xasprintf("commandname '%s'", p->commandname ?: "NULL"), FREE); | ||
| 17070 | for (int i = 0; i < ARRAY_SIZE(p->trap); i++) { | ||
| 17071 | new->trap[i] = nodeckstrdup(p->trap[i]); | ||
| 17072 | SAVE_PTR(new->trap[i], xasprintf("trap[%d]", i), FREE); | ||
| 17073 | } | ||
| 17074 | return new; | ||
| 17075 | } | ||
| 17076 | |||
| 17077 | static struct datasize | ||
| 17078 | forkshell_size(struct forkshell *fs) | ||
| 17079 | { | ||
| 17080 | struct datasize ds = {0, 0}; | ||
| 17081 | |||
| 17082 | ds.funcstringsize += align_len(fs->path); | ||
| 17083 | if (fs->fpid == FS_OPENHERE) | ||
| 17084 | return ds; | ||
| 17085 | |||
| 17086 | ds = globals_var_size(ds); | ||
| 17087 | ds = globals_misc_size(ds); | ||
| 17088 | ds = cmdtable_size(ds); | ||
| 17089 | |||
| 17090 | ds.funcblocksize = calcsize(ds.funcblocksize, fs->n); | ||
| 17091 | ds = argv_size(ds, fs->argv); | ||
| 17092 | |||
| 17093 | if ((ENABLE_ASH_ALIAS || MAX_HISTORY || JOBS_WIN32) && | ||
| 17094 | fs->fpid != FS_SHELLEXEC) { | ||
| 17095 | #if ENABLE_ASH_ALIAS | ||
| 17096 | ds = atab_size(ds); | ||
| 17097 | #endif | ||
| 17098 | #if MAX_HISTORY | ||
| 17099 | if (line_input_state) | ||
| 17100 | ds = history_size(ds); | ||
| 17101 | #endif | ||
| 17102 | #if JOBS_WIN32 | ||
| 17103 | ds = jobtab_size(ds); | ||
| 17104 | #endif | ||
| 17105 | } | ||
| 17106 | return ds; | ||
| 17107 | } | ||
| 17108 | |||
| 17109 | static void | ||
| 17110 | forkshell_copy(struct forkshell *fs, struct forkshell *new) | ||
| 17111 | { | ||
| 17112 | memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */ | ||
| 17113 | |||
| 17114 | new->path = nodeckstrdup(fs->path); | ||
| 17115 | SAVE_PTR(new->path, xasprintf("path '%s'", fs->path ?: "NULL"), FREE); | ||
| 17116 | if (fs->fpid == FS_OPENHERE) | ||
| 17117 | return; | ||
| 17118 | |||
| 17119 | new->gvp = globals_var_copy(); | ||
| 17120 | new->gmp = globals_misc_copy(); | ||
| 17121 | new->cmdtable = cmdtable_copy(); | ||
| 17122 | SAVE_PTR(new->gvp, "gvp", NO_FREE); | ||
| 17123 | SAVE_PTR(new->gmp, "gmp", NO_FREE); | ||
| 17124 | SAVE_PTR(new->cmdtable, "cmdtable", NO_FREE); | ||
| 17125 | |||
| 17126 | new->n = copynode(fs->n); | ||
| 17127 | new->argv = argv_copy(fs->argv); | ||
| 17128 | SAVE_PTR(new->n, "n", NO_FREE); | ||
| 17129 | SAVE_PTR(new->argv, "argv", NO_FREE); | ||
| 17130 | |||
| 17131 | if ((ENABLE_ASH_ALIAS || MAX_HISTORY || JOBS_WIN32) && | ||
| 17132 | fs->fpid != FS_SHELLEXEC) { | ||
| 17133 | #if ENABLE_ASH_ALIAS | ||
| 17134 | new->atab = atab_copy(); | ||
| 17135 | SAVE_PTR(new->atab, "atab", NO_FREE); | ||
| 17136 | #endif | ||
| 17137 | #if MAX_HISTORY | ||
| 17138 | if (line_input_state) { | ||
| 17139 | new->history = history_copy(); | ||
| 17140 | SAVE_PTR(new->history, "history", NO_FREE); | ||
| 17141 | new->cnt_history = line_input_state->cnt_history; | ||
| 17142 | } | ||
| 17143 | #endif | ||
| 17144 | #if JOBS_WIN32 | ||
| 17145 | if (njobs) { | ||
| 17146 | new->jobtab = jobtab_copy(); | ||
| 17147 | SAVE_PTR(new->jobtab, "jobtab", NO_FREE); | ||
| 17148 | new->njobs = njobs; | ||
| 17149 | if (curjob) { | ||
| 17150 | new->curjob = new->jobtab + (curjob - jobtab); | ||
| 17151 | SAVE_PTR(new->curjob, "curjob", NO_FREE); | ||
| 17152 | } | ||
| 17153 | } | ||
| 17154 | #endif | ||
| 17155 | } | ||
| 17156 | } | ||
| 17157 | |||
| 17158 | #if FORKSHELL_DEBUG | ||
| 17159 | #define NUM_BLOCKS FUNCSTRING | ||
| 17160 | enum {GVP, GMP, CMDTABLE, NODE, ARGV, ATAB, HISTORY, JOBTAB, FUNCSTRING}; | ||
| 17161 | |||
| 17162 | /* fp0 and notes can each be NULL */ | ||
| 17163 | static void | ||
| 17164 | forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes) | ||
| 17165 | { | ||
| 17166 | FILE *fp; | ||
| 17167 | void *lfuncblock; | ||
| 17168 | char *lfuncstring; | ||
| 17169 | char *lrelocate; | ||
| 17170 | char *s; | ||
| 17171 | int count, i, total, bitmapsize; | ||
| 17172 | int size[NUM_BLOCKS]; | ||
| 17173 | char *lptr[NUM_BLOCKS+1]; | ||
| 17174 | const char *fsname[] = { | ||
| 17175 | "FS_OPENHERE", | ||
| 17176 | "FS_EVALBACKCMD", | ||
| 17177 | "FS_EVALSUBSHELL", | ||
| 17178 | "FS_EVALPIPE", | ||
| 17179 | "FS_SHELLEXEC" | ||
| 17180 | }; | ||
| 17181 | |||
| 17182 | if (fp0 != NULL) { | ||
| 17183 | fp = fp0; | ||
| 17184 | } | ||
| 17185 | else { | ||
| 17186 | char name[64]; | ||
| 17187 | static int num = 0; | ||
| 17188 | |||
| 17189 | sprintf(name, "fs_%d_%03d.out", getpid(), ++num % 100); | ||
| 17190 | if ((fp=fopen(name, "w")) == NULL) | ||
| 17191 | return; | ||
| 17192 | } | ||
| 17193 | |||
| 17194 | bitmapsize = (fs->relocatesize + 7)/8; | ||
| 17195 | total = sizeof(struct forkshell) + fs->funcblocksize + | ||
| 17196 | fs->funcstringsize + bitmapsize; | ||
| 17197 | fprintf(fp, "total size %6d = %d + %d + %d + %d = %d\n", | ||
| 17198 | fs->size + bitmapsize, | ||
| 17199 | (int)sizeof(struct forkshell), fs->funcblocksize, | ||
| 17200 | fs->funcstringsize, bitmapsize, total); | ||
| 17201 | |||
| 17202 | lfuncblock = (char *)(fs + 1); | ||
| 17203 | lfuncstring = (char *)lfuncblock + fs->funcblocksize; | ||
| 17204 | lrelocate = (char *)lfuncstring + fs->funcstringsize; | ||
| 17205 | |||
| 17206 | /* funcblocksize is zero for FS_OPENHERE */ | ||
| 17207 | if (fs->funcblocksize != 0) { | ||
| 17208 | /* Depending on the configuration and the type of forkshell | ||
| 17209 | * some items may not be present. */ | ||
| 17210 | lptr[FUNCSTRING] = lfuncstring; | ||
| 17211 | #if JOBS_WIN32 | ||
| 17212 | lptr[JOBTAB] = fs->jobtab ? (char *)fs->jobtab : lptr[FUNCSTRING]; | ||
| 17213 | #else | ||
| 17214 | lptr[JOBTAB] = lptr[FUNCSTRING]; | ||
| 17215 | #endif | ||
| 17216 | #if MAX_HISTORY | ||
| 17217 | lptr[HISTORY] = fs->history ? (char *)fs->history : lptr[JOBTAB]; | ||
| 17218 | #else | ||
| 17219 | lptr[HISTORY] = lptr[JOBTAB]; | ||
| 17220 | #endif | ||
| 17221 | lptr[ATAB] = IF_ASH_ALIAS(fs->atab ? (char *)fs->atab :) lptr[HISTORY]; | ||
| 17222 | lptr[ARGV] = fs->argv ? (char *)fs->argv : lptr[ATAB]; | ||
| 17223 | lptr[NODE] = fs->n ? (char *)fs->n : lptr[ARGV]; | ||
| 17224 | lptr[CMDTABLE] = (char *)fs->cmdtable; | ||
| 17225 | lptr[GMP] = (char *)fs->gmp; | ||
| 17226 | lptr[GVP] = (char *)fs->gvp; | ||
| 17227 | |||
| 17228 | fprintf(fp, "funcblocksize %6d = ", fs->funcblocksize); | ||
| 17229 | total = 0; | ||
| 17230 | for (i=0; i<NUM_BLOCKS; ++i) { | ||
| 17231 | size[i] = (int)(lptr[i+1] - lptr[i]); | ||
| 17232 | total += size[i]; | ||
| 17233 | fprintf(fp, "%d %c ", size[i], i == NUM_BLOCKS - 1 ? '=' : '+'); | ||
| 17234 | } | ||
| 17235 | fprintf(fp, "%d\n\n", total); | ||
| 17236 | } | ||
| 17237 | else { | ||
| 17238 | fprintf(fp, "\n"); | ||
| 17239 | } | ||
| 17240 | |||
| 17241 | fprintf(fp, "%s\n\n", fsname[fs->fpid]); | ||
| 17242 | fprintf(fp, "--- relocate ---\n"); | ||
| 17243 | count = 0; | ||
| 17244 | for (i = 0; i < fs->relocatesize; ++i) { | ||
| 17245 | if (lrelocate[i/8] & (1 << i % 8)) { | ||
| 17246 | char **ptr = (char **)((char *)fs + i * sizeof(char *)); | ||
| 17247 | fprintf(fp, "%p %p %s\n", ptr, *ptr, | ||
| 17248 | notes && notes[i] ? notes[i] : ""); | ||
| 17249 | ++count; | ||
| 17250 | } | ||
| 17251 | } | ||
| 17252 | fprintf(fp, "--- %d relocations ---\n\n", count); | ||
| 17253 | |||
| 17254 | fprintf(fp, "--- funcstring ---\n"); | ||
| 17255 | count = 0; | ||
| 17256 | s = lfuncstring; | ||
| 17257 | while (s-lfuncstring < fs->funcstringsize) { | ||
| 17258 | if (!*s) { | ||
| 17259 | ++s; | ||
| 17260 | continue; | ||
| 17261 | } | ||
| 17262 | fprintf(fp, "%p '%s'\n", s, s); | ||
| 17263 | s += strlen(s)+1; | ||
| 17264 | ++count; | ||
| 17265 | } | ||
| 17266 | fprintf(fp, "--- %d strings ---\n", count); | ||
| 17267 | |||
| 17268 | if (fp0 == NULL) | ||
| 17269 | fclose(fp); | ||
| 17270 | } | ||
| 17271 | #endif | ||
| 17272 | |||
| 17273 | static struct forkshell * | ||
| 17274 | forkshell_prepare(struct forkshell *fs) | ||
| 17275 | { | ||
| 17276 | struct forkshell *new; | ||
| 17277 | struct datasize ds; | ||
| 17278 | int size, relocatesize, bitmapsize; | ||
| 17279 | HANDLE h; | ||
| 17280 | SECURITY_ATTRIBUTES sa; | ||
| 17281 | #if FORKSHELL_DEBUG | ||
| 17282 | char *relocate; | ||
| 17283 | char name[64]; | ||
| 17284 | FILE *fp; | ||
| 17285 | static int num = 0; | ||
| 17286 | #endif | ||
| 17287 | |||
| 17288 | /* calculate size of structure, funcblock and funcstring */ | ||
| 17289 | ds = forkshell_size(fs); | ||
| 17290 | size = sizeof(struct forkshell) + ds.funcblocksize + ds.funcstringsize; | ||
| 17291 | relocatesize = (sizeof(struct forkshell) + ds.funcblocksize)/sizeof(char *); | ||
| 17292 | bitmapsize = (relocatesize + 7)/8; | ||
| 17293 | |||
| 17294 | /* Allocate shared memory region */ | ||
| 17295 | memset(&sa, 0, sizeof(sa)); | ||
| 17296 | sa.nLength = sizeof(sa); | ||
| 17297 | sa.lpSecurityDescriptor = NULL; | ||
| 17298 | sa.bInheritHandle = TRUE; | ||
| 17299 | h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, | ||
| 17300 | size+bitmapsize, NULL); | ||
| 17301 | |||
| 17302 | /* Initialise pointers */ | ||
| 17303 | new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
| 17304 | if (new == NULL) | ||
| 17305 | return NULL; | ||
| 17306 | fs_size = size; | ||
| 17307 | fs_start = new; | ||
| 17308 | funcblock = (char *)(new + 1); | ||
| 17309 | funcstring_end = (char *)new + size; | ||
| 17310 | #if FORKSHELL_DEBUG | ||
| 17311 | fs_funcstring = (char *)new + sizeof(struct forkshell) + ds.funcblocksize; | ||
| 17312 | relocate = (char *)new + size; | ||
| 17313 | annot = (const char **)xzalloc(sizeof(char *)*relocatesize); | ||
| 17314 | annot_free = xzalloc(relocatesize); | ||
| 17315 | #endif | ||
| 17316 | |||
| 17317 | /* Now pack them all */ | ||
| 17318 | forkshell_copy(fs, new); | ||
| 17319 | |||
| 17320 | /* Finish it up */ | ||
| 17321 | new->size = size; | ||
| 17322 | new->relocatesize = relocatesize; | ||
| 17323 | new->old_base = (char *)new; | ||
| 17324 | new->hMapFile = h; | ||
| 17325 | #if FORKSHELL_DEBUG | ||
| 17326 | sprintf(name, "fs_%d_%03d.out", getpid(), ++num % 100); | ||
| 17327 | if ((fp=fopen(name, "w")) != NULL) { | ||
| 17328 | int i; | ||
| 17329 | |||
| 17330 | new->funcblocksize = (char *)funcblock - (char *)(new + 1); | ||
| 17331 | new->funcstringsize = (char *)new + size - funcstring_end; | ||
| 17332 | |||
| 17333 | /* perform some sanity checks on pointers */ | ||
| 17334 | fprintf(fp, "forkshell %p %6d\n", new, (int)sizeof(*new)); | ||
| 17335 | fprintf(fp, "funcblock %p %6d\n", new+1, new->funcblocksize); | ||
| 17336 | fprintf(fp, "funcstring %p %6d\n", funcstring_end, | ||
| 17337 | new->funcstringsize); | ||
| 17338 | if ((char *)funcblock != funcstring_end) | ||
| 17339 | fprintf(fp, " funcstring != end funcblock + 1 %p\n", funcblock); | ||
| 17340 | fprintf(fp, "relocate %p %6d\n\n", relocate, bitmapsize); | ||
| 17341 | |||
| 17342 | forkshell_print(fp, new, annot); | ||
| 17343 | |||
| 17344 | for (i = 0; i < relocatesize; ++i) { | ||
| 17345 | if (annot_free[i]) { | ||
| 17346 | free((void *)annot[i]); | ||
| 17347 | } | ||
| 17348 | } | ||
| 17349 | free(annot); | ||
| 17350 | free(annot_free); | ||
| 17351 | annot = NULL; | ||
| 17352 | fclose(fp); | ||
| 17353 | } | ||
| 17354 | #endif | ||
| 17355 | return new; | ||
| 17356 | } | ||
| 17357 | |||
| 17358 | #undef trap_ptr | ||
| 17359 | static void | ||
| 17360 | forkshell_init(const char *idstr) | ||
| 17361 | { | ||
| 17362 | struct forkshell *fs; | ||
| 17363 | void *map_handle; | ||
| 17364 | HANDLE h; | ||
| 17365 | int i; | ||
| 17366 | char **ptr; | ||
| 17367 | char *lrelocate; | ||
| 17368 | struct jmploc jmploc; | ||
| 17369 | |||
| 17370 | if (sscanf(idstr, "%p", &map_handle) != 1) | ||
| 17371 | return; | ||
| 17372 | |||
| 17373 | h = (HANDLE)map_handle; | ||
| 17374 | fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
| 17375 | if (!fs) | ||
| 17376 | return; | ||
| 17377 | |||
| 17378 | /* this memory can't be freed */ | ||
| 17379 | sticky_mem_start = fs; | ||
| 17380 | sticky_mem_end = (char *) fs + fs->size; | ||
| 17381 | |||
| 17382 | /* pointer fixup */ | ||
| 17383 | lrelocate = (char *)fs + fs->size; | ||
| 17384 | for (i = 0; i < fs->relocatesize; i++) { | ||
| 17385 | if (lrelocate[i/8] & (1 << i % 8)) { | ||
| 17386 | ptr = (char **)((char *)fs + i * sizeof(char *)); | ||
| 17387 | if (*ptr) | ||
| 17388 | *ptr = (char *)fs + (*ptr - fs->old_base); | ||
| 17389 | } | ||
| 17390 | } | ||
| 17391 | |||
| 17392 | if (fs->fpid == FS_OPENHERE) | ||
| 17393 | goto end; | ||
| 17394 | |||
| 17395 | /* Now fix up stuff that can't be transferred */ | ||
| 17396 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
| 17397 | struct tblentry *e = fs->cmdtable[i]; | ||
| 17398 | while (e) { | ||
| 17399 | if (e->cmdtype == CMDBUILTIN) | ||
| 17400 | e->param.cmd = builtintab + e->param.index; | ||
| 17401 | e = e->next; | ||
| 17402 | } | ||
| 17403 | } | ||
| 17404 | fs->gmp->trap_ptr = fs->gmp->trap; | ||
| 17405 | |||
| 17406 | /* Set global variables */ | ||
| 17407 | ASSIGN_CONST_PTR(&ash_ptr_to_globals_var, fs->gvp); | ||
| 17408 | ASSIGN_CONST_PTR(&ash_ptr_to_globals_misc, fs->gmp); | ||
| 17409 | cmdtable = fs->cmdtable; | ||
| 17410 | #if ENABLE_ASH_ALIAS | ||
| 17411 | atab = fs->atab; /* will be NULL for FS_SHELLEXEC */ | ||
| 17412 | #endif | ||
| 17413 | #if MAX_HISTORY | ||
| 17414 | if (fs->cnt_history) { | ||
| 17415 | line_input_state = new_line_input_t(FOR_SHELL); | ||
| 17416 | line_input_state->cnt_history = fs->cnt_history; | ||
| 17417 | for (i = 0; i < line_input_state->cnt_history; i++) | ||
| 17418 | line_input_state->history[i] = fs->history[i]; | ||
| 17419 | } | ||
| 17420 | #endif | ||
| 17421 | #if JOBS_WIN32 | ||
| 17422 | jobtab = fs->jobtab; | ||
| 17423 | njobs = fs->njobs; | ||
| 17424 | curjob = fs->curjob; | ||
| 17425 | #endif | ||
| 17426 | |||
| 17427 | CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */ | ||
| 17428 | |||
| 17429 | reinitvar(); | ||
| 17430 | |||
| 17431 | if (setjmp(jmploc.loc)) { | ||
| 17432 | exitreset(); | ||
| 17433 | exitshell(); | ||
| 17434 | } | ||
| 17435 | exception_handler = &jmploc; | ||
| 17436 | |||
| 17437 | shlvl++; | ||
| 17438 | if (fs->mode == FORK_BG) { | ||
| 17439 | SetConsoleCtrlHandler(NULL, TRUE); | ||
| 17440 | if (fs->nprocs == 0) { | ||
| 17441 | close(0); | ||
| 17442 | if (open(bb_dev_null, O_RDONLY) != 0) | ||
| 17443 | ash_msg_and_raise_perror("can't open '%s'", bb_dev_null); | ||
| 17444 | } | ||
| 17445 | } | ||
| 17446 | else { | ||
| 17447 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
| 17448 | } | ||
| 17449 | |||
| 17450 | if (fs->n && fs->n->type == NCMD /* is it single cmd? */ | ||
| 17451 | /* && n->ncmd.args->type == NARG - always true? */ | ||
| 17452 | && fs->n->ncmd.args && strcmp(fs->n->ncmd.args->narg.text, "trap") == 0 | ||
| 17453 | && fs->n->ncmd.args->narg.next == NULL /* "trap" with no arguments */ | ||
| 17454 | /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */ | ||
| 17455 | ) { | ||
| 17456 | TRACE(("Trap hack\n")); | ||
| 17457 | /* Save trap handler strings for trap builtin to print */ | ||
| 17458 | fs->gmp->trap_ptr = xmemdup(fs->gmp->trap, sizeof(fs->gmp->trap)); | ||
| 17459 | /* Fall through into clearing traps */ | ||
| 17460 | } | ||
| 17461 | clear_traps(); | ||
| 17462 | #if JOBS_WIN32 | ||
| 17463 | /* do job control only in root shell */ | ||
| 17464 | doing_jobctl = 0; | ||
| 17465 | |||
| 17466 | if (fs->n && fs->n->type == NCMD && fs->n->ncmd.args && | ||
| 17467 | strcmp(fs->n->ncmd.args->narg.text, "jobs") == 0) { | ||
| 17468 | TRACE(("Job hack\n")); | ||
| 17469 | if (!fs->jpnull) | ||
| 17470 | freejob(curjob); | ||
| 17471 | goto end; | ||
| 17472 | } | ||
| 17473 | for (struct job *jp = curjob; jp; jp = jp->prev_job) | ||
| 17474 | freejob(jp); | ||
| 17475 | #endif | ||
| 17476 | end: | ||
| 17477 | forkshell_child(fs); | ||
| 17478 | } | ||
| 17479 | |||
| 17480 | #undef free | ||
| 17481 | static void | ||
| 17482 | sticky_free(void *base) | ||
| 17483 | { | ||
| 17484 | if (base >= sticky_mem_start && base < sticky_mem_end) | ||
| 17485 | return; | ||
| 17486 | free(base); | ||
| 17487 | } | ||
| 17488 | #endif | ||
| 14823 | 17489 | ||
| 14824 | /*- | 17490 | /*- |
| 14825 | * Copyright (c) 1989, 1991, 1993, 1994 | 17491 | * Copyright (c) 1989, 1991, 1993, 1994 |
