diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 1701 |
1 files changed, 1683 insertions, 18 deletions
diff --git a/shell/ash.c b/shell/ash.c index 924e17f32..b82c51029 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 | * the path to the interpreter is ignored, PATH is searched to find it | ||
27 | * - both / and \ are supported in PATH. Usually you must use / | ||
28 | * - trap/job does not work | ||
29 | * - /dev/null is supported for redirection | ||
30 | * - fake $PPID | ||
31 | */ | ||
32 | |||
18 | //config:config ASH | 33 | //config:config ASH |
19 | //config: bool "ash (78 kb)" | 34 | //config: bool "ash (78 kb)" |
20 | //config: default y | 35 | //config: default y |
@@ -148,6 +163,25 @@ | |||
148 | //config: you to run the specified command or builtin, | 163 | //config: you to run the specified command or builtin, |
149 | //config: even when there is a function with the same name. | 164 | //config: even when there is a function with the same name. |
150 | //config: | 165 | //config: |
166 | //config: | ||
167 | //config:config ASH_NOCONSOLE | ||
168 | //config: bool "'noconsole' option" | ||
169 | //config: default y | ||
170 | //config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32 | ||
171 | //config: help | ||
172 | //config: Enable support for the 'noconsole' option, which attempts to | ||
173 | //config: hide the console normally associated with a command line | ||
174 | //config: application. This may be useful when running a shell script | ||
175 | //config: from a GUI application. | ||
176 | //config: | ||
177 | //config:config ASH_NOCASEGLOB | ||
178 | //config: bool "'nocaseglob' option" | ||
179 | //config: default y | ||
180 | //config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32 | ||
181 | //config: help | ||
182 | //config: Enable support for the 'nocaseglob' option, which allows | ||
183 | //config: case-insensitive filename globbing. | ||
184 | //config: | ||
151 | //config:endif # ash options | 185 | //config:endif # ash options |
152 | 186 | ||
153 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) | 187 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) |
@@ -284,6 +318,10 @@ typedef long arith_t; | |||
284 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ | 318 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ |
285 | #endif | 319 | #endif |
286 | 320 | ||
321 | #if !ENABLE_PLATFORM_MINGW32 | ||
322 | # define is_absolute_path(path) ((path)[0] == '/') | ||
323 | #endif | ||
324 | |||
287 | #if !BB_MMU | 325 | #if !BB_MMU |
288 | # error "Do not even bother, ash will not run on NOMMU machine" | 326 | # error "Do not even bother, ash will not run on NOMMU machine" |
289 | #endif | 327 | #endif |
@@ -301,6 +339,69 @@ typedef long arith_t; | |||
301 | # define BB_GLOBAL_CONST const | 339 | # define BB_GLOBAL_CONST const |
302 | #endif | 340 | #endif |
303 | 341 | ||
342 | #define FORKSHELL_DEBUG 0 | ||
343 | #if ENABLE_PLATFORM_MINGW32 | ||
344 | union node; | ||
345 | struct strlist; | ||
346 | struct job; | ||
347 | |||
348 | struct forkshell { | ||
349 | /* filled by forkshell_copy() */ | ||
350 | struct globals_var *gvp; | ||
351 | struct globals_misc *gmp; | ||
352 | struct tblentry **cmdtable; | ||
353 | /* struct alias **atab; */ | ||
354 | /* struct parsefile *g_parsefile; */ | ||
355 | HANDLE hMapFile; | ||
356 | char *old_base; | ||
357 | # if FORKSHELL_DEBUG | ||
358 | int nodeptrcount; | ||
359 | int funcblocksize; | ||
360 | int funcstringsize; | ||
361 | # endif | ||
362 | int size; | ||
363 | |||
364 | /* type of forkshell */ | ||
365 | int fpid; | ||
366 | |||
367 | /* generic data, used by forkshell_child */ | ||
368 | int mode; | ||
369 | int nprocs; | ||
370 | |||
371 | /* optional data, used by forkshell_child */ | ||
372 | int flags; | ||
373 | int fd[3]; | ||
374 | union node *n; | ||
375 | char **argv; | ||
376 | char *path; | ||
377 | struct strlist *varlist; | ||
378 | |||
379 | /* start of data block */ | ||
380 | char **nodeptr[1]; | ||
381 | }; | ||
382 | |||
383 | enum { | ||
384 | FS_OPENHERE, | ||
385 | FS_EVALBACKCMD, | ||
386 | FS_EVALSUBSHELL, | ||
387 | FS_EVALPIPE, | ||
388 | FS_SHELLEXEC | ||
389 | }; | ||
390 | |||
391 | static struct forkshell* forkshell_prepare(struct forkshell *fs); | ||
392 | static void forkshell_init(const char *idstr); | ||
393 | static void forkshell_child(struct forkshell *fs); | ||
394 | static void sticky_free(void *p); | ||
395 | # define free(p) sticky_free(p) | ||
396 | #if !JOBS | ||
397 | #define spawn_forkshell(fs, jp, n, mode) spawn_forkshell(fs, jp, mode) | ||
398 | #endif | ||
399 | static void spawn_forkshell(struct forkshell *fs, struct job *jp, | ||
400 | union node *n, int mode); | ||
401 | # if FORKSHELL_DEBUG | ||
402 | static void forkshell_print(FILE *fp0, struct forkshell *fs, char **notes); | ||
403 | # endif | ||
404 | #endif | ||
304 | 405 | ||
305 | /* ============ Hash table sizes. Configurable. */ | 406 | /* ============ Hash table sizes. Configurable. */ |
306 | 407 | ||
@@ -333,6 +434,15 @@ static const char *const optletters_optnames[] = { | |||
333 | ,"\0" "nolog" | 434 | ,"\0" "nolog" |
334 | ,"\0" "debug" | 435 | ,"\0" "debug" |
335 | #endif | 436 | #endif |
437 | #if ENABLE_PLATFORM_MINGW32 | ||
438 | ,"X" "winxp" | ||
439 | #endif | ||
440 | #if ENABLE_ASH_NOCONSOLE | ||
441 | ,"\0" "noconsole" | ||
442 | #endif | ||
443 | #if ENABLE_ASH_NOCASEGLOB | ||
444 | ,"\0" "nocaseglob" | ||
445 | #endif | ||
336 | }; | 446 | }; |
337 | 447 | ||
338 | #define optletters(n) optletters_optnames[n][0] | 448 | #define optletters(n) optletters_optnames[n][0] |
@@ -365,15 +475,25 @@ struct globals_misc { | |||
365 | int rootpid; /* pid of main shell */ | 475 | int rootpid; /* pid of main shell */ |
366 | /* shell level: 0 for the main shell, 1 for its children, and so on */ | 476 | /* shell level: 0 for the main shell, 1 for its children, and so on */ |
367 | int shlvl; | 477 | int shlvl; |
478 | #if ENABLE_PLATFORM_MINGW32 | ||
479 | int loopnest; /* current loop nesting level */ | ||
480 | #endif | ||
368 | #define rootshell (!shlvl) | 481 | #define rootshell (!shlvl) |
369 | int errlinno; | 482 | int errlinno; |
370 | 483 | ||
371 | char *minusc; /* argument to -c option */ | 484 | char *minusc; /* argument to -c option */ |
485 | #if ENABLE_PLATFORM_MINGW32 | ||
486 | char *dirarg; /* argument to -d option */ | ||
487 | char *title; /* argument to -t option */ | ||
488 | #endif | ||
372 | 489 | ||
373 | char *curdir; // = nullstr; /* current working directory */ | 490 | char *curdir; // = nullstr; /* current working directory */ |
374 | char *physdir; // = nullstr; /* physical working directory */ | 491 | char *physdir; // = nullstr; /* physical working directory */ |
375 | 492 | ||
376 | char *arg0; /* value of $0 */ | 493 | char *arg0; /* value of $0 */ |
494 | #if ENABLE_PLATFORM_MINGW32 | ||
495 | char *commandname; | ||
496 | #endif | ||
377 | 497 | ||
378 | struct jmploc *exception_handler; | 498 | struct jmploc *exception_handler; |
379 | 499 | ||
@@ -413,6 +533,15 @@ struct globals_misc { | |||
413 | # define nolog optlist[14 + BASH_PIPEFAIL] | 533 | # define nolog optlist[14 + BASH_PIPEFAIL] |
414 | # define debug optlist[15 + BASH_PIPEFAIL] | 534 | # define debug optlist[15 + BASH_PIPEFAIL] |
415 | #endif | 535 | #endif |
536 | #if ENABLE_PLATFORM_MINGW32 | ||
537 | # define winxp optlist[14 + BASH_PIPEFAIL + 2*DEBUG] | ||
538 | #endif | ||
539 | #if ENABLE_ASH_NOCONSOLE | ||
540 | # define noconsole optlist[15 + BASH_PIPEFAIL + 2*DEBUG] | ||
541 | #endif | ||
542 | #if ENABLE_ASH_NOCASEGLOB | ||
543 | # define nocaseglob optlist[15 + BASH_PIPEFAIL + 2*DEBUG + ENABLE_ASH_NOCONSOLE] | ||
544 | #endif | ||
416 | 545 | ||
417 | /* trap handler commands */ | 546 | /* trap handler commands */ |
418 | /* | 547 | /* |
@@ -446,10 +575,20 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
446 | #define rootpid (G_misc.rootpid ) | 575 | #define rootpid (G_misc.rootpid ) |
447 | #define shlvl (G_misc.shlvl ) | 576 | #define shlvl (G_misc.shlvl ) |
448 | #define errlinno (G_misc.errlinno ) | 577 | #define errlinno (G_misc.errlinno ) |
578 | #if ENABLE_PLATFORM_MINGW32 | ||
579 | #define loopnest (G_misc.loopnest ) | ||
580 | #endif | ||
449 | #define minusc (G_misc.minusc ) | 581 | #define minusc (G_misc.minusc ) |
582 | #if ENABLE_PLATFORM_MINGW32 | ||
583 | #define dirarg (G_misc.dirarg ) | ||
584 | #define title (G_misc.title ) | ||
585 | #endif | ||
450 | #define curdir (G_misc.curdir ) | 586 | #define curdir (G_misc.curdir ) |
451 | #define physdir (G_misc.physdir ) | 587 | #define physdir (G_misc.physdir ) |
452 | #define arg0 (G_misc.arg0 ) | 588 | #define arg0 (G_misc.arg0 ) |
589 | #if ENABLE_PLATFORM_MINGW32 | ||
590 | #define commandname (G_misc.commandname) | ||
591 | #endif | ||
453 | #define exception_handler (G_misc.exception_handler) | 592 | #define exception_handler (G_misc.exception_handler) |
454 | #define exception_type (G_misc.exception_type ) | 593 | #define exception_type (G_misc.exception_type ) |
455 | #define suppress_int (G_misc.suppress_int ) | 594 | #define suppress_int (G_misc.suppress_int ) |
@@ -1322,7 +1461,9 @@ struct parsefile { | |||
1322 | 1461 | ||
1323 | static struct parsefile basepf; /* top level input file */ | 1462 | static struct parsefile basepf; /* top level input file */ |
1324 | static struct parsefile *g_parsefile = &basepf; /* current input file */ | 1463 | static struct parsefile *g_parsefile = &basepf; /* current input file */ |
1464 | #if ENABLE_PLATFORM_POSIX | ||
1325 | static char *commandname; /* currently executing command */ | 1465 | static char *commandname; /* currently executing command */ |
1466 | #endif | ||
1326 | 1467 | ||
1327 | 1468 | ||
1328 | /* ============ Message printing */ | 1469 | /* ============ Message printing */ |
@@ -2327,6 +2468,42 @@ bltinlookup(const char *name) | |||
2327 | return lookupvar(name); | 2468 | return lookupvar(name); |
2328 | } | 2469 | } |
2329 | 2470 | ||
2471 | #if ENABLE_PLATFORM_MINGW32 | ||
2472 | static char * | ||
2473 | fix_pathvar(const char *path, int len) | ||
2474 | { | ||
2475 | char *newpath = xstrdup(path); | ||
2476 | char *p; | ||
2477 | int modified = FALSE; | ||
2478 | |||
2479 | p = newpath + len; | ||
2480 | while (*p) { | ||
2481 | if (*p != ':' && *p != ';') { | ||
2482 | /* skip drive */ | ||
2483 | if (isalpha(*p) && p[1] == ':') | ||
2484 | p += 2; | ||
2485 | /* skip through path component */ | ||
2486 | for (; *p != '\0' && *p != ':' && *p != ';'; ++p) | ||
2487 | continue; | ||
2488 | } | ||
2489 | /* *p is ':', ';' or '\0' here */ | ||
2490 | if (*p == ':') { | ||
2491 | *p++ = ';'; | ||
2492 | modified = TRUE; | ||
2493 | } | ||
2494 | else if (*p == ';') { | ||
2495 | ++p; | ||
2496 | } | ||
2497 | } | ||
2498 | |||
2499 | if (!modified) { | ||
2500 | free(newpath); | ||
2501 | newpath = NULL; | ||
2502 | } | ||
2503 | return newpath; | ||
2504 | } | ||
2505 | #endif | ||
2506 | |||
2330 | /* | 2507 | /* |
2331 | * Same as setvar except that the variable and value are passed in | 2508 | * Same as setvar except that the variable and value are passed in |
2332 | * the first argument as name=value. Since the first argument will | 2509 | * the first argument as name=value. Since the first argument will |
@@ -2339,6 +2516,27 @@ setvareq(char *s, int flags) | |||
2339 | { | 2516 | { |
2340 | struct var *vp, **vpp; | 2517 | struct var *vp, **vpp; |
2341 | 2518 | ||
2519 | #if ENABLE_PLATFORM_MINGW32 | ||
2520 | const char *paths = "PATH=\0""CDPATH=\0""MANPATH=\0"; | ||
2521 | const char *p; | ||
2522 | int len; | ||
2523 | |||
2524 | for (p = paths; *p; p += len + 1) { | ||
2525 | len = strlen(p); | ||
2526 | if (strncmp(s, p, len) == 0) { | ||
2527 | char *newpath = fix_pathvar(s, len); | ||
2528 | if (newpath) { | ||
2529 | if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE) | ||
2530 | free(s); | ||
2531 | flags |= VNOSAVE; | ||
2532 | flags &= ~(VTEXTFIXED|VSTACK); | ||
2533 | s = newpath; | ||
2534 | } | ||
2535 | break; | ||
2536 | } | ||
2537 | } | ||
2538 | #endif | ||
2539 | |||
2342 | vpp = hashvar(s); | 2540 | vpp = hashvar(s); |
2343 | flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); | 2541 | flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); |
2344 | vpp = findvar(vpp, s); | 2542 | vpp = findvar(vpp, s); |
@@ -2555,10 +2753,12 @@ path_advance(const char **path, const char *name) | |||
2555 | if (*path == NULL) | 2753 | if (*path == NULL) |
2556 | return NULL; | 2754 | return NULL; |
2557 | start = *path; | 2755 | start = *path; |
2558 | for (p = start; *p && *p != ':' && *p != '%'; p++) | 2756 | for (p = start; *p && *p != PATH_SEP && *p != '%'; p++) |
2559 | continue; | 2757 | continue; |
2560 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ | 2758 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ |
2561 | while (stackblocksize() < len) | 2759 | |
2760 | /* reserve space for suffix on WIN32 */ | ||
2761 | while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len)) | ||
2562 | growstackblock(); | 2762 | growstackblock(); |
2563 | q = stackblock(); | 2763 | q = stackblock(); |
2564 | if (p != start) { | 2764 | if (p != start) { |
@@ -2569,10 +2769,10 @@ path_advance(const char **path, const char *name) | |||
2569 | pathopt = NULL; | 2769 | pathopt = NULL; |
2570 | if (*p == '%') { | 2770 | if (*p == '%') { |
2571 | pathopt = ++p; | 2771 | pathopt = ++p; |
2572 | while (*p && *p != ':') | 2772 | while (*p && *p != PATH_SEP) |
2573 | p++; | 2773 | p++; |
2574 | } | 2774 | } |
2575 | if (*p == ':') | 2775 | if (*p == PATH_SEP) |
2576 | *path = p + 1; | 2776 | *path = p + 1; |
2577 | else | 2777 | else |
2578 | *path = NULL; | 2778 | *path = NULL; |
@@ -2656,6 +2856,7 @@ setprompt_if(smallint do_set, int whichprompt) | |||
2656 | 2856 | ||
2657 | #define CD_PHYSICAL 1 | 2857 | #define CD_PHYSICAL 1 |
2658 | #define CD_PRINT 2 | 2858 | #define CD_PRINT 2 |
2859 | #define CD_PRINT_ALL 4 | ||
2659 | 2860 | ||
2660 | static int | 2861 | static int |
2661 | cdopt(void) | 2862 | cdopt(void) |
@@ -2664,7 +2865,14 @@ cdopt(void) | |||
2664 | int i, j; | 2865 | int i, j; |
2665 | 2866 | ||
2666 | j = 'L'; | 2867 | j = 'L'; |
2868 | #if ENABLE_PLATFORM_MINGW32 | ||
2869 | while ((i = nextopt("LPa")) != '\0') { | ||
2870 | if (i == 'a') | ||
2871 | flags |= CD_PRINT_ALL; | ||
2872 | else | ||
2873 | #else | ||
2667 | while ((i = nextopt("LP")) != '\0') { | 2874 | while ((i = nextopt("LP")) != '\0') { |
2875 | #endif | ||
2668 | if (i != j) { | 2876 | if (i != j) { |
2669 | flags ^= CD_PHYSICAL; | 2877 | flags ^= CD_PHYSICAL; |
2670 | j = i; | 2878 | j = i; |
@@ -2681,6 +2889,114 @@ cdopt(void) | |||
2681 | static const char * | 2889 | static const char * |
2682 | updatepwd(const char *dir) | 2890 | updatepwd(const char *dir) |
2683 | { | 2891 | { |
2892 | #if ENABLE_PLATFORM_MINGW32 | ||
2893 | # define is_path_sep(x) ((x) == '/' || (x) == '\\') | ||
2894 | # define is_root(x) (is_path_sep(x[0]) && x[1] == '\0') | ||
2895 | /* | ||
2896 | * Due to Windows drive notion, getting pwd is a completely | ||
2897 | * different thing. Handle it in a separate routine | ||
2898 | */ | ||
2899 | |||
2900 | char *new; | ||
2901 | char *p; | ||
2902 | char *cdcomppath; | ||
2903 | const char *lim; | ||
2904 | int len = 0; | ||
2905 | /* | ||
2906 | * There are five cases that make some kind of sense | ||
2907 | * | ||
2908 | * Absolute paths: | ||
2909 | * c:/path | ||
2910 | * //host/share | ||
2911 | * | ||
2912 | * Relative to current drive: | ||
2913 | * /path | ||
2914 | * | ||
2915 | * Relative to current working directory of current drive | ||
2916 | * path | ||
2917 | * | ||
2918 | * Relative to current working directory of other drive | ||
2919 | * c:path | ||
2920 | */ | ||
2921 | int absdrive = has_dos_drive_prefix(dir); | ||
2922 | int curr_relpath = !absdrive && !is_path_sep(*dir); | ||
2923 | int other_relpath = absdrive && !is_path_sep(dir[2]); | ||
2924 | int relpath = curr_relpath || other_relpath; | ||
2925 | |||
2926 | cdcomppath = sstrdup(dir); | ||
2927 | STARTSTACKSTR(new); | ||
2928 | |||
2929 | /* prefix new path with current directory, if required */ | ||
2930 | if (other_relpath) { | ||
2931 | /* c:path */ | ||
2932 | char buffer[PATH_MAX]; | ||
2933 | |||
2934 | if (get_drive_cwd(dir, buffer, PATH_MAX) == NULL) | ||
2935 | return 0; | ||
2936 | new = stack_putstr(buffer, new); | ||
2937 | } | ||
2938 | else if (curr_relpath || (is_root(dir) && unc_root_len(curdir))) { | ||
2939 | /* relative path on current drive or explicit root of UNC curdir */ | ||
2940 | if (curdir == nullstr) | ||
2941 | return 0; | ||
2942 | new = stack_putstr(curdir, new); | ||
2943 | } | ||
2944 | |||
2945 | new = makestrspace(strlen(dir) + 2, new); | ||
2946 | |||
2947 | if ( (len=unc_root_len(dir)) || ((len=unc_root_len(curdir)) && | ||
2948 | (is_root(dir) || curr_relpath)) ) { | ||
2949 | /* //host/share or path relative to //host/share */ | ||
2950 | lim = (char *)stackblock() + len; | ||
2951 | } | ||
2952 | else { | ||
2953 | if (absdrive) { | ||
2954 | if (!relpath) | ||
2955 | new = stack_nputstr(dir, 2, new); | ||
2956 | cdcomppath += 2; | ||
2957 | dir += 2; | ||
2958 | } | ||
2959 | lim = (char *)stackblock() + 3; | ||
2960 | } | ||
2961 | |||
2962 | if (relpath) { | ||
2963 | if (!is_path_sep(new[-1])) | ||
2964 | USTPUTC('/', new); | ||
2965 | } else { | ||
2966 | USTPUTC('/', new); | ||
2967 | cdcomppath ++; | ||
2968 | if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) { | ||
2969 | USTPUTC('/', new); | ||
2970 | cdcomppath++; | ||
2971 | } | ||
2972 | } | ||
2973 | p = strtok(cdcomppath, "/\\"); | ||
2974 | while (p) { | ||
2975 | switch (*p) { | ||
2976 | case '.': | ||
2977 | if (p[1] == '.' && p[2] == '\0') { | ||
2978 | while (new > lim) { | ||
2979 | STUNPUTC(new); | ||
2980 | if (is_path_sep(new[-1])) | ||
2981 | break; | ||
2982 | } | ||
2983 | break; | ||
2984 | } | ||
2985 | if (p[1] == '\0') | ||
2986 | break; | ||
2987 | /* fall through */ | ||
2988 | default: | ||
2989 | new = stack_putstr(p, new); | ||
2990 | USTPUTC('/', new); | ||
2991 | } | ||
2992 | p = strtok(0, "/\\"); | ||
2993 | } | ||
2994 | if (new > lim) | ||
2995 | STUNPUTC(new); | ||
2996 | *new = 0; | ||
2997 | fix_path_case((char *)stackblock()); | ||
2998 | return stackblock(); | ||
2999 | #else | ||
2684 | char *new; | 3000 | char *new; |
2685 | char *p; | 3001 | char *p; |
2686 | char *cdcomppath; | 3002 | char *cdcomppath; |
@@ -2734,6 +3050,7 @@ updatepwd(const char *dir) | |||
2734 | STUNPUTC(new); | 3050 | STUNPUTC(new); |
2735 | *new = 0; | 3051 | *new = 0; |
2736 | return stackblock(); | 3052 | return stackblock(); |
3053 | #endif | ||
2737 | } | 3054 | } |
2738 | 3055 | ||
2739 | /* | 3056 | /* |
@@ -2828,7 +3145,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2828 | } | 3145 | } |
2829 | if (!dest) | 3146 | if (!dest) |
2830 | dest = nullstr; | 3147 | dest = nullstr; |
2831 | if (*dest == '/') | 3148 | if (is_absolute_path(dest)) |
2832 | goto step6; | 3149 | goto step6; |
2833 | if (*dest == '.') { | 3150 | if (*dest == '.') { |
2834 | c = dest[1]; | 3151 | c = dest[1]; |
@@ -2850,7 +3167,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2850 | c = *path; | 3167 | c = *path; |
2851 | p = path_advance(&path, dest); | 3168 | p = path_advance(&path, dest); |
2852 | if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { | 3169 | if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { |
2853 | if (c && c != ':') | 3170 | if (c && c != PATH_SEP) |
2854 | flags |= CD_PRINT; | 3171 | flags |= CD_PRINT; |
2855 | docd: | 3172 | docd: |
2856 | if (!docd(p, flags)) | 3173 | if (!docd(p, flags)) |
@@ -2872,6 +3189,26 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2872 | return 0; | 3189 | return 0; |
2873 | } | 3190 | } |
2874 | 3191 | ||
3192 | #if ENABLE_PLATFORM_MINGW32 | ||
3193 | static void | ||
3194 | print_all_cwd(void) | ||
3195 | { | ||
3196 | FILE *mnt; | ||
3197 | struct mntent *entry; | ||
3198 | char buffer[PATH_MAX]; | ||
3199 | |||
3200 | mnt = setmntent(bb_path_mtab_file, "r"); | ||
3201 | if (mnt) { | ||
3202 | while ((entry=getmntent(mnt)) != NULL) { | ||
3203 | entry->mnt_dir[2] = '\0'; | ||
3204 | if (get_drive_cwd(entry->mnt_dir, buffer, PATH_MAX) != NULL) | ||
3205 | out1fmt("%s\n", buffer); | ||
3206 | } | ||
3207 | endmntent(mnt); | ||
3208 | } | ||
3209 | } | ||
3210 | #endif | ||
3211 | |||
2875 | static int FAST_FUNC | 3212 | static int FAST_FUNC |
2876 | pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 3213 | pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) |
2877 | { | 3214 | { |
@@ -2879,6 +3216,12 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2879 | const char *dir = curdir; | 3216 | const char *dir = curdir; |
2880 | 3217 | ||
2881 | flags = cdopt(); | 3218 | flags = cdopt(); |
3219 | #if ENABLE_PLATFORM_MINGW32 | ||
3220 | if (flags & CD_PRINT_ALL) { | ||
3221 | print_all_cwd(); | ||
3222 | return 0; | ||
3223 | } | ||
3224 | #endif | ||
2882 | if (flags) { | 3225 | if (flags) { |
2883 | if (physdir == nullstr) | 3226 | if (physdir == nullstr) |
2884 | setpwd(dir, 0); | 3227 | setpwd(dir, 0); |
@@ -3530,6 +3873,9 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
3530 | */ | 3873 | */ |
3531 | struct procstat { | 3874 | struct procstat { |
3532 | pid_t ps_pid; /* process id */ | 3875 | pid_t ps_pid; /* process id */ |
3876 | #if ENABLE_PLATFORM_MINGW32 | ||
3877 | HANDLE ps_proc; | ||
3878 | #endif | ||
3533 | int ps_status; /* last process status from wait() */ | 3879 | int ps_status; /* last process status from wait() */ |
3534 | char *ps_cmd; /* text of command being run */ | 3880 | char *ps_cmd; /* text of command being run */ |
3535 | }; | 3881 | }; |
@@ -3558,7 +3904,9 @@ struct job { | |||
3558 | }; | 3904 | }; |
3559 | 3905 | ||
3560 | static struct job *makejob(/*union node *,*/ int); | 3906 | static struct job *makejob(/*union node *,*/ int); |
3907 | #if !ENABLE_PLATFORM_MINGW32 | ||
3561 | static int forkshell(struct job *, union node *, int); | 3908 | static int forkshell(struct job *, union node *, int); |
3909 | #endif | ||
3562 | static int waitforjob(struct job *); | 3910 | static int waitforjob(struct job *); |
3563 | 3911 | ||
3564 | #if !JOBS | 3912 | #if !JOBS |
@@ -3569,6 +3917,7 @@ static smallint doing_jobctl; //references:8 | |||
3569 | static void setjobctl(int); | 3917 | static void setjobctl(int); |
3570 | #endif | 3918 | #endif |
3571 | 3919 | ||
3920 | #if !ENABLE_PLATFORM_MINGW32 | ||
3572 | /* | 3921 | /* |
3573 | * Ignore a signal. | 3922 | * Ignore a signal. |
3574 | */ | 3923 | */ |
@@ -3715,6 +4064,10 @@ setsignal(int signo) | |||
3715 | 4064 | ||
3716 | sigaction_set(signo, &act); | 4065 | sigaction_set(signo, &act); |
3717 | } | 4066 | } |
4067 | #else | ||
4068 | #define setsignal(s) | ||
4069 | #define ignoresig(s) | ||
4070 | #endif | ||
3718 | 4071 | ||
3719 | /* mode flags for set_curjob */ | 4072 | /* mode flags for set_curjob */ |
3720 | #define CUR_DELETE 2 | 4073 | #define CUR_DELETE 2 |
@@ -4213,6 +4566,122 @@ sprint_status48(char *s, int status, int sigonly) | |||
4213 | return col; | 4566 | return col; |
4214 | } | 4567 | } |
4215 | 4568 | ||
4569 | #if ENABLE_PLATFORM_MINGW32 | ||
4570 | |||
4571 | HANDLE hSIGINT; /* Ctrl-C is pressed */ | ||
4572 | |||
4573 | static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) | ||
4574 | { | ||
4575 | if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { | ||
4576 | pending_int = 1; | ||
4577 | SetEvent(hSIGINT); | ||
4578 | return TRUE; | ||
4579 | } | ||
4580 | return FALSE; | ||
4581 | } | ||
4582 | |||
4583 | /* | ||
4584 | * Windows does not know about parent-child relationship | ||
4585 | * They don't support waitpid(-1) | ||
4586 | */ | ||
4587 | static pid_t | ||
4588 | waitpid_child(int *status, int wait_flags) | ||
4589 | { | ||
4590 | struct job *jb; | ||
4591 | struct procstat *ps; | ||
4592 | int pid_nr = 0; | ||
4593 | pid_t *pidlist; | ||
4594 | HANDLE *proclist; | ||
4595 | pid_t pid = -1; | ||
4596 | DWORD win_status, idx; | ||
4597 | int i, delay; | ||
4598 | |||
4599 | for (jb = curjob; jb; jb = jb->prev_job) { | ||
4600 | if (jb->state != JOBDONE) | ||
4601 | pid_nr += jb->nprocs; | ||
4602 | } | ||
4603 | if ( pid_nr++ == 0 ) | ||
4604 | return -1; | ||
4605 | |||
4606 | pidlist = ckmalloc(sizeof(*pidlist)*pid_nr); | ||
4607 | proclist = ckmalloc(sizeof(*proclist)*pid_nr); | ||
4608 | |||
4609 | pidlist[0] = -1; | ||
4610 | proclist[0] = hSIGINT; | ||
4611 | pid_nr = 1; | ||
4612 | for (jb = curjob; jb; jb = jb->prev_job) { | ||
4613 | if (jb->state == JOBDONE) | ||
4614 | continue; | ||
4615 | ps = jb->ps; | ||
4616 | for (i = 0; i < jb->nprocs; ++i) { | ||
4617 | if (ps[i].ps_proc) { | ||
4618 | pidlist[pid_nr] = ps[i].ps_pid; | ||
4619 | proclist[pid_nr++] = ps[i].ps_proc; | ||
4620 | } | ||
4621 | } | ||
4622 | } | ||
4623 | |||
4624 | if (pid_nr == 1) | ||
4625 | goto done; | ||
4626 | |||
4627 | idx = WaitForMultipleObjects(pid_nr, proclist, FALSE, | ||
4628 | wait_flags&WNOHANG ? 1 : INFINITE); | ||
4629 | if (idx < pid_nr) { | ||
4630 | if (idx == 0) { /* hSIGINT */ | ||
4631 | ResetEvent(hSIGINT); | ||
4632 | |||
4633 | ps = curjob->ps; | ||
4634 | for (i = 0; i < curjob->nprocs; ++i) { | ||
4635 | if (ps[i].ps_proc) { | ||
4636 | kill_SIGTERM_by_handle(ps[i].ps_proc, 128+SIGINT); | ||
4637 | pid = ps[i].ps_pid; /* remember last valid pid */ | ||
4638 | } | ||
4639 | } | ||
4640 | |||
4641 | Sleep(200); | ||
4642 | delay = FALSE; | ||
4643 | for (i = 0; i < curjob->nprocs; ++i) { | ||
4644 | DWORD code; | ||
4645 | if (ps[i].ps_proc && | ||
4646 | GetExitCodeProcess(ps[i].ps_proc, &code) && | ||
4647 | code == STILL_ACTIVE) { | ||
4648 | TerminateProcess(ps[i].ps_proc, 128+SIGINT); | ||
4649 | delay = TRUE; | ||
4650 | } | ||
4651 | } | ||
4652 | |||
4653 | if (delay) | ||
4654 | Sleep(200); | ||
4655 | for (i = 0; i < curjob->nprocs; ++i) { | ||
4656 | /* mark all pids dead except the one we'll return */ | ||
4657 | if (ps[i].ps_pid != pid) { | ||
4658 | ps[i].ps_status = 128 + SIGINT; | ||
4659 | ps[i].ps_pid = -1; | ||
4660 | CloseHandle(ps[i].ps_proc); | ||
4661 | ps[i].ps_proc = NULL; | ||
4662 | } | ||
4663 | } | ||
4664 | |||
4665 | *status = 128 + SIGINT; /* terminated by a signal */ | ||
4666 | if (iflag) | ||
4667 | write(STDOUT_FILENO, "^C", 2); | ||
4668 | } | ||
4669 | else { /* valid pid index */ | ||
4670 | GetExitCodeProcess(proclist[idx], &win_status); | ||
4671 | *status = (int)win_status << 8; | ||
4672 | pid = pidlist[idx]; | ||
4673 | } | ||
4674 | } | ||
4675 | done: | ||
4676 | free(pidlist); | ||
4677 | free(proclist); | ||
4678 | return pid; | ||
4679 | } | ||
4680 | #define waitpid(p, s, f) waitpid_child(s, f) | ||
4681 | #define wait_block_or_sig(s) waitpid_child(s, 0) | ||
4682 | |||
4683 | #else | ||
4684 | |||
4216 | static int | 4685 | static int |
4217 | wait_block_or_sig(int *status) | 4686 | wait_block_or_sig(int *status) |
4218 | { | 4687 | { |
@@ -4245,6 +4714,7 @@ wait_block_or_sig(int *status) | |||
4245 | 4714 | ||
4246 | return pid; | 4715 | return pid; |
4247 | } | 4716 | } |
4717 | #endif | ||
4248 | 4718 | ||
4249 | #define DOWAIT_NONBLOCK 0 | 4719 | #define DOWAIT_NONBLOCK 0 |
4250 | #define DOWAIT_BLOCK 1 | 4720 | #define DOWAIT_BLOCK 1 |
@@ -4320,6 +4790,11 @@ dowait(int block, struct job *job) | |||
4320 | jobno(jp), pid, ps->ps_status, status)); | 4790 | jobno(jp), pid, ps->ps_status, status)); |
4321 | ps->ps_status = status; | 4791 | ps->ps_status = status; |
4322 | thisjob = jp; | 4792 | thisjob = jp; |
4793 | #if ENABLE_PLATFORM_MINGW32 | ||
4794 | ps->ps_pid = -1; | ||
4795 | CloseHandle(ps->ps_proc); | ||
4796 | ps->ps_proc = NULL; | ||
4797 | #endif | ||
4323 | } | 4798 | } |
4324 | if (ps->ps_status == -1) | 4799 | if (ps->ps_status == -1) |
4325 | jobstate = JOBRUNNING; | 4800 | jobstate = JOBRUNNING; |
@@ -5036,6 +5511,7 @@ commandtext(union node *n) | |||
5036 | * | 5511 | * |
5037 | * Called with interrupts off. | 5512 | * Called with interrupts off. |
5038 | */ | 5513 | */ |
5514 | #if !ENABLE_PLATFORM_MINGW32 | ||
5039 | /* | 5515 | /* |
5040 | * Clear traps on a fork. | 5516 | * Clear traps on a fork. |
5041 | */ | 5517 | */ |
@@ -5185,16 +5661,24 @@ forkchild(struct job *jp, union node *n, int mode) | |||
5185 | freejob(jp); | 5661 | freejob(jp); |
5186 | jobless = 0; | 5662 | jobless = 0; |
5187 | } | 5663 | } |
5664 | #endif | ||
5188 | 5665 | ||
5189 | /* Called after fork(), in parent */ | 5666 | /* Called after fork(), in parent */ |
5190 | #if !JOBS | 5667 | #if !JOBS |
5191 | #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) | 5668 | #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) |
5192 | #endif | 5669 | #endif |
5193 | static void | 5670 | static void |
5671 | #if !ENABLE_PLATFORM_MINGW32 | ||
5194 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 5672 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
5673 | #else | ||
5674 | forkparent(struct job *jp, union node *n, int mode, HANDLE proc) | ||
5675 | #endif | ||
5195 | { | 5676 | { |
5677 | #if ENABLE_PLATFORM_MINGW32 | ||
5678 | pid_t pid = GetProcessId(proc); | ||
5679 | #endif | ||
5196 | TRACE(("In parent shell: child = %d\n", pid)); | 5680 | TRACE(("In parent shell: child = %d\n", pid)); |
5197 | if (!jp) { | 5681 | if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */ |
5198 | /* jp is NULL when called by openhere() for heredoc support */ | 5682 | /* jp is NULL when called by openhere() for heredoc support */ |
5199 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) | 5683 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) |
5200 | continue; | 5684 | continue; |
@@ -5220,6 +5704,9 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) | |||
5220 | if (jp) { | 5704 | if (jp) { |
5221 | struct procstat *ps = &jp->ps[jp->nprocs++]; | 5705 | struct procstat *ps = &jp->ps[jp->nprocs++]; |
5222 | ps->ps_pid = pid; | 5706 | ps->ps_pid = pid; |
5707 | #if ENABLE_PLATFORM_MINGW32 | ||
5708 | ps->ps_proc = proc; | ||
5709 | #endif | ||
5223 | ps->ps_status = -1; | 5710 | ps->ps_status = -1; |
5224 | ps->ps_cmd = nullstr; | 5711 | ps->ps_cmd = nullstr; |
5225 | #if JOBS | 5712 | #if JOBS |
@@ -5229,6 +5716,7 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) | |||
5229 | } | 5716 | } |
5230 | } | 5717 | } |
5231 | 5718 | ||
5719 | #if !ENABLE_PLATFORM_MINGW32 | ||
5232 | /* jp and n are NULL when called by openhere() for heredoc support */ | 5720 | /* jp and n are NULL when called by openhere() for heredoc support */ |
5233 | static int | 5721 | static int |
5234 | forkshell(struct job *jp, union node *n, int mode) | 5722 | forkshell(struct job *jp, union node *n, int mode) |
@@ -5251,6 +5739,7 @@ forkshell(struct job *jp, union node *n, int mode) | |||
5251 | } | 5739 | } |
5252 | return pid; | 5740 | return pid; |
5253 | } | 5741 | } |
5742 | #endif | ||
5254 | 5743 | ||
5255 | /* | 5744 | /* |
5256 | * Wait for job to finish. | 5745 | * Wait for job to finish. |
@@ -5382,6 +5871,7 @@ openhere(union node *redir) | |||
5382 | { | 5871 | { |
5383 | int pip[2]; | 5872 | int pip[2]; |
5384 | size_t len = 0; | 5873 | size_t len = 0; |
5874 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5385 | 5875 | ||
5386 | if (pipe(pip) < 0) | 5876 | if (pipe(pip) < 0) |
5387 | ash_msg_and_raise_perror("can't create pipe"); | 5877 | ash_msg_and_raise_perror("can't create pipe"); |
@@ -5392,6 +5882,14 @@ openhere(union node *redir) | |||
5392 | goto out; | 5882 | goto out; |
5393 | } | 5883 | } |
5394 | } | 5884 | } |
5885 | #if ENABLE_PLATFORM_MINGW32 | ||
5886 | memset(&fs, 0, sizeof(fs)); | ||
5887 | fs.fpid = FS_OPENHERE; | ||
5888 | fs.n = redir; | ||
5889 | fs.fd[0] = pip[0]; | ||
5890 | fs.fd[1] = pip[1]; | ||
5891 | spawn_forkshell(&fs, NULL, NULL, FORK_NOJOB); | ||
5892 | #else | ||
5395 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | 5893 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { |
5396 | /* child */ | 5894 | /* child */ |
5397 | close(pip[0]); | 5895 | close(pip[0]); |
@@ -5406,6 +5904,7 @@ openhere(union node *redir) | |||
5406 | expandhere(redir->nhere.doc, pip[1]); | 5904 | expandhere(redir->nhere.doc, pip[1]); |
5407 | _exit(EXIT_SUCCESS); | 5905 | _exit(EXIT_SUCCESS); |
5408 | } | 5906 | } |
5907 | #endif | ||
5409 | out: | 5908 | out: |
5410 | close(pip[1]); | 5909 | close(pip[1]); |
5411 | return pip[0]; | 5910 | return pip[0]; |
@@ -5483,6 +5982,9 @@ openredirect(union node *redir) | |||
5483 | f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); | 5982 | f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); |
5484 | if (f < 0) | 5983 | if (f < 0) |
5485 | goto ecreate; | 5984 | goto ecreate; |
5985 | #if ENABLE_PLATFORM_MINGW32 | ||
5986 | lseek(f, 0, SEEK_END); | ||
5987 | #endif | ||
5486 | break; | 5988 | break; |
5487 | } | 5989 | } |
5488 | 5990 | ||
@@ -6462,6 +6964,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
6462 | { | 6964 | { |
6463 | int pip[2]; | 6965 | int pip[2]; |
6464 | struct job *jp; | 6966 | struct job *jp; |
6967 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
6465 | 6968 | ||
6466 | result->fd = -1; | 6969 | result->fd = -1; |
6467 | result->buf = NULL; | 6970 | result->buf = NULL; |
@@ -6474,6 +6977,14 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
6474 | if (pipe(pip) < 0) | 6977 | if (pipe(pip) < 0) |
6475 | ash_msg_and_raise_perror("can't create pipe"); | 6978 | ash_msg_and_raise_perror("can't create pipe"); |
6476 | jp = makejob(/*n,*/ 1); | 6979 | jp = makejob(/*n,*/ 1); |
6980 | #if ENABLE_PLATFORM_MINGW32 | ||
6981 | memset(&fs, 0, sizeof(fs)); | ||
6982 | fs.fpid = FS_EVALBACKCMD; | ||
6983 | fs.n = n; | ||
6984 | fs.fd[0] = pip[0]; | ||
6985 | fs.fd[1] = pip[1]; | ||
6986 | spawn_forkshell(&fs, jp, n, FORK_NOJOB); | ||
6987 | #else | ||
6477 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 6988 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
6478 | /* child */ | 6989 | /* child */ |
6479 | FORCE_INT_ON; | 6990 | FORCE_INT_ON; |
@@ -6496,6 +7007,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
6496 | evaltreenr(n, EV_EXIT); | 7007 | evaltreenr(n, EV_EXIT); |
6497 | /* NOTREACHED */ | 7008 | /* NOTREACHED */ |
6498 | } | 7009 | } |
7010 | #endif | ||
6499 | /* parent */ | 7011 | /* parent */ |
6500 | close(pip[1]); | 7012 | close(pip[1]); |
6501 | result->fd = pip[0]; | 7013 | result->fd = pip[0]; |
@@ -6552,7 +7064,8 @@ expbackq(union node *cmd, int flag) | |||
6552 | 7064 | ||
6553 | /* Eat all trailing newlines */ | 7065 | /* Eat all trailing newlines */ |
6554 | dest = expdest; | 7066 | dest = expdest; |
6555 | for (; dest > (char *)stackblock() && dest[-1] == '\n';) | 7067 | for (; dest > (char *)stackblock() && (dest[-1] == '\n' || |
7068 | (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));) | ||
6556 | STUNPUTC(dest); | 7069 | STUNPUTC(dest); |
6557 | expdest = dest; | 7070 | expdest = dest; |
6558 | 7071 | ||
@@ -7752,6 +8265,10 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
7752 | while (!pending_int && (dp = readdir(dirp)) != NULL) { | 8265 | while (!pending_int && (dp = readdir(dirp)) != NULL) { |
7753 | if (dp->d_name[0] == '.' && !matchdot) | 8266 | if (dp->d_name[0] == '.' && !matchdot) |
7754 | continue; | 8267 | continue; |
8268 | #if ENABLE_ASH_NOCASEGLOB | ||
8269 | # undef pmatch | ||
8270 | # define pmatch(a, b) !fnmatch((a), (b), nocaseglob ? FNM_CASEFOLD : 0) | ||
8271 | #endif | ||
7755 | if (pmatch(start, dp->d_name)) { | 8272 | if (pmatch(start, dp->d_name)) { |
7756 | if (atend) { | 8273 | if (atend) { |
7757 | strcpy(enddir, dp->d_name); | 8274 | strcpy(enddir, dp->d_name); |
@@ -7781,6 +8298,10 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) | |||
7781 | endname[-esc - 1] = esc ? '\\' : '/'; | 8298 | endname[-esc - 1] = esc ? '\\' : '/'; |
7782 | #undef expdir | 8299 | #undef expdir |
7783 | #undef expdir_max | 8300 | #undef expdir_max |
8301 | #if ENABLE_ASH_NOCASEGLOB | ||
8302 | # undef pmatch | ||
8303 | # define pmatch(a, b) !fnmatch((a), (b), 0) | ||
8304 | #endif | ||
7784 | } | 8305 | } |
7785 | 8306 | ||
7786 | static struct strlist * | 8307 | static struct strlist * |
@@ -8075,6 +8596,11 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
8075 | } | 8596 | } |
8076 | #endif | 8597 | #endif |
8077 | 8598 | ||
8599 | #if ENABLE_PLATFORM_MINGW32 | ||
8600 | cmd = auto_win32_extension(cmd) ?: cmd; | ||
8601 | execve(cmd, argv, envp); | ||
8602 | /* skip POSIX-mandated retry on ENOEXEC */ | ||
8603 | #else | ||
8078 | repeat: | 8604 | repeat: |
8079 | #ifdef SYSV | 8605 | #ifdef SYSV |
8080 | do { | 8606 | do { |
@@ -8110,6 +8636,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
8110 | argv[0] = (char*) "ash"; | 8636 | argv[0] = (char*) "ash"; |
8111 | goto repeat; | 8637 | goto repeat; |
8112 | } | 8638 | } |
8639 | #endif /* ENABLE_PLATFORM_MINGW32 */ | ||
8113 | } | 8640 | } |
8114 | 8641 | ||
8115 | /* | 8642 | /* |
@@ -8127,7 +8654,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
8127 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ | 8654 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ |
8128 | 8655 | ||
8129 | envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); | 8656 | envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); |
8130 | if (strchr(prog, '/') != NULL | 8657 | if ((strchr(prog, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(prog, '\\'))) |
8131 | #if ENABLE_FEATURE_SH_STANDALONE | 8658 | #if ENABLE_FEATURE_SH_STANDALONE |
8132 | || (applet_no = find_applet_by_name(prog)) >= 0 | 8659 | || (applet_no = find_applet_by_name(prog)) >= 0 |
8133 | #endif | 8660 | #endif |
@@ -8186,6 +8713,9 @@ printentry(struct tblentry *cmdp) | |||
8186 | name = path_advance(&path, cmdp->cmdname); | 8713 | name = path_advance(&path, cmdp->cmdname); |
8187 | stunalloc(name); | 8714 | stunalloc(name); |
8188 | } while (--idx >= 0); | 8715 | } while (--idx >= 0); |
8716 | #if ENABLE_PLATFORM_MINGW32 | ||
8717 | add_win32_extension(name); | ||
8718 | #endif | ||
8189 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); | 8719 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); |
8190 | } | 8720 | } |
8191 | 8721 | ||
@@ -8382,8 +8912,8 @@ changepath(const char *new) | |||
8382 | for (;;) { | 8912 | for (;;) { |
8383 | if (*old != *new) { | 8913 | if (*old != *new) { |
8384 | firstchange = idx; | 8914 | firstchange = idx; |
8385 | if ((*old == '\0' && *new == ':') | 8915 | if ((*old == '\0' && *new == PATH_SEP) |
8386 | || (*old == ':' && *new == '\0') | 8916 | || (*old == PATH_SEP && *new == '\0') |
8387 | ) { | 8917 | ) { |
8388 | firstchange++; | 8918 | firstchange++; |
8389 | } | 8919 | } |
@@ -8393,7 +8923,7 @@ changepath(const char *new) | |||
8393 | break; | 8923 | break; |
8394 | if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin")) | 8924 | if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin")) |
8395 | idx_bltin = idx; | 8925 | idx_bltin = idx; |
8396 | if (*new == ':') | 8926 | if (*new == PATH_SEP) |
8397 | idx++; | 8927 | idx++; |
8398 | new++; | 8928 | new++; |
8399 | old++; | 8929 | old++; |
@@ -8582,6 +9112,9 @@ describe_command(char *command, const char *path, int describe_command_verbose) | |||
8582 | stunalloc(p); | 9112 | stunalloc(p); |
8583 | } while (--j >= 0); | 9113 | } while (--j >= 0); |
8584 | } | 9114 | } |
9115 | #if ENABLE_PLATFORM_MINGW32 | ||
9116 | add_win32_extension(p); | ||
9117 | #endif | ||
8585 | if (describe_command_verbose) { | 9118 | if (describe_command_verbose) { |
8586 | out1fmt(" is %s", p); | 9119 | out1fmt(" is %s", p); |
8587 | } else { | 9120 | } else { |
@@ -8716,6 +9249,14 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
8716 | /*static int funcstringsize; // size of strings in node */ | 9249 | /*static int funcstringsize; // size of strings in node */ |
8717 | static void *funcblock; /* block to allocate function from */ | 9250 | static void *funcblock; /* block to allocate function from */ |
8718 | static char *funcstring_end; /* end of block to allocate strings from */ | 9251 | static char *funcstring_end; /* end of block to allocate strings from */ |
9252 | #if ENABLE_PLATFORM_MINGW32 | ||
9253 | static int nodeptrcount; | ||
9254 | static char ***nodeptr; | ||
9255 | # if FORKSHELL_DEBUG | ||
9256 | static int annot_count; | ||
9257 | static char **annot; | ||
9258 | # endif | ||
9259 | #endif | ||
8719 | 9260 | ||
8720 | static const uint8_t nodesize[N_NUMBER] ALIGN1 = { | 9261 | static const uint8_t nodesize[N_NUMBER] ALIGN1 = { |
8721 | [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), | 9262 | [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), |
@@ -8756,6 +9297,7 @@ sizenodelist(int funcblocksize, struct nodelist *lp) | |||
8756 | { | 9297 | { |
8757 | while (lp) { | 9298 | while (lp) { |
8758 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); | 9299 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); |
9300 | IF_PLATFORM_MINGW32(nodeptrcount += 2); | ||
8759 | funcblocksize = calcsize(funcblocksize, lp->n); | 9301 | funcblocksize = calcsize(funcblocksize, lp->n); |
8760 | lp = lp->next; | 9302 | lp = lp->next; |
8761 | } | 9303 | } |
@@ -8773,15 +9315,18 @@ calcsize(int funcblocksize, union node *n) | |||
8773 | funcblocksize = calcsize(funcblocksize, n->ncmd.redirect); | 9315 | funcblocksize = calcsize(funcblocksize, n->ncmd.redirect); |
8774 | funcblocksize = calcsize(funcblocksize, n->ncmd.args); | 9316 | funcblocksize = calcsize(funcblocksize, n->ncmd.args); |
8775 | funcblocksize = calcsize(funcblocksize, n->ncmd.assign); | 9317 | funcblocksize = calcsize(funcblocksize, n->ncmd.assign); |
9318 | IF_PLATFORM_MINGW32(nodeptrcount += 3); | ||
8776 | break; | 9319 | break; |
8777 | case NPIPE: | 9320 | case NPIPE: |
8778 | funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist); | 9321 | funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist); |
9322 | IF_PLATFORM_MINGW32(nodeptrcount++); | ||
8779 | break; | 9323 | break; |
8780 | case NREDIR: | 9324 | case NREDIR: |
8781 | case NBACKGND: | 9325 | case NBACKGND: |
8782 | case NSUBSHELL: | 9326 | case NSUBSHELL: |
8783 | funcblocksize = calcsize(funcblocksize, n->nredir.redirect); | 9327 | funcblocksize = calcsize(funcblocksize, n->nredir.redirect); |
8784 | funcblocksize = calcsize(funcblocksize, n->nredir.n); | 9328 | funcblocksize = calcsize(funcblocksize, n->nredir.n); |
9329 | IF_PLATFORM_MINGW32(nodeptrcount += 2); | ||
8785 | break; | 9330 | break; |
8786 | case NAND: | 9331 | case NAND: |
8787 | case NOR: | 9332 | case NOR: |
@@ -8790,34 +9335,41 @@ calcsize(int funcblocksize, union node *n) | |||
8790 | case NUNTIL: | 9335 | case NUNTIL: |
8791 | funcblocksize = calcsize(funcblocksize, n->nbinary.ch2); | 9336 | funcblocksize = calcsize(funcblocksize, n->nbinary.ch2); |
8792 | funcblocksize = calcsize(funcblocksize, n->nbinary.ch1); | 9337 | funcblocksize = calcsize(funcblocksize, n->nbinary.ch1); |
9338 | IF_PLATFORM_MINGW32(nodeptrcount += 2); | ||
8793 | break; | 9339 | break; |
8794 | case NIF: | 9340 | case NIF: |
8795 | funcblocksize = calcsize(funcblocksize, n->nif.elsepart); | 9341 | funcblocksize = calcsize(funcblocksize, n->nif.elsepart); |
8796 | funcblocksize = calcsize(funcblocksize, n->nif.ifpart); | 9342 | funcblocksize = calcsize(funcblocksize, n->nif.ifpart); |
8797 | funcblocksize = calcsize(funcblocksize, n->nif.test); | 9343 | funcblocksize = calcsize(funcblocksize, n->nif.test); |
9344 | IF_PLATFORM_MINGW32(nodeptrcount += 3); | ||
8798 | break; | 9345 | break; |
8799 | case NFOR: | 9346 | case NFOR: |
8800 | funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */ | 9347 | funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */ |
8801 | funcblocksize = calcsize(funcblocksize, n->nfor.body); | 9348 | funcblocksize = calcsize(funcblocksize, n->nfor.body); |
8802 | funcblocksize = calcsize(funcblocksize, n->nfor.args); | 9349 | funcblocksize = calcsize(funcblocksize, n->nfor.args); |
9350 | IF_PLATFORM_MINGW32(nodeptrcount += 3); | ||
8803 | break; | 9351 | break; |
8804 | case NCASE: | 9352 | case NCASE: |
8805 | funcblocksize = calcsize(funcblocksize, n->ncase.cases); | 9353 | funcblocksize = calcsize(funcblocksize, n->ncase.cases); |
8806 | funcblocksize = calcsize(funcblocksize, n->ncase.expr); | 9354 | funcblocksize = calcsize(funcblocksize, n->ncase.expr); |
9355 | IF_PLATFORM_MINGW32(nodeptrcount += 2); | ||
8807 | break; | 9356 | break; |
8808 | case NCLIST: | 9357 | case NCLIST: |
8809 | funcblocksize = calcsize(funcblocksize, n->nclist.body); | 9358 | funcblocksize = calcsize(funcblocksize, n->nclist.body); |
8810 | funcblocksize = calcsize(funcblocksize, n->nclist.pattern); | 9359 | funcblocksize = calcsize(funcblocksize, n->nclist.pattern); |
8811 | funcblocksize = calcsize(funcblocksize, n->nclist.next); | 9360 | funcblocksize = calcsize(funcblocksize, n->nclist.next); |
9361 | IF_PLATFORM_MINGW32(nodeptrcount += 3); | ||
8812 | break; | 9362 | break; |
8813 | case NDEFUN: | 9363 | case NDEFUN: |
8814 | funcblocksize = calcsize(funcblocksize, n->ndefun.body); | 9364 | funcblocksize = calcsize(funcblocksize, n->ndefun.body); |
8815 | funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1); | 9365 | funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1); |
9366 | IF_PLATFORM_MINGW32(nodeptrcount += 2); | ||
8816 | break; | 9367 | break; |
8817 | case NARG: | 9368 | case NARG: |
8818 | funcblocksize = sizenodelist(funcblocksize, n->narg.backquote); | 9369 | funcblocksize = sizenodelist(funcblocksize, n->narg.backquote); |
8819 | funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */ | 9370 | funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */ |
8820 | funcblocksize = calcsize(funcblocksize, n->narg.next); | 9371 | funcblocksize = calcsize(funcblocksize, n->narg.next); |
9372 | IF_PLATFORM_MINGW32(nodeptrcount += 3); | ||
8821 | break; | 9373 | break; |
8822 | case NTO: | 9374 | case NTO: |
8823 | #if BASH_REDIR_OUTPUT | 9375 | #if BASH_REDIR_OUTPUT |
@@ -8829,33 +9381,65 @@ calcsize(int funcblocksize, union node *n) | |||
8829 | case NAPPEND: | 9381 | case NAPPEND: |
8830 | funcblocksize = calcsize(funcblocksize, n->nfile.fname); | 9382 | funcblocksize = calcsize(funcblocksize, n->nfile.fname); |
8831 | funcblocksize = calcsize(funcblocksize, n->nfile.next); | 9383 | funcblocksize = calcsize(funcblocksize, n->nfile.next); |
9384 | IF_PLATFORM_MINGW32(nodeptrcount += 2); | ||
8832 | break; | 9385 | break; |
8833 | case NTOFD: | 9386 | case NTOFD: |
8834 | case NFROMFD: | 9387 | case NFROMFD: |
8835 | funcblocksize = calcsize(funcblocksize, n->ndup.vname); | 9388 | funcblocksize = calcsize(funcblocksize, n->ndup.vname); |
8836 | funcblocksize = calcsize(funcblocksize, n->ndup.next); | 9389 | funcblocksize = calcsize(funcblocksize, n->ndup.next); |
9390 | IF_PLATFORM_MINGW32(nodeptrcount += 2); | ||
8837 | break; | 9391 | break; |
8838 | case NHERE: | 9392 | case NHERE: |
8839 | case NXHERE: | 9393 | case NXHERE: |
8840 | funcblocksize = calcsize(funcblocksize, n->nhere.doc); | 9394 | funcblocksize = calcsize(funcblocksize, n->nhere.doc); |
8841 | funcblocksize = calcsize(funcblocksize, n->nhere.next); | 9395 | funcblocksize = calcsize(funcblocksize, n->nhere.next); |
9396 | IF_PLATFORM_MINGW32(nodeptrcount += 2); | ||
8842 | break; | 9397 | break; |
8843 | case NNOT: | 9398 | case NNOT: |
8844 | funcblocksize = calcsize(funcblocksize, n->nnot.com); | 9399 | funcblocksize = calcsize(funcblocksize, n->nnot.com); |
9400 | IF_PLATFORM_MINGW32(nodeptrcount++); | ||
8845 | break; | 9401 | break; |
8846 | }; | 9402 | }; |
8847 | return funcblocksize; | 9403 | return funcblocksize; |
8848 | } | 9404 | } |
8849 | 9405 | ||
8850 | static char * | 9406 | static char * |
8851 | nodeckstrdup(char *s) | 9407 | nodeckstrdup(const char *s) |
8852 | { | 9408 | { |
9409 | #if ENABLE_PLATFORM_MINGW32 | ||
9410 | if(!s) | ||
9411 | return NULL; | ||
9412 | #endif | ||
8853 | funcstring_end -= SHELL_ALIGN(strlen(s) + 1); | 9413 | funcstring_end -= SHELL_ALIGN(strlen(s) + 1); |
8854 | return strcpy(funcstring_end, s); | 9414 | return strcpy(funcstring_end, s); |
8855 | } | 9415 | } |
8856 | 9416 | ||
8857 | static union node *copynode(union node *); | 9417 | static union node *copynode(union node *); |
8858 | 9418 | ||
9419 | #if ENABLE_PLATFORM_MINGW32 | ||
9420 | # define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (char **)&(dst);} | ||
9421 | # define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (char **)&(dst1);*nodeptr++ = (char **)&(dst2);}} | ||
9422 | # define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (char **)&(dst1);*nodeptr++ = (char **)&(dst2);*nodeptr++ = (char **)&(dst3);}} | ||
9423 | #else | ||
9424 | # define SAVE_PTR(dst) | ||
9425 | # define SAVE_PTR2(dst,dst2) | ||
9426 | # define SAVE_PTR3(dst,dst2,dst3) | ||
9427 | #endif | ||
9428 | |||
9429 | #if ENABLE_PLATFORM_MINGW32 && FORKSHELL_DEBUG | ||
9430 | # define ANNOT_NO_DUP(note) {if (annot) annot[annot_count++] = note;} | ||
9431 | # define ANNOT(note) {ANNOT_NO_DUP(xstrdup(note));} | ||
9432 | # define ANNOT2(n1,n2) {ANNOT(n1); ANNOT(n2)} | ||
9433 | # define ANNOT3(n1,n2,n3) {ANNOT2(n1,n2); ANNOT(n3);} | ||
9434 | # define ANNOT4(n1,n2,n3,n4) {ANNOT3(n1,n2,n3); ANNOT(n4);} | ||
9435 | #else | ||
9436 | # define ANNOT_NO_DUP(note) | ||
9437 | # define ANNOT(note) | ||
9438 | # define ANNOT2(n1,n2) | ||
9439 | # define ANNOT3(n1,n2,n3) | ||
9440 | # define ANNOT4(n1,n2,n3,n4) | ||
9441 | #endif | ||
9442 | |||
8859 | static struct nodelist * | 9443 | static struct nodelist * |
8860 | copynodelist(struct nodelist *lp) | 9444 | copynodelist(struct nodelist *lp) |
8861 | { | 9445 | { |
@@ -8867,6 +9451,8 @@ copynodelist(struct nodelist *lp) | |||
8867 | *lpp = funcblock; | 9451 | *lpp = funcblock; |
8868 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); | 9452 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); |
8869 | (*lpp)->n = copynode(lp->n); | 9453 | (*lpp)->n = copynode(lp->n); |
9454 | SAVE_PTR2((*lpp)->n, (*lpp)->next); | ||
9455 | ANNOT2("(*lpp)->n","(*lpp)->next"); | ||
8870 | lp = lp->next; | 9456 | lp = lp->next; |
8871 | lpp = &(*lpp)->next; | 9457 | lpp = &(*lpp)->next; |
8872 | } | 9458 | } |
@@ -8890,10 +9476,14 @@ copynode(union node *n) | |||
8890 | new->ncmd.args = copynode(n->ncmd.args); | 9476 | new->ncmd.args = copynode(n->ncmd.args); |
8891 | new->ncmd.assign = copynode(n->ncmd.assign); | 9477 | new->ncmd.assign = copynode(n->ncmd.assign); |
8892 | new->ncmd.linno = n->ncmd.linno; | 9478 | new->ncmd.linno = n->ncmd.linno; |
9479 | SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign); | ||
9480 | ANNOT3("ncmd.redirect","ncmd.args","ncmd.assign"); | ||
8893 | break; | 9481 | break; |
8894 | case NPIPE: | 9482 | case NPIPE: |
8895 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | 9483 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); |
8896 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; | 9484 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; |
9485 | SAVE_PTR(new->npipe.cmdlist); | ||
9486 | ANNOT("npipe.cmdlist"); | ||
8897 | break; | 9487 | break; |
8898 | case NREDIR: | 9488 | case NREDIR: |
8899 | case NBACKGND: | 9489 | case NBACKGND: |
@@ -8901,6 +9491,8 @@ copynode(union node *n) | |||
8901 | new->nredir.redirect = copynode(n->nredir.redirect); | 9491 | new->nredir.redirect = copynode(n->nredir.redirect); |
8902 | new->nredir.n = copynode(n->nredir.n); | 9492 | new->nredir.n = copynode(n->nredir.n); |
8903 | new->nredir.linno = n->nredir.linno; | 9493 | new->nredir.linno = n->nredir.linno; |
9494 | SAVE_PTR2(new->nredir.redirect,new->nredir.n); | ||
9495 | ANNOT2("nredir.redirect","nredir.n"); | ||
8904 | break; | 9496 | break; |
8905 | case NAND: | 9497 | case NAND: |
8906 | case NOR: | 9498 | case NOR: |
@@ -8909,37 +9501,54 @@ copynode(union node *n) | |||
8909 | case NUNTIL: | 9501 | case NUNTIL: |
8910 | new->nbinary.ch2 = copynode(n->nbinary.ch2); | 9502 | new->nbinary.ch2 = copynode(n->nbinary.ch2); |
8911 | new->nbinary.ch1 = copynode(n->nbinary.ch1); | 9503 | new->nbinary.ch1 = copynode(n->nbinary.ch1); |
9504 | SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2); | ||
9505 | ANNOT2("nbinary.ch1","nbinary.ch2"); | ||
8912 | break; | 9506 | break; |
8913 | case NIF: | 9507 | case NIF: |
8914 | new->nif.elsepart = copynode(n->nif.elsepart); | 9508 | new->nif.elsepart = copynode(n->nif.elsepart); |
8915 | new->nif.ifpart = copynode(n->nif.ifpart); | 9509 | new->nif.ifpart = copynode(n->nif.ifpart); |
8916 | new->nif.test = copynode(n->nif.test); | 9510 | new->nif.test = copynode(n->nif.test); |
9511 | SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test); | ||
9512 | ANNOT3("nif.elsepart","nif.ifpart","nif.test"); | ||
8917 | break; | 9513 | break; |
8918 | case NFOR: | 9514 | case NFOR: |
8919 | new->nfor.var = nodeckstrdup(n->nfor.var); | 9515 | new->nfor.var = nodeckstrdup(n->nfor.var); |
8920 | new->nfor.body = copynode(n->nfor.body); | 9516 | new->nfor.body = copynode(n->nfor.body); |
8921 | new->nfor.args = copynode(n->nfor.args); | 9517 | new->nfor.args = copynode(n->nfor.args); |
8922 | new->nfor.linno = n->nfor.linno; | 9518 | new->nfor.linno = n->nfor.linno; |
9519 | SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args); | ||
9520 | ANNOT_NO_DUP(xasprintf("nfor.var '%s'", n->nfor.var ?: "NULL")); | ||
9521 | ANNOT2("nfor.body","nfor.args"); | ||
8923 | break; | 9522 | break; |
8924 | case NCASE: | 9523 | case NCASE: |
8925 | new->ncase.cases = copynode(n->ncase.cases); | 9524 | new->ncase.cases = copynode(n->ncase.cases); |
8926 | new->ncase.expr = copynode(n->ncase.expr); | 9525 | new->ncase.expr = copynode(n->ncase.expr); |
8927 | new->ncase.linno = n->ncase.linno; | 9526 | new->ncase.linno = n->ncase.linno; |
9527 | SAVE_PTR2(new->ncase.cases,new->ncase.expr); | ||
9528 | ANNOT2("ncase.cases","ncase.expr"); | ||
8928 | break; | 9529 | break; |
8929 | case NCLIST: | 9530 | case NCLIST: |
8930 | new->nclist.body = copynode(n->nclist.body); | 9531 | new->nclist.body = copynode(n->nclist.body); |
8931 | new->nclist.pattern = copynode(n->nclist.pattern); | 9532 | new->nclist.pattern = copynode(n->nclist.pattern); |
8932 | new->nclist.next = copynode(n->nclist.next); | 9533 | new->nclist.next = copynode(n->nclist.next); |
9534 | SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next); | ||
9535 | ANNOT3("nclist.body","nclist.pattern","nclist.next"); | ||
8933 | break; | 9536 | break; |
8934 | case NDEFUN: | 9537 | case NDEFUN: |
8935 | new->ndefun.body = copynode(n->ndefun.body); | 9538 | new->ndefun.body = copynode(n->ndefun.body); |
8936 | new->ndefun.text = nodeckstrdup(n->ndefun.text); | 9539 | new->ndefun.text = nodeckstrdup(n->ndefun.text); |
8937 | new->ndefun.linno = n->ndefun.linno; | 9540 | new->ndefun.linno = n->ndefun.linno; |
9541 | SAVE_PTR2(new->ndefun.body,new->ndefun.text); | ||
9542 | ANNOT("ndefun.body"); | ||
9543 | ANNOT_NO_DUP(xasprintf("ndefun.text '%s'", n->ndefun.text ?: "NULL")); | ||
8938 | break; | 9544 | break; |
8939 | case NARG: | 9545 | case NARG: |
8940 | new->narg.backquote = copynodelist(n->narg.backquote); | 9546 | new->narg.backquote = copynodelist(n->narg.backquote); |
8941 | new->narg.text = nodeckstrdup(n->narg.text); | 9547 | new->narg.text = nodeckstrdup(n->narg.text); |
8942 | new->narg.next = copynode(n->narg.next); | 9548 | new->narg.next = copynode(n->narg.next); |
9549 | SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next); | ||
9550 | ANNOT2("narg.backquote","narg.next"); | ||
9551 | ANNOT_NO_DUP(xasprintf("narg.text '%s'", n->narg.text ?: "NULL")); | ||
8943 | break; | 9552 | break; |
8944 | case NTO: | 9553 | case NTO: |
8945 | #if BASH_REDIR_OUTPUT | 9554 | #if BASH_REDIR_OUTPUT |
@@ -8952,6 +9561,8 @@ copynode(union node *n) | |||
8952 | new->nfile.fname = copynode(n->nfile.fname); | 9561 | new->nfile.fname = copynode(n->nfile.fname); |
8953 | new->nfile.fd = n->nfile.fd; | 9562 | new->nfile.fd = n->nfile.fd; |
8954 | new->nfile.next = copynode(n->nfile.next); | 9563 | new->nfile.next = copynode(n->nfile.next); |
9564 | SAVE_PTR2(new->nfile.fname,new->nfile.next); | ||
9565 | ANNOT2("nfile.fname","nfile.next"); | ||
8955 | break; | 9566 | break; |
8956 | case NTOFD: | 9567 | case NTOFD: |
8957 | case NFROMFD: | 9568 | case NFROMFD: |
@@ -8959,15 +9570,21 @@ copynode(union node *n) | |||
8959 | new->ndup.dupfd = n->ndup.dupfd; | 9570 | new->ndup.dupfd = n->ndup.dupfd; |
8960 | new->ndup.fd = n->ndup.fd; | 9571 | new->ndup.fd = n->ndup.fd; |
8961 | new->ndup.next = copynode(n->ndup.next); | 9572 | new->ndup.next = copynode(n->ndup.next); |
9573 | SAVE_PTR2(new->ndup.vname,new->ndup.next); | ||
9574 | ANNOT2("ndup.vname","ndup.next"); | ||
8962 | break; | 9575 | break; |
8963 | case NHERE: | 9576 | case NHERE: |
8964 | case NXHERE: | 9577 | case NXHERE: |
8965 | new->nhere.doc = copynode(n->nhere.doc); | 9578 | new->nhere.doc = copynode(n->nhere.doc); |
8966 | new->nhere.fd = n->nhere.fd; | 9579 | new->nhere.fd = n->nhere.fd; |
8967 | new->nhere.next = copynode(n->nhere.next); | 9580 | new->nhere.next = copynode(n->nhere.next); |
9581 | SAVE_PTR2(new->nhere.doc,new->nhere.next); | ||
9582 | ANNOT2("nhere.doc","nhere.next"); | ||
8968 | break; | 9583 | break; |
8969 | case NNOT: | 9584 | case NNOT: |
8970 | new->nnot.com = copynode(n->nnot.com); | 9585 | new->nnot.com = copynode(n->nnot.com); |
9586 | SAVE_PTR(new->nnot.com); | ||
9587 | ANNOT("nnot.com"); | ||
8971 | break; | 9588 | break; |
8972 | }; | 9589 | }; |
8973 | new->type = n->type; | 9590 | new->type = n->type; |
@@ -8988,6 +9605,7 @@ copyfunc(union node *n) | |||
8988 | f = ckzalloc(blocksize /* + funcstringsize */); | 9605 | f = ckzalloc(blocksize /* + funcstringsize */); |
8989 | funcblock = (char *) f + offsetof(struct funcnode, n); | 9606 | funcblock = (char *) f + offsetof(struct funcnode, n); |
8990 | funcstring_end = (char *) f + blocksize; | 9607 | funcstring_end = (char *) f + blocksize; |
9608 | IF_PLATFORM_MINGW32(nodeptr = NULL); | ||
8991 | copynode(n); | 9609 | copynode(n); |
8992 | /* f->count = 0; - ckzalloc did it */ | 9610 | /* f->count = 0; - ckzalloc did it */ |
8993 | return f; | 9611 | return f; |
@@ -9014,7 +9632,9 @@ defun(union node *func) | |||
9014 | #define SKIPFUNC (1 << 2) | 9632 | #define SKIPFUNC (1 << 2) |
9015 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ | 9633 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ |
9016 | static int skipcount; /* number of levels to skip */ | 9634 | static int skipcount; /* number of levels to skip */ |
9635 | #if ENABLE_PLATFORM_POSIX | ||
9017 | static int loopnest; /* current loop nesting level */ | 9636 | static int loopnest; /* current loop nesting level */ |
9637 | #endif | ||
9018 | static int funcline; /* starting line number of current function, or 0 if not in a function */ | 9638 | static int funcline; /* starting line number of current function, or 0 if not in a function */ |
9019 | 9639 | ||
9020 | /* Forward decl way out to parsing code - dotrap needs it */ | 9640 | /* Forward decl way out to parsing code - dotrap needs it */ |
@@ -9333,6 +9953,7 @@ evalcase(union node *n, int flags) | |||
9333 | static int | 9953 | static int |
9334 | evalsubshell(union node *n, int flags) | 9954 | evalsubshell(union node *n, int flags) |
9335 | { | 9955 | { |
9956 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
9336 | struct job *jp; | 9957 | struct job *jp; |
9337 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ | 9958 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ |
9338 | int status; | 9959 | int status; |
@@ -9348,12 +9969,21 @@ evalsubshell(union node *n, int flags) | |||
9348 | if (backgnd == FORK_FG) | 9969 | if (backgnd == FORK_FG) |
9349 | get_tty_state(); | 9970 | get_tty_state(); |
9350 | jp = makejob(/*n,*/ 1); | 9971 | jp = makejob(/*n,*/ 1); |
9972 | #if ENABLE_PLATFORM_MINGW32 | ||
9973 | memset(&fs, 0, sizeof(fs)); | ||
9974 | fs.fpid = FS_EVALSUBSHELL; | ||
9975 | fs.n = n; | ||
9976 | fs.flags = flags; | ||
9977 | spawn_forkshell(&fs, jp, n, backgnd); | ||
9978 | if ( 0 ) { | ||
9979 | #else | ||
9351 | if (forkshell(jp, n, backgnd) == 0) { | 9980 | if (forkshell(jp, n, backgnd) == 0) { |
9352 | /* child */ | 9981 | /* child */ |
9353 | INT_ON; | 9982 | INT_ON; |
9354 | flags |= EV_EXIT; | 9983 | flags |= EV_EXIT; |
9355 | if (backgnd) | 9984 | if (backgnd) |
9356 | flags &= ~EV_TESTED; | 9985 | flags &= ~EV_TESTED; |
9986 | #endif | ||
9357 | nofork: | 9987 | nofork: |
9358 | redirect(n->nredir.redirect, 0); | 9988 | redirect(n->nredir.redirect, 0); |
9359 | evaltreenr(n->nredir.n, flags); | 9989 | evaltreenr(n->nredir.n, flags); |
@@ -9440,6 +10070,7 @@ expredir(union node *n) | |||
9440 | static int | 10070 | static int |
9441 | evalpipe(union node *n, int flags) | 10071 | evalpipe(union node *n, int flags) |
9442 | { | 10072 | { |
10073 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
9443 | struct job *jp; | 10074 | struct job *jp; |
9444 | struct nodelist *lp; | 10075 | struct nodelist *lp; |
9445 | int pipelen; | 10076 | int pipelen; |
@@ -9466,6 +10097,16 @@ evalpipe(union node *n, int flags) | |||
9466 | ash_msg_and_raise_perror("can't create pipe"); | 10097 | ash_msg_and_raise_perror("can't create pipe"); |
9467 | } | 10098 | } |
9468 | } | 10099 | } |
10100 | #if ENABLE_PLATFORM_MINGW32 | ||
10101 | memset(&fs, 0, sizeof(fs)); | ||
10102 | fs.fpid = FS_EVALPIPE; | ||
10103 | fs.flags = flags; | ||
10104 | fs.n = lp->n; | ||
10105 | fs.fd[0] = pip[0]; | ||
10106 | fs.fd[1] = pip[1]; | ||
10107 | fs.fd[2] = prevfd; | ||
10108 | spawn_forkshell(&fs, jp, lp->n, n->npipe.pipe_backgnd); | ||
10109 | #else | ||
9469 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { | 10110 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { |
9470 | /* child */ | 10111 | /* child */ |
9471 | INT_ON; | 10112 | INT_ON; |
@@ -9483,6 +10124,7 @@ evalpipe(union node *n, int flags) | |||
9483 | evaltreenr(lp->n, flags); | 10124 | evaltreenr(lp->n, flags); |
9484 | /* never returns */ | 10125 | /* never returns */ |
9485 | } | 10126 | } |
10127 | #endif | ||
9486 | /* parent */ | 10128 | /* parent */ |
9487 | if (prevfd >= 0) | 10129 | if (prevfd >= 0) |
9488 | close(prevfd); | 10130 | close(prevfd); |
@@ -10013,6 +10655,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
10013 | * as POSIX mandates */ | 10655 | * as POSIX mandates */ |
10014 | return back_exitstatus; | 10656 | return back_exitstatus; |
10015 | } | 10657 | } |
10658 | |||
10016 | static int | 10659 | static int |
10017 | evalcommand(union node *cmd, int flags) | 10660 | evalcommand(union node *cmd, int flags) |
10018 | { | 10661 | { |
@@ -10036,6 +10679,9 @@ evalcommand(union node *cmd, int flags) | |||
10036 | int status; | 10679 | int status; |
10037 | char **nargv; | 10680 | char **nargv; |
10038 | smallint cmd_is_exec; | 10681 | smallint cmd_is_exec; |
10682 | #if ENABLE_PLATFORM_MINGW32 | ||
10683 | int cmdpath; | ||
10684 | #endif | ||
10039 | 10685 | ||
10040 | errlinno = lineno = cmd->ncmd.linno; | 10686 | errlinno = lineno = cmd->ncmd.linno; |
10041 | if (funcline) | 10687 | if (funcline) |
@@ -10103,6 +10749,7 @@ evalcommand(union node *cmd, int flags) | |||
10103 | } | 10749 | } |
10104 | status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); | 10750 | status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); |
10105 | 10751 | ||
10752 | #if !ENABLE_PLATFORM_MINGW32 | ||
10106 | path = vpath.var_text; | 10753 | path = vpath.var_text; |
10107 | for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { | 10754 | for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { |
10108 | struct strlist **spp; | 10755 | struct strlist **spp; |
@@ -10121,6 +10768,15 @@ evalcommand(union node *cmd, int flags) | |||
10121 | if (varcmp(p, path) == 0) | 10768 | if (varcmp(p, path) == 0) |
10122 | path = p; | 10769 | path = p; |
10123 | } | 10770 | } |
10771 | #else | ||
10772 | /* Set path after any local PATH= has been processed. */ | ||
10773 | for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { | ||
10774 | struct strlist **spp = varlist.lastp; | ||
10775 | expandarg(argp, &varlist, EXP_VARTILDE); | ||
10776 | mklocal((*spp)->text); | ||
10777 | } | ||
10778 | path = vpath.var_text; | ||
10779 | #endif | ||
10124 | 10780 | ||
10125 | /* Print the command if xflag is set. */ | 10781 | /* Print the command if xflag is set. */ |
10126 | if (xflag) { | 10782 | if (xflag) { |
@@ -10259,6 +10915,33 @@ evalcommand(union node *cmd, int flags) | |||
10259 | * in a script or a subshell does not need forking, | 10915 | * in a script or a subshell does not need forking, |
10260 | * we can just exec it. | 10916 | * we can just exec it. |
10261 | */ | 10917 | */ |
10918 | #if ENABLE_PLATFORM_MINGW32 | ||
10919 | if (!(flags & EV_EXIT) || may_have_traps) { | ||
10920 | /* No, forking off a child is necessary */ | ||
10921 | struct forkshell fs; | ||
10922 | |||
10923 | INT_OFF; | ||
10924 | memset(&fs, 0, sizeof(fs)); | ||
10925 | fs.fpid = FS_SHELLEXEC; | ||
10926 | fs.argv = argv; | ||
10927 | fs.path = (char*)path; | ||
10928 | fs.fd[0] = cmdentry.u.index; | ||
10929 | fs.varlist = varlist.list; | ||
10930 | jp = makejob(/*cmd,*/ 1); | ||
10931 | spawn_forkshell(&fs, jp, cmd, FORK_FG); | ||
10932 | status = waitforjob(jp); | ||
10933 | INT_ON; | ||
10934 | TRACE(("forked child exited with %d\n", status)); | ||
10935 | break; | ||
10936 | } | ||
10937 | /* If we're running 'command -p' we need to use the value stored | ||
10938 | * in path by parse_command_args(). If PATH is a local variable | ||
10939 | * listsetvar() will free the value currently in path so we need | ||
10940 | * to fetch the updated version. */ | ||
10941 | cmdpath = (path != pathval()); | ||
10942 | listsetvar(varlist.list, VEXPORT|VSTACK); | ||
10943 | shellexec(argv[0], argv, cmdpath ? path : pathval(), cmdentry.u.index); | ||
10944 | #else | ||
10262 | if (!(flags & EV_EXIT) || may_have_traps) { | 10945 | if (!(flags & EV_EXIT) || may_have_traps) { |
10263 | /* No, forking off a child is necessary */ | 10946 | /* No, forking off a child is necessary */ |
10264 | INT_OFF; | 10947 | INT_OFF; |
@@ -10277,6 +10960,7 @@ evalcommand(union node *cmd, int flags) | |||
10277 | } | 10960 | } |
10278 | listsetvar(varlist.list, VEXPORT|VSTACK); | 10961 | listsetvar(varlist.list, VEXPORT|VSTACK); |
10279 | shellexec(argv[0], argv, path, cmdentry.u.index); | 10962 | shellexec(argv[0], argv, path, cmdentry.u.index); |
10963 | #endif | ||
10280 | /* NOTREACHED */ | 10964 | /* NOTREACHED */ |
10281 | } /* default */ | 10965 | } /* default */ |
10282 | case CMDBUILTIN: | 10966 | case CMDBUILTIN: |
@@ -10658,7 +11342,7 @@ preadbuffer(void) | |||
10658 | more--; | 11342 | more--; |
10659 | 11343 | ||
10660 | c = *q; | 11344 | c = *q; |
10661 | if (c == '\0') { | 11345 | if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) { |
10662 | memmove(q, q + 1, more); | 11346 | memmove(q, q + 1, more); |
10663 | } else { | 11347 | } else { |
10664 | q++; | 11348 | q++; |
@@ -10854,6 +11538,7 @@ popallfiles(void) | |||
10854 | unwindfiles(&basepf); | 11538 | unwindfiles(&basepf); |
10855 | } | 11539 | } |
10856 | 11540 | ||
11541 | #if !ENABLE_PLATFORM_MINGW32 | ||
10857 | /* | 11542 | /* |
10858 | * Close the file(s) that the shell is reading commands from. Called | 11543 | * Close the file(s) that the shell is reading commands from. Called |
10859 | * after a fork is done. | 11544 | * after a fork is done. |
@@ -10867,6 +11552,7 @@ closescript(void) | |||
10867 | g_parsefile->pf_fd = 0; | 11552 | g_parsefile->pf_fd = 0; |
10868 | } | 11553 | } |
10869 | } | 11554 | } |
11555 | #endif | ||
10870 | 11556 | ||
10871 | /* | 11557 | /* |
10872 | * Like setinputfile, but takes an open file descriptor. Call this with | 11558 | * Like setinputfile, but takes an open file descriptor. Call this with |
@@ -11093,8 +11779,13 @@ options(int cmdline, int *login_sh) | |||
11093 | int val; | 11779 | int val; |
11094 | int c; | 11780 | int c; |
11095 | 11781 | ||
11096 | if (cmdline) | 11782 | if (cmdline) { |
11097 | minusc = NULL; | 11783 | minusc = NULL; |
11784 | #if ENABLE_PLATFORM_MINGW32 | ||
11785 | dirarg = NULL; | ||
11786 | title = NULL; | ||
11787 | #endif | ||
11788 | } | ||
11098 | while ((p = *argptr) != NULL) { | 11789 | while ((p = *argptr) != NULL) { |
11099 | c = *p++; | 11790 | c = *p++; |
11100 | if (c != '-' && c != '+') | 11791 | if (c != '-' && c != '+') |
@@ -11120,6 +11811,20 @@ options(int cmdline, int *login_sh) | |||
11120 | /* bash 3.2 indeed handles -c CMD and +c CMD the same */ | 11811 | /* bash 3.2 indeed handles -c CMD and +c CMD the same */ |
11121 | if (c == 'c' && cmdline) { | 11812 | if (c == 'c' && cmdline) { |
11122 | minusc = p; /* command is after shell args */ | 11813 | minusc = p; /* command is after shell args */ |
11814 | #if ENABLE_PLATFORM_MINGW32 | ||
11815 | /* Undocumented flags; | ||
11816 | * -d force current directory | ||
11817 | * -t title to display in console window | ||
11818 | * Must appear before -s or -c. */ | ||
11819 | } else if (c == 'd' && cmdline && val == 1) { | ||
11820 | if (*argptr == NULL) | ||
11821 | ash_msg_and_raise_error(bb_msg_requires_arg, "-d"); | ||
11822 | dirarg = *argptr++; | ||
11823 | } else if (c == 't' && cmdline && val == 1) { | ||
11824 | if (*argptr == NULL) | ||
11825 | ash_msg_and_raise_error(bb_msg_requires_arg, "-t"); | ||
11826 | title = *argptr++; | ||
11827 | #endif | ||
11123 | } else if (c == 'o') { | 11828 | } else if (c == 'o') { |
11124 | if (plus_minus_o(*argptr, val)) { | 11829 | if (plus_minus_o(*argptr, val)) { |
11125 | /* it already printed err message */ | 11830 | /* it already printed err message */ |
@@ -13110,6 +13815,9 @@ evalstring(char *s, int flags) | |||
13110 | int status; | 13815 | int status; |
13111 | 13816 | ||
13112 | s = sstrdup(s); | 13817 | s = sstrdup(s); |
13818 | #if ENABLE_PLATFORM_MINGW32 | ||
13819 | remove_cr(s, strlen(s)+1); | ||
13820 | #endif | ||
13113 | setinputstring(s); | 13821 | setinputstring(s); |
13114 | setstackmark(&smark); | 13822 | setstackmark(&smark); |
13115 | 13823 | ||
@@ -13253,7 +13961,7 @@ find_dot_file(char *name) | |||
13253 | struct stat statb; | 13961 | struct stat statb; |
13254 | 13962 | ||
13255 | /* don't try this for absolute or relative paths */ | 13963 | /* don't try this for absolute or relative paths */ |
13256 | if (strchr(name, '/')) | 13964 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) |
13257 | return name; | 13965 | return name; |
13258 | 13966 | ||
13259 | while ((fullname = path_advance(&path, name)) != NULL) { | 13967 | while ((fullname = path_advance(&path, name)) != NULL) { |
@@ -13375,14 +14083,18 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13375 | struct builtincmd *bcmd; | 14083 | struct builtincmd *bcmd; |
13376 | 14084 | ||
13377 | /* If name contains a slash, don't use PATH or hash table */ | 14085 | /* If name contains a slash, don't use PATH or hash table */ |
13378 | if (strchr(name, '/') != NULL) { | 14086 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) { |
13379 | entry->u.index = -1; | 14087 | entry->u.index = -1; |
13380 | if (act & DO_ABS) { | 14088 | if (act & DO_ABS) { |
14089 | #if ENABLE_PLATFORM_MINGW32 | ||
14090 | if (auto_win32_extension(name) == NULL && stat(name, &statb) < 0) { | ||
14091 | #else | ||
13381 | while (stat(name, &statb) < 0) { | 14092 | while (stat(name, &statb) < 0) { |
13382 | #ifdef SYSV | 14093 | #ifdef SYSV |
13383 | if (errno == EINTR) | 14094 | if (errno == EINTR) |
13384 | continue; | 14095 | continue; |
13385 | #endif | 14096 | #endif |
14097 | #endif | ||
13386 | entry->cmdtype = CMDUNKNOWN; | 14098 | entry->cmdtype = CMDUNKNOWN; |
13387 | return; | 14099 | return; |
13388 | } | 14100 | } |
@@ -13482,12 +14194,15 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13482 | } | 14194 | } |
13483 | } | 14195 | } |
13484 | /* if rehash, don't redo absolute path names */ | 14196 | /* if rehash, don't redo absolute path names */ |
13485 | if (fullname[0] == '/' && idx <= prev) { | 14197 | if (is_absolute_path(fullname) && idx <= prev) { |
13486 | if (idx < prev) | 14198 | if (idx < prev) |
13487 | continue; | 14199 | continue; |
13488 | TRACE(("searchexec \"%s\": no change\n", name)); | 14200 | TRACE(("searchexec \"%s\": no change\n", name)); |
13489 | goto success; | 14201 | goto success; |
13490 | } | 14202 | } |
14203 | #if ENABLE_PLATFORM_MINGW32 | ||
14204 | add_win32_extension(fullname); | ||
14205 | #endif | ||
13491 | while (stat(fullname, &statb) < 0) { | 14206 | while (stat(fullname, &statb) < 0) { |
13492 | #ifdef SYSV | 14207 | #ifdef SYSV |
13493 | if (errno == EINTR) | 14208 | if (errno == EINTR) |
@@ -13978,6 +14693,9 @@ umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
13978 | if (!isdigit(modestr[0])) | 14693 | if (!isdigit(modestr[0])) |
13979 | mask ^= 0777; | 14694 | mask ^= 0777; |
13980 | umask(mask); | 14695 | umask(mask); |
14696 | #if ENABLE_PLATFORM_MINGW32 | ||
14697 | setvareq(xasprintf("BB_UMASK=0%o", mask), VEXPORT|VNOSAVE); | ||
14698 | #endif | ||
13981 | } | 14699 | } |
13982 | return 0; | 14700 | return 0; |
13983 | } | 14701 | } |
@@ -14036,6 +14754,7 @@ init(void) | |||
14036 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); | 14754 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); |
14037 | basepf.linno = 1; | 14755 | basepf.linno = 1; |
14038 | 14756 | ||
14757 | #if !ENABLE_PLATFORM_MINGW32 | ||
14039 | sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ | 14758 | sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ |
14040 | setsignal(SIGCHLD); | 14759 | setsignal(SIGCHLD); |
14041 | 14760 | ||
@@ -14043,12 +14762,89 @@ init(void) | |||
14043 | * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" | 14762 | * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" |
14044 | */ | 14763 | */ |
14045 | signal(SIGHUP, SIG_DFL); | 14764 | signal(SIGHUP, SIG_DFL); |
14765 | #endif | ||
14046 | 14766 | ||
14047 | { | 14767 | { |
14048 | char **envp; | 14768 | char **envp; |
14049 | const char *p; | 14769 | const char *p; |
14050 | 14770 | ||
14051 | initvar(); | 14771 | initvar(); |
14772 | |||
14773 | #if ENABLE_PLATFORM_MINGW32 | ||
14774 | /* | ||
14775 | * case insensitive env names from Windows world | ||
14776 | * | ||
14777 | * Some standard env names such as PATH is named Path and so on | ||
14778 | * ash itself is case sensitive, so "Path" will confuse it, as | ||
14779 | * MSVC getenv() is case insensitive. | ||
14780 | * | ||
14781 | * We may end up having both Path and PATH. Then Path will be chosen | ||
14782 | * because it appears first. | ||
14783 | */ | ||
14784 | for (envp = environ; envp && *envp; envp++) { | ||
14785 | if (strncasecmp(*envp, "PATH=", 5) == 0 && | ||
14786 | strncmp(*envp, "PATH=", 5) != 0) { | ||
14787 | break; | ||
14788 | } | ||
14789 | } | ||
14790 | |||
14791 | if (envp && *envp) { | ||
14792 | /* | ||
14793 | * If we get here it's because the environment contains a path | ||
14794 | * variable called something other than PATH. This suggests we | ||
14795 | * haven't been invoked from an earlier instance of BusyBox. | ||
14796 | */ | ||
14797 | char *start, *end; | ||
14798 | struct passwd *pw; | ||
14799 | |||
14800 | for (envp = environ; envp && *envp; envp++) { | ||
14801 | if (!(end=strchr(*envp, '='))) | ||
14802 | continue; | ||
14803 | |||
14804 | /* make all variable names uppercase */ | ||
14805 | for (start = *envp;start < end;start++) | ||
14806 | *start = toupper(*start); | ||
14807 | |||
14808 | /* Convert backslashes to forward slashes in value but | ||
14809 | * not if we're on Windows XP or for variables known to | ||
14810 | * cause problems */ | ||
14811 | if ( !winxp && strncmp(*envp, "SYSTEMROOT=", 11) != 0 && | ||
14812 | strncmp(*envp, "COMSPEC=", 8) != 0 ) { | ||
14813 | bs_to_slash(end+1); | ||
14814 | } | ||
14815 | |||
14816 | /* check for invalid characters in name */ | ||
14817 | for (start = *envp;start < end;start++) { | ||
14818 | if (!isdigit(*start) && !isalpha(*start) && *start != '_') { | ||
14819 | break; | ||
14820 | } | ||
14821 | } | ||
14822 | |||
14823 | if (start != end) { | ||
14824 | /* | ||
14825 | * Make a copy of the variable, replacing invalid | ||
14826 | * characters in the name with underscores. | ||
14827 | */ | ||
14828 | char *var = xstrdup(*envp); | ||
14829 | |||
14830 | for (start = var;*start != '=';start++) { | ||
14831 | if (!isdigit(*start) && !isalpha(*start)) { | ||
14832 | *start = '_'; | ||
14833 | } | ||
14834 | } | ||
14835 | setvareq(var, VEXPORT|VNOSAVE); | ||
14836 | } | ||
14837 | } | ||
14838 | |||
14839 | /* Initialise some variables normally set at login, but | ||
14840 | * only if someone hasn't already set them. */ | ||
14841 | pw = xgetpwuid(getuid()); | ||
14842 | if (!getenv("USER")) xsetenv("USER", pw->pw_name); | ||
14843 | if (!getenv("LOGNAME")) xsetenv("LOGNAME", pw->pw_name); | ||
14844 | if (!getenv("HOME")) xsetenv("HOME", pw->pw_dir); | ||
14845 | if (!getenv("SHELL")) xsetenv("SHELL", DEFAULT_SHELL); | ||
14846 | } | ||
14847 | #endif | ||
14052 | for (envp = environ; envp && *envp; envp++) { | 14848 | for (envp = environ; envp && *envp; envp++) { |
14053 | /* Used to have | 14849 | /* Used to have |
14054 | * p = endofname(*envp); | 14850 | * p = endofname(*envp); |
@@ -14062,7 +14858,11 @@ init(void) | |||
14062 | * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this | 14858 | * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this |
14063 | */ | 14859 | */ |
14064 | if (strchr(*envp, '=')) { | 14860 | if (strchr(*envp, '=')) { |
14861 | #if !ENABLE_PLATFORM_MINGW32 | ||
14065 | setvareq(*envp, VEXPORT|VTEXTFIXED); | 14862 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
14863 | #else | ||
14864 | setvareq(*envp, VEXPORT); | ||
14865 | #endif | ||
14066 | } | 14866 | } |
14067 | } | 14867 | } |
14068 | 14868 | ||
@@ -14151,6 +14951,9 @@ procargs(char **argv) | |||
14151 | goto setarg0; | 14951 | goto setarg0; |
14152 | } else if (!sflag) { | 14952 | } else if (!sflag) { |
14153 | setinputfile(*xargv, 0); | 14953 | setinputfile(*xargv, 0); |
14954 | #if ENABLE_PLATFORM_MINGW32 | ||
14955 | bs_to_slash(*xargv); | ||
14956 | #endif | ||
14154 | setarg0: | 14957 | setarg0: |
14155 | arg0 = *xargv++; | 14958 | arg0 = *xargv++; |
14156 | commandname = arg0; | 14959 | commandname = arg0; |
@@ -14235,6 +15038,9 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14235 | struct jmploc jmploc; | 15038 | struct jmploc jmploc; |
14236 | struct stackmark smark; | 15039 | struct stackmark smark; |
14237 | int login_sh; | 15040 | int login_sh; |
15041 | #if ENABLE_PLATFORM_MINGW32 | ||
15042 | char *sd; | ||
15043 | #endif | ||
14238 | 15044 | ||
14239 | /* Initialize global data */ | 15045 | /* Initialize global data */ |
14240 | INIT_G_misc(); | 15046 | INIT_G_misc(); |
@@ -14281,9 +15087,24 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14281 | exception_handler = &jmploc; | 15087 | exception_handler = &jmploc; |
14282 | rootpid = getpid(); | 15088 | rootpid = getpid(); |
14283 | 15089 | ||
15090 | #if ENABLE_PLATFORM_MINGW32 | ||
15091 | winxp = (argv[1] != NULL && strcmp(argv[1], "-X") == 0); | ||
15092 | #endif | ||
14284 | init(); | 15093 | init(); |
14285 | setstackmark(&smark); | 15094 | setstackmark(&smark); |
14286 | 15095 | ||
15096 | #if ENABLE_PLATFORM_MINGW32 | ||
15097 | hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL); | ||
15098 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
15099 | |||
15100 | if (argc == 3 && !strcmp(argv[1], "--fs")) { | ||
15101 | forkshell_init(argv[2]); | ||
15102 | |||
15103 | /* NOTREACHED */ | ||
15104 | bb_error_msg_and_die("forkshell failed"); | ||
15105 | } | ||
15106 | #endif | ||
15107 | |||
14287 | #if NUM_SCRIPTS > 0 | 15108 | #if NUM_SCRIPTS > 0 |
14288 | if (argc < 0) | 15109 | if (argc < 0) |
14289 | /* Non-NULL minusc tells procargs that an embedded script is being run */ | 15110 | /* Non-NULL minusc tells procargs that an embedded script is being run */ |
@@ -14295,10 +15116,49 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14295 | trace_puts_args(argv); | 15116 | trace_puts_args(argv); |
14296 | #endif | 15117 | #endif |
14297 | 15118 | ||
15119 | #if ENABLE_ASH_NOCONSOLE | ||
15120 | if (noconsole) | ||
15121 | hide_console(); | ||
15122 | #endif | ||
15123 | |||
15124 | #if ENABLE_PLATFORM_MINGW32 | ||
15125 | if (dirarg) { | ||
15126 | chdir(dirarg); | ||
15127 | setpwd(NULL, 0); | ||
15128 | } | ||
15129 | else if (!login_sh && iflag) { | ||
15130 | char *cwd = getcwd(NULL, 0); | ||
15131 | if (cwd) { | ||
15132 | docd(cwd, 0); | ||
15133 | free(cwd); | ||
15134 | } | ||
15135 | } | ||
15136 | |||
15137 | if (title) | ||
15138 | set_title(title); | ||
15139 | #endif | ||
15140 | |||
14298 | if (login_sh) { | 15141 | if (login_sh) { |
14299 | const char *hp; | 15142 | const char *hp; |
14300 | 15143 | ||
15144 | #if ENABLE_PLATFORM_MINGW32 | ||
15145 | if (!dirarg) { | ||
15146 | chdir(xgetpwuid(getuid())->pw_dir); | ||
15147 | setpwd(NULL, 0); | ||
15148 | } | ||
15149 | #endif | ||
15150 | |||
14301 | state = 1; | 15151 | state = 1; |
15152 | #if ENABLE_PLATFORM_MINGW32 | ||
15153 | sd = get_system_drive(); | ||
15154 | if (sd) { | ||
15155 | char *path = xasprintf("%s/etc/profile", sd); | ||
15156 | read_profile(path); | ||
15157 | free(sd); | ||
15158 | free(path); | ||
15159 | } | ||
15160 | else | ||
15161 | #endif | ||
14302 | read_profile("/etc/profile"); | 15162 | read_profile("/etc/profile"); |
14303 | state1: | 15163 | state1: |
14304 | state = 2; | 15164 | state = 2; |
@@ -14309,9 +15169,11 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14309 | state2: | 15169 | state2: |
14310 | state = 3; | 15170 | state = 3; |
14311 | if ( | 15171 | if ( |
15172 | #if ENABLE_PLATFORM_POSIX | ||
14312 | #ifndef linux | 15173 | #ifndef linux |
14313 | getuid() == geteuid() && getgid() == getegid() && | 15174 | getuid() == geteuid() && getgid() == getegid() && |
14314 | #endif | 15175 | #endif |
15176 | #endif | ||
14315 | iflag | 15177 | iflag |
14316 | ) { | 15178 | ) { |
14317 | const char *shinit = lookupvar("ENV"); | 15179 | const char *shinit = lookupvar("ENV"); |
@@ -14372,6 +15234,809 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14372 | /* NOTREACHED */ | 15234 | /* NOTREACHED */ |
14373 | } | 15235 | } |
14374 | 15236 | ||
15237 | #if ENABLE_PLATFORM_MINGW32 | ||
15238 | static void | ||
15239 | forkshell_openhere(struct forkshell *fs) | ||
15240 | { | ||
15241 | union node *redir = fs->n; | ||
15242 | int pip[2]; | ||
15243 | |||
15244 | pip[0] = fs->fd[0]; | ||
15245 | pip[1] = fs->fd[1]; | ||
15246 | |||
15247 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
15248 | |||
15249 | close(pip[0]); | ||
15250 | ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); | ||
15251 | ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); | ||
15252 | ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); | ||
15253 | ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); | ||
15254 | signal(SIGPIPE, SIG_DFL); | ||
15255 | if (redir->type == NHERE) { | ||
15256 | size_t len = strlen(redir->nhere.doc->narg.text); | ||
15257 | full_write(pip[1], redir->nhere.doc->narg.text, len); | ||
15258 | } else /* NXHERE */ | ||
15259 | expandhere(redir->nhere.doc, pip[1]); | ||
15260 | _exit(EXIT_SUCCESS); | ||
15261 | } | ||
15262 | |||
15263 | static void | ||
15264 | forkshell_evalbackcmd(struct forkshell *fs) | ||
15265 | { | ||
15266 | union node *n = fs->n; | ||
15267 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
15268 | |||
15269 | FORCE_INT_ON; | ||
15270 | close(pip[0]); | ||
15271 | if (pip[1] != 1) { | ||
15272 | /*close(1);*/ | ||
15273 | dup2_or_raise(pip[1], 1); | ||
15274 | close(pip[1]); | ||
15275 | } | ||
15276 | eflag = 0; | ||
15277 | ifsfree(); | ||
15278 | evaltreenr(n, EV_EXIT); | ||
15279 | /* NOTREACHED */ | ||
15280 | } | ||
15281 | |||
15282 | static void | ||
15283 | forkshell_evalsubshell(struct forkshell *fs) | ||
15284 | { | ||
15285 | union node *n = fs->n; | ||
15286 | int flags = fs->flags; | ||
15287 | |||
15288 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
15289 | INT_ON; | ||
15290 | flags |= EV_EXIT; | ||
15291 | expredir(n->nredir.redirect); | ||
15292 | redirect(n->nredir.redirect, 0); | ||
15293 | evaltreenr(n->nredir.n, flags); | ||
15294 | /* never returns */ | ||
15295 | } | ||
15296 | |||
15297 | static void | ||
15298 | forkshell_evalpipe(struct forkshell *fs) | ||
15299 | { | ||
15300 | union node *n = fs->n; | ||
15301 | int flags = fs->flags; | ||
15302 | int prevfd = fs->fd[2]; | ||
15303 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
15304 | |||
15305 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
15306 | INT_ON; | ||
15307 | if (pip[1] >= 0) { | ||
15308 | close(pip[0]); | ||
15309 | } | ||
15310 | if (prevfd > 0) { | ||
15311 | dup2(prevfd, 0); | ||
15312 | close(prevfd); | ||
15313 | } | ||
15314 | if (pip[1] > 1) { | ||
15315 | dup2(pip[1], 1); | ||
15316 | close(pip[1]); | ||
15317 | } | ||
15318 | evaltreenr(n, flags); | ||
15319 | } | ||
15320 | |||
15321 | static void | ||
15322 | forkshell_shellexec(struct forkshell *fs) | ||
15323 | { | ||
15324 | int idx = fs->fd[0]; | ||
15325 | struct strlist *varlist = fs->varlist; | ||
15326 | char **argv = fs->argv; | ||
15327 | char *path = fs->path; | ||
15328 | |||
15329 | FORCE_INT_ON; | ||
15330 | listsetvar(varlist, VEXPORT|VSTACK); | ||
15331 | shellexec(argv[0], argv, path, idx); | ||
15332 | } | ||
15333 | |||
15334 | static void | ||
15335 | forkshell_child(struct forkshell *fs) | ||
15336 | { | ||
15337 | switch ( fs->fpid ) { | ||
15338 | case FS_OPENHERE: | ||
15339 | forkshell_openhere(fs); | ||
15340 | break; | ||
15341 | case FS_EVALBACKCMD: | ||
15342 | forkshell_evalbackcmd(fs); | ||
15343 | break; | ||
15344 | case FS_EVALSUBSHELL: | ||
15345 | forkshell_evalsubshell(fs); | ||
15346 | break; | ||
15347 | case FS_EVALPIPE: | ||
15348 | forkshell_evalpipe(fs); | ||
15349 | break; | ||
15350 | case FS_SHELLEXEC: | ||
15351 | forkshell_shellexec(fs); | ||
15352 | break; | ||
15353 | } | ||
15354 | } | ||
15355 | |||
15356 | /* | ||
15357 | * Reinitialise the builtin environment variables in varinit. Their | ||
15358 | * current settings have been copied from the parent in vartab. Look | ||
15359 | * these up using the names from varinit_data, copy the details from | ||
15360 | * vartab to varinit and replace the old copy in vartab with the new | ||
15361 | * one in varinit. | ||
15362 | * | ||
15363 | * Also reinitialise the function pointers and line number variable. | ||
15364 | */ | ||
15365 | static void | ||
15366 | reinitvar(void) | ||
15367 | { | ||
15368 | int i; | ||
15369 | const char *name; | ||
15370 | struct var **vpp, **old; | ||
15371 | |||
15372 | for (i=0; i<ARRAY_SIZE(varinit); ++i) { | ||
15373 | name = varinit_data[i].var_text ? varinit_data[i].var_text : "LINENO="; | ||
15374 | vpp = hashvar(name); | ||
15375 | if ( (old=findvar(vpp, name)) != NULL ) { | ||
15376 | varinit[i] = **old; | ||
15377 | *old = varinit+i; | ||
15378 | } | ||
15379 | varinit[i].var_func = varinit_data[i].var_func; | ||
15380 | } | ||
15381 | vlineno.var_text = linenovar; | ||
15382 | } | ||
15383 | |||
15384 | static void | ||
15385 | spawn_forkshell(struct forkshell *fs, struct job *jp, union node *n, int mode) | ||
15386 | { | ||
15387 | struct forkshell *new; | ||
15388 | char buf[32]; | ||
15389 | const char *argv[] = { "sh", "--fs", NULL, NULL }; | ||
15390 | intptr_t ret; | ||
15391 | |||
15392 | new = forkshell_prepare(fs); | ||
15393 | new->mode = mode; | ||
15394 | new->nprocs = jp == NULL ? 0 : jp->nprocs; | ||
15395 | sprintf(buf, "%p", new->hMapFile); | ||
15396 | argv[2] = buf; | ||
15397 | ret = mingw_spawn_proc(argv); | ||
15398 | CloseHandle(new->hMapFile); | ||
15399 | UnmapViewOfFile(new); | ||
15400 | if (ret == -1) { | ||
15401 | if (jp) | ||
15402 | freejob(jp); | ||
15403 | ash_msg_and_raise_error("unable to spawn shell"); | ||
15404 | } | ||
15405 | forkparent(jp, n, mode, (HANDLE)ret); | ||
15406 | } | ||
15407 | |||
15408 | /* | ||
15409 | * forkshell_prepare() and friends | ||
15410 | * | ||
15411 | * The sequence is as follows: | ||
15412 | * - funcblocksize, nodeptrcount are initialized | ||
15413 | * - forkshell_size(fs) is called to calculate the exact memory needed | ||
15414 | * - a new struct is allocated | ||
15415 | * - funcblock, funcstring, nodeptr are initialized from the new block | ||
15416 | * - forkshell_copy(fs) is called to copy recursively everything over | ||
15417 | * it will record all pointers along the way, to nodeptr | ||
15418 | * | ||
15419 | * When this memory is mapped elsewhere, pointer fixup will be needed | ||
15420 | */ | ||
15421 | |||
15422 | /* redefine without test that nodeptr is non-NULL */ | ||
15423 | #undef SAVE_PTR | ||
15424 | #undef SAVE_PTR2 | ||
15425 | #undef SAVE_PTR3 | ||
15426 | #define SAVE_PTR(dst) {*nodeptr++ = (char **)&(dst);} | ||
15427 | #define SAVE_PTR2(dst1,dst2) {SAVE_PTR(dst1); SAVE_PTR(dst2);} | ||
15428 | #define SAVE_PTR3(dst1,dst2,dst3) {SAVE_PTR2(dst1,dst2); SAVE_PTR(dst3);} | ||
15429 | #define SAVE_PTR4(dst1,dst2,dst3,dst4) {SAVE_PTR2(dst1,dst2); SAVE_PTR2(dst3,dst4);} | ||
15430 | |||
15431 | static int align_len(const char *s) | ||
15432 | { | ||
15433 | return s ? SHELL_ALIGN(strlen(s)+1) : 0; | ||
15434 | } | ||
15435 | |||
15436 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
15437 | static int \ | ||
15438 | name(int funcblocksize, type *p) \ | ||
15439 | { \ | ||
15440 | while (p) { \ | ||
15441 | funcblocksize += sizeof(type); | ||
15442 | /* do something here with p */ | ||
15443 | #define SLIST_SIZE_END() \ | ||
15444 | nodeptrcount++; \ | ||
15445 | p = p->next; \ | ||
15446 | } \ | ||
15447 | return funcblocksize; \ | ||
15448 | } | ||
15449 | |||
15450 | #define SLIST_COPY_BEGIN(name,type) \ | ||
15451 | static type * \ | ||
15452 | name(type *vp) \ | ||
15453 | { \ | ||
15454 | type *start; \ | ||
15455 | type **vpp; \ | ||
15456 | vpp = &start; \ | ||
15457 | while (vp) { \ | ||
15458 | *vpp = funcblock; \ | ||
15459 | funcblock = (char *) funcblock + sizeof(type); | ||
15460 | /* do something here with vpp and vp */ | ||
15461 | #define SLIST_COPY_END() \ | ||
15462 | SAVE_PTR((*vpp)->next); \ | ||
15463 | ANNOT("(*vpp)->next"); \ | ||
15464 | vp = vp->next; \ | ||
15465 | vpp = &(*vpp)->next; \ | ||
15466 | } \ | ||
15467 | *vpp = NULL; \ | ||
15468 | return start; \ | ||
15469 | } | ||
15470 | |||
15471 | /* | ||
15472 | * struct var | ||
15473 | */ | ||
15474 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
15475 | funcblocksize += align_len(p->var_text); | ||
15476 | nodeptrcount++; /* p->text */ | ||
15477 | SLIST_SIZE_END() | ||
15478 | |||
15479 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
15480 | (*vpp)->var_text = nodeckstrdup(vp->var_text); | ||
15481 | (*vpp)->flags = vp->flags; | ||
15482 | (*vpp)->var_func = NULL; | ||
15483 | SAVE_PTR((*vpp)->var_text); | ||
15484 | ANNOT_NO_DUP(xasprintf("(*vpp)->var_text '%s'", vp->var_text ?: "NULL")); | ||
15485 | SLIST_COPY_END() | ||
15486 | |||
15487 | /* | ||
15488 | * struct strlist | ||
15489 | */ | ||
15490 | SLIST_SIZE_BEGIN(strlist_size,struct strlist) | ||
15491 | funcblocksize += align_len(p->text); | ||
15492 | nodeptrcount++; /* p->text */ | ||
15493 | SLIST_SIZE_END() | ||
15494 | |||
15495 | SLIST_COPY_BEGIN(strlist_copy,struct strlist) | ||
15496 | (*vpp)->text = nodeckstrdup(vp->text); | ||
15497 | SAVE_PTR((*vpp)->text); | ||
15498 | ANNOT_NO_DUP(xasprintf("(*vpp)->text '%s'", vp->text ?: "NULL")); | ||
15499 | SLIST_COPY_END() | ||
15500 | |||
15501 | /* | ||
15502 | * struct tblentry | ||
15503 | */ | ||
15504 | static int | ||
15505 | tblentry_size(int funcblocksize, struct tblentry *tep) | ||
15506 | { | ||
15507 | while (tep) { | ||
15508 | funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname); | ||
15509 | /* CMDBUILTIN, e->param.cmd needs no pointer relocation */ | ||
15510 | if (tep->cmdtype == CMDFUNCTION) { | ||
15511 | funcblocksize += offsetof(struct funcnode, n); | ||
15512 | funcblocksize = calcsize(funcblocksize, &tep->param.func->n); | ||
15513 | nodeptrcount++; /* tep->param.func */ | ||
15514 | } | ||
15515 | nodeptrcount++; /* tep->next */ | ||
15516 | tep = tep->next; | ||
15517 | } | ||
15518 | return funcblocksize; | ||
15519 | } | ||
15520 | |||
15521 | static struct tblentry * | ||
15522 | tblentry_copy(struct tblentry *tep) | ||
15523 | { | ||
15524 | struct tblentry *start; | ||
15525 | struct tblentry **newp; | ||
15526 | int size; | ||
15527 | |||
15528 | newp = &start; | ||
15529 | while (tep) { | ||
15530 | *newp = funcblock; | ||
15531 | size = sizeof(struct tblentry) + strlen(tep->cmdname); | ||
15532 | |||
15533 | funcblock = (char *) funcblock + size; | ||
15534 | memcpy(*newp, tep, size); | ||
15535 | switch (tep->cmdtype) { | ||
15536 | case CMDBUILTIN: | ||
15537 | /* Save index of builtin, not pointer; fixed by forkshell_init() */ | ||
15538 | (*newp)->param.index = tep->param.cmd - builtintab; | ||
15539 | break; | ||
15540 | case CMDFUNCTION: | ||
15541 | (*newp)->param.func = funcblock; | ||
15542 | funcblock = (char *) funcblock + offsetof(struct funcnode, n); | ||
15543 | copynode(&tep->param.func->n); | ||
15544 | SAVE_PTR((*newp)->param.func); | ||
15545 | ANNOT("param.func"); | ||
15546 | break; | ||
15547 | default: | ||
15548 | break; | ||
15549 | } | ||
15550 | SAVE_PTR((*newp)->next); | ||
15551 | ANNOT_NO_DUP(xasprintf("cmdname '%s'", tep->cmdname)); | ||
15552 | tep = tep->next; | ||
15553 | newp = &(*newp)->next; | ||
15554 | } | ||
15555 | *newp = NULL; | ||
15556 | return start; | ||
15557 | } | ||
15558 | |||
15559 | static int | ||
15560 | cmdtable_size(int funcblocksize, struct tblentry **cmdtablep) | ||
15561 | { | ||
15562 | int i; | ||
15563 | nodeptrcount += CMDTABLESIZE; | ||
15564 | funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE; | ||
15565 | for (i = 0; i < CMDTABLESIZE; i++) | ||
15566 | funcblocksize = tblentry_size(funcblocksize, cmdtablep[i]); | ||
15567 | return funcblocksize; | ||
15568 | } | ||
15569 | |||
15570 | static struct tblentry ** | ||
15571 | cmdtable_copy(struct tblentry **cmdtablep) | ||
15572 | { | ||
15573 | struct tblentry **new = funcblock; | ||
15574 | int i; | ||
15575 | |||
15576 | funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE; | ||
15577 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
15578 | new[i] = tblentry_copy(cmdtablep[i]); | ||
15579 | SAVE_PTR(new[i]); | ||
15580 | ANNOT_NO_DUP(xasprintf("cmdtablep[%d]", i)); | ||
15581 | } | ||
15582 | return new; | ||
15583 | } | ||
15584 | |||
15585 | /* | ||
15586 | * char ** | ||
15587 | */ | ||
15588 | static int | ||
15589 | argv_size(int funcblocksize, char **p) | ||
15590 | { | ||
15591 | while (p && *p) { | ||
15592 | funcblocksize += sizeof(char *); | ||
15593 | funcblocksize += align_len(*p); | ||
15594 | nodeptrcount++; | ||
15595 | p++; | ||
15596 | } | ||
15597 | funcblocksize += sizeof(char *); | ||
15598 | return funcblocksize; | ||
15599 | } | ||
15600 | |||
15601 | static char ** | ||
15602 | argv_copy(char **p) | ||
15603 | { | ||
15604 | char **new, **start = funcblock; | ||
15605 | #if FORKSHELL_DEBUG | ||
15606 | int i = 0; | ||
15607 | #endif | ||
15608 | |||
15609 | while (p && *p) { | ||
15610 | new = funcblock; | ||
15611 | funcblock = (char *) funcblock + sizeof(char *); | ||
15612 | *new = nodeckstrdup(*p); | ||
15613 | SAVE_PTR(*new); | ||
15614 | ANNOT_NO_DUP(xasprintf("argv[%d] '%s'", i++, *p)); | ||
15615 | p++; | ||
15616 | new++; | ||
15617 | } | ||
15618 | new = funcblock; | ||
15619 | funcblock = (char *) funcblock + sizeof(char *); | ||
15620 | *new = NULL; | ||
15621 | return start; | ||
15622 | } | ||
15623 | |||
15624 | /* | ||
15625 | * struct redirtab | ||
15626 | */ | ||
15627 | static int | ||
15628 | redirtab_size(int funcblocksize, struct redirtab *rdtp) | ||
15629 | { | ||
15630 | while (rdtp) { | ||
15631 | funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
15632 | rdtp = rdtp->next; | ||
15633 | nodeptrcount++; /* rdtp->next */ | ||
15634 | } | ||
15635 | return funcblocksize; | ||
15636 | } | ||
15637 | |||
15638 | static struct redirtab * | ||
15639 | redirtab_copy(struct redirtab *rdtp) | ||
15640 | { | ||
15641 | struct redirtab *start; | ||
15642 | struct redirtab **vpp; | ||
15643 | |||
15644 | vpp = &start; | ||
15645 | while (rdtp) { | ||
15646 | int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
15647 | *vpp = funcblock; | ||
15648 | funcblock = (char *) funcblock + size; | ||
15649 | memcpy(*vpp, rdtp, size); | ||
15650 | SAVE_PTR((*vpp)->next); | ||
15651 | ANNOT("(*vpp)->next"); | ||
15652 | rdtp = rdtp->next; | ||
15653 | vpp = &(*vpp)->next; | ||
15654 | } | ||
15655 | *vpp = NULL; | ||
15656 | return start; | ||
15657 | } | ||
15658 | |||
15659 | #undef shellparam | ||
15660 | #undef redirlist | ||
15661 | #undef vartab | ||
15662 | static int | ||
15663 | globals_var_size(int funcblocksize, struct globals_var *gvp) | ||
15664 | { | ||
15665 | int i; | ||
15666 | |||
15667 | funcblocksize += sizeof(struct globals_var); | ||
15668 | funcblocksize = argv_size(funcblocksize, gvp->shellparam.p); | ||
15669 | funcblocksize = redirtab_size(funcblocksize, gvp->redirlist); | ||
15670 | for (i = 0; i < VTABSIZE; i++) | ||
15671 | funcblocksize = var_size(funcblocksize, gvp->vartab[i]); | ||
15672 | /* gvp->redirlist, gvp->shellparam.p, vartab */ | ||
15673 | nodeptrcount += 2 + VTABSIZE; | ||
15674 | return funcblocksize; | ||
15675 | } | ||
15676 | |||
15677 | static struct globals_var * | ||
15678 | globals_var_copy(struct globals_var *gvp) | ||
15679 | { | ||
15680 | int i; | ||
15681 | struct globals_var *new; | ||
15682 | |||
15683 | new = funcblock; | ||
15684 | funcblock = (char *) funcblock + sizeof(struct globals_var); | ||
15685 | memcpy(new, gvp, sizeof(struct globals_var)); | ||
15686 | |||
15687 | /* shparam */ | ||
15688 | new->shellparam.malloced = 0; | ||
15689 | new->shellparam.p = argv_copy(gvp->shellparam.p); | ||
15690 | SAVE_PTR(new->shellparam.p); | ||
15691 | ANNOT("shellparam.p"); | ||
15692 | |||
15693 | new->redirlist = redirtab_copy(gvp->redirlist); | ||
15694 | SAVE_PTR(new->redirlist); | ||
15695 | ANNOT("redirlist"); | ||
15696 | |||
15697 | for (i = 0; i < VTABSIZE; i++) { | ||
15698 | new->vartab[i] = var_copy(gvp->vartab[i]); | ||
15699 | SAVE_PTR(new->vartab[i]); | ||
15700 | ANNOT_NO_DUP(xasprintf("vartab[%d]", i)); | ||
15701 | } | ||
15702 | |||
15703 | return new; | ||
15704 | } | ||
15705 | |||
15706 | #undef minusc | ||
15707 | #undef curdir | ||
15708 | #undef physdir | ||
15709 | #undef arg0 | ||
15710 | #undef commandname | ||
15711 | #undef nullstr | ||
15712 | static int | ||
15713 | globals_misc_size(int funcblocksize, struct globals_misc *p) | ||
15714 | { | ||
15715 | funcblocksize += sizeof(struct globals_misc); | ||
15716 | funcblocksize += align_len(p->minusc); | ||
15717 | if (p->curdir != p->nullstr) | ||
15718 | funcblocksize += align_len(p->curdir); | ||
15719 | if (p->physdir != p->nullstr) | ||
15720 | funcblocksize += align_len(p->physdir); | ||
15721 | funcblocksize += align_len(p->arg0); | ||
15722 | funcblocksize += align_len(p->commandname); | ||
15723 | nodeptrcount += 5; /* minusc, curdir, physdir, arg0, commandname */ | ||
15724 | return funcblocksize; | ||
15725 | } | ||
15726 | |||
15727 | static struct globals_misc * | ||
15728 | globals_misc_copy(struct globals_misc *p) | ||
15729 | { | ||
15730 | struct globals_misc *new = funcblock; | ||
15731 | |||
15732 | funcblock = (char *) funcblock + sizeof(struct globals_misc); | ||
15733 | memcpy(new, p, sizeof(struct globals_misc)); | ||
15734 | |||
15735 | new->minusc = nodeckstrdup(p->minusc); | ||
15736 | new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr; | ||
15737 | new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr; | ||
15738 | new->arg0 = nodeckstrdup(p->arg0); | ||
15739 | new->commandname = nodeckstrdup(p->commandname); | ||
15740 | SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0); | ||
15741 | SAVE_PTR(new->commandname); | ||
15742 | ANNOT_NO_DUP(xasprintf("minusc '%s'", p->minusc ?: "NULL")); | ||
15743 | ANNOT_NO_DUP(xasprintf("curdir '%s'", new->curdir ?: "NULL")); | ||
15744 | ANNOT_NO_DUP(xasprintf("physdir '%s'", new->physdir ?: "NULL")); | ||
15745 | ANNOT_NO_DUP(xasprintf("arg0 '%s'", p->arg0 ?: "NULL");) | ||
15746 | ANNOT_NO_DUP(xasprintf("commandname '%s'", p->commandname ?: "NULL")); | ||
15747 | return new; | ||
15748 | } | ||
15749 | |||
15750 | static int | ||
15751 | forkshell_size(int funcblocksize, struct forkshell *fs) | ||
15752 | { | ||
15753 | funcblocksize = globals_var_size(funcblocksize, fs->gvp); | ||
15754 | funcblocksize = globals_misc_size(funcblocksize, fs->gmp); | ||
15755 | funcblocksize = cmdtable_size(funcblocksize, fs->cmdtable); | ||
15756 | /* optlist_transfer(sending, fd); */ | ||
15757 | /* misc_transfer(sending, fd); */ | ||
15758 | |||
15759 | funcblocksize = calcsize(funcblocksize, fs->n); | ||
15760 | funcblocksize = argv_size(funcblocksize, fs->argv); | ||
15761 | funcblocksize += align_len(fs->path); | ||
15762 | funcblocksize = strlist_size(funcblocksize, fs->varlist); | ||
15763 | |||
15764 | nodeptrcount += 7; /* gvp, gmp, cmdtable, n, argv, string, strlist */ | ||
15765 | return funcblocksize; | ||
15766 | } | ||
15767 | |||
15768 | static void | ||
15769 | forkshell_copy(struct forkshell *fs, struct forkshell *new) | ||
15770 | { | ||
15771 | memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */ | ||
15772 | new->gvp = globals_var_copy(fs->gvp); | ||
15773 | new->gmp = globals_misc_copy(fs->gmp); | ||
15774 | new->cmdtable = cmdtable_copy(fs->cmdtable); | ||
15775 | SAVE_PTR3(new->gvp, new->gmp, new->cmdtable); | ||
15776 | ANNOT3("gvp", "gmp", "cmdtable"); | ||
15777 | |||
15778 | new->n = copynode(fs->n); | ||
15779 | new->argv = argv_copy(fs->argv); | ||
15780 | new->path = nodeckstrdup(fs->path); | ||
15781 | new->varlist = strlist_copy(fs->varlist); | ||
15782 | SAVE_PTR4(new->n, new->argv, new->path, new->varlist); | ||
15783 | ANNOT2("n", "argv"); | ||
15784 | ANNOT_NO_DUP(xasprintf("path '%s'", fs->path ?: "NULL")); | ||
15785 | ANNOT("varlist"); | ||
15786 | } | ||
15787 | |||
15788 | #if FORKSHELL_DEBUG | ||
15789 | /* fp and notes can each be NULL */ | ||
15790 | static void | ||
15791 | forkshell_print(FILE *fp0, struct forkshell *fs, char **notes) | ||
15792 | { | ||
15793 | FILE *fp; | ||
15794 | void *lfuncblock; | ||
15795 | char *lfuncstring; | ||
15796 | char ***lnodeptr; | ||
15797 | char *s; | ||
15798 | int count; | ||
15799 | |||
15800 | if (fp0 != NULL) { | ||
15801 | fp = fp0; | ||
15802 | } | ||
15803 | else { | ||
15804 | char name[32]; | ||
15805 | |||
15806 | sprintf(name, "fs_%d.out", getpid()); | ||
15807 | if ((fp=fopen(name, "w")) == NULL) | ||
15808 | return; | ||
15809 | } | ||
15810 | |||
15811 | fprintf(fp, "size %d = %d + %d*%d + %d + %d\n", fs->size, | ||
15812 | (int)sizeof(struct forkshell), fs->nodeptrcount, | ||
15813 | (int)sizeof(char *), fs->funcblocksize, fs->funcstringsize); | ||
15814 | |||
15815 | lnodeptr = fs->nodeptr; | ||
15816 | lfuncblock = (char *)lnodeptr + (fs->nodeptrcount+1)*sizeof(char *); | ||
15817 | lfuncstring = (char *)lfuncblock + fs->funcblocksize; | ||
15818 | |||
15819 | fprintf(fp, "funcblocksize %d = %d + %d + %d\n\n", fs->funcblocksize, | ||
15820 | (int)((char *)fs->gmp-(char *)fs->gvp), | ||
15821 | (int)((char *)fs->cmdtable-(char *)fs->gmp), | ||
15822 | (int)(lfuncstring-(char *)fs->cmdtable)); | ||
15823 | |||
15824 | fprintf(fp, "--- nodeptr ---\n"); | ||
15825 | count = 0; | ||
15826 | if (notes == NULL) { | ||
15827 | while (*lnodeptr) { | ||
15828 | fprintf(fp, "%p ", *lnodeptr++); | ||
15829 | if ((count&3) == 3) | ||
15830 | fprintf(fp, "\n"); | ||
15831 | ++count; | ||
15832 | } | ||
15833 | if (((count-1)&3) != 3) | ||
15834 | fprintf(fp, "\n"); | ||
15835 | } | ||
15836 | else { | ||
15837 | while (*lnodeptr) { | ||
15838 | fprintf(fp, "%p %p %s\n", *lnodeptr, **lnodeptr, notes[count++]); | ||
15839 | lnodeptr++; | ||
15840 | } | ||
15841 | } | ||
15842 | if (count != fs->nodeptrcount) | ||
15843 | fprintf(fp, "--- %d pointers (expected %d) ---\n\n", count, | ||
15844 | fs->nodeptrcount); | ||
15845 | else | ||
15846 | fprintf(fp, "--- %d pointers ---\n\n", count); | ||
15847 | |||
15848 | fprintf(fp, "--- funcstring ---\n"); | ||
15849 | count = 0; | ||
15850 | s = lfuncstring; | ||
15851 | while (s-lfuncstring < fs->funcstringsize) { | ||
15852 | if (!*s) { | ||
15853 | ++s; | ||
15854 | continue; | ||
15855 | } | ||
15856 | fprintf(fp, "%p '%s'\n", s, s); | ||
15857 | s += strlen(s)+1; | ||
15858 | ++count; | ||
15859 | } | ||
15860 | fprintf(fp, "--- %d strings ---\n", count); | ||
15861 | |||
15862 | if (fp0 == NULL) | ||
15863 | fclose(fp); | ||
15864 | } | ||
15865 | #endif | ||
15866 | |||
15867 | static struct forkshell * | ||
15868 | forkshell_prepare(struct forkshell *fs) | ||
15869 | { | ||
15870 | int funcblocksize; | ||
15871 | struct forkshell *new; | ||
15872 | int size; | ||
15873 | HANDLE h; | ||
15874 | SECURITY_ATTRIBUTES sa; | ||
15875 | #if FORKSHELL_DEBUG | ||
15876 | void *fb0; | ||
15877 | char name[32]; | ||
15878 | FILE *fp; | ||
15879 | #endif | ||
15880 | |||
15881 | /* Calculate size of "new" */ | ||
15882 | fs->gvp = ash_ptr_to_globals_var; | ||
15883 | fs->gmp = ash_ptr_to_globals_misc; | ||
15884 | fs->cmdtable = cmdtable; | ||
15885 | |||
15886 | /* | ||
15887 | * Careful: much scope for off-by-one errors. nodeptrcount is the | ||
15888 | * number of actual pointers. There's also a terminating NULL pointer. | ||
15889 | * The array in the forkshell structure gives us one element for free. | ||
15890 | */ | ||
15891 | nodeptrcount = 0; | ||
15892 | funcblocksize = forkshell_size(0, fs); | ||
15893 | size = sizeof(struct forkshell) + nodeptrcount*sizeof(char *) + | ||
15894 | funcblocksize; | ||
15895 | |||
15896 | /* Allocate, initialize pointers */ | ||
15897 | memset(&sa, 0, sizeof(sa)); | ||
15898 | sa.nLength = sizeof(sa); | ||
15899 | sa.lpSecurityDescriptor = NULL; | ||
15900 | sa.bInheritHandle = TRUE; | ||
15901 | h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL); | ||
15902 | new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
15903 | nodeptr = new->nodeptr; | ||
15904 | funcblock = (char *)nodeptr + (nodeptrcount+1)*sizeof(char *); | ||
15905 | funcstring_end = (char *)new + size; | ||
15906 | #if FORKSHELL_DEBUG | ||
15907 | fb0 = funcblock; | ||
15908 | annot = xmalloc(sizeof(char *)*nodeptrcount); | ||
15909 | annot_count = 0; | ||
15910 | #endif | ||
15911 | |||
15912 | /* Now pack them all */ | ||
15913 | forkshell_copy(fs, new); | ||
15914 | |||
15915 | /* Finish it up */ | ||
15916 | *nodeptr = NULL; | ||
15917 | new->size = size; | ||
15918 | new->old_base = (char *)new; | ||
15919 | new->hMapFile = h; | ||
15920 | #if FORKSHELL_DEBUG | ||
15921 | sprintf(name, "fs_%d.out", getpid()); | ||
15922 | if ((fp=fopen(name, "w")) != NULL) { | ||
15923 | int i; | ||
15924 | |||
15925 | /* perform some sanity checks on pointers */ | ||
15926 | fprintf(fp, "%p start of forkshell struct\n", new); | ||
15927 | fprintf(fp, "%p start of nodeptr\n", new->nodeptr); | ||
15928 | fprintf(fp, "%p start of funcblock", fb0); | ||
15929 | if ((char *)(nodeptr+1) != (char *)fb0) | ||
15930 | fprintf(fp, " != end nodeptr block + 1 %p\n", nodeptr+1); | ||
15931 | else | ||
15932 | fprintf(fp, "\n"); | ||
15933 | |||
15934 | fprintf(fp, "%p start of funcstring", funcstring_end); | ||
15935 | if ((char *)funcblock != funcstring_end) | ||
15936 | fprintf(fp, " != end funcblock + 1 %p\n\n", funcblock); | ||
15937 | else | ||
15938 | fprintf(fp, "\n\n"); | ||
15939 | |||
15940 | if (nodeptrcount != annot_count) | ||
15941 | fprintf(fp, "nodeptrcount (%d) != annot_count (%d)\n\n", | ||
15942 | nodeptrcount, annot_count); | ||
15943 | |||
15944 | new->nodeptrcount = nodeptrcount; | ||
15945 | new->funcblocksize = (char *)funcblock - (char *)fb0; | ||
15946 | new->funcstringsize = (char *)new + size - funcstring_end; | ||
15947 | forkshell_print(fp, new, nodeptrcount == annot_count ? annot : NULL); | ||
15948 | |||
15949 | for (i = 0; i < annot_count; ++i) | ||
15950 | free(annot[i]); | ||
15951 | free(annot); | ||
15952 | annot = NULL; | ||
15953 | annot_count = 0; | ||
15954 | fclose(fp); | ||
15955 | } | ||
15956 | #endif | ||
15957 | return new; | ||
15958 | } | ||
15959 | |||
15960 | #undef exception_handler | ||
15961 | #undef trap | ||
15962 | #undef trap_ptr | ||
15963 | static void *sticky_mem_start, *sticky_mem_end; | ||
15964 | static void | ||
15965 | forkshell_init(const char *idstr) | ||
15966 | { | ||
15967 | struct forkshell *fs; | ||
15968 | void *map_handle; | ||
15969 | HANDLE h; | ||
15970 | struct globals_var **gvpp; | ||
15971 | struct globals_misc **gmpp; | ||
15972 | int i; | ||
15973 | char **ptr; | ||
15974 | |||
15975 | if (sscanf(idstr, "%p", &map_handle) != 1) | ||
15976 | bb_error_msg_and_die("invalid forkshell ID"); | ||
15977 | |||
15978 | h = (HANDLE)map_handle; | ||
15979 | fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
15980 | if (!fs) | ||
15981 | bb_error_msg_and_die("Invalid forkshell memory"); | ||
15982 | |||
15983 | /* this memory can't be freed */ | ||
15984 | sticky_mem_start = fs; | ||
15985 | sticky_mem_end = (char *) fs + fs->size; | ||
15986 | |||
15987 | /* pointer fixup */ | ||
15988 | for ( i=0; fs->nodeptr[i]; ++i ) { | ||
15989 | ptr = (char **)((char *)fs + ((char *)fs->nodeptr[i] - fs->old_base)); | ||
15990 | if (*ptr) | ||
15991 | *ptr = (char *)fs + (*ptr - fs->old_base); | ||
15992 | } | ||
15993 | |||
15994 | /* Now fix up stuff that can't be transferred */ | ||
15995 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
15996 | struct tblentry *e = fs->cmdtable[i]; | ||
15997 | while (e) { | ||
15998 | if (e->cmdtype == CMDBUILTIN) | ||
15999 | e->param.cmd = builtintab + e->param.index; | ||
16000 | e = e->next; | ||
16001 | } | ||
16002 | } | ||
16003 | fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler; | ||
16004 | for (i = 0; i < NSIG; i++) | ||
16005 | fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i]; | ||
16006 | fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr; | ||
16007 | |||
16008 | /* Switch global variables */ | ||
16009 | gvpp = (struct globals_var **)&ash_ptr_to_globals_var; | ||
16010 | *gvpp = fs->gvp; | ||
16011 | gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc; | ||
16012 | *gmpp = fs->gmp; | ||
16013 | cmdtable = fs->cmdtable; | ||
16014 | |||
16015 | CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */ | ||
16016 | |||
16017 | reinitvar(); | ||
16018 | |||
16019 | shlvl++; | ||
16020 | if (fs->mode == FORK_BG) { | ||
16021 | SetConsoleCtrlHandler(NULL, TRUE); | ||
16022 | if (fs->nprocs == 0) { | ||
16023 | close(0); | ||
16024 | if (open(bb_dev_null, O_RDONLY) != 0) | ||
16025 | ash_msg_and_raise_perror("can't open '%s'", bb_dev_null); | ||
16026 | } | ||
16027 | } | ||
16028 | forkshell_child(fs); | ||
16029 | } | ||
16030 | |||
16031 | #undef free | ||
16032 | static void | ||
16033 | sticky_free(void *base) | ||
16034 | { | ||
16035 | if (base >= sticky_mem_start && base < sticky_mem_end) | ||
16036 | return; | ||
16037 | free(base); | ||
16038 | } | ||
16039 | #endif | ||
14375 | 16040 | ||
14376 | /*- | 16041 | /*- |
14377 | * Copyright (c) 1989, 1991, 1993, 1994 | 16042 | * Copyright (c) 1989, 1991, 1993, 1994 |