diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 1407 |
1 files changed, 1344 insertions, 63 deletions
diff --git a/shell/ash.c b/shell/ash.c index 1deae7c2f..18e53a0da 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 (77 kb)" | 34 | //config: bool "ash (77 kb)" |
20 | //config: default y | 35 | //config: default y |
@@ -132,6 +147,18 @@ | |||
132 | //config: you to run the specified command or builtin, | 147 | //config: you to run the specified command or builtin, |
133 | //config: even when there is a function with the same name. | 148 | //config: even when there is a function with the same name. |
134 | //config: | 149 | //config: |
150 | //config: | ||
151 | //config:config ASH_NOCONSOLE | ||
152 | //config: bool "'noconsole' option" | ||
153 | //config: default y | ||
154 | //config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32 | ||
155 | //config: help | ||
156 | //config: Enable support for the 'noconsole' option, which attempts to | ||
157 | //config: hide the console normally associated with a command line | ||
158 | //config: application. This may be useful when running a shell script | ||
159 | //config: from a GUI application. Disable this if your platform doesn't | ||
160 | //config: support the required APIs. | ||
161 | //config: | ||
135 | //config:endif # ash options | 162 | //config:endif # ash options |
136 | 163 | ||
137 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) | 164 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) |
@@ -240,10 +267,58 @@ typedef long arith_t; | |||
240 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ | 267 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ |
241 | #endif | 268 | #endif |
242 | 269 | ||
270 | #if !ENABLE_PLATFORM_MINGW32 | ||
271 | # define is_absolute_path(path) ((path)[0] == '/') | ||
272 | #endif | ||
273 | |||
243 | #if !BB_MMU | 274 | #if !BB_MMU |
244 | # error "Do not even bother, ash will not run on NOMMU machine" | 275 | # error "Do not even bother, ash will not run on NOMMU machine" |
245 | #endif | 276 | #endif |
246 | 277 | ||
278 | #if ENABLE_PLATFORM_MINGW32 | ||
279 | union node; | ||
280 | struct strlist; | ||
281 | struct job; | ||
282 | |||
283 | struct forkshell { | ||
284 | /* filled by forkshell_copy() */ | ||
285 | struct globals_var *gvp; | ||
286 | struct globals_misc *gmp; | ||
287 | struct tblentry **cmdtable; | ||
288 | /* struct alias **atab; */ | ||
289 | /* struct parsefile *g_parsefile; */ | ||
290 | HANDLE hMapFile; | ||
291 | void *old_base; | ||
292 | int nodeptr_offset; | ||
293 | int size; | ||
294 | |||
295 | /* type of forkshell */ | ||
296 | int fpid; | ||
297 | |||
298 | /* optional data, used by forkshell_child */ | ||
299 | int flags; | ||
300 | int fd[10]; | ||
301 | union node *n; | ||
302 | char **argv; | ||
303 | char *string; | ||
304 | struct strlist *strlist; | ||
305 | }; | ||
306 | |||
307 | enum { | ||
308 | FS_OPENHERE, | ||
309 | FS_EVALBACKCMD, | ||
310 | FS_EVALSUBSHELL, | ||
311 | FS_EVALPIPE, | ||
312 | FS_SHELLEXEC | ||
313 | }; | ||
314 | |||
315 | static struct forkshell* forkshell_prepare(struct forkshell *fs); | ||
316 | static void forkshell_init(const char *idstr); | ||
317 | static void forkshell_child(struct forkshell *fs); | ||
318 | static void sticky_free(void *p); | ||
319 | #define free(p) sticky_free(p) | ||
320 | static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode); | ||
321 | #endif | ||
247 | 322 | ||
248 | /* ============ Hash table sizes. Configurable. */ | 323 | /* ============ Hash table sizes. Configurable. */ |
249 | 324 | ||
@@ -276,6 +351,12 @@ static const char *const optletters_optnames[] = { | |||
276 | ,"\0" "nolog" | 351 | ,"\0" "nolog" |
277 | ,"\0" "debug" | 352 | ,"\0" "debug" |
278 | #endif | 353 | #endif |
354 | #if ENABLE_PLATFORM_MINGW32 | ||
355 | ,"X" "winxp" | ||
356 | #endif | ||
357 | #if ENABLE_ASH_NOCONSOLE | ||
358 | ,"\0" "noconsole" | ||
359 | #endif | ||
279 | }; | 360 | }; |
280 | 361 | ||
281 | #define optletters(n) optletters_optnames[n][0] | 362 | #define optletters(n) optletters_optnames[n][0] |
@@ -354,6 +435,12 @@ struct globals_misc { | |||
354 | # define nolog optlist[14 + BASH_PIPEFAIL] | 435 | # define nolog optlist[14 + BASH_PIPEFAIL] |
355 | # define debug optlist[15 + BASH_PIPEFAIL] | 436 | # define debug optlist[15 + BASH_PIPEFAIL] |
356 | #endif | 437 | #endif |
438 | #if ENABLE_PLATFORM_MINGW32 | ||
439 | # define winxp optlist[14 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG] | ||
440 | #endif | ||
441 | #if ENABLE_ASH_NOCONSOLE | ||
442 | # define noconsole optlist[15 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG] | ||
443 | #endif | ||
357 | 444 | ||
358 | /* trap handler commands */ | 445 | /* trap handler commands */ |
359 | /* | 446 | /* |
@@ -2434,10 +2521,22 @@ path_advance(const char **path, const char *name) | |||
2434 | if (*path == NULL) | 2521 | if (*path == NULL) |
2435 | return NULL; | 2522 | return NULL; |
2436 | start = *path; | 2523 | start = *path; |
2524 | #if ENABLE_PLATFORM_MINGW32 | ||
2525 | p = next_path_sep(start); | ||
2526 | q = strchr(start, '%'); | ||
2527 | if ((p && q && q < p) || (!p && q)) | ||
2528 | p = q; | ||
2529 | if (!p) | ||
2530 | for (p = start; *p; p++) | ||
2531 | continue; | ||
2532 | #else | ||
2437 | for (p = start; *p && *p != ':' && *p != '%'; p++) | 2533 | for (p = start; *p && *p != ':' && *p != '%'; p++) |
2438 | continue; | 2534 | continue; |
2535 | #endif | ||
2439 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ | 2536 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ |
2440 | while (stackblocksize() < len) | 2537 | |
2538 | /* preserve space for .exe too */ | ||
2539 | while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len)) | ||
2441 | growstackblock(); | 2540 | growstackblock(); |
2442 | q = stackblock(); | 2541 | q = stackblock(); |
2443 | if (p != start) { | 2542 | if (p != start) { |
@@ -2448,10 +2547,19 @@ path_advance(const char **path, const char *name) | |||
2448 | pathopt = NULL; | 2547 | pathopt = NULL; |
2449 | if (*p == '%') { | 2548 | if (*p == '%') { |
2450 | pathopt = ++p; | 2549 | pathopt = ++p; |
2550 | #if ENABLE_PLATFORM_MINGW32 | ||
2551 | p = next_path_sep(start); | ||
2552 | |||
2553 | /* *p != ':' and '*' would suffice */ | ||
2554 | if (!p) | ||
2555 | p = pathopt - 1; | ||
2556 | #else | ||
2451 | while (*p && *p != ':') | 2557 | while (*p && *p != ':') |
2452 | p++; | 2558 | p++; |
2559 | #endif | ||
2453 | } | 2560 | } |
2454 | if (*p == ':') | 2561 | if (*p == ':' || |
2562 | (ENABLE_PLATFORM_MINGW32 && *p == ';')) | ||
2455 | *path = p + 1; | 2563 | *path = p + 1; |
2456 | else | 2564 | else |
2457 | *path = NULL; | 2565 | *path = NULL; |
@@ -2560,6 +2668,106 @@ cdopt(void) | |||
2560 | static const char * | 2668 | static const char * |
2561 | updatepwd(const char *dir) | 2669 | updatepwd(const char *dir) |
2562 | { | 2670 | { |
2671 | #if ENABLE_PLATFORM_MINGW32 | ||
2672 | #define is_path_sep(x) ((x) == '/' || (x) == '\\') | ||
2673 | #define is_unc_path(x) (is_path_sep(x[0]) && is_path_sep(x[1])) | ||
2674 | /* | ||
2675 | * Due to Windows drive notion, getting pwd is a completely | ||
2676 | * different thing. Handle it in a separate routine | ||
2677 | */ | ||
2678 | |||
2679 | char *new; | ||
2680 | char *p; | ||
2681 | char *cdcomppath; | ||
2682 | const char *lim; | ||
2683 | /* | ||
2684 | * There are five cases that make some kind of sense | ||
2685 | * absdrive + abspath: c:/path | ||
2686 | * absdrive + !abspath: c:path | ||
2687 | * !absdrive + abspath: /path | ||
2688 | * !absdrive + uncpath: //host/share | ||
2689 | * !absdrive + !abspath: path | ||
2690 | * | ||
2691 | * Damn DOS! | ||
2692 | * c:path behaviour is "undefined" | ||
2693 | * To properly handle this case, I have to keep track of cwd | ||
2694 | * of every drive, which is too painful to do. | ||
2695 | * So when c:path is given, I assume it's c:${curdir}path | ||
2696 | * with ${curdir} comes from the current drive | ||
2697 | */ | ||
2698 | int absdrive = *dir && dir[1] == ':'; | ||
2699 | int abspath = absdrive ? is_path_sep(dir[2]) : is_path_sep(*dir); | ||
2700 | |||
2701 | cdcomppath = sstrdup(dir); | ||
2702 | STARTSTACKSTR(new); | ||
2703 | if (!absdrive && curdir == nullstr) | ||
2704 | return 0; | ||
2705 | if (!abspath) { | ||
2706 | if (curdir == nullstr) | ||
2707 | return 0; | ||
2708 | new = stack_putstr(curdir, new); | ||
2709 | } | ||
2710 | new = makestrspace(strlen(dir) + 2, new); | ||
2711 | |||
2712 | if ( is_unc_path(dir) || (!absdrive && !abspath && is_unc_path(curdir)) ) { | ||
2713 | lim = (char *)stackblock() + 1; | ||
2714 | } | ||
2715 | else { | ||
2716 | char *drive = stackblock(); | ||
2717 | if (absdrive) { | ||
2718 | *drive = *dir; | ||
2719 | cdcomppath += 2; | ||
2720 | dir += 2; | ||
2721 | } else { | ||
2722 | *drive = *curdir; | ||
2723 | } | ||
2724 | drive[1] = ':'; /* in case of absolute drive+path */ | ||
2725 | |||
2726 | if (abspath) | ||
2727 | new = drive + 2; | ||
2728 | lim = drive + 3; | ||
2729 | } | ||
2730 | |||
2731 | if (!abspath) { | ||
2732 | if (!is_path_sep(new[-1])) | ||
2733 | USTPUTC('/', new); | ||
2734 | if (new > lim && is_path_sep(*lim)) | ||
2735 | lim++; | ||
2736 | } else { | ||
2737 | USTPUTC('/', new); | ||
2738 | cdcomppath ++; | ||
2739 | if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) { | ||
2740 | USTPUTC('/', new); | ||
2741 | cdcomppath++; | ||
2742 | lim++; | ||
2743 | } | ||
2744 | } | ||
2745 | p = strtok(cdcomppath, "/\\"); | ||
2746 | while (p) { | ||
2747 | switch (*p) { | ||
2748 | case '.': | ||
2749 | if (p[1] == '.' && p[2] == '\0') { | ||
2750 | while (new > lim) { | ||
2751 | STUNPUTC(new); | ||
2752 | if (is_path_sep(new[-1])) | ||
2753 | break; | ||
2754 | } | ||
2755 | break; | ||
2756 | } | ||
2757 | if (p[1] == '\0') | ||
2758 | break; | ||
2759 | /* fall through */ | ||
2760 | default: | ||
2761 | new = stack_putstr(p, new); | ||
2762 | USTPUTC('/', new); | ||
2763 | } | ||
2764 | p = strtok(0, "/\\"); | ||
2765 | } | ||
2766 | if (new > lim) | ||
2767 | STUNPUTC(new); | ||
2768 | *new = 0; | ||
2769 | return stackblock(); | ||
2770 | #else | ||
2563 | char *new; | 2771 | char *new; |
2564 | char *p; | 2772 | char *p; |
2565 | char *cdcomppath; | 2773 | char *cdcomppath; |
@@ -2613,6 +2821,7 @@ updatepwd(const char *dir) | |||
2613 | STUNPUTC(new); | 2821 | STUNPUTC(new); |
2614 | *new = 0; | 2822 | *new = 0; |
2615 | return stackblock(); | 2823 | return stackblock(); |
2824 | #endif | ||
2616 | } | 2825 | } |
2617 | 2826 | ||
2618 | /* | 2827 | /* |
@@ -2707,7 +2916,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2707 | } | 2916 | } |
2708 | if (!dest) | 2917 | if (!dest) |
2709 | dest = nullstr; | 2918 | dest = nullstr; |
2710 | if (*dest == '/') | 2919 | if (is_absolute_path(dest)) |
2711 | goto step6; | 2920 | goto step6; |
2712 | if (*dest == '.') { | 2921 | if (*dest == '.') { |
2713 | c = dest[1]; | 2922 | c = dest[1]; |
@@ -3409,6 +3618,9 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
3409 | */ | 3618 | */ |
3410 | struct procstat { | 3619 | struct procstat { |
3411 | pid_t ps_pid; /* process id */ | 3620 | pid_t ps_pid; /* process id */ |
3621 | #if ENABLE_PLATFORM_MINGW32 | ||
3622 | HANDLE ps_proc; | ||
3623 | #endif | ||
3412 | int ps_status; /* last process status from wait() */ | 3624 | int ps_status; /* last process status from wait() */ |
3413 | char *ps_cmd; /* text of command being run */ | 3625 | char *ps_cmd; /* text of command being run */ |
3414 | }; | 3626 | }; |
@@ -3437,7 +3649,9 @@ struct job { | |||
3437 | }; | 3649 | }; |
3438 | 3650 | ||
3439 | static struct job *makejob(/*union node *,*/ int); | 3651 | static struct job *makejob(/*union node *,*/ int); |
3652 | #if !ENABLE_PLATFORM_MINGW32 | ||
3440 | static int forkshell(struct job *, union node *, int); | 3653 | static int forkshell(struct job *, union node *, int); |
3654 | #endif | ||
3441 | static int waitforjob(struct job *); | 3655 | static int waitforjob(struct job *); |
3442 | 3656 | ||
3443 | #if !JOBS | 3657 | #if !JOBS |
@@ -3462,6 +3676,7 @@ ignoresig(int signo) | |||
3462 | sigmode[signo - 1] = S_HARD_IGN; | 3676 | sigmode[signo - 1] = S_HARD_IGN; |
3463 | } | 3677 | } |
3464 | 3678 | ||
3679 | #if !ENABLE_PLATFORM_MINGW32 | ||
3465 | /* | 3680 | /* |
3466 | * Only one usage site - in setsignal() | 3681 | * Only one usage site - in setsignal() |
3467 | */ | 3682 | */ |
@@ -3586,6 +3801,9 @@ setsignal(int signo) | |||
3586 | 3801 | ||
3587 | *t = new_act; | 3802 | *t = new_act; |
3588 | } | 3803 | } |
3804 | #else | ||
3805 | #define setsignal(s) | ||
3806 | #endif | ||
3589 | 3807 | ||
3590 | /* mode flags for set_curjob */ | 3808 | /* mode flags for set_curjob */ |
3591 | #define CUR_DELETE 2 | 3809 | #define CUR_DELETE 2 |
@@ -4083,6 +4301,98 @@ sprint_status48(char *s, int status, int sigonly) | |||
4083 | return col; | 4301 | return col; |
4084 | } | 4302 | } |
4085 | 4303 | ||
4304 | #if ENABLE_PLATFORM_MINGW32 | ||
4305 | |||
4306 | HANDLE hSIGINT; /* Ctrl-C is pressed */ | ||
4307 | |||
4308 | static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) | ||
4309 | { | ||
4310 | if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { | ||
4311 | SetEvent(hSIGINT); | ||
4312 | pending_int = 1; | ||
4313 | return TRUE; | ||
4314 | } | ||
4315 | return FALSE; | ||
4316 | } | ||
4317 | |||
4318 | /* | ||
4319 | * Windows does not know about parent-child relationship | ||
4320 | * They don't support waitpid(-1) | ||
4321 | */ | ||
4322 | static pid_t | ||
4323 | waitpid_child(int *status, int wait_flags) | ||
4324 | { | ||
4325 | pid_t *pidlist; | ||
4326 | HANDLE *proclist; | ||
4327 | int pid_nr = 0; | ||
4328 | pid_t pid; | ||
4329 | DWORD win_status, idx; | ||
4330 | struct job *jb; | ||
4331 | |||
4332 | for (jb = curjob; jb; jb = jb->prev_job) { | ||
4333 | if (jb->state != JOBDONE) | ||
4334 | pid_nr += jb->nprocs; | ||
4335 | } | ||
4336 | if ( pid_nr++ == 0 ) | ||
4337 | return -1; | ||
4338 | |||
4339 | pidlist = ckmalloc(sizeof(*pidlist)*pid_nr); | ||
4340 | proclist = ckmalloc(sizeof(*proclist)*pid_nr); | ||
4341 | |||
4342 | pidlist[0] = -1; | ||
4343 | proclist[0] = hSIGINT; | ||
4344 | pid_nr = 1; | ||
4345 | for (jb = curjob; jb; jb = jb->prev_job) { | ||
4346 | struct procstat *ps, *psend; | ||
4347 | if (jb->state == JOBDONE) | ||
4348 | continue; | ||
4349 | ps = jb->ps; | ||
4350 | psend = ps + jb->nprocs; | ||
4351 | while (ps < psend) { | ||
4352 | if (ps->ps_pid != -1 && ps->ps_proc != NULL) { | ||
4353 | pidlist[pid_nr] = ps->ps_pid; | ||
4354 | proclist[pid_nr++] = ps->ps_proc; | ||
4355 | } | ||
4356 | ps++; | ||
4357 | } | ||
4358 | } | ||
4359 | |||
4360 | if (pid_nr == 1) { | ||
4361 | free(pidlist); | ||
4362 | free(proclist); | ||
4363 | return -1; | ||
4364 | } | ||
4365 | |||
4366 | idx = WaitForMultipleObjects(pid_nr, proclist, FALSE, | ||
4367 | wait_flags|WNOHANG ? 1 : INFINITE); | ||
4368 | if (idx >= pid_nr) { | ||
4369 | free(pidlist); | ||
4370 | free(proclist); | ||
4371 | return -1; | ||
4372 | } | ||
4373 | if (!idx) { /* hSIGINT */ | ||
4374 | int i; | ||
4375 | ResetEvent(hSIGINT); | ||
4376 | for (i = 1; i < pid_nr; i++) | ||
4377 | TerminateProcess(proclist[i], 1); | ||
4378 | pid = pidlist[1]; | ||
4379 | free(pidlist); | ||
4380 | free(proclist); | ||
4381 | *status = 260; /* terminated by a signal */ | ||
4382 | return pid; | ||
4383 | } | ||
4384 | GetExitCodeProcess(proclist[idx], &win_status); | ||
4385 | pid = pidlist[idx]; | ||
4386 | free(pidlist); | ||
4387 | free(proclist); | ||
4388 | *status = (int)win_status; | ||
4389 | return pid; | ||
4390 | } | ||
4391 | #define waitpid(p, s, f) waitpid_child(s, f) | ||
4392 | #define wait_block_or_sig(s) waitpid_child(s, 0) | ||
4393 | |||
4394 | #else | ||
4395 | |||
4086 | static int | 4396 | static int |
4087 | wait_block_or_sig(int *status) | 4397 | wait_block_or_sig(int *status) |
4088 | { | 4398 | { |
@@ -4115,6 +4425,7 @@ wait_block_or_sig(int *status) | |||
4115 | 4425 | ||
4116 | return pid; | 4426 | return pid; |
4117 | } | 4427 | } |
4428 | #endif | ||
4118 | 4429 | ||
4119 | #define DOWAIT_NONBLOCK 0 | 4430 | #define DOWAIT_NONBLOCK 0 |
4120 | #define DOWAIT_BLOCK 1 | 4431 | #define DOWAIT_BLOCK 1 |
@@ -4183,6 +4494,11 @@ dowait(int block, struct job *job) | |||
4183 | jobno(jp), pid, ps->ps_status, status)); | 4494 | jobno(jp), pid, ps->ps_status, status)); |
4184 | ps->ps_status = status; | 4495 | ps->ps_status = status; |
4185 | thisjob = jp; | 4496 | thisjob = jp; |
4497 | #if ENABLE_PLATFORM_MINGW32 | ||
4498 | ps->ps_pid = -1; | ||
4499 | CloseHandle(ps->ps_proc); | ||
4500 | ps->ps_proc = NULL; | ||
4501 | #endif | ||
4186 | } | 4502 | } |
4187 | if (ps->ps_status == -1) | 4503 | if (ps->ps_status == -1) |
4188 | jobstate = JOBRUNNING; | 4504 | jobstate = JOBRUNNING; |
@@ -4865,6 +5181,7 @@ commandtext(union node *n) | |||
4865 | * | 5181 | * |
4866 | * Called with interrupts off. | 5182 | * Called with interrupts off. |
4867 | */ | 5183 | */ |
5184 | #if !ENABLE_PLATFORM_MINGW32 | ||
4868 | /* | 5185 | /* |
4869 | * Clear traps on a fork. | 5186 | * Clear traps on a fork. |
4870 | */ | 5187 | */ |
@@ -5014,16 +5331,24 @@ forkchild(struct job *jp, union node *n, int mode) | |||
5014 | freejob(jp); | 5331 | freejob(jp); |
5015 | jobless = 0; | 5332 | jobless = 0; |
5016 | } | 5333 | } |
5334 | #endif | ||
5017 | 5335 | ||
5018 | /* Called after fork(), in parent */ | 5336 | /* Called after fork(), in parent */ |
5019 | #if !JOBS | 5337 | #if !JOBS |
5020 | #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) | 5338 | #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) |
5021 | #endif | 5339 | #endif |
5022 | static void | 5340 | static void |
5341 | #if !ENABLE_PLATFORM_MINGW32 | ||
5023 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 5342 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
5343 | #else | ||
5344 | forkparent(struct job *jp, union node *n, int mode, HANDLE proc) | ||
5345 | #endif | ||
5024 | { | 5346 | { |
5347 | #if ENABLE_PLATFORM_MINGW32 | ||
5348 | pid_t pid = GetProcessId(proc); | ||
5349 | #endif | ||
5025 | TRACE(("In parent shell: child = %d\n", pid)); | 5350 | TRACE(("In parent shell: child = %d\n", pid)); |
5026 | if (!jp) { | 5351 | if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */ |
5027 | /* jp is NULL when called by openhere() for heredoc support */ | 5352 | /* jp is NULL when called by openhere() for heredoc support */ |
5028 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) | 5353 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) |
5029 | continue; | 5354 | continue; |
@@ -5049,6 +5374,9 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) | |||
5049 | if (jp) { | 5374 | if (jp) { |
5050 | struct procstat *ps = &jp->ps[jp->nprocs++]; | 5375 | struct procstat *ps = &jp->ps[jp->nprocs++]; |
5051 | ps->ps_pid = pid; | 5376 | ps->ps_pid = pid; |
5377 | #if ENABLE_PLATFORM_MINGW32 | ||
5378 | ps->ps_proc = proc; | ||
5379 | #endif | ||
5052 | ps->ps_status = -1; | 5380 | ps->ps_status = -1; |
5053 | ps->ps_cmd = nullstr; | 5381 | ps->ps_cmd = nullstr; |
5054 | #if JOBS | 5382 | #if JOBS |
@@ -5058,6 +5386,7 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) | |||
5058 | } | 5386 | } |
5059 | } | 5387 | } |
5060 | 5388 | ||
5389 | #if !ENABLE_PLATFORM_MINGW32 | ||
5061 | /* jp and n are NULL when called by openhere() for heredoc support */ | 5390 | /* jp and n are NULL when called by openhere() for heredoc support */ |
5062 | static int | 5391 | static int |
5063 | forkshell(struct job *jp, union node *n, int mode) | 5392 | forkshell(struct job *jp, union node *n, int mode) |
@@ -5080,6 +5409,7 @@ forkshell(struct job *jp, union node *n, int mode) | |||
5080 | } | 5409 | } |
5081 | return pid; | 5410 | return pid; |
5082 | } | 5411 | } |
5412 | #endif | ||
5083 | 5413 | ||
5084 | /* | 5414 | /* |
5085 | * Wait for job to finish. | 5415 | * Wait for job to finish. |
@@ -5211,6 +5541,7 @@ openhere(union node *redir) | |||
5211 | { | 5541 | { |
5212 | int pip[2]; | 5542 | int pip[2]; |
5213 | size_t len = 0; | 5543 | size_t len = 0; |
5544 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5214 | 5545 | ||
5215 | if (pipe(pip) < 0) | 5546 | if (pipe(pip) < 0) |
5216 | ash_msg_and_raise_error("pipe call failed"); | 5547 | ash_msg_and_raise_error("pipe call failed"); |
@@ -5221,6 +5552,15 @@ openhere(union node *redir) | |||
5221 | goto out; | 5552 | goto out; |
5222 | } | 5553 | } |
5223 | } | 5554 | } |
5555 | #if ENABLE_PLATFORM_MINGW32 | ||
5556 | memset(&fs, 0, sizeof(fs)); | ||
5557 | fs.fpid = FS_OPENHERE; | ||
5558 | fs.n = redir; | ||
5559 | fs.fd[0] = pip[0]; | ||
5560 | fs.fd[1] = pip[1]; | ||
5561 | if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0) | ||
5562 | ash_msg_and_raise_error("unable to spawn shell"); | ||
5563 | #else | ||
5224 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | 5564 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { |
5225 | /* child */ | 5565 | /* child */ |
5226 | close(pip[0]); | 5566 | close(pip[0]); |
@@ -5235,6 +5575,7 @@ openhere(union node *redir) | |||
5235 | expandhere(redir->nhere.doc, pip[1]); | 5575 | expandhere(redir->nhere.doc, pip[1]); |
5236 | _exit(EXIT_SUCCESS); | 5576 | _exit(EXIT_SUCCESS); |
5237 | } | 5577 | } |
5578 | #endif | ||
5238 | out: | 5579 | out: |
5239 | close(pip[1]); | 5580 | close(pip[1]); |
5240 | return pip[0]; | 5581 | return pip[0]; |
@@ -5261,6 +5602,31 @@ openredirect(union node *redir) | |||
5261 | * allocated space. Do it only when we know it is safe. | 5602 | * allocated space. Do it only when we know it is safe. |
5262 | */ | 5603 | */ |
5263 | fname = redir->nfile.expfname; | 5604 | fname = redir->nfile.expfname; |
5605 | #if ENABLE_PLATFORM_MINGW32 | ||
5606 | /* Support for /dev/null */ | ||
5607 | switch (redir->nfile.type) { | ||
5608 | case NFROM: | ||
5609 | if (!strcmp(fname, "/dev/null")) | ||
5610 | return open("nul",O_RDWR); | ||
5611 | if (!strncmp(fname, "/dev/", 5)) { | ||
5612 | ash_msg("Unhandled device %s\n", fname); | ||
5613 | return -1; | ||
5614 | } | ||
5615 | break; | ||
5616 | |||
5617 | case NFROMTO: | ||
5618 | case NTO: | ||
5619 | case NCLOBBER: | ||
5620 | case NAPPEND: | ||
5621 | if (!strcmp(fname, "/dev/null")) | ||
5622 | return open("nul",O_RDWR); | ||
5623 | if (!strncmp(fname, "/dev/", 5)) { | ||
5624 | ash_msg("Unhandled device %s\n", fname); | ||
5625 | return -1; | ||
5626 | } | ||
5627 | break; | ||
5628 | } | ||
5629 | #endif | ||
5264 | 5630 | ||
5265 | switch (redir->nfile.type) { | 5631 | switch (redir->nfile.type) { |
5266 | default: | 5632 | default: |
@@ -5312,6 +5678,9 @@ openredirect(union node *redir) | |||
5312 | f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); | 5678 | f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); |
5313 | if (f < 0) | 5679 | if (f < 0) |
5314 | goto ecreate; | 5680 | goto ecreate; |
5681 | #if ENABLE_PLATFORM_MINGW32 | ||
5682 | lseek(f, 0, SEEK_END); | ||
5683 | #endif | ||
5315 | break; | 5684 | break; |
5316 | } | 5685 | } |
5317 | 5686 | ||
@@ -6240,6 +6609,7 @@ struct backcmd { /* result of evalbackcmd */ | |||
6240 | int fd; /* file descriptor to read from */ | 6609 | int fd; /* file descriptor to read from */ |
6241 | int nleft; /* number of chars in buffer */ | 6610 | int nleft; /* number of chars in buffer */ |
6242 | char *buf; /* buffer */ | 6611 | char *buf; /* buffer */ |
6612 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
6243 | struct job *jp; /* job structure for command */ | 6613 | struct job *jp; /* job structure for command */ |
6244 | }; | 6614 | }; |
6245 | 6615 | ||
@@ -6271,6 +6641,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
6271 | result->fd = -1; | 6641 | result->fd = -1; |
6272 | result->buf = NULL; | 6642 | result->buf = NULL; |
6273 | result->nleft = 0; | 6643 | result->nleft = 0; |
6644 | IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs))); | ||
6274 | result->jp = NULL; | 6645 | result->jp = NULL; |
6275 | if (n == NULL) { | 6646 | if (n == NULL) { |
6276 | goto out; | 6647 | goto out; |
@@ -6279,6 +6650,14 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
6279 | if (pipe(pip) < 0) | 6650 | if (pipe(pip) < 0) |
6280 | ash_msg_and_raise_error("pipe call failed"); | 6651 | ash_msg_and_raise_error("pipe call failed"); |
6281 | jp = makejob(/*n,*/ 1); | 6652 | jp = makejob(/*n,*/ 1); |
6653 | #if ENABLE_PLATFORM_MINGW32 | ||
6654 | result->fs.fpid = FS_EVALBACKCMD; | ||
6655 | result->fs.n = n; | ||
6656 | result->fs.fd[0] = pip[0]; | ||
6657 | result->fs.fd[1] = pip[1]; | ||
6658 | if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0) | ||
6659 | ash_msg_and_raise_error("unable to spawn shell"); | ||
6660 | #else | ||
6282 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 6661 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
6283 | /* child */ | 6662 | /* child */ |
6284 | FORCE_INT_ON; | 6663 | FORCE_INT_ON; |
@@ -6301,6 +6680,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
6301 | evaltreenr(n, EV_EXIT); | 6680 | evaltreenr(n, EV_EXIT); |
6302 | /* NOTREACHED */ | 6681 | /* NOTREACHED */ |
6303 | } | 6682 | } |
6683 | #endif | ||
6304 | /* parent */ | 6684 | /* parent */ |
6305 | close(pip[1]); | 6685 | close(pip[1]); |
6306 | result->fd = pip[0]; | 6686 | result->fd = pip[0]; |
@@ -6357,7 +6737,8 @@ expbackq(union node *cmd, int flag) | |||
6357 | 6737 | ||
6358 | /* Eat all trailing newlines */ | 6738 | /* Eat all trailing newlines */ |
6359 | dest = expdest; | 6739 | dest = expdest; |
6360 | for (; dest > (char *)stackblock() && dest[-1] == '\n';) | 6740 | for (; dest > (char *)stackblock() && (dest[-1] == '\n' || |
6741 | (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));) | ||
6361 | STUNPUTC(dest); | 6742 | STUNPUTC(dest); |
6362 | expdest = dest; | 6743 | expdest = dest; |
6363 | 6744 | ||
@@ -7856,7 +8237,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
7856 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ | 8237 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ |
7857 | 8238 | ||
7858 | envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); | 8239 | envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); |
7859 | if (strchr(prog, '/') != NULL | 8240 | if ((strchr(prog, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(prog, '\\'))) |
7860 | #if ENABLE_FEATURE_SH_STANDALONE | 8241 | #if ENABLE_FEATURE_SH_STANDALONE |
7861 | || (applet_no = find_applet_by_name(prog)) >= 0 | 8242 | || (applet_no = find_applet_by_name(prog)) >= 0 |
7862 | #endif | 8243 | #endif |
@@ -8440,10 +8821,14 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
8440 | #endif | 8821 | #endif |
8441 | 8822 | ||
8442 | 8823 | ||
8443 | /*static int funcblocksize; // size of structures in function */ | 8824 | static int funcblocksize; /* size of structures in function */ |
8444 | /*static int funcstringsize; // size of strings in node */ | 8825 | static int funcstringsize; /* size of strings in node */ |
8445 | static void *funcblock; /* block to allocate function from */ | 8826 | static void *funcblock; /* block to allocate function from */ |
8446 | static char *funcstring_end; /* end of block to allocate strings from */ | 8827 | static char *funcstring; /* block to allocate strings from */ |
8828 | #if ENABLE_PLATFORM_MINGW32 | ||
8829 | static int nodeptrsize; | ||
8830 | static char **nodeptr; | ||
8831 | #endif | ||
8447 | 8832 | ||
8448 | static const uint8_t nodesize[N_NUMBER] ALIGN1 = { | 8833 | static const uint8_t nodesize[N_NUMBER] ALIGN1 = { |
8449 | [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), | 8834 | [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), |
@@ -8477,72 +8862,81 @@ static const uint8_t nodesize[N_NUMBER] ALIGN1 = { | |||
8477 | [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)), | 8862 | [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)), |
8478 | }; | 8863 | }; |
8479 | 8864 | ||
8480 | static int calcsize(int funcblocksize, union node *n); | 8865 | static void calcsize(union node *n); |
8481 | 8866 | ||
8482 | static int | 8867 | static void |
8483 | sizenodelist(int funcblocksize, struct nodelist *lp) | 8868 | sizenodelist(struct nodelist *lp) |
8484 | { | 8869 | { |
8485 | while (lp) { | 8870 | while (lp) { |
8486 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); | 8871 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); |
8487 | funcblocksize = calcsize(funcblocksize, lp->n); | 8872 | IF_PLATFORM_MINGW32(nodeptrsize += 2); |
8873 | calcsize(lp->n); | ||
8488 | lp = lp->next; | 8874 | lp = lp->next; |
8489 | } | 8875 | } |
8490 | return funcblocksize; | ||
8491 | } | 8876 | } |
8492 | 8877 | ||
8493 | static int | 8878 | static void |
8494 | calcsize(int funcblocksize, union node *n) | 8879 | calcsize(union node *n) |
8495 | { | 8880 | { |
8496 | if (n == NULL) | 8881 | if (n == NULL) |
8497 | return funcblocksize; | 8882 | return; |
8498 | funcblocksize += nodesize[n->type]; | 8883 | funcblocksize += nodesize[n->type]; |
8499 | switch (n->type) { | 8884 | switch (n->type) { |
8500 | case NCMD: | 8885 | case NCMD: |
8501 | funcblocksize = calcsize(funcblocksize, n->ncmd.redirect); | 8886 | calcsize(n->ncmd.redirect); |
8502 | funcblocksize = calcsize(funcblocksize, n->ncmd.args); | 8887 | calcsize(n->ncmd.args); |
8503 | funcblocksize = calcsize(funcblocksize, n->ncmd.assign); | 8888 | calcsize(n->ncmd.assign); |
8889 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8504 | break; | 8890 | break; |
8505 | case NPIPE: | 8891 | case NPIPE: |
8506 | funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist); | 8892 | sizenodelist(n->npipe.cmdlist); |
8893 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
8507 | break; | 8894 | break; |
8508 | case NREDIR: | 8895 | case NREDIR: |
8509 | case NBACKGND: | 8896 | case NBACKGND: |
8510 | case NSUBSHELL: | 8897 | case NSUBSHELL: |
8511 | funcblocksize = calcsize(funcblocksize, n->nredir.redirect); | 8898 | calcsize(n->nredir.redirect); |
8512 | funcblocksize = calcsize(funcblocksize, n->nredir.n); | 8899 | calcsize(n->nredir.n); |
8900 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8513 | break; | 8901 | break; |
8514 | case NAND: | 8902 | case NAND: |
8515 | case NOR: | 8903 | case NOR: |
8516 | case NSEMI: | 8904 | case NSEMI: |
8517 | case NWHILE: | 8905 | case NWHILE: |
8518 | case NUNTIL: | 8906 | case NUNTIL: |
8519 | funcblocksize = calcsize(funcblocksize, n->nbinary.ch2); | 8907 | calcsize(n->nbinary.ch2); |
8520 | funcblocksize = calcsize(funcblocksize, n->nbinary.ch1); | 8908 | calcsize(n->nbinary.ch1); |
8909 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8521 | break; | 8910 | break; |
8522 | case NIF: | 8911 | case NIF: |
8523 | funcblocksize = calcsize(funcblocksize, n->nif.elsepart); | 8912 | calcsize(n->nif.elsepart); |
8524 | funcblocksize = calcsize(funcblocksize, n->nif.ifpart); | 8913 | calcsize(n->nif.ifpart); |
8525 | funcblocksize = calcsize(funcblocksize, n->nif.test); | 8914 | calcsize(n->nif.test); |
8915 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8526 | break; | 8916 | break; |
8527 | case NFOR: | 8917 | case NFOR: |
8528 | funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */ | 8918 | funcstringsize += strlen(n->nfor.var) + 1; |
8529 | funcblocksize = calcsize(funcblocksize, n->nfor.body); | 8919 | calcsize(n->nfor.body); |
8530 | funcblocksize = calcsize(funcblocksize, n->nfor.args); | 8920 | calcsize(n->nfor.args); |
8921 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8531 | break; | 8922 | break; |
8532 | case NCASE: | 8923 | case NCASE: |
8533 | funcblocksize = calcsize(funcblocksize, n->ncase.cases); | 8924 | calcsize(n->ncase.cases); |
8534 | funcblocksize = calcsize(funcblocksize, n->ncase.expr); | 8925 | calcsize(n->ncase.expr); |
8926 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8535 | break; | 8927 | break; |
8536 | case NCLIST: | 8928 | case NCLIST: |
8537 | funcblocksize = calcsize(funcblocksize, n->nclist.body); | 8929 | calcsize(n->nclist.body); |
8538 | funcblocksize = calcsize(funcblocksize, n->nclist.pattern); | 8930 | calcsize(n->nclist.pattern); |
8539 | funcblocksize = calcsize(funcblocksize, n->nclist.next); | 8931 | calcsize(n->nclist.next); |
8932 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8540 | break; | 8933 | break; |
8541 | case NDEFUN: | 8934 | case NDEFUN: |
8542 | case NARG: | 8935 | case NARG: |
8543 | funcblocksize = sizenodelist(funcblocksize, n->narg.backquote); | 8936 | sizenodelist(n->narg.backquote); |
8544 | funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */ | 8937 | funcstringsize += strlen(n->narg.text) + 1; |
8545 | funcblocksize = calcsize(funcblocksize, n->narg.next); | 8938 | calcsize(n->narg.next); |
8939 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8546 | break; | 8940 | break; |
8547 | case NTO: | 8941 | case NTO: |
8548 | #if BASH_REDIR_OUTPUT | 8942 | #if BASH_REDIR_OUTPUT |
@@ -8552,35 +8946,55 @@ calcsize(int funcblocksize, union node *n) | |||
8552 | case NFROM: | 8946 | case NFROM: |
8553 | case NFROMTO: | 8947 | case NFROMTO: |
8554 | case NAPPEND: | 8948 | case NAPPEND: |
8555 | funcblocksize = calcsize(funcblocksize, n->nfile.fname); | 8949 | calcsize(n->nfile.fname); |
8556 | funcblocksize = calcsize(funcblocksize, n->nfile.next); | 8950 | calcsize(n->nfile.next); |
8951 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8557 | break; | 8952 | break; |
8558 | case NTOFD: | 8953 | case NTOFD: |
8559 | case NFROMFD: | 8954 | case NFROMFD: |
8560 | funcblocksize = calcsize(funcblocksize, n->ndup.vname); | 8955 | calcsize(n->ndup.vname); |
8561 | funcblocksize = calcsize(funcblocksize, n->ndup.next); | 8956 | calcsize(n->ndup.next); |
8957 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8562 | break; | 8958 | break; |
8563 | case NHERE: | 8959 | case NHERE: |
8564 | case NXHERE: | 8960 | case NXHERE: |
8565 | funcblocksize = calcsize(funcblocksize, n->nhere.doc); | 8961 | calcsize(n->nhere.doc); |
8566 | funcblocksize = calcsize(funcblocksize, n->nhere.next); | 8962 | calcsize(n->nhere.next); |
8963 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8567 | break; | 8964 | break; |
8568 | case NNOT: | 8965 | case NNOT: |
8569 | funcblocksize = calcsize(funcblocksize, n->nnot.com); | 8966 | calcsize(n->nnot.com); |
8967 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
8570 | break; | 8968 | break; |
8571 | }; | 8969 | }; |
8572 | return funcblocksize; | ||
8573 | } | 8970 | } |
8574 | 8971 | ||
8575 | static char * | 8972 | static char * |
8576 | nodeckstrdup(char *s) | 8973 | nodeckstrdup(const char *s) |
8577 | { | 8974 | { |
8578 | funcstring_end -= SHELL_ALIGN(strlen(s) + 1); | 8975 | char *rtn = funcstring; |
8579 | return strcpy(funcstring_end, s); | 8976 | |
8977 | if (!s) | ||
8978 | return NULL; | ||
8979 | strcpy(funcstring, s); | ||
8980 | funcstring += strlen(s) + 1; | ||
8981 | return rtn; | ||
8580 | } | 8982 | } |
8581 | 8983 | ||
8582 | static union node *copynode(union node *); | 8984 | static union node *copynode(union node *); |
8583 | 8985 | ||
8986 | #if ENABLE_PLATFORM_MINGW32 | ||
8987 | # define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (char *)&(dst);} | ||
8988 | # define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);}} | ||
8989 | # define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);}} | ||
8990 | # define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);*nodeptr++ = (char *)&(dst4);}} | ||
8991 | #else | ||
8992 | # define SAVE_PTR(dst) | ||
8993 | # define SAVE_PTR2(dst,dst2) | ||
8994 | # define SAVE_PTR3(dst,dst2,dst3) | ||
8995 | # define SAVE_PTR4(dst,dst2,dst3,dst4) | ||
8996 | #endif | ||
8997 | |||
8584 | static struct nodelist * | 8998 | static struct nodelist * |
8585 | copynodelist(struct nodelist *lp) | 8999 | copynodelist(struct nodelist *lp) |
8586 | { | 9000 | { |
@@ -8592,6 +9006,7 @@ copynodelist(struct nodelist *lp) | |||
8592 | *lpp = funcblock; | 9006 | *lpp = funcblock; |
8593 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); | 9007 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); |
8594 | (*lpp)->n = copynode(lp->n); | 9008 | (*lpp)->n = copynode(lp->n); |
9009 | SAVE_PTR2((*lpp)->n, (*lpp)->next); | ||
8595 | lp = lp->next; | 9010 | lp = lp->next; |
8596 | lpp = &(*lpp)->next; | 9011 | lpp = &(*lpp)->next; |
8597 | } | 9012 | } |
@@ -8614,16 +9029,19 @@ copynode(union node *n) | |||
8614 | new->ncmd.redirect = copynode(n->ncmd.redirect); | 9029 | new->ncmd.redirect = copynode(n->ncmd.redirect); |
8615 | new->ncmd.args = copynode(n->ncmd.args); | 9030 | new->ncmd.args = copynode(n->ncmd.args); |
8616 | new->ncmd.assign = copynode(n->ncmd.assign); | 9031 | new->ncmd.assign = copynode(n->ncmd.assign); |
9032 | SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign); | ||
8617 | break; | 9033 | break; |
8618 | case NPIPE: | 9034 | case NPIPE: |
8619 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | 9035 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); |
8620 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; | 9036 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; |
9037 | SAVE_PTR(new->npipe.cmdlist); | ||
8621 | break; | 9038 | break; |
8622 | case NREDIR: | 9039 | case NREDIR: |
8623 | case NBACKGND: | 9040 | case NBACKGND: |
8624 | case NSUBSHELL: | 9041 | case NSUBSHELL: |
8625 | new->nredir.redirect = copynode(n->nredir.redirect); | 9042 | new->nredir.redirect = copynode(n->nredir.redirect); |
8626 | new->nredir.n = copynode(n->nredir.n); | 9043 | new->nredir.n = copynode(n->nredir.n); |
9044 | SAVE_PTR2(new->nredir.redirect,new->nredir.n); | ||
8627 | break; | 9045 | break; |
8628 | case NAND: | 9046 | case NAND: |
8629 | case NOR: | 9047 | case NOR: |
@@ -8632,31 +9050,37 @@ copynode(union node *n) | |||
8632 | case NUNTIL: | 9050 | case NUNTIL: |
8633 | new->nbinary.ch2 = copynode(n->nbinary.ch2); | 9051 | new->nbinary.ch2 = copynode(n->nbinary.ch2); |
8634 | new->nbinary.ch1 = copynode(n->nbinary.ch1); | 9052 | new->nbinary.ch1 = copynode(n->nbinary.ch1); |
9053 | SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2); | ||
8635 | break; | 9054 | break; |
8636 | case NIF: | 9055 | case NIF: |
8637 | new->nif.elsepart = copynode(n->nif.elsepart); | 9056 | new->nif.elsepart = copynode(n->nif.elsepart); |
8638 | new->nif.ifpart = copynode(n->nif.ifpart); | 9057 | new->nif.ifpart = copynode(n->nif.ifpart); |
8639 | new->nif.test = copynode(n->nif.test); | 9058 | new->nif.test = copynode(n->nif.test); |
9059 | SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test); | ||
8640 | break; | 9060 | break; |
8641 | case NFOR: | 9061 | case NFOR: |
8642 | new->nfor.var = nodeckstrdup(n->nfor.var); | 9062 | new->nfor.var = nodeckstrdup(n->nfor.var); |
8643 | new->nfor.body = copynode(n->nfor.body); | 9063 | new->nfor.body = copynode(n->nfor.body); |
8644 | new->nfor.args = copynode(n->nfor.args); | 9064 | new->nfor.args = copynode(n->nfor.args); |
9065 | SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args); | ||
8645 | break; | 9066 | break; |
8646 | case NCASE: | 9067 | case NCASE: |
8647 | new->ncase.cases = copynode(n->ncase.cases); | 9068 | new->ncase.cases = copynode(n->ncase.cases); |
8648 | new->ncase.expr = copynode(n->ncase.expr); | 9069 | new->ncase.expr = copynode(n->ncase.expr); |
9070 | SAVE_PTR2(new->ncase.cases,new->ncase.expr); | ||
8649 | break; | 9071 | break; |
8650 | case NCLIST: | 9072 | case NCLIST: |
8651 | new->nclist.body = copynode(n->nclist.body); | 9073 | new->nclist.body = copynode(n->nclist.body); |
8652 | new->nclist.pattern = copynode(n->nclist.pattern); | 9074 | new->nclist.pattern = copynode(n->nclist.pattern); |
8653 | new->nclist.next = copynode(n->nclist.next); | 9075 | new->nclist.next = copynode(n->nclist.next); |
9076 | SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next); | ||
8654 | break; | 9077 | break; |
8655 | case NDEFUN: | 9078 | case NDEFUN: |
8656 | case NARG: | 9079 | case NARG: |
8657 | new->narg.backquote = copynodelist(n->narg.backquote); | 9080 | new->narg.backquote = copynodelist(n->narg.backquote); |
8658 | new->narg.text = nodeckstrdup(n->narg.text); | 9081 | new->narg.text = nodeckstrdup(n->narg.text); |
8659 | new->narg.next = copynode(n->narg.next); | 9082 | new->narg.next = copynode(n->narg.next); |
9083 | SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next); | ||
8660 | break; | 9084 | break; |
8661 | case NTO: | 9085 | case NTO: |
8662 | #if BASH_REDIR_OUTPUT | 9086 | #if BASH_REDIR_OUTPUT |
@@ -8669,6 +9093,7 @@ copynode(union node *n) | |||
8669 | new->nfile.fname = copynode(n->nfile.fname); | 9093 | new->nfile.fname = copynode(n->nfile.fname); |
8670 | new->nfile.fd = n->nfile.fd; | 9094 | new->nfile.fd = n->nfile.fd; |
8671 | new->nfile.next = copynode(n->nfile.next); | 9095 | new->nfile.next = copynode(n->nfile.next); |
9096 | SAVE_PTR2(new->nfile.fname,new->nfile.next); | ||
8672 | break; | 9097 | break; |
8673 | case NTOFD: | 9098 | case NTOFD: |
8674 | case NFROMFD: | 9099 | case NFROMFD: |
@@ -8676,15 +9101,18 @@ copynode(union node *n) | |||
8676 | new->ndup.dupfd = n->ndup.dupfd; | 9101 | new->ndup.dupfd = n->ndup.dupfd; |
8677 | new->ndup.fd = n->ndup.fd; | 9102 | new->ndup.fd = n->ndup.fd; |
8678 | new->ndup.next = copynode(n->ndup.next); | 9103 | new->ndup.next = copynode(n->ndup.next); |
9104 | SAVE_PTR2(new->ndup.vname,new->ndup.next); | ||
8679 | break; | 9105 | break; |
8680 | case NHERE: | 9106 | case NHERE: |
8681 | case NXHERE: | 9107 | case NXHERE: |
8682 | new->nhere.doc = copynode(n->nhere.doc); | 9108 | new->nhere.doc = copynode(n->nhere.doc); |
8683 | new->nhere.fd = n->nhere.fd; | 9109 | new->nhere.fd = n->nhere.fd; |
8684 | new->nhere.next = copynode(n->nhere.next); | 9110 | new->nhere.next = copynode(n->nhere.next); |
9111 | SAVE_PTR2(new->nhere.doc,new->nhere.next); | ||
8685 | break; | 9112 | break; |
8686 | case NNOT: | 9113 | case NNOT: |
8687 | new->nnot.com = copynode(n->nnot.com); | 9114 | new->nnot.com = copynode(n->nnot.com); |
9115 | SAVE_PTR(new->nnot.com); | ||
8688 | break; | 9116 | break; |
8689 | }; | 9117 | }; |
8690 | new->type = n->type; | 9118 | new->type = n->type; |
@@ -8700,13 +9128,16 @@ copyfunc(union node *n) | |||
8700 | struct funcnode *f; | 9128 | struct funcnode *f; |
8701 | size_t blocksize; | 9129 | size_t blocksize; |
8702 | 9130 | ||
8703 | /*funcstringsize = 0;*/ | 9131 | funcblocksize = offsetof(struct funcnode, n); |
8704 | blocksize = offsetof(struct funcnode, n) + calcsize(0, n); | 9132 | funcstringsize = 0; |
8705 | f = ckzalloc(blocksize /* + funcstringsize */); | 9133 | calcsize(n); |
9134 | blocksize = funcblocksize; | ||
9135 | f = ckmalloc(blocksize + funcstringsize); | ||
8706 | funcblock = (char *) f + offsetof(struct funcnode, n); | 9136 | funcblock = (char *) f + offsetof(struct funcnode, n); |
8707 | funcstring_end = (char *) f + blocksize; | 9137 | funcstring = (char *) f + blocksize; |
9138 | IF_PLATFORM_MINGW32(nodeptr = NULL); | ||
8708 | copynode(n); | 9139 | copynode(n); |
8709 | /* f->count = 0; - ckzalloc did it */ | 9140 | f->count = 0; |
8710 | return f; | 9141 | return f; |
8711 | } | 9142 | } |
8712 | 9143 | ||
@@ -9042,6 +9473,7 @@ evalcase(union node *n, int flags) | |||
9042 | static int | 9473 | static int |
9043 | evalsubshell(union node *n, int flags) | 9474 | evalsubshell(union node *n, int flags) |
9044 | { | 9475 | { |
9476 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
9045 | struct job *jp; | 9477 | struct job *jp; |
9046 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ | 9478 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ |
9047 | int status; | 9479 | int status; |
@@ -9053,12 +9485,22 @@ evalsubshell(union node *n, int flags) | |||
9053 | if (backgnd == FORK_FG) | 9485 | if (backgnd == FORK_FG) |
9054 | get_tty_state(); | 9486 | get_tty_state(); |
9055 | jp = makejob(/*n,*/ 1); | 9487 | jp = makejob(/*n,*/ 1); |
9488 | #if ENABLE_PLATFORM_MINGW32 | ||
9489 | memset(&fs, 0, sizeof(fs)); | ||
9490 | fs.fpid = FS_EVALSUBSHELL; | ||
9491 | fs.n = n; | ||
9492 | fs.flags = flags; | ||
9493 | if (spawn_forkshell(jp, &fs, backgnd) < 0) | ||
9494 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9495 | if ( 0 ) { | ||
9496 | #else | ||
9056 | if (forkshell(jp, n, backgnd) == 0) { | 9497 | if (forkshell(jp, n, backgnd) == 0) { |
9057 | /* child */ | 9498 | /* child */ |
9058 | INT_ON; | 9499 | INT_ON; |
9059 | flags |= EV_EXIT; | 9500 | flags |= EV_EXIT; |
9060 | if (backgnd) | 9501 | if (backgnd) |
9061 | flags &= ~EV_TESTED; | 9502 | flags &= ~EV_TESTED; |
9503 | #endif | ||
9062 | nofork: | 9504 | nofork: |
9063 | redirect(n->nredir.redirect, 0); | 9505 | redirect(n->nredir.redirect, 0); |
9064 | evaltreenr(n->nredir.n, flags); | 9506 | evaltreenr(n->nredir.n, flags); |
@@ -9145,6 +9587,7 @@ expredir(union node *n) | |||
9145 | static int | 9587 | static int |
9146 | evalpipe(union node *n, int flags) | 9588 | evalpipe(union node *n, int flags) |
9147 | { | 9589 | { |
9590 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
9148 | struct job *jp; | 9591 | struct job *jp; |
9149 | struct nodelist *lp; | 9592 | struct nodelist *lp; |
9150 | int pipelen; | 9593 | int pipelen; |
@@ -9171,6 +9614,17 @@ evalpipe(union node *n, int flags) | |||
9171 | ash_msg_and_raise_error("pipe call failed"); | 9614 | ash_msg_and_raise_error("pipe call failed"); |
9172 | } | 9615 | } |
9173 | } | 9616 | } |
9617 | #if ENABLE_PLATFORM_MINGW32 | ||
9618 | memset(&fs, 0, sizeof(fs)); | ||
9619 | fs.fpid = FS_EVALPIPE; | ||
9620 | fs.flags = flags; | ||
9621 | fs.n = lp->n; | ||
9622 | fs.fd[0] = pip[0]; | ||
9623 | fs.fd[1] = pip[1]; | ||
9624 | fs.fd[2] = prevfd; | ||
9625 | if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0) | ||
9626 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9627 | #else | ||
9174 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { | 9628 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { |
9175 | /* child */ | 9629 | /* child */ |
9176 | INT_ON; | 9630 | INT_ON; |
@@ -9188,6 +9642,7 @@ evalpipe(union node *n, int flags) | |||
9188 | evaltreenr(lp->n, flags); | 9642 | evaltreenr(lp->n, flags); |
9189 | /* never returns */ | 9643 | /* never returns */ |
9190 | } | 9644 | } |
9645 | #endif | ||
9191 | /* parent */ | 9646 | /* parent */ |
9192 | if (prevfd >= 0) | 9647 | if (prevfd >= 0) |
9193 | close(prevfd); | 9648 | close(prevfd); |
@@ -9717,6 +10172,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
9717 | * as POSIX mandates */ | 10172 | * as POSIX mandates */ |
9718 | return back_exitstatus; | 10173 | return back_exitstatus; |
9719 | } | 10174 | } |
10175 | |||
9720 | static int | 10176 | static int |
9721 | evalcommand(union node *cmd, int flags) | 10177 | evalcommand(union node *cmd, int flags) |
9722 | { | 10178 | { |
@@ -9915,7 +10371,15 @@ evalcommand(union node *cmd, int flags) | |||
9915 | */ | 10371 | */ |
9916 | /* find_command() encodes applet_no as (-2 - applet_no) */ | 10372 | /* find_command() encodes applet_no as (-2 - applet_no) */ |
9917 | int applet_no = (- cmdentry.u.index - 2); | 10373 | int applet_no = (- cmdentry.u.index - 2); |
9918 | if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { | 10374 | if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no) |
10375 | #if ENABLE_PLATFORM_MINGW32 | ||
10376 | /* | ||
10377 | * Fork long-running nofork applets (e.g. yes) in interactive | ||
10378 | * sessions. Otherwise ctrl-c won't let the user kill them. | ||
10379 | */ | ||
10380 | && !(iflag && long_running_applet(applet_no)) | ||
10381 | #endif | ||
10382 | ) { | ||
9919 | listsetvar(varlist.list, VEXPORT|VSTACK); | 10383 | listsetvar(varlist.list, VEXPORT|VSTACK); |
9920 | /* run <applet>_main() */ | 10384 | /* run <applet>_main() */ |
9921 | status = run_nofork_applet(applet_no, argv); | 10385 | status = run_nofork_applet(applet_no, argv); |
@@ -9926,6 +10390,28 @@ evalcommand(union node *cmd, int flags) | |||
9926 | * in a script or a subshell does not need forking, | 10390 | * in a script or a subshell does not need forking, |
9927 | * we can just exec it. | 10391 | * we can just exec it. |
9928 | */ | 10392 | */ |
10393 | #if ENABLE_PLATFORM_MINGW32 | ||
10394 | if (!(flags & EV_EXIT) || trap[0]) { | ||
10395 | /* No, forking off a child is necessary */ | ||
10396 | struct forkshell fs; | ||
10397 | |||
10398 | INT_OFF; | ||
10399 | memset(&fs, 0, sizeof(fs)); | ||
10400 | fs.fpid = FS_SHELLEXEC; | ||
10401 | fs.argv = argv; | ||
10402 | fs.string = (char*)path; | ||
10403 | fs.fd[0] = cmdentry.u.index; | ||
10404 | fs.strlist = varlist.list; | ||
10405 | jp = makejob(/*cmd,*/ 1); | ||
10406 | if (spawn_forkshell(jp, &fs, FORK_FG) < 0) | ||
10407 | ash_msg_and_raise_error("unable to spawn shell"); | ||
10408 | status = waitforjob(jp); | ||
10409 | INT_ON; | ||
10410 | TRACE(("forked child exited with %d\n", exitstatus)); | ||
10411 | break; | ||
10412 | } | ||
10413 | /* goes through to shellexec() */ | ||
10414 | #else | ||
9929 | if (!(flags & EV_EXIT) || may_have_traps) { | 10415 | if (!(flags & EV_EXIT) || may_have_traps) { |
9930 | /* No, forking off a child is necessary */ | 10416 | /* No, forking off a child is necessary */ |
9931 | INT_OFF; | 10417 | INT_OFF; |
@@ -9942,6 +10428,7 @@ evalcommand(union node *cmd, int flags) | |||
9942 | FORCE_INT_ON; | 10428 | FORCE_INT_ON; |
9943 | /* fall through to exec'ing external program */ | 10429 | /* fall through to exec'ing external program */ |
9944 | } | 10430 | } |
10431 | #endif | ||
9945 | listsetvar(varlist.list, VEXPORT|VSTACK); | 10432 | listsetvar(varlist.list, VEXPORT|VSTACK); |
9946 | shellexec(argv[0], argv, path, cmdentry.u.index); | 10433 | shellexec(argv[0], argv, path, cmdentry.u.index); |
9947 | /* NOTREACHED */ | 10434 | /* NOTREACHED */ |
@@ -10325,7 +10812,7 @@ preadbuffer(void) | |||
10325 | more--; | 10812 | more--; |
10326 | 10813 | ||
10327 | c = *q; | 10814 | c = *q; |
10328 | if (c == '\0') { | 10815 | if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) { |
10329 | memmove(q, q + 1, more); | 10816 | memmove(q, q + 1, more); |
10330 | } else { | 10817 | } else { |
10331 | q++; | 10818 | q++; |
@@ -10487,6 +10974,7 @@ popallfiles(void) | |||
10487 | popfile(); | 10974 | popfile(); |
10488 | } | 10975 | } |
10489 | 10976 | ||
10977 | #if !ENABLE_PLATFORM_MINGW32 | ||
10490 | /* | 10978 | /* |
10491 | * Close the file(s) that the shell is reading commands from. Called | 10979 | * Close the file(s) that the shell is reading commands from. Called |
10492 | * after a fork is done. | 10980 | * after a fork is done. |
@@ -10500,6 +10988,7 @@ closescript(void) | |||
10500 | g_parsefile->pf_fd = 0; | 10988 | g_parsefile->pf_fd = 0; |
10501 | } | 10989 | } |
10502 | } | 10990 | } |
10991 | #endif | ||
10503 | 10992 | ||
10504 | /* | 10993 | /* |
10505 | * Like setinputfile, but takes an open file descriptor. Call this with | 10994 | * Like setinputfile, but takes an open file descriptor. Call this with |
@@ -12786,7 +13275,7 @@ find_dot_file(char *name) | |||
12786 | struct stat statb; | 13275 | struct stat statb; |
12787 | 13276 | ||
12788 | /* don't try this for absolute or relative paths */ | 13277 | /* don't try this for absolute or relative paths */ |
12789 | if (strchr(name, '/')) | 13278 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) |
12790 | return name; | 13279 | return name; |
12791 | 13280 | ||
12792 | while ((fullname = path_advance(&path, name)) != NULL) { | 13281 | while ((fullname = path_advance(&path, name)) != NULL) { |
@@ -12897,17 +13386,22 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12897 | struct tblentry *cmdp; | 13386 | struct tblentry *cmdp; |
12898 | int idx; | 13387 | int idx; |
12899 | int prev; | 13388 | int prev; |
12900 | char *fullname; | 13389 | char *fullname IF_PLATFORM_MINGW32(= NULL); |
12901 | struct stat statb; | 13390 | struct stat statb; |
12902 | int e; | 13391 | int e; |
12903 | int updatetbl; | 13392 | int updatetbl; |
13393 | IF_PLATFORM_MINGW32(int len;) | ||
12904 | struct builtincmd *bcmd; | 13394 | struct builtincmd *bcmd; |
12905 | 13395 | ||
12906 | /* If name contains a slash, don't use PATH or hash table */ | 13396 | /* If name contains a slash, don't use PATH or hash table */ |
12907 | if (strchr(name, '/') != NULL) { | 13397 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) { |
12908 | entry->u.index = -1; | 13398 | entry->u.index = -1; |
12909 | if (act & DO_ABS) { | 13399 | if (act & DO_ABS) { |
12910 | while (stat(name, &statb) < 0) { | 13400 | while (stat(name, &statb) < 0 |
13401 | #if ENABLE_PLATFORM_MINGW32 | ||
13402 | && (fullname=file_is_win32_executable(name)) == NULL | ||
13403 | #endif | ||
13404 | ) { | ||
12911 | #ifdef SYSV | 13405 | #ifdef SYSV |
12912 | if (errno == EINTR) | 13406 | if (errno == EINTR) |
12913 | continue; | 13407 | continue; |
@@ -12915,6 +13409,9 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12915 | entry->cmdtype = CMDUNKNOWN; | 13409 | entry->cmdtype = CMDUNKNOWN; |
12916 | return; | 13410 | return; |
12917 | } | 13411 | } |
13412 | #if ENABLE_PLATFORM_MINGW32 | ||
13413 | free(fullname); | ||
13414 | #endif | ||
12918 | } | 13415 | } |
12919 | entry->cmdtype = CMDNORMAL; | 13416 | entry->cmdtype = CMDNORMAL; |
12920 | return; | 13417 | return; |
@@ -13011,12 +13508,48 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13011 | } | 13508 | } |
13012 | } | 13509 | } |
13013 | /* if rehash, don't redo absolute path names */ | 13510 | /* if rehash, don't redo absolute path names */ |
13014 | if (fullname[0] == '/' && idx <= prev) { | 13511 | if (is_absolute_path(fullname) && idx <= prev) { |
13015 | if (idx < prev) | 13512 | if (idx < prev) |
13016 | continue; | 13513 | continue; |
13017 | TRACE(("searchexec \"%s\": no change\n", name)); | 13514 | TRACE(("searchexec \"%s\": no change\n", name)); |
13018 | goto success; | 13515 | goto success; |
13019 | } | 13516 | } |
13517 | #if ENABLE_PLATFORM_MINGW32 | ||
13518 | len = strlen(fullname); | ||
13519 | if (len > 4 && | ||
13520 | (!strcasecmp(fullname+len-4, ".exe") || | ||
13521 | !strcasecmp(fullname+len-4, ".com"))) { | ||
13522 | if (stat(fullname, &statb) < 0) { | ||
13523 | if (errno != ENOENT && errno != ENOTDIR) | ||
13524 | e = errno; | ||
13525 | goto loop; | ||
13526 | } | ||
13527 | } | ||
13528 | else { | ||
13529 | /* path_advance() has reserved space for .exe */ | ||
13530 | memcpy(fullname+len, ".exe", 5); | ||
13531 | if (stat(fullname, &statb) < 0) { | ||
13532 | if (errno != ENOENT && errno != ENOTDIR) | ||
13533 | e = errno; | ||
13534 | memcpy(fullname+len, ".com", 5); | ||
13535 | if (stat(fullname, &statb) < 0) { | ||
13536 | if (errno != ENOENT && errno != ENOTDIR) | ||
13537 | e = errno; | ||
13538 | fullname[len] = '\0'; | ||
13539 | if (stat(fullname, &statb) < 0) { | ||
13540 | if (errno != ENOENT && errno != ENOTDIR) | ||
13541 | e = errno; | ||
13542 | goto loop; | ||
13543 | } | ||
13544 | if (!file_is_executable(fullname)) { | ||
13545 | e = ENOEXEC; | ||
13546 | goto loop; | ||
13547 | } | ||
13548 | } | ||
13549 | } | ||
13550 | fullname[len] = '\0'; | ||
13551 | } | ||
13552 | #else | ||
13020 | while (stat(fullname, &statb) < 0) { | 13553 | while (stat(fullname, &statb) < 0) { |
13021 | #ifdef SYSV | 13554 | #ifdef SYSV |
13022 | if (errno == EINTR) | 13555 | if (errno == EINTR) |
@@ -13026,6 +13559,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13026 | e = errno; | 13559 | e = errno; |
13027 | goto loop; | 13560 | goto loop; |
13028 | } | 13561 | } |
13562 | #endif | ||
13029 | e = EACCES; /* if we fail, this will be the error */ | 13563 | e = EACCES; /* if we fail, this will be the error */ |
13030 | if (!S_ISREG(statb.st_mode)) | 13564 | if (!S_ISREG(statb.st_mode)) |
13031 | continue; | 13565 | continue; |
@@ -13542,7 +14076,11 @@ exitshell(void) | |||
13542 | } | 14076 | } |
13543 | 14077 | ||
13544 | static void | 14078 | static void |
14079 | #if ENABLE_PLATFORM_MINGW32 | ||
14080 | init(int xp) | ||
14081 | #else | ||
13545 | init(void) | 14082 | init(void) |
14083 | #endif | ||
13546 | { | 14084 | { |
13547 | /* we will never free this */ | 14085 | /* we will never free this */ |
13548 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); | 14086 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); |
@@ -13561,6 +14099,86 @@ init(void) | |||
13561 | struct stat st1, st2; | 14099 | struct stat st1, st2; |
13562 | 14100 | ||
13563 | initvar(); | 14101 | initvar(); |
14102 | |||
14103 | #if ENABLE_PLATFORM_MINGW32 | ||
14104 | /* | ||
14105 | * case insensitive env names from Windows world | ||
14106 | * | ||
14107 | * Some standard env names such as PATH is named Path and so on | ||
14108 | * ash itself is case sensitive, so "Path" will confuse it, as | ||
14109 | * MSVC getenv() is case insensitive. | ||
14110 | * | ||
14111 | * We may end up having both Path and PATH. Then Path will be chosen | ||
14112 | * because it appears first. | ||
14113 | */ | ||
14114 | for (envp = environ; envp && *envp; envp++) { | ||
14115 | if (strncasecmp(*envp, "PATH=", 5) == 0 && | ||
14116 | strncmp(*envp, "PATH=", 5) != 0) { | ||
14117 | break; | ||
14118 | } | ||
14119 | } | ||
14120 | |||
14121 | if (envp && *envp) { | ||
14122 | /* | ||
14123 | * If we get here it's because the environment contains a path | ||
14124 | * variable called something other than PATH. This suggests we | ||
14125 | * haven't been invoked from an earlier instance of BusyBox. | ||
14126 | */ | ||
14127 | char *start, *end, *s; | ||
14128 | struct passwd *pw; | ||
14129 | |||
14130 | for (envp = environ; envp && *envp; envp++) { | ||
14131 | if (!(end=strchr(*envp, '='))) | ||
14132 | continue; | ||
14133 | |||
14134 | /* make all variable names uppercase */ | ||
14135 | for (start = *envp;start < end;start++) | ||
14136 | *start = toupper(*start); | ||
14137 | |||
14138 | /* skip conversion of variables known to cause problems */ | ||
14139 | if ( strncmp(*envp, "SYSTEMROOT=", 11) == 0 || | ||
14140 | strncmp(*envp, "COMSPEC=", 8) == 0 ) { | ||
14141 | continue; | ||
14142 | } | ||
14143 | |||
14144 | /* convert backslashes to forward slashes in value */ | ||
14145 | if (!xp) { | ||
14146 | for ( s=end+1; *s; ++s ) { | ||
14147 | if ( *s == '\\' ) { | ||
14148 | *s = '/'; | ||
14149 | } | ||
14150 | } | ||
14151 | } | ||
14152 | |||
14153 | /* check for invalid characters in name */ | ||
14154 | for (start = *envp;start < end;start++) { | ||
14155 | if (!isdigit(*start) && !isalpha(*start) && *start != '_') { | ||
14156 | break; | ||
14157 | } | ||
14158 | } | ||
14159 | |||
14160 | if (start != end) { | ||
14161 | /* | ||
14162 | * Make a copy of the variable, replacing invalid | ||
14163 | * characters in the name with underscores. | ||
14164 | */ | ||
14165 | char *var = xstrdup(*envp); | ||
14166 | |||
14167 | for (start = var;*start != '=';start++) { | ||
14168 | if (!isdigit(*start) && !isalpha(*start)) { | ||
14169 | *start = '_'; | ||
14170 | } | ||
14171 | } | ||
14172 | setvareq(var, VEXPORT|VNOSAVE); | ||
14173 | } | ||
14174 | } | ||
14175 | |||
14176 | /* some initialisation normally performed at login */ | ||
14177 | pw = xgetpwuid(getuid()); | ||
14178 | setup_environment(pw->pw_shell, | ||
14179 | SETUP_ENV_CHANGEENV|SETUP_ENV_NO_CHDIR, pw); | ||
14180 | } | ||
14181 | #endif | ||
13564 | for (envp = environ; envp && *envp; envp++) { | 14182 | for (envp = environ; envp && *envp; envp++) { |
13565 | p = endofname(*envp); | 14183 | p = endofname(*envp); |
13566 | if (p != *envp && *p == '=') { | 14184 | if (p != *envp && *p == '=') { |
@@ -13772,17 +14390,44 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13772 | exception_handler = &jmploc; | 14390 | exception_handler = &jmploc; |
13773 | rootpid = getpid(); | 14391 | rootpid = getpid(); |
13774 | 14392 | ||
13775 | init(); | 14393 | init(IF_PLATFORM_MINGW32(argc >= 2 && strcmp(argv[1], "-X") == 0)); |
13776 | setstackmark(&smark); | 14394 | setstackmark(&smark); |
14395 | |||
14396 | #if ENABLE_PLATFORM_MINGW32 | ||
14397 | hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL); | ||
14398 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
14399 | |||
14400 | if (argc == 3 && !strcmp(argv[1], "--forkshell")) { | ||
14401 | forkshell_init(argv[2]); | ||
14402 | |||
14403 | /* NOTREACHED */ | ||
14404 | bb_error_msg_and_die("subshell ended unexpectedly"); | ||
14405 | } | ||
14406 | #endif | ||
13777 | login_sh = procargs(argv); | 14407 | login_sh = procargs(argv); |
13778 | #if DEBUG | 14408 | #if DEBUG |
13779 | TRACE(("Shell args: ")); | 14409 | TRACE(("Shell args: ")); |
13780 | trace_puts_args(argv); | 14410 | trace_puts_args(argv); |
13781 | #endif | 14411 | #endif |
13782 | 14412 | ||
14413 | #if ENABLE_ASH_NOCONSOLE | ||
14414 | if ( noconsole ) { | ||
14415 | DWORD dummy; | ||
14416 | |||
14417 | if ( GetConsoleProcessList(&dummy, 1) == 1 ) { | ||
14418 | ShowWindow(GetConsoleWindow(), SW_HIDE); | ||
14419 | } | ||
14420 | } | ||
14421 | #endif | ||
14422 | |||
13783 | if (login_sh) { | 14423 | if (login_sh) { |
13784 | const char *hp; | 14424 | const char *hp; |
13785 | 14425 | ||
14426 | #if ENABLE_PLATFORM_MINGW32 | ||
14427 | chdir(xgetpwuid(getuid())->pw_dir); | ||
14428 | setpwd(NULL, 0); | ||
14429 | #endif | ||
14430 | |||
13786 | state = 1; | 14431 | state = 1; |
13787 | read_profile("/etc/profile"); | 14432 | read_profile("/etc/profile"); |
13788 | state1: | 14433 | state1: |
@@ -13857,6 +14502,642 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13857 | /* NOTREACHED */ | 14502 | /* NOTREACHED */ |
13858 | } | 14503 | } |
13859 | 14504 | ||
14505 | #if ENABLE_PLATFORM_MINGW32 | ||
14506 | static void | ||
14507 | forkshell_openhere(struct forkshell *fs) | ||
14508 | { | ||
14509 | union node *redir = fs->n; | ||
14510 | int pip[2]; | ||
14511 | |||
14512 | pip[0] = fs->fd[0]; | ||
14513 | pip[1] = fs->fd[1]; | ||
14514 | |||
14515 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
14516 | |||
14517 | close(pip[0]); | ||
14518 | ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); | ||
14519 | ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); | ||
14520 | ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); | ||
14521 | ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); | ||
14522 | signal(SIGPIPE, SIG_DFL); | ||
14523 | if (redir->type == NHERE) { | ||
14524 | size_t len = strlen(redir->nhere.doc->narg.text); | ||
14525 | full_write(pip[1], redir->nhere.doc->narg.text, len); | ||
14526 | } else /* NXHERE */ | ||
14527 | expandhere(redir->nhere.doc, pip[1]); | ||
14528 | _exit(EXIT_SUCCESS); | ||
14529 | } | ||
14530 | |||
14531 | static void | ||
14532 | forkshell_evalbackcmd(struct forkshell *fs) | ||
14533 | { | ||
14534 | union node *n = fs->n; | ||
14535 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
14536 | |||
14537 | FORCE_INT_ON; | ||
14538 | close(pip[0]); | ||
14539 | if (pip[1] != 1) { | ||
14540 | /*close(1);*/ | ||
14541 | dup2_or_raise(pip[1], 1); | ||
14542 | close(pip[1]); | ||
14543 | } | ||
14544 | eflag = 0; | ||
14545 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ | ||
14546 | /* NOTREACHED */ | ||
14547 | } | ||
14548 | |||
14549 | static void | ||
14550 | forkshell_evalsubshell(struct forkshell *fs) | ||
14551 | { | ||
14552 | union node *n = fs->n; | ||
14553 | int flags = fs->flags; | ||
14554 | |||
14555 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
14556 | INT_ON; | ||
14557 | flags |= EV_EXIT; | ||
14558 | expredir(n->nredir.redirect); | ||
14559 | redirect(n->nredir.redirect, 0); | ||
14560 | evaltreenr(n->nredir.n, flags); | ||
14561 | /* never returns */ | ||
14562 | } | ||
14563 | |||
14564 | static void | ||
14565 | forkshell_evalpipe(struct forkshell *fs) | ||
14566 | { | ||
14567 | union node *n = fs->n; | ||
14568 | int flags = fs->flags; | ||
14569 | int prevfd = fs->fd[2]; | ||
14570 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
14571 | |||
14572 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
14573 | INT_ON; | ||
14574 | if (pip[1] >= 0) { | ||
14575 | close(pip[0]); | ||
14576 | } | ||
14577 | if (prevfd > 0) { | ||
14578 | dup2(prevfd, 0); | ||
14579 | close(prevfd); | ||
14580 | } | ||
14581 | if (pip[1] > 1) { | ||
14582 | dup2(pip[1], 1); | ||
14583 | close(pip[1]); | ||
14584 | } | ||
14585 | evaltreenr(n, flags); | ||
14586 | } | ||
14587 | |||
14588 | static void | ||
14589 | forkshell_shellexec(struct forkshell *fs) | ||
14590 | { | ||
14591 | int idx = fs->fd[0]; | ||
14592 | struct strlist *varlist = fs->strlist; | ||
14593 | char **argv = fs->argv; | ||
14594 | char *path = fs->string; | ||
14595 | |||
14596 | FORCE_INT_ON; | ||
14597 | listsetvar(varlist, VEXPORT|VSTACK); | ||
14598 | shellexec(argv[0], argv, path, idx); | ||
14599 | } | ||
14600 | |||
14601 | static void | ||
14602 | forkshell_child(struct forkshell *fs) | ||
14603 | { | ||
14604 | switch ( fs->fpid ) { | ||
14605 | case FS_OPENHERE: | ||
14606 | forkshell_openhere(fs); | ||
14607 | break; | ||
14608 | case FS_EVALBACKCMD: | ||
14609 | forkshell_evalbackcmd(fs); | ||
14610 | break; | ||
14611 | case FS_EVALSUBSHELL: | ||
14612 | forkshell_evalsubshell(fs); | ||
14613 | break; | ||
14614 | case FS_EVALPIPE: | ||
14615 | forkshell_evalpipe(fs); | ||
14616 | break; | ||
14617 | case FS_SHELLEXEC: | ||
14618 | forkshell_shellexec(fs); | ||
14619 | break; | ||
14620 | } | ||
14621 | } | ||
14622 | |||
14623 | /* | ||
14624 | * Reset the pointers to the builtin environment variables in the hash | ||
14625 | * table to point to varinit rather than the bogus copy created during | ||
14626 | * forkshell_prepare. | ||
14627 | */ | ||
14628 | static void | ||
14629 | reinitvar(void) | ||
14630 | { | ||
14631 | struct var *vp; | ||
14632 | struct var *end; | ||
14633 | struct var **vpp; | ||
14634 | struct var **old; | ||
14635 | |||
14636 | vp = varinit; | ||
14637 | end = vp + ARRAY_SIZE(varinit); | ||
14638 | do { | ||
14639 | vpp = hashvar(vp->var_text); | ||
14640 | if ( (old=findvar(vpp, vp->var_text)) != NULL ) { | ||
14641 | vp->next = (*old)->next; | ||
14642 | *old = vp; | ||
14643 | } | ||
14644 | } while (++vp < end); | ||
14645 | } | ||
14646 | |||
14647 | /* FIXME: should consider running forkparent() and forkchild() */ | ||
14648 | static int | ||
14649 | spawn_forkshell(struct job *jp, struct forkshell *fs, int mode) | ||
14650 | { | ||
14651 | struct forkshell *new; | ||
14652 | char buf[16]; | ||
14653 | const char *argv[] = { "sh", "--forkshell", NULL, NULL }; | ||
14654 | intptr_t ret; | ||
14655 | |||
14656 | new = forkshell_prepare(fs); | ||
14657 | sprintf(buf, "%x", (unsigned int)new->hMapFile); | ||
14658 | argv[2] = buf; | ||
14659 | ret = mingw_spawn_proc(argv); | ||
14660 | CloseHandle(new->hMapFile); | ||
14661 | UnmapViewOfFile(new); | ||
14662 | if (ret == -1) { | ||
14663 | free(jp); | ||
14664 | return -1; | ||
14665 | } | ||
14666 | forkparent(jp, fs->node, mode, (HANDLE)ret); | ||
14667 | return ret == -1 ? -1 : 0; | ||
14668 | } | ||
14669 | |||
14670 | /* | ||
14671 | * forkshell_prepare() and friends | ||
14672 | * | ||
14673 | * The sequence is as follows: | ||
14674 | * - funcblocksize, funcstringsize, nodeptrsize are initialized | ||
14675 | * - forkshell_size(fs) is called to calculate the exact memory needed | ||
14676 | * - a new struct is allocated | ||
14677 | * - funcblock, funcstring, nodeptr are initialized from the new block | ||
14678 | * - forkshell_copy(fs) is called to copy recursively everything over | ||
14679 | * it will record all pointers along the way, to nodeptr | ||
14680 | * | ||
14681 | * When this memory is mapped elsewhere, pointer fixup will be needed | ||
14682 | */ | ||
14683 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
14684 | static void \ | ||
14685 | name(type *p) \ | ||
14686 | { \ | ||
14687 | while (p) { \ | ||
14688 | funcblocksize += sizeof(type); | ||
14689 | /* do something here with p */ | ||
14690 | #define SLIST_SIZE_END() \ | ||
14691 | nodeptrsize++; \ | ||
14692 | p = p->next; \ | ||
14693 | } \ | ||
14694 | } | ||
14695 | |||
14696 | #define SLIST_COPY_BEGIN(name,type) \ | ||
14697 | static type * \ | ||
14698 | name(type *vp) \ | ||
14699 | { \ | ||
14700 | type *start; \ | ||
14701 | type **vpp; \ | ||
14702 | vpp = &start; \ | ||
14703 | while (vp) { \ | ||
14704 | *vpp = funcblock; \ | ||
14705 | funcblock = (char *) funcblock + sizeof(type); | ||
14706 | /* do something here with vpp and vp */ | ||
14707 | #define SLIST_COPY_END() \ | ||
14708 | SAVE_PTR((*vpp)->next); \ | ||
14709 | vp = vp->next; \ | ||
14710 | vpp = &(*vpp)->next; \ | ||
14711 | } \ | ||
14712 | *vpp = NULL; \ | ||
14713 | return start; \ | ||
14714 | } | ||
14715 | |||
14716 | /* | ||
14717 | * struct var | ||
14718 | */ | ||
14719 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
14720 | funcstringsize += strlen(p->var_text) + 1; | ||
14721 | nodeptrsize++; /* p->text */ | ||
14722 | SLIST_SIZE_END() | ||
14723 | |||
14724 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
14725 | (*vpp)->var_text = nodeckstrdup(vp->var_text); | ||
14726 | (*vpp)->flags = vp->flags; | ||
14727 | /* | ||
14728 | * The only place that can set struct var#func is varinit[], | ||
14729 | * which will be fixed by forkshell_init() | ||
14730 | */ | ||
14731 | (*vpp)->var_func = NULL; | ||
14732 | SAVE_PTR((*vpp)->var_text); | ||
14733 | SLIST_COPY_END() | ||
14734 | |||
14735 | /* | ||
14736 | * struct strlist | ||
14737 | */ | ||
14738 | SLIST_SIZE_BEGIN(strlist_size,struct strlist) | ||
14739 | funcstringsize += strlen(p->text) + 1; | ||
14740 | nodeptrsize++; /* p->text */ | ||
14741 | SLIST_SIZE_END() | ||
14742 | |||
14743 | SLIST_COPY_BEGIN(strlist_copy,struct strlist) | ||
14744 | (*vpp)->text = nodeckstrdup(vp->text); | ||
14745 | SAVE_PTR((*vpp)->text); | ||
14746 | SLIST_COPY_END() | ||
14747 | |||
14748 | /* | ||
14749 | * struct tblentry | ||
14750 | */ | ||
14751 | static void | ||
14752 | tblentry_size(struct tblentry *tep) | ||
14753 | { | ||
14754 | while (tep) { | ||
14755 | funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
14756 | /* CMDBUILTIN, e->param.cmd needs no pointer relocation */ | ||
14757 | if (tep->cmdtype == CMDFUNCTION) { | ||
14758 | funcblocksize += offsetof(struct funcnode, n); | ||
14759 | calcsize(&tep->param.func->n); | ||
14760 | nodeptrsize++; /* tep->param.func */ | ||
14761 | } | ||
14762 | nodeptrsize++; /* tep->next */ | ||
14763 | tep = tep->next; | ||
14764 | } | ||
14765 | } | ||
14766 | |||
14767 | static struct tblentry * | ||
14768 | tblentry_copy(struct tblentry *tep) | ||
14769 | { | ||
14770 | struct tblentry *start; | ||
14771 | struct tblentry **newp; | ||
14772 | int size; | ||
14773 | |||
14774 | newp = &start; | ||
14775 | while (tep) { | ||
14776 | *newp = funcblock; | ||
14777 | size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
14778 | |||
14779 | funcblock = (char *) funcblock + size; | ||
14780 | memcpy(*newp, tep, size); | ||
14781 | switch (tep->cmdtype) { | ||
14782 | case CMDBUILTIN: | ||
14783 | /* No pointer saving, this field must be fixed by forkshell_init() */ | ||
14784 | (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab); | ||
14785 | break; | ||
14786 | case CMDFUNCTION: | ||
14787 | (*newp)->param.func = funcblock; | ||
14788 | funcblock = (char *) funcblock + offsetof(struct funcnode, n); | ||
14789 | copynode(&tep->param.func->n); | ||
14790 | SAVE_PTR((*newp)->param.func); | ||
14791 | break; | ||
14792 | default: | ||
14793 | break; | ||
14794 | } | ||
14795 | SAVE_PTR((*newp)->next); | ||
14796 | tep = tep->next; | ||
14797 | newp = &(*newp)->next; | ||
14798 | } | ||
14799 | *newp = NULL; | ||
14800 | return start; | ||
14801 | } | ||
14802 | |||
14803 | static void | ||
14804 | cmdtable_size(struct tblentry **cmdtablep) | ||
14805 | { | ||
14806 | int i; | ||
14807 | nodeptrsize += CMDTABLESIZE; | ||
14808 | funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE; | ||
14809 | for (i = 0; i < CMDTABLESIZE; i++) | ||
14810 | tblentry_size(cmdtablep[i]); | ||
14811 | } | ||
14812 | |||
14813 | static struct tblentry ** | ||
14814 | cmdtable_copy(struct tblentry **cmdtablep) | ||
14815 | { | ||
14816 | struct tblentry **new = funcblock; | ||
14817 | int i; | ||
14818 | |||
14819 | funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE; | ||
14820 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
14821 | new[i] = tblentry_copy(cmdtablep[i]); | ||
14822 | SAVE_PTR(new[i]); | ||
14823 | } | ||
14824 | return new; | ||
14825 | } | ||
14826 | |||
14827 | /* | ||
14828 | * char ** | ||
14829 | */ | ||
14830 | static void | ||
14831 | argv_size(char **p) | ||
14832 | { | ||
14833 | while (p && *p) { | ||
14834 | funcblocksize += sizeof(char *); | ||
14835 | funcstringsize += strlen(*p)+1; | ||
14836 | nodeptrsize++; | ||
14837 | p++; | ||
14838 | } | ||
14839 | funcblocksize += sizeof(char *); | ||
14840 | } | ||
14841 | |||
14842 | static char ** | ||
14843 | argv_copy(char **p) | ||
14844 | { | ||
14845 | char **new, **start = funcblock; | ||
14846 | |||
14847 | while (p && *p) { | ||
14848 | new = funcblock; | ||
14849 | funcblock = (char *) funcblock + sizeof(char *); | ||
14850 | *new = nodeckstrdup(*p); | ||
14851 | SAVE_PTR(*new); | ||
14852 | p++; | ||
14853 | new++; | ||
14854 | } | ||
14855 | new = funcblock; | ||
14856 | funcblock = (char *) funcblock + sizeof(char *); | ||
14857 | *new = NULL; | ||
14858 | return start; | ||
14859 | } | ||
14860 | |||
14861 | /* | ||
14862 | * struct redirtab | ||
14863 | */ | ||
14864 | static void | ||
14865 | redirtab_size(struct redirtab *rdtp) | ||
14866 | { | ||
14867 | while (rdtp) { | ||
14868 | funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
14869 | rdtp = rdtp->next; | ||
14870 | nodeptrsize++; /* rdtp->next */ | ||
14871 | } | ||
14872 | } | ||
14873 | |||
14874 | static struct redirtab * | ||
14875 | redirtab_copy(struct redirtab *rdtp) | ||
14876 | { | ||
14877 | struct redirtab *start; | ||
14878 | struct redirtab **vpp; | ||
14879 | |||
14880 | vpp = &start; | ||
14881 | while (rdtp) { | ||
14882 | int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
14883 | *vpp = funcblock; | ||
14884 | funcblock = (char *) funcblock + size; | ||
14885 | memcpy(*vpp, rdtp, size); | ||
14886 | SAVE_PTR((*vpp)->next); | ||
14887 | rdtp = rdtp->next; | ||
14888 | vpp = &(*vpp)->next; | ||
14889 | } | ||
14890 | *vpp = NULL; | ||
14891 | return start; | ||
14892 | } | ||
14893 | |||
14894 | #undef shellparam | ||
14895 | #undef redirlist | ||
14896 | #undef varinit | ||
14897 | #undef vartab | ||
14898 | static void | ||
14899 | globals_var_size(struct globals_var *gvp) | ||
14900 | { | ||
14901 | int i; | ||
14902 | |||
14903 | funcblocksize += sizeof(struct globals_var); | ||
14904 | argv_size(gvp->shellparam.p); | ||
14905 | redirtab_size(gvp->redirlist); | ||
14906 | for (i = 0; i < VTABSIZE; i++) | ||
14907 | var_size(gvp->vartab[i]); | ||
14908 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
14909 | var_size(gvp->varinit+i); | ||
14910 | nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */ | ||
14911 | } | ||
14912 | |||
14913 | #undef preverrout_fd | ||
14914 | static struct globals_var * | ||
14915 | globals_var_copy(struct globals_var *gvp) | ||
14916 | { | ||
14917 | int i; | ||
14918 | struct globals_var *new; | ||
14919 | |||
14920 | new = funcblock; | ||
14921 | funcblock = (char *) funcblock + sizeof(struct globals_var); | ||
14922 | |||
14923 | /* shparam */ | ||
14924 | memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam)); | ||
14925 | new->shellparam.malloced = 0; | ||
14926 | new->shellparam.p = argv_copy(gvp->shellparam.p); | ||
14927 | SAVE_PTR(new->shellparam.p); | ||
14928 | |||
14929 | new->redirlist = redirtab_copy(gvp->redirlist); | ||
14930 | SAVE_PTR(new->redirlist); | ||
14931 | |||
14932 | new->preverrout_fd = gvp->preverrout_fd; | ||
14933 | for (i = 0; i < VTABSIZE; i++) { | ||
14934 | new->vartab[i] = var_copy(gvp->vartab[i]); | ||
14935 | SAVE_PTR(new->vartab[i]); | ||
14936 | } | ||
14937 | |||
14938 | /* Can't use var_copy because varinit is already allocated */ | ||
14939 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { | ||
14940 | new->varinit[i].next = NULL; | ||
14941 | new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text); | ||
14942 | SAVE_PTR(new->varinit[i].var_text); | ||
14943 | new->varinit[i].flags = gvp->varinit[i].flags; | ||
14944 | new->varinit[i].var_func = gvp->varinit[i].var_func; | ||
14945 | } | ||
14946 | return new; | ||
14947 | } | ||
14948 | |||
14949 | #undef minusc | ||
14950 | #undef curdir | ||
14951 | #undef physdir | ||
14952 | #undef arg0 | ||
14953 | #undef nullstr | ||
14954 | static void | ||
14955 | globals_misc_size(struct globals_misc *p) | ||
14956 | { | ||
14957 | funcblocksize += sizeof(struct globals_misc); | ||
14958 | funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1; | ||
14959 | if (p->curdir != p->nullstr) | ||
14960 | funcstringsize += strlen(p->curdir) + 1; | ||
14961 | if (p->physdir != p->nullstr) | ||
14962 | funcstringsize += strlen(p->physdir) + 1; | ||
14963 | funcstringsize += strlen(p->arg0) + 1; | ||
14964 | nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */ | ||
14965 | } | ||
14966 | |||
14967 | static struct globals_misc * | ||
14968 | globals_misc_copy(struct globals_misc *p) | ||
14969 | { | ||
14970 | struct globals_misc *new = funcblock; | ||
14971 | |||
14972 | funcblock = (char *) funcblock + sizeof(struct globals_misc); | ||
14973 | memcpy(new, p, sizeof(struct globals_misc)); | ||
14974 | |||
14975 | new->minusc = nodeckstrdup(p->minusc); | ||
14976 | new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr; | ||
14977 | new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr; | ||
14978 | new->arg0 = nodeckstrdup(p->arg0); | ||
14979 | SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0); | ||
14980 | return new; | ||
14981 | } | ||
14982 | |||
14983 | static void | ||
14984 | forkshell_size(struct forkshell *fs) | ||
14985 | { | ||
14986 | funcblocksize += sizeof(struct forkshell); | ||
14987 | globals_var_size(fs->gvp); | ||
14988 | globals_misc_size(fs->gmp); | ||
14989 | cmdtable_size(fs->cmdtable); | ||
14990 | /* optlist_transfer(sending, fd); */ | ||
14991 | /* misc_transfer(sending, fd); */ | ||
14992 | |||
14993 | calcsize(fs->n); | ||
14994 | argv_size(fs->argv); | ||
14995 | funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1; | ||
14996 | strlist_size(fs->strlist); | ||
14997 | |||
14998 | nodeptrsize += 7; /* gvp, gmp, cmdtable, n, argv, string, strlist */ | ||
14999 | } | ||
15000 | |||
15001 | static struct forkshell * | ||
15002 | forkshell_copy(struct forkshell *fs) | ||
15003 | { | ||
15004 | struct forkshell *new; | ||
15005 | |||
15006 | new = funcblock; | ||
15007 | funcblock = (char *) funcblock + sizeof(struct forkshell); | ||
15008 | |||
15009 | memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */ | ||
15010 | new->gvp = globals_var_copy(fs->gvp); | ||
15011 | new->gmp = globals_misc_copy(fs->gmp); | ||
15012 | new->cmdtable = cmdtable_copy(fs->cmdtable); | ||
15013 | SAVE_PTR3(new->gvp, new->gmp, new->cmdtable); | ||
15014 | |||
15015 | new->n = copynode(fs->n); | ||
15016 | new->argv = argv_copy(fs->argv); | ||
15017 | new->string = nodeckstrdup(fs->string); | ||
15018 | new->strlist = strlist_copy(fs->strlist); | ||
15019 | SAVE_PTR4(new->n, new->argv, new->string, new->strlist); | ||
15020 | return new; | ||
15021 | } | ||
15022 | |||
15023 | static struct forkshell * | ||
15024 | forkshell_prepare(struct forkshell *fs) | ||
15025 | { | ||
15026 | struct forkshell *new; | ||
15027 | int size, nodeptr_offset; | ||
15028 | HANDLE h; | ||
15029 | SECURITY_ATTRIBUTES sa; | ||
15030 | |||
15031 | /* Calculate size of "new" */ | ||
15032 | fs->gvp = ash_ptr_to_globals_var; | ||
15033 | fs->gmp = ash_ptr_to_globals_misc; | ||
15034 | fs->cmdtable = cmdtable; | ||
15035 | |||
15036 | nodeptrsize = 1; /* NULL terminated */ | ||
15037 | funcblocksize = 0; | ||
15038 | funcstringsize = 0; | ||
15039 | forkshell_size(fs); | ||
15040 | size = funcblocksize + funcstringsize + nodeptrsize*sizeof(char *); | ||
15041 | |||
15042 | /* Allocate, initialize pointers */ | ||
15043 | memset(&sa, 0, sizeof(sa)); | ||
15044 | sa.nLength = sizeof(sa); | ||
15045 | sa.lpSecurityDescriptor = NULL; | ||
15046 | sa.bInheritHandle = TRUE; | ||
15047 | h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL); | ||
15048 | new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
15049 | /* new = ckmalloc(size); */ | ||
15050 | funcblock = new; | ||
15051 | funcstring = (char *) funcblock + funcblocksize; | ||
15052 | nodeptr = (char **)((char *)funcstring + funcstringsize); | ||
15053 | nodeptr_offset = (char *)nodeptr - (char *)new; | ||
15054 | |||
15055 | /* Now pack them all */ | ||
15056 | forkshell_copy(fs); | ||
15057 | |||
15058 | /* Finish it up */ | ||
15059 | *nodeptr = NULL; | ||
15060 | new->size = size; | ||
15061 | new->nodeptr_offset = nodeptr_offset; | ||
15062 | new->old_base = new; | ||
15063 | new->hMapFile = h; | ||
15064 | return new; | ||
15065 | } | ||
15066 | |||
15067 | #undef exception_handler | ||
15068 | #undef trap | ||
15069 | #undef trap_ptr | ||
15070 | static void *sticky_mem_start, *sticky_mem_end; | ||
15071 | static void | ||
15072 | forkshell_init(const char *idstr) | ||
15073 | { | ||
15074 | struct forkshell *fs; | ||
15075 | int map_handle; | ||
15076 | HANDLE h; | ||
15077 | struct globals_var **gvpp; | ||
15078 | struct globals_misc **gmpp; | ||
15079 | int i; | ||
15080 | char **ptr; | ||
15081 | |||
15082 | if (sscanf(idstr, "%x", &map_handle) != 1) | ||
15083 | bb_error_msg_and_die("invalid forkshell ID"); | ||
15084 | |||
15085 | h = (HANDLE)map_handle; | ||
15086 | fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
15087 | if (!fs) | ||
15088 | bb_error_msg_and_die("Invalid forkshell memory"); | ||
15089 | |||
15090 | /* this memory can't be freed */ | ||
15091 | sticky_mem_start = fs; | ||
15092 | sticky_mem_end = (char *) fs + fs->size; | ||
15093 | |||
15094 | /* pointer fixup */ | ||
15095 | nodeptr = (char **)((char *)fs + fs->nodeptr_offset); | ||
15096 | for ( i=0; nodeptr[i]; ++i ) { | ||
15097 | ptr = (char **)((char *)fs + (nodeptr[i] - (char *)fs->old_base)); | ||
15098 | if (*ptr) | ||
15099 | *ptr = (char *)fs + (*ptr - (char *)fs->old_base); | ||
15100 | } | ||
15101 | |||
15102 | /* Now fix up stuff that can't be transferred */ | ||
15103 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
15104 | fs->gvp->varinit[i].var_func = varinit_data[i].var_func; | ||
15105 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
15106 | struct tblentry *e = fs->cmdtable[i]; | ||
15107 | while (e) { | ||
15108 | if (e->cmdtype == CMDBUILTIN) | ||
15109 | e->param.cmd = builtintab + (int)e->param.cmd; | ||
15110 | e = e->next; | ||
15111 | } | ||
15112 | } | ||
15113 | fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler; | ||
15114 | for (i = 0; i < NSIG; i++) | ||
15115 | fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i]; | ||
15116 | fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr; | ||
15117 | |||
15118 | /* Switch global variables */ | ||
15119 | gvpp = (struct globals_var **)&ash_ptr_to_globals_var; | ||
15120 | *gvpp = fs->gvp; | ||
15121 | gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc; | ||
15122 | *gmpp = fs->gmp; | ||
15123 | cmdtable = fs->cmdtable; | ||
15124 | |||
15125 | CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */ | ||
15126 | |||
15127 | reinitvar(); | ||
15128 | |||
15129 | forkshell_child(fs); | ||
15130 | } | ||
15131 | |||
15132 | #undef free | ||
15133 | static void | ||
15134 | sticky_free(void *base) | ||
15135 | { | ||
15136 | if (base >= sticky_mem_start && base < sticky_mem_end) | ||
15137 | return; | ||
15138 | free(base); | ||
15139 | } | ||
15140 | #endif | ||
13860 | 15141 | ||
13861 | /*- | 15142 | /*- |
13862 | * Copyright (c) 1989, 1991, 1993, 1994 | 15143 | * Copyright (c) 1989, 1991, 1993, 1994 |