diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 1260 |
1 files changed, 1248 insertions, 12 deletions
diff --git a/shell/ash.c b/shell/ash.c index 84502636a..08b6aa430 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -17,6 +17,20 @@ | |||
17 | */ | 17 | */ |
18 | 18 | ||
19 | /* | 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 | |||
33 | /* | ||
20 | * The following should be set to reflect the type of system you have: | 34 | * The following should be set to reflect the type of system you have: |
21 | * JOBS -> 1 if you have Berkeley job control, 0 otherwise. | 35 | * JOBS -> 1 if you have Berkeley job control, 0 otherwise. |
22 | * define SYSV if you are running under System V. | 36 | * define SYSV if you are running under System V. |
@@ -72,6 +86,10 @@ | |||
72 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ | 86 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ |
73 | #endif | 87 | #endif |
74 | 88 | ||
89 | #if !ENABLE_PLATFORM_MINGW32 | ||
90 | # define is_absolute_path(path) ((path)[0] == '/') | ||
91 | #endif | ||
92 | |||
75 | #if !BB_MMU | 93 | #if !BB_MMU |
76 | # error "Do not even bother, ash will not run on NOMMU machine" | 94 | # error "Do not even bother, ash will not run on NOMMU machine" |
77 | #endif | 95 | #endif |
@@ -201,6 +219,50 @@ | |||
201 | //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o | 219 | //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o |
202 | //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o | 220 | //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o |
203 | 221 | ||
222 | #if ENABLE_PLATFORM_MINGW32 | ||
223 | union node; | ||
224 | struct strlist; | ||
225 | struct job; | ||
226 | |||
227 | struct forkshell { | ||
228 | /* filled by forkshell_copy() */ | ||
229 | struct globals_var *gvp; | ||
230 | struct globals_misc *gmp; | ||
231 | struct tblentry **cmdtable; | ||
232 | /* struct alias **atab; */ | ||
233 | /* struct parsefile *g_parsefile; */ | ||
234 | HANDLE hMapFile; | ||
235 | void *old_base; | ||
236 | int nodeptr_offset; | ||
237 | int size; | ||
238 | |||
239 | /* type of forkshell */ | ||
240 | int fpid; | ||
241 | |||
242 | /* optional data, used by forkshell_child */ | ||
243 | int flags; | ||
244 | int fd[10]; | ||
245 | union node *n; | ||
246 | char **argv; | ||
247 | char *string; | ||
248 | struct strlist *strlist; | ||
249 | }; | ||
250 | |||
251 | enum { | ||
252 | FS_OPENHERE, | ||
253 | FS_EVALBACKCMD, | ||
254 | FS_EVALSUBSHELL, | ||
255 | FS_EVALPIPE, | ||
256 | FS_SHELLEXEC | ||
257 | }; | ||
258 | |||
259 | static struct forkshell* forkshell_prepare(struct forkshell *fs); | ||
260 | static void forkshell_init(const char *idstr); | ||
261 | static void forkshell_child(struct forkshell *fs); | ||
262 | static void sticky_free(void *p); | ||
263 | #define free(p) sticky_free(p) | ||
264 | static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode); | ||
265 | #endif | ||
204 | 266 | ||
205 | /* ============ Hash table sizes. Configurable. */ | 267 | /* ============ Hash table sizes. Configurable. */ |
206 | 268 | ||
@@ -233,6 +295,10 @@ static const char *const optletters_optnames[] = { | |||
233 | ,"\0" "nolog" | 295 | ,"\0" "nolog" |
234 | ,"\0" "debug" | 296 | ,"\0" "debug" |
235 | #endif | 297 | #endif |
298 | #if ENABLE_PLATFORM_MINGW32 | ||
299 | ,"\0" "noconsole" | ||
300 | ,"X" "winxp" | ||
301 | #endif | ||
236 | }; | 302 | }; |
237 | 303 | ||
238 | #define optletters(n) optletters_optnames[n][0] | 304 | #define optletters(n) optletters_optnames[n][0] |
@@ -313,6 +379,10 @@ struct globals_misc { | |||
313 | # define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] | 379 | # define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] |
314 | # define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] | 380 | # define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] |
315 | #endif | 381 | #endif |
382 | #if ENABLE_PLATFORM_MINGW32 | ||
383 | # define noconsole optlist[14 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG] | ||
384 | # define winxp optlist[15 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG] | ||
385 | #endif | ||
316 | 386 | ||
317 | /* trap handler commands */ | 387 | /* trap handler commands */ |
318 | /* | 388 | /* |
@@ -2389,10 +2459,22 @@ path_advance(const char **path, const char *name) | |||
2389 | if (*path == NULL) | 2459 | if (*path == NULL) |
2390 | return NULL; | 2460 | return NULL; |
2391 | start = *path; | 2461 | start = *path; |
2462 | #if ENABLE_PLATFORM_MINGW32 | ||
2463 | p = next_path_sep(start); | ||
2464 | q = strchr(start, '%'); | ||
2465 | if ((p && q && q < p) || (!p && q)) | ||
2466 | p = q; | ||
2467 | if (!p) | ||
2468 | for (p = start; *p; p++) | ||
2469 | continue; | ||
2470 | #else | ||
2392 | for (p = start; *p && *p != ':' && *p != '%'; p++) | 2471 | for (p = start; *p && *p != ':' && *p != '%'; p++) |
2393 | continue; | 2472 | continue; |
2473 | #endif | ||
2394 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ | 2474 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ |
2395 | while (stackblocksize() < len) | 2475 | |
2476 | /* preserve space for .exe too */ | ||
2477 | while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len)) | ||
2396 | growstackblock(); | 2478 | growstackblock(); |
2397 | q = stackblock(); | 2479 | q = stackblock(); |
2398 | if (p != start) { | 2480 | if (p != start) { |
@@ -2404,10 +2486,19 @@ path_advance(const char **path, const char *name) | |||
2404 | pathopt = NULL; | 2486 | pathopt = NULL; |
2405 | if (*p == '%') { | 2487 | if (*p == '%') { |
2406 | pathopt = ++p; | 2488 | pathopt = ++p; |
2489 | #if ENABLE_PLATFORM_MINGW32 | ||
2490 | p = next_path_sep(start); | ||
2491 | |||
2492 | /* *p != ':' and '*' would suffice */ | ||
2493 | if (!p) | ||
2494 | p = pathopt - 1; | ||
2495 | #else | ||
2407 | while (*p && *p != ':') | 2496 | while (*p && *p != ':') |
2408 | p++; | 2497 | p++; |
2498 | #endif | ||
2409 | } | 2499 | } |
2410 | if (*p == ':') | 2500 | if (*p == ':' || |
2501 | (ENABLE_PLATFORM_MINGW32 && *p == ';')) | ||
2411 | *path = p + 1; | 2502 | *path = p + 1; |
2412 | else | 2503 | else |
2413 | *path = NULL; | 2504 | *path = NULL; |
@@ -2509,6 +2600,106 @@ cdopt(void) | |||
2509 | static const char * | 2600 | static const char * |
2510 | updatepwd(const char *dir) | 2601 | updatepwd(const char *dir) |
2511 | { | 2602 | { |
2603 | #if ENABLE_PLATFORM_MINGW32 | ||
2604 | #define is_path_sep(x) ((x) == '/' || (x) == '\\') | ||
2605 | #define is_unc_path(x) (is_path_sep(x[0]) && is_path_sep(x[1])) | ||
2606 | /* | ||
2607 | * Due to Windows drive notion, getting pwd is a completely | ||
2608 | * different thing. Handle it in a separate routine | ||
2609 | */ | ||
2610 | |||
2611 | char *new; | ||
2612 | char *p; | ||
2613 | char *cdcomppath; | ||
2614 | const char *lim; | ||
2615 | /* | ||
2616 | * There are five cases that make some kind of sense | ||
2617 | * absdrive + abspath: c:/path | ||
2618 | * absdrive + !abspath: c:path | ||
2619 | * !absdrive + abspath: /path | ||
2620 | * !absdrive + uncpath: //host/share | ||
2621 | * !absdrive + !abspath: path | ||
2622 | * | ||
2623 | * Damn DOS! | ||
2624 | * c:path behaviour is "undefined" | ||
2625 | * To properly handle this case, I have to keep track of cwd | ||
2626 | * of every drive, which is too painful to do. | ||
2627 | * So when c:path is given, I assume it's c:${curdir}path | ||
2628 | * with ${curdir} comes from the current drive | ||
2629 | */ | ||
2630 | int absdrive = *dir && dir[1] == ':'; | ||
2631 | int abspath = absdrive ? is_path_sep(dir[2]) : is_path_sep(*dir); | ||
2632 | |||
2633 | cdcomppath = ststrdup(dir); | ||
2634 | STARTSTACKSTR(new); | ||
2635 | if (!absdrive && curdir == nullstr) | ||
2636 | return 0; | ||
2637 | if (!abspath) { | ||
2638 | if (curdir == nullstr) | ||
2639 | return 0; | ||
2640 | new = stack_putstr(curdir, new); | ||
2641 | } | ||
2642 | new = makestrspace(strlen(dir) + 2, new); | ||
2643 | |||
2644 | if ( is_unc_path(dir) || (!absdrive && !abspath && is_unc_path(curdir)) ) { | ||
2645 | lim = (char *)stackblock() + 1; | ||
2646 | } | ||
2647 | else { | ||
2648 | char *drive = stackblock(); | ||
2649 | if (absdrive) { | ||
2650 | *drive = *dir; | ||
2651 | cdcomppath += 2; | ||
2652 | dir += 2; | ||
2653 | } else { | ||
2654 | *drive = *curdir; | ||
2655 | } | ||
2656 | drive[1] = ':'; /* in case of absolute drive+path */ | ||
2657 | |||
2658 | if (abspath) | ||
2659 | new = drive + 2; | ||
2660 | lim = drive + 3; | ||
2661 | } | ||
2662 | |||
2663 | if (!abspath) { | ||
2664 | if (!is_path_sep(new[-1])) | ||
2665 | USTPUTC('/', new); | ||
2666 | if (new > lim && is_path_sep(*lim)) | ||
2667 | lim++; | ||
2668 | } else { | ||
2669 | USTPUTC('/', new); | ||
2670 | cdcomppath ++; | ||
2671 | if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) { | ||
2672 | USTPUTC('/', new); | ||
2673 | cdcomppath++; | ||
2674 | lim++; | ||
2675 | } | ||
2676 | } | ||
2677 | p = strtok(cdcomppath, "/\\"); | ||
2678 | while (p) { | ||
2679 | switch (*p) { | ||
2680 | case '.': | ||
2681 | if (p[1] == '.' && p[2] == '\0') { | ||
2682 | while (new > lim) { | ||
2683 | STUNPUTC(new); | ||
2684 | if (is_path_sep(new[-1])) | ||
2685 | break; | ||
2686 | } | ||
2687 | break; | ||
2688 | } | ||
2689 | if (p[1] == '\0') | ||
2690 | break; | ||
2691 | /* fall through */ | ||
2692 | default: | ||
2693 | new = stack_putstr(p, new); | ||
2694 | USTPUTC('/', new); | ||
2695 | } | ||
2696 | p = strtok(0, "/\\"); | ||
2697 | } | ||
2698 | if (new > lim) | ||
2699 | STUNPUTC(new); | ||
2700 | *new = 0; | ||
2701 | return stackblock(); | ||
2702 | #else | ||
2512 | char *new; | 2703 | char *new; |
2513 | char *p; | 2704 | char *p; |
2514 | char *cdcomppath; | 2705 | char *cdcomppath; |
@@ -2562,6 +2753,7 @@ updatepwd(const char *dir) | |||
2562 | STUNPUTC(new); | 2753 | STUNPUTC(new); |
2563 | *new = 0; | 2754 | *new = 0; |
2564 | return stackblock(); | 2755 | return stackblock(); |
2756 | #endif | ||
2565 | } | 2757 | } |
2566 | 2758 | ||
2567 | /* | 2759 | /* |
@@ -2656,7 +2848,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2656 | } | 2848 | } |
2657 | if (!dest) | 2849 | if (!dest) |
2658 | dest = nullstr; | 2850 | dest = nullstr; |
2659 | if (*dest == '/') | 2851 | if (is_absolute_path(dest)) |
2660 | goto step7; | 2852 | goto step7; |
2661 | if (*dest == '.') { | 2853 | if (*dest == '.') { |
2662 | c = dest[1]; | 2854 | c = dest[1]; |
@@ -3374,7 +3566,9 @@ struct job { | |||
3374 | }; | 3566 | }; |
3375 | 3567 | ||
3376 | static struct job *makejob(/*union node *,*/ int); | 3568 | static struct job *makejob(/*union node *,*/ int); |
3569 | #if !ENABLE_PLATFORM_MINGW32 | ||
3377 | static int forkshell(struct job *, union node *, int); | 3570 | static int forkshell(struct job *, union node *, int); |
3571 | #endif | ||
3378 | static int waitforjob(struct job *); | 3572 | static int waitforjob(struct job *); |
3379 | 3573 | ||
3380 | #if !JOBS | 3574 | #if !JOBS |
@@ -3429,6 +3623,8 @@ setsignal(int signo) | |||
3429 | char cur_act, new_act; | 3623 | char cur_act, new_act; |
3430 | struct sigaction act; | 3624 | struct sigaction act; |
3431 | 3625 | ||
3626 | if (ENABLE_PLATFORM_MINGW32) | ||
3627 | return; | ||
3432 | t = trap[signo]; | 3628 | t = trap[signo]; |
3433 | new_act = S_DFL; | 3629 | new_act = S_DFL; |
3434 | if (t != NULL) { /* trap for this sig is set */ | 3630 | if (t != NULL) { /* trap for this sig is set */ |
@@ -3944,6 +4140,79 @@ sprint_status48(char *s, int status, int sigonly) | |||
3944 | return col; | 4140 | return col; |
3945 | } | 4141 | } |
3946 | 4142 | ||
4143 | #if ENABLE_PLATFORM_MINGW32 | ||
4144 | |||
4145 | HANDLE hSIGINT; /* Ctrl-C is pressed */ | ||
4146 | |||
4147 | static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) | ||
4148 | { | ||
4149 | if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { | ||
4150 | SetEvent(hSIGINT); | ||
4151 | return TRUE; | ||
4152 | } | ||
4153 | return FALSE; | ||
4154 | } | ||
4155 | |||
4156 | /* | ||
4157 | * Windows does not know about parent-child relationship | ||
4158 | * They don't support waitpid(-1) | ||
4159 | */ | ||
4160 | static pid_t | ||
4161 | waitpid_child(int *status, int wait_flags) | ||
4162 | { | ||
4163 | HANDLE *pidlist, *pidp; | ||
4164 | int pid_nr = 0; | ||
4165 | pid_t pid; | ||
4166 | DWORD win_status, idx; | ||
4167 | struct job *jb; | ||
4168 | |||
4169 | #define LOOP(stmt) \ | ||
4170 | for (jb = curjob; jb; jb = jb->prev_job) { \ | ||
4171 | struct procstat *ps, *psend; \ | ||
4172 | if (jb->state == JOBDONE) \ | ||
4173 | continue; \ | ||
4174 | ps = jb->ps; \ | ||
4175 | psend = ps + jb->nprocs; \ | ||
4176 | while (ps < psend) { \ | ||
4177 | if (ps->ps_pid != -1) { \ | ||
4178 | stmt; \ | ||
4179 | } \ | ||
4180 | ps++; \ | ||
4181 | } \ | ||
4182 | } | ||
4183 | |||
4184 | LOOP(pid_nr++); | ||
4185 | if (!pid_nr) | ||
4186 | return -1; | ||
4187 | pid_nr++; | ||
4188 | pidp = pidlist = ckmalloc(sizeof(*pidlist)*pid_nr); | ||
4189 | *pidp++ = hSIGINT; | ||
4190 | LOOP(*pidp++ = (HANDLE)ps->ps_pid); | ||
4191 | #undef LOOP | ||
4192 | |||
4193 | idx = WaitForMultipleObjects(pid_nr, pidlist, FALSE, | ||
4194 | wait_flags|WNOHANG ? 1 : INFINITE); | ||
4195 | if (idx >= pid_nr) { | ||
4196 | free(pidlist); | ||
4197 | return -1; | ||
4198 | } | ||
4199 | if (!idx) { /* hSIGINT */ | ||
4200 | int i; | ||
4201 | ResetEvent(hSIGINT); | ||
4202 | for (i = 1; i < pid_nr; i++) | ||
4203 | TerminateProcess(pidlist[i], 1); | ||
4204 | free(pidlist); | ||
4205 | *status = 260; /* terminated by a signal */ | ||
4206 | return pidlist[1]; | ||
4207 | } | ||
4208 | GetExitCodeProcess(pidlist[idx], &win_status); | ||
4209 | pid = (int)pidlist[idx]; | ||
4210 | free(pidlist); | ||
4211 | *status = (int)win_status; | ||
4212 | return pid; | ||
4213 | } | ||
4214 | #endif | ||
4215 | |||
3947 | static int | 4216 | static int |
3948 | dowait(int wait_flags, struct job *job) | 4217 | dowait(int wait_flags, struct job *job) |
3949 | { | 4218 | { |
@@ -3959,7 +4228,11 @@ dowait(int wait_flags, struct job *job) | |||
3959 | * NB: _not_ safe_waitpid, we need to detect EINTR */ | 4228 | * NB: _not_ safe_waitpid, we need to detect EINTR */ |
3960 | if (doing_jobctl) | 4229 | if (doing_jobctl) |
3961 | wait_flags |= WUNTRACED; | 4230 | wait_flags |= WUNTRACED; |
4231 | #if ENABLE_PLATFORM_MINGW32 | ||
4232 | pid = waitpid_child(&status, wait_flags); | ||
4233 | #else | ||
3962 | pid = waitpid(-1, &status, wait_flags); | 4234 | pid = waitpid(-1, &status, wait_flags); |
4235 | #endif | ||
3963 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", | 4236 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", |
3964 | pid, status, errno, strerror(errno))); | 4237 | pid, status, errno, strerror(errno))); |
3965 | if (pid <= 0) | 4238 | if (pid <= 0) |
@@ -3983,6 +4256,8 @@ dowait(int wait_flags, struct job *job) | |||
3983 | jobno(jp), pid, ps->ps_status, status)); | 4256 | jobno(jp), pid, ps->ps_status, status)); |
3984 | ps->ps_status = status; | 4257 | ps->ps_status = status; |
3985 | thisjob = jp; | 4258 | thisjob = jp; |
4259 | if (ENABLE_PLATFORM_MINGW32) | ||
4260 | ps->ps_pid = -1; | ||
3986 | } | 4261 | } |
3987 | if (ps->ps_status == -1) | 4262 | if (ps->ps_status == -1) |
3988 | jobstate = JOBRUNNING; | 4263 | jobstate = JOBRUNNING; |
@@ -4215,6 +4490,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
4215 | int retval; | 4490 | int retval; |
4216 | struct job *jp; | 4491 | struct job *jp; |
4217 | 4492 | ||
4493 | if (ENABLE_PLATFORM_MINGW32) | ||
4494 | return 0; | ||
4495 | |||
4218 | if (pending_sig) | 4496 | if (pending_sig) |
4219 | raise_exception(EXSIG); | 4497 | raise_exception(EXSIG); |
4220 | 4498 | ||
@@ -4663,6 +4941,7 @@ commandtext(union node *n) | |||
4663 | * | 4941 | * |
4664 | * Called with interrupts off. | 4942 | * Called with interrupts off. |
4665 | */ | 4943 | */ |
4944 | #if !ENABLE_PLATFORM_MINGW32 | ||
4666 | /* | 4945 | /* |
4667 | * Clear traps on a fork. | 4946 | * Clear traps on a fork. |
4668 | */ | 4947 | */ |
@@ -4811,6 +5090,7 @@ forkchild(struct job *jp, union node *n, int mode) | |||
4811 | freejob(jp); | 5090 | freejob(jp); |
4812 | jobless = 0; | 5091 | jobless = 0; |
4813 | } | 5092 | } |
5093 | #endif | ||
4814 | 5094 | ||
4815 | /* Called after fork(), in parent */ | 5095 | /* Called after fork(), in parent */ |
4816 | #if !JOBS | 5096 | #if !JOBS |
@@ -4820,7 +5100,7 @@ static void | |||
4820 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 5100 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
4821 | { | 5101 | { |
4822 | TRACE(("In parent shell: child = %d\n", pid)); | 5102 | TRACE(("In parent shell: child = %d\n", pid)); |
4823 | if (!jp) { | 5103 | if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */ |
4824 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) | 5104 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) |
4825 | continue; | 5105 | continue; |
4826 | jobless++; | 5106 | jobless++; |
@@ -4854,12 +5134,14 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) | |||
4854 | } | 5134 | } |
4855 | } | 5135 | } |
4856 | 5136 | ||
5137 | #if !ENABLE_PLATFORM_MINGW32 | ||
4857 | static int | 5138 | static int |
4858 | forkshell(struct job *jp, union node *n, int mode) | 5139 | forkshell(struct job *jp, union node *n, int mode) |
4859 | { | 5140 | { |
4860 | int pid; | 5141 | int pid; |
4861 | 5142 | ||
4862 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); | 5143 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); |
5144 | |||
4863 | pid = fork(); | 5145 | pid = fork(); |
4864 | if (pid < 0) { | 5146 | if (pid < 0) { |
4865 | TRACE(("Fork failed, errno=%d", errno)); | 5147 | TRACE(("Fork failed, errno=%d", errno)); |
@@ -4875,6 +5157,7 @@ forkshell(struct job *jp, union node *n, int mode) | |||
4875 | } | 5157 | } |
4876 | return pid; | 5158 | return pid; |
4877 | } | 5159 | } |
5160 | #endif | ||
4878 | 5161 | ||
4879 | /* | 5162 | /* |
4880 | * Wait for job to finish. | 5163 | * Wait for job to finish. |
@@ -5067,6 +5350,7 @@ openhere(union node *redir) | |||
5067 | { | 5350 | { |
5068 | int pip[2]; | 5351 | int pip[2]; |
5069 | size_t len = 0; | 5352 | size_t len = 0; |
5353 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5070 | 5354 | ||
5071 | if (pipe(pip) < 0) | 5355 | if (pipe(pip) < 0) |
5072 | ash_msg_and_raise_error("pipe call failed"); | 5356 | ash_msg_and_raise_error("pipe call failed"); |
@@ -5077,6 +5361,15 @@ openhere(union node *redir) | |||
5077 | goto out; | 5361 | goto out; |
5078 | } | 5362 | } |
5079 | } | 5363 | } |
5364 | #if ENABLE_PLATFORM_MINGW32 | ||
5365 | memset(&fs, 0, sizeof(fs)); | ||
5366 | fs.fpid = FS_OPENHERE; | ||
5367 | fs.n = redir; | ||
5368 | fs.fd[0] = pip[0]; | ||
5369 | fs.fd[1] = pip[1]; | ||
5370 | if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0) | ||
5371 | ash_msg_and_raise_error("unable to spawn shell"); | ||
5372 | #else | ||
5080 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | 5373 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { |
5081 | /* child */ | 5374 | /* child */ |
5082 | close(pip[0]); | 5375 | close(pip[0]); |
@@ -5091,6 +5384,7 @@ openhere(union node *redir) | |||
5091 | expandhere(redir->nhere.doc, pip[1]); | 5384 | expandhere(redir->nhere.doc, pip[1]); |
5092 | _exit(EXIT_SUCCESS); | 5385 | _exit(EXIT_SUCCESS); |
5093 | } | 5386 | } |
5387 | #endif | ||
5094 | out: | 5388 | out: |
5095 | close(pip[1]); | 5389 | close(pip[1]); |
5096 | return pip[0]; | 5390 | return pip[0]; |
@@ -5103,6 +5397,31 @@ openredirect(union node *redir) | |||
5103 | int f; | 5397 | int f; |
5104 | 5398 | ||
5105 | fname = redir->nfile.expfname; | 5399 | fname = redir->nfile.expfname; |
5400 | #if ENABLE_PLATFORM_MINGW32 | ||
5401 | /* Support for /dev/null */ | ||
5402 | switch (redir->nfile.type) { | ||
5403 | case NFROM: | ||
5404 | if (!strcmp(fname, "/dev/null")) | ||
5405 | return open("nul",O_RDWR); | ||
5406 | if (!strncmp(fname, "/dev/", 5)) { | ||
5407 | ash_msg("Unhandled device %s\n", fname); | ||
5408 | return -1; | ||
5409 | } | ||
5410 | break; | ||
5411 | |||
5412 | case NFROMTO: | ||
5413 | case NTO: | ||
5414 | case NCLOBBER: | ||
5415 | case NAPPEND: | ||
5416 | if (!strcmp(fname, "/dev/null")) | ||
5417 | return open("nul",O_RDWR); | ||
5418 | if (!strncmp(fname, "/dev/", 5)) { | ||
5419 | ash_msg("Unhandled device %s\n", fname); | ||
5420 | return -1; | ||
5421 | } | ||
5422 | break; | ||
5423 | } | ||
5424 | #endif | ||
5106 | switch (redir->nfile.type) { | 5425 | switch (redir->nfile.type) { |
5107 | case NFROM: | 5426 | case NFROM: |
5108 | f = open(fname, O_RDONLY); | 5427 | f = open(fname, O_RDONLY); |
@@ -5135,6 +5454,9 @@ openredirect(union node *redir) | |||
5135 | f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); | 5454 | f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); |
5136 | if (f < 0) | 5455 | if (f < 0) |
5137 | goto ecreate; | 5456 | goto ecreate; |
5457 | #if ENABLE_PLATFORM_MINGW32 | ||
5458 | lseek(f, 0, SEEK_END); | ||
5459 | #endif | ||
5138 | break; | 5460 | break; |
5139 | default: | 5461 | default: |
5140 | #if DEBUG | 5462 | #if DEBUG |
@@ -5838,6 +6160,7 @@ struct backcmd { /* result of evalbackcmd */ | |||
5838 | int fd; /* file descriptor to read from */ | 6160 | int fd; /* file descriptor to read from */ |
5839 | int nleft; /* number of chars in buffer */ | 6161 | int nleft; /* number of chars in buffer */ |
5840 | char *buf; /* buffer */ | 6162 | char *buf; /* buffer */ |
6163 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5841 | struct job *jp; /* job structure for command */ | 6164 | struct job *jp; /* job structure for command */ |
5842 | }; | 6165 | }; |
5843 | 6166 | ||
@@ -5854,6 +6177,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5854 | result->fd = -1; | 6177 | result->fd = -1; |
5855 | result->buf = NULL; | 6178 | result->buf = NULL; |
5856 | result->nleft = 0; | 6179 | result->nleft = 0; |
6180 | IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs))); | ||
5857 | result->jp = NULL; | 6181 | result->jp = NULL; |
5858 | if (n == NULL) | 6182 | if (n == NULL) |
5859 | goto out; | 6183 | goto out; |
@@ -5868,6 +6192,14 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5868 | if (pipe(pip) < 0) | 6192 | if (pipe(pip) < 0) |
5869 | ash_msg_and_raise_error("pipe call failed"); | 6193 | ash_msg_and_raise_error("pipe call failed"); |
5870 | jp = makejob(/*n,*/ 1); | 6194 | jp = makejob(/*n,*/ 1); |
6195 | #if ENABLE_PLATFORM_MINGW32 | ||
6196 | result->fs.fpid = FS_EVALBACKCMD; | ||
6197 | result->fs.n = n; | ||
6198 | result->fs.fd[0] = pip[0]; | ||
6199 | result->fs.fd[1] = pip[1]; | ||
6200 | if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0) | ||
6201 | ash_msg_and_raise_error("unable to spawn shell"); | ||
6202 | #else | ||
5871 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 6203 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
5872 | FORCE_INT_ON; | 6204 | FORCE_INT_ON; |
5873 | close(pip[0]); | 6205 | close(pip[0]); |
@@ -5880,6 +6212,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5880 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ | 6212 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ |
5881 | /* NOTREACHED */ | 6213 | /* NOTREACHED */ |
5882 | } | 6214 | } |
6215 | #endif | ||
5883 | close(pip[1]); | 6216 | close(pip[1]); |
5884 | result->fd = pip[0]; | 6217 | result->fd = pip[0]; |
5885 | result->jp = jp; | 6218 | result->jp = jp; |
@@ -5938,7 +6271,8 @@ expbackq(union node *cmd, int flag) | |||
5938 | 6271 | ||
5939 | /* Eat all trailing newlines */ | 6272 | /* Eat all trailing newlines */ |
5940 | dest = expdest; | 6273 | dest = expdest; |
5941 | for (; dest > (char *)stackblock() && dest[-1] == '\n';) | 6274 | for (; dest > (char *)stackblock() && (dest[-1] == '\n' || |
6275 | (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));) | ||
5942 | STUNPUTC(dest); | 6276 | STUNPUTC(dest); |
5943 | expdest = dest; | 6277 | expdest = dest; |
5944 | 6278 | ||
@@ -7432,6 +7766,15 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** | |||
7432 | } | 7766 | } |
7433 | } | 7767 | } |
7434 | 7768 | ||
7769 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
7770 | /* check if command and executable are both busybox */ | ||
7771 | static int busybox_cmd_and_exe(const char *name) | ||
7772 | { | ||
7773 | return strcmp(name, "busybox") == 0 && | ||
7774 | strcmp(bb_basename(bb_busybox_exec_path), "busybox.exe") == 0; | ||
7775 | } | ||
7776 | #endif | ||
7777 | |||
7435 | /* | 7778 | /* |
7436 | * Exec a program. Never returns. If you change this routine, you may | 7779 | * Exec a program. Never returns. If you change this routine, you may |
7437 | * have to change the find_command routine as well. | 7780 | * have to change the find_command routine as well. |
@@ -7448,7 +7791,7 @@ shellexec(char **argv, const char *path, int idx) | |||
7448 | 7791 | ||
7449 | clearredir(/*drop:*/ 1); | 7792 | clearredir(/*drop:*/ 1); |
7450 | envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); | 7793 | envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); |
7451 | if (strchr(argv[0], '/') != NULL | 7794 | if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\'))) |
7452 | #if ENABLE_FEATURE_SH_STANDALONE | 7795 | #if ENABLE_FEATURE_SH_STANDALONE |
7453 | || (applet_no = find_applet_by_name(argv[0])) >= 0 | 7796 | || (applet_no = find_applet_by_name(argv[0])) >= 0 |
7454 | #endif | 7797 | #endif |
@@ -7462,6 +7805,10 @@ shellexec(char **argv, const char *path, int idx) | |||
7462 | goto try_PATH; | 7805 | goto try_PATH; |
7463 | } | 7806 | } |
7464 | e = errno; | 7807 | e = errno; |
7808 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
7809 | } else if (busybox_cmd_and_exe(argv[0])) { | ||
7810 | tryexec(-1, bb_busybox_exec_path, argv, envp); | ||
7811 | #endif | ||
7465 | } else { | 7812 | } else { |
7466 | try_PATH: | 7813 | try_PATH: |
7467 | e = ENOENT; | 7814 | e = ENOENT; |
@@ -7963,6 +8310,10 @@ static int funcblocksize; /* size of structures in function */ | |||
7963 | static int funcstringsize; /* size of strings in node */ | 8310 | static int funcstringsize; /* size of strings in node */ |
7964 | static void *funcblock; /* block to allocate function from */ | 8311 | static void *funcblock; /* block to allocate function from */ |
7965 | static char *funcstring; /* block to allocate strings from */ | 8312 | static char *funcstring; /* block to allocate strings from */ |
8313 | #if ENABLE_PLATFORM_MINGW32 | ||
8314 | static int nodeptrsize; | ||
8315 | static char **nodeptr; | ||
8316 | #endif | ||
7966 | 8317 | ||
7967 | /* flags in argument to evaltree */ | 8318 | /* flags in argument to evaltree */ |
7968 | #define EV_EXIT 01 /* exit after evaluating tree */ | 8319 | #define EV_EXIT 01 /* exit after evaluating tree */ |
@@ -8008,6 +8359,7 @@ sizenodelist(struct nodelist *lp) | |||
8008 | { | 8359 | { |
8009 | while (lp) { | 8360 | while (lp) { |
8010 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); | 8361 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); |
8362 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8011 | calcsize(lp->n); | 8363 | calcsize(lp->n); |
8012 | lp = lp->next; | 8364 | lp = lp->next; |
8013 | } | 8365 | } |
@@ -8024,15 +8376,18 @@ calcsize(union node *n) | |||
8024 | calcsize(n->ncmd.redirect); | 8376 | calcsize(n->ncmd.redirect); |
8025 | calcsize(n->ncmd.args); | 8377 | calcsize(n->ncmd.args); |
8026 | calcsize(n->ncmd.assign); | 8378 | calcsize(n->ncmd.assign); |
8379 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8027 | break; | 8380 | break; |
8028 | case NPIPE: | 8381 | case NPIPE: |
8029 | sizenodelist(n->npipe.cmdlist); | 8382 | sizenodelist(n->npipe.cmdlist); |
8383 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
8030 | break; | 8384 | break; |
8031 | case NREDIR: | 8385 | case NREDIR: |
8032 | case NBACKGND: | 8386 | case NBACKGND: |
8033 | case NSUBSHELL: | 8387 | case NSUBSHELL: |
8034 | calcsize(n->nredir.redirect); | 8388 | calcsize(n->nredir.redirect); |
8035 | calcsize(n->nredir.n); | 8389 | calcsize(n->nredir.n); |
8390 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8036 | break; | 8391 | break; |
8037 | case NAND: | 8392 | case NAND: |
8038 | case NOR: | 8393 | case NOR: |
@@ -8041,31 +8396,37 @@ calcsize(union node *n) | |||
8041 | case NUNTIL: | 8396 | case NUNTIL: |
8042 | calcsize(n->nbinary.ch2); | 8397 | calcsize(n->nbinary.ch2); |
8043 | calcsize(n->nbinary.ch1); | 8398 | calcsize(n->nbinary.ch1); |
8399 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8044 | break; | 8400 | break; |
8045 | case NIF: | 8401 | case NIF: |
8046 | calcsize(n->nif.elsepart); | 8402 | calcsize(n->nif.elsepart); |
8047 | calcsize(n->nif.ifpart); | 8403 | calcsize(n->nif.ifpart); |
8048 | calcsize(n->nif.test); | 8404 | calcsize(n->nif.test); |
8405 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8049 | break; | 8406 | break; |
8050 | case NFOR: | 8407 | case NFOR: |
8051 | funcstringsize += strlen(n->nfor.var) + 1; | 8408 | funcstringsize += strlen(n->nfor.var) + 1; |
8052 | calcsize(n->nfor.body); | 8409 | calcsize(n->nfor.body); |
8053 | calcsize(n->nfor.args); | 8410 | calcsize(n->nfor.args); |
8411 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8054 | break; | 8412 | break; |
8055 | case NCASE: | 8413 | case NCASE: |
8056 | calcsize(n->ncase.cases); | 8414 | calcsize(n->ncase.cases); |
8057 | calcsize(n->ncase.expr); | 8415 | calcsize(n->ncase.expr); |
8416 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8058 | break; | 8417 | break; |
8059 | case NCLIST: | 8418 | case NCLIST: |
8060 | calcsize(n->nclist.body); | 8419 | calcsize(n->nclist.body); |
8061 | calcsize(n->nclist.pattern); | 8420 | calcsize(n->nclist.pattern); |
8062 | calcsize(n->nclist.next); | 8421 | calcsize(n->nclist.next); |
8422 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8063 | break; | 8423 | break; |
8064 | case NDEFUN: | 8424 | case NDEFUN: |
8065 | case NARG: | 8425 | case NARG: |
8066 | sizenodelist(n->narg.backquote); | 8426 | sizenodelist(n->narg.backquote); |
8067 | funcstringsize += strlen(n->narg.text) + 1; | 8427 | funcstringsize += strlen(n->narg.text) + 1; |
8068 | calcsize(n->narg.next); | 8428 | calcsize(n->narg.next); |
8429 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8069 | break; | 8430 | break; |
8070 | case NTO: | 8431 | case NTO: |
8071 | #if ENABLE_ASH_BASH_COMPAT | 8432 | #if ENABLE_ASH_BASH_COMPAT |
@@ -8077,28 +8438,34 @@ calcsize(union node *n) | |||
8077 | case NAPPEND: | 8438 | case NAPPEND: |
8078 | calcsize(n->nfile.fname); | 8439 | calcsize(n->nfile.fname); |
8079 | calcsize(n->nfile.next); | 8440 | calcsize(n->nfile.next); |
8441 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8080 | break; | 8442 | break; |
8081 | case NTOFD: | 8443 | case NTOFD: |
8082 | case NFROMFD: | 8444 | case NFROMFD: |
8083 | calcsize(n->ndup.vname); | 8445 | calcsize(n->ndup.vname); |
8084 | calcsize(n->ndup.next); | 8446 | calcsize(n->ndup.next); |
8447 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8085 | break; | 8448 | break; |
8086 | case NHERE: | 8449 | case NHERE: |
8087 | case NXHERE: | 8450 | case NXHERE: |
8088 | calcsize(n->nhere.doc); | 8451 | calcsize(n->nhere.doc); |
8089 | calcsize(n->nhere.next); | 8452 | calcsize(n->nhere.next); |
8453 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8090 | break; | 8454 | break; |
8091 | case NNOT: | 8455 | case NNOT: |
8092 | calcsize(n->nnot.com); | 8456 | calcsize(n->nnot.com); |
8457 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
8093 | break; | 8458 | break; |
8094 | }; | 8459 | }; |
8095 | } | 8460 | } |
8096 | 8461 | ||
8097 | static char * | 8462 | static char * |
8098 | nodeckstrdup(char *s) | 8463 | nodeckstrdup(const char *s) |
8099 | { | 8464 | { |
8100 | char *rtn = funcstring; | 8465 | char *rtn = funcstring; |
8101 | 8466 | ||
8467 | if (!s) | ||
8468 | return NULL; | ||
8102 | strcpy(funcstring, s); | 8469 | strcpy(funcstring, s); |
8103 | funcstring += strlen(s) + 1; | 8470 | funcstring += strlen(s) + 1; |
8104 | return rtn; | 8471 | return rtn; |
@@ -8106,6 +8473,18 @@ nodeckstrdup(char *s) | |||
8106 | 8473 | ||
8107 | static union node *copynode(union node *); | 8474 | static union node *copynode(union node *); |
8108 | 8475 | ||
8476 | #if ENABLE_PLATFORM_MINGW32 | ||
8477 | # define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (char *)&(dst);} | ||
8478 | # define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);}} | ||
8479 | # define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);}} | ||
8480 | # define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);*nodeptr++ = (char *)&(dst4);}} | ||
8481 | #else | ||
8482 | # define SAVE_PTR(dst) | ||
8483 | # define SAVE_PTR2(dst,dst2) | ||
8484 | # define SAVE_PTR3(dst,dst2,dst3) | ||
8485 | # define SAVE_PTR4(dst,dst2,dst3,dst4) | ||
8486 | #endif | ||
8487 | |||
8109 | static struct nodelist * | 8488 | static struct nodelist * |
8110 | copynodelist(struct nodelist *lp) | 8489 | copynodelist(struct nodelist *lp) |
8111 | { | 8490 | { |
@@ -8117,6 +8496,7 @@ copynodelist(struct nodelist *lp) | |||
8117 | *lpp = funcblock; | 8496 | *lpp = funcblock; |
8118 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); | 8497 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); |
8119 | (*lpp)->n = copynode(lp->n); | 8498 | (*lpp)->n = copynode(lp->n); |
8499 | SAVE_PTR2((*lpp)->n, (*lpp)->next); | ||
8120 | lp = lp->next; | 8500 | lp = lp->next; |
8121 | lpp = &(*lpp)->next; | 8501 | lpp = &(*lpp)->next; |
8122 | } | 8502 | } |
@@ -8139,16 +8519,19 @@ copynode(union node *n) | |||
8139 | new->ncmd.redirect = copynode(n->ncmd.redirect); | 8519 | new->ncmd.redirect = copynode(n->ncmd.redirect); |
8140 | new->ncmd.args = copynode(n->ncmd.args); | 8520 | new->ncmd.args = copynode(n->ncmd.args); |
8141 | new->ncmd.assign = copynode(n->ncmd.assign); | 8521 | new->ncmd.assign = copynode(n->ncmd.assign); |
8522 | SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign); | ||
8142 | break; | 8523 | break; |
8143 | case NPIPE: | 8524 | case NPIPE: |
8144 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | 8525 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); |
8145 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; | 8526 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; |
8527 | SAVE_PTR(new->npipe.cmdlist); | ||
8146 | break; | 8528 | break; |
8147 | case NREDIR: | 8529 | case NREDIR: |
8148 | case NBACKGND: | 8530 | case NBACKGND: |
8149 | case NSUBSHELL: | 8531 | case NSUBSHELL: |
8150 | new->nredir.redirect = copynode(n->nredir.redirect); | 8532 | new->nredir.redirect = copynode(n->nredir.redirect); |
8151 | new->nredir.n = copynode(n->nredir.n); | 8533 | new->nredir.n = copynode(n->nredir.n); |
8534 | SAVE_PTR2(new->nredir.redirect,new->nredir.n); | ||
8152 | break; | 8535 | break; |
8153 | case NAND: | 8536 | case NAND: |
8154 | case NOR: | 8537 | case NOR: |
@@ -8157,31 +8540,37 @@ copynode(union node *n) | |||
8157 | case NUNTIL: | 8540 | case NUNTIL: |
8158 | new->nbinary.ch2 = copynode(n->nbinary.ch2); | 8541 | new->nbinary.ch2 = copynode(n->nbinary.ch2); |
8159 | new->nbinary.ch1 = copynode(n->nbinary.ch1); | 8542 | new->nbinary.ch1 = copynode(n->nbinary.ch1); |
8543 | SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2); | ||
8160 | break; | 8544 | break; |
8161 | case NIF: | 8545 | case NIF: |
8162 | new->nif.elsepart = copynode(n->nif.elsepart); | 8546 | new->nif.elsepart = copynode(n->nif.elsepart); |
8163 | new->nif.ifpart = copynode(n->nif.ifpart); | 8547 | new->nif.ifpart = copynode(n->nif.ifpart); |
8164 | new->nif.test = copynode(n->nif.test); | 8548 | new->nif.test = copynode(n->nif.test); |
8549 | SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test); | ||
8165 | break; | 8550 | break; |
8166 | case NFOR: | 8551 | case NFOR: |
8167 | new->nfor.var = nodeckstrdup(n->nfor.var); | 8552 | new->nfor.var = nodeckstrdup(n->nfor.var); |
8168 | new->nfor.body = copynode(n->nfor.body); | 8553 | new->nfor.body = copynode(n->nfor.body); |
8169 | new->nfor.args = copynode(n->nfor.args); | 8554 | new->nfor.args = copynode(n->nfor.args); |
8555 | SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args); | ||
8170 | break; | 8556 | break; |
8171 | case NCASE: | 8557 | case NCASE: |
8172 | new->ncase.cases = copynode(n->ncase.cases); | 8558 | new->ncase.cases = copynode(n->ncase.cases); |
8173 | new->ncase.expr = copynode(n->ncase.expr); | 8559 | new->ncase.expr = copynode(n->ncase.expr); |
8560 | SAVE_PTR2(new->ncase.cases,new->ncase.expr); | ||
8174 | break; | 8561 | break; |
8175 | case NCLIST: | 8562 | case NCLIST: |
8176 | new->nclist.body = copynode(n->nclist.body); | 8563 | new->nclist.body = copynode(n->nclist.body); |
8177 | new->nclist.pattern = copynode(n->nclist.pattern); | 8564 | new->nclist.pattern = copynode(n->nclist.pattern); |
8178 | new->nclist.next = copynode(n->nclist.next); | 8565 | new->nclist.next = copynode(n->nclist.next); |
8566 | SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next); | ||
8179 | break; | 8567 | break; |
8180 | case NDEFUN: | 8568 | case NDEFUN: |
8181 | case NARG: | 8569 | case NARG: |
8182 | new->narg.backquote = copynodelist(n->narg.backquote); | 8570 | new->narg.backquote = copynodelist(n->narg.backquote); |
8183 | new->narg.text = nodeckstrdup(n->narg.text); | 8571 | new->narg.text = nodeckstrdup(n->narg.text); |
8184 | new->narg.next = copynode(n->narg.next); | 8572 | new->narg.next = copynode(n->narg.next); |
8573 | SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next); | ||
8185 | break; | 8574 | break; |
8186 | case NTO: | 8575 | case NTO: |
8187 | #if ENABLE_ASH_BASH_COMPAT | 8576 | #if ENABLE_ASH_BASH_COMPAT |
@@ -8194,6 +8583,7 @@ copynode(union node *n) | |||
8194 | new->nfile.fname = copynode(n->nfile.fname); | 8583 | new->nfile.fname = copynode(n->nfile.fname); |
8195 | new->nfile.fd = n->nfile.fd; | 8584 | new->nfile.fd = n->nfile.fd; |
8196 | new->nfile.next = copynode(n->nfile.next); | 8585 | new->nfile.next = copynode(n->nfile.next); |
8586 | SAVE_PTR2(new->nfile.fname,new->nfile.next); | ||
8197 | break; | 8587 | break; |
8198 | case NTOFD: | 8588 | case NTOFD: |
8199 | case NFROMFD: | 8589 | case NFROMFD: |
@@ -8201,15 +8591,18 @@ copynode(union node *n) | |||
8201 | new->ndup.dupfd = n->ndup.dupfd; | 8591 | new->ndup.dupfd = n->ndup.dupfd; |
8202 | new->ndup.fd = n->ndup.fd; | 8592 | new->ndup.fd = n->ndup.fd; |
8203 | new->ndup.next = copynode(n->ndup.next); | 8593 | new->ndup.next = copynode(n->ndup.next); |
8594 | SAVE_PTR2(new->ndup.vname,new->ndup.next); | ||
8204 | break; | 8595 | break; |
8205 | case NHERE: | 8596 | case NHERE: |
8206 | case NXHERE: | 8597 | case NXHERE: |
8207 | new->nhere.doc = copynode(n->nhere.doc); | 8598 | new->nhere.doc = copynode(n->nhere.doc); |
8208 | new->nhere.fd = n->nhere.fd; | 8599 | new->nhere.fd = n->nhere.fd; |
8209 | new->nhere.next = copynode(n->nhere.next); | 8600 | new->nhere.next = copynode(n->nhere.next); |
8601 | SAVE_PTR2(new->nhere.doc,new->nhere.next); | ||
8210 | break; | 8602 | break; |
8211 | case NNOT: | 8603 | case NNOT: |
8212 | new->nnot.com = copynode(n->nnot.com); | 8604 | new->nnot.com = copynode(n->nnot.com); |
8605 | SAVE_PTR(new->nnot.com); | ||
8213 | break; | 8606 | break; |
8214 | }; | 8607 | }; |
8215 | new->type = n->type; | 8608 | new->type = n->type; |
@@ -8232,6 +8625,7 @@ copyfunc(union node *n) | |||
8232 | f = ckmalloc(blocksize + funcstringsize); | 8625 | f = ckmalloc(blocksize + funcstringsize); |
8233 | funcblock = (char *) f + offsetof(struct funcnode, n); | 8626 | funcblock = (char *) f + offsetof(struct funcnode, n); |
8234 | funcstring = (char *) f + blocksize; | 8627 | funcstring = (char *) f + blocksize; |
8628 | IF_PLATFORM_MINGW32(nodeptr = NULL); | ||
8235 | copynode(n); | 8629 | copynode(n); |
8236 | f->count = 0; | 8630 | f->count = 0; |
8237 | return f; | 8631 | return f; |
@@ -8591,6 +8985,7 @@ evalcase(union node *n, int flags) | |||
8591 | static void | 8985 | static void |
8592 | evalsubshell(union node *n, int flags) | 8986 | evalsubshell(union node *n, int flags) |
8593 | { | 8987 | { |
8988 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
8594 | struct job *jp; | 8989 | struct job *jp; |
8595 | int backgnd = (n->type == NBACKGND); | 8990 | int backgnd = (n->type == NBACKGND); |
8596 | int status; | 8991 | int status; |
@@ -8600,12 +8995,22 @@ evalsubshell(union node *n, int flags) | |||
8600 | goto nofork; | 8995 | goto nofork; |
8601 | INT_OFF; | 8996 | INT_OFF; |
8602 | jp = makejob(/*n,*/ 1); | 8997 | jp = makejob(/*n,*/ 1); |
8998 | #if ENABLE_PLATFORM_MINGW32 | ||
8999 | memset(&fs, 0, sizeof(fs)); | ||
9000 | fs.fpid = FS_EVALSUBSHELL; | ||
9001 | fs.n = n; | ||
9002 | fs.flags = flags; | ||
9003 | if (spawn_forkshell(jp, &fs, backgnd) < 0) | ||
9004 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9005 | if ( 0 ) { | ||
9006 | #else | ||
8603 | if (forkshell(jp, n, backgnd) == 0) { | 9007 | if (forkshell(jp, n, backgnd) == 0) { |
8604 | /* child */ | 9008 | /* child */ |
8605 | INT_ON; | 9009 | INT_ON; |
8606 | flags |= EV_EXIT; | 9010 | flags |= EV_EXIT; |
8607 | if (backgnd) | 9011 | if (backgnd) |
8608 | flags &= ~EV_TESTED; | 9012 | flags &= ~EV_TESTED; |
9013 | #endif | ||
8609 | nofork: | 9014 | nofork: |
8610 | redirect(n->nredir.redirect, 0); | 9015 | redirect(n->nredir.redirect, 0); |
8611 | evaltreenr(n->nredir.n, flags); | 9016 | evaltreenr(n->nredir.n, flags); |
@@ -8691,6 +9096,7 @@ expredir(union node *n) | |||
8691 | static void | 9096 | static void |
8692 | evalpipe(union node *n, int flags) | 9097 | evalpipe(union node *n, int flags) |
8693 | { | 9098 | { |
9099 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
8694 | struct job *jp; | 9100 | struct job *jp; |
8695 | struct nodelist *lp; | 9101 | struct nodelist *lp; |
8696 | int pipelen; | 9102 | int pipelen; |
@@ -8714,6 +9120,17 @@ evalpipe(union node *n, int flags) | |||
8714 | ash_msg_and_raise_error("pipe call failed"); | 9120 | ash_msg_and_raise_error("pipe call failed"); |
8715 | } | 9121 | } |
8716 | } | 9122 | } |
9123 | #if ENABLE_PLATFORM_MINGW32 | ||
9124 | memset(&fs, 0, sizeof(fs)); | ||
9125 | fs.fpid = FS_EVALPIPE; | ||
9126 | fs.flags = flags; | ||
9127 | fs.n = lp->n; | ||
9128 | fs.fd[0] = pip[0]; | ||
9129 | fs.fd[1] = pip[1]; | ||
9130 | fs.fd[2] = prevfd; | ||
9131 | if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0) | ||
9132 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9133 | #else | ||
8717 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { | 9134 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { |
8718 | INT_ON; | 9135 | INT_ON; |
8719 | if (pip[1] >= 0) { | 9136 | if (pip[1] >= 0) { |
@@ -8730,6 +9147,7 @@ evalpipe(union node *n, int flags) | |||
8730 | evaltreenr(lp->n, flags); | 9147 | evaltreenr(lp->n, flags); |
8731 | /* never returns */ | 9148 | /* never returns */ |
8732 | } | 9149 | } |
9150 | #endif | ||
8733 | if (prevfd >= 0) | 9151 | if (prevfd >= 0) |
8734 | close(prevfd); | 9152 | close(prevfd); |
8735 | prevfd = pip[0]; | 9153 | prevfd = pip[0]; |
@@ -9215,6 +9633,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
9215 | * as POSIX mandates */ | 9633 | * as POSIX mandates */ |
9216 | return back_exitstatus; | 9634 | return back_exitstatus; |
9217 | } | 9635 | } |
9636 | |||
9218 | static void | 9637 | static void |
9219 | evalcommand(union node *cmd, int flags) | 9638 | evalcommand(union node *cmd, int flags) |
9220 | { | 9639 | { |
@@ -9392,6 +9811,27 @@ evalcommand(union node *cmd, int flags) | |||
9392 | * in a script or a subshell does not need forking, | 9811 | * in a script or a subshell does not need forking, |
9393 | * we can just exec it. | 9812 | * we can just exec it. |
9394 | */ | 9813 | */ |
9814 | #if ENABLE_PLATFORM_MINGW32 | ||
9815 | if (!(flags & EV_EXIT) || trap[0]) { | ||
9816 | /* No, forking off a child is necessary */ | ||
9817 | struct forkshell fs; | ||
9818 | |||
9819 | memset(&fs, 0, sizeof(fs)); | ||
9820 | fs.fpid = FS_SHELLEXEC; | ||
9821 | fs.argv = argv; | ||
9822 | fs.string = (char*)path; | ||
9823 | fs.fd[0] = cmdentry.u.index; | ||
9824 | fs.strlist = varlist.list; | ||
9825 | jp = makejob(/*cmd,*/ 1); | ||
9826 | if (spawn_forkshell(jp, &fs, FORK_FG) < 0) | ||
9827 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9828 | exitstatus = waitforjob(jp); | ||
9829 | INT_ON; | ||
9830 | TRACE(("forked child exited with %d\n", exitstatus)); | ||
9831 | break; | ||
9832 | } | ||
9833 | /* goes through to shellexec() */ | ||
9834 | #else | ||
9395 | if (!(flags & EV_EXIT) || may_have_traps) { | 9835 | if (!(flags & EV_EXIT) || may_have_traps) { |
9396 | /* No, forking off a child is necessary */ | 9836 | /* No, forking off a child is necessary */ |
9397 | INT_OFF; | 9837 | INT_OFF; |
@@ -9407,6 +9847,7 @@ evalcommand(union node *cmd, int flags) | |||
9407 | FORCE_INT_ON; | 9847 | FORCE_INT_ON; |
9408 | /* fall through to exec'ing external program */ | 9848 | /* fall through to exec'ing external program */ |
9409 | } | 9849 | } |
9850 | #endif | ||
9410 | listsetvar(varlist.list, VEXPORT|VSTACK); | 9851 | listsetvar(varlist.list, VEXPORT|VSTACK); |
9411 | shellexec(argv, path, cmdentry.u.index); | 9852 | shellexec(argv, path, cmdentry.u.index); |
9412 | /* NOTREACHED */ | 9853 | /* NOTREACHED */ |
@@ -9794,7 +10235,7 @@ preadbuffer(void) | |||
9794 | more--; | 10235 | more--; |
9795 | 10236 | ||
9796 | c = *q; | 10237 | c = *q; |
9797 | if (c == '\0') { | 10238 | if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) { |
9798 | memmove(q, q + 1, more); | 10239 | memmove(q, q + 1, more); |
9799 | } else { | 10240 | } else { |
9800 | q++; | 10241 | q++; |
@@ -9950,6 +10391,7 @@ popallfiles(void) | |||
9950 | popfile(); | 10391 | popfile(); |
9951 | } | 10392 | } |
9952 | 10393 | ||
10394 | #if !ENABLE_PLATFORM_MINGW32 | ||
9953 | /* | 10395 | /* |
9954 | * Close the file(s) that the shell is reading commands from. Called | 10396 | * Close the file(s) that the shell is reading commands from. Called |
9955 | * after a fork is done. | 10397 | * after a fork is done. |
@@ -9963,6 +10405,7 @@ closescript(void) | |||
9963 | g_parsefile->pf_fd = 0; | 10405 | g_parsefile->pf_fd = 0; |
9964 | } | 10406 | } |
9965 | } | 10407 | } |
10408 | #endif | ||
9966 | 10409 | ||
9967 | /* | 10410 | /* |
9968 | * Like setinputfile, but takes an open file descriptor. Call this with | 10411 | * Like setinputfile, but takes an open file descriptor. Call this with |
@@ -12160,7 +12603,7 @@ find_dot_file(char *name) | |||
12160 | struct stat statb; | 12603 | struct stat statb; |
12161 | 12604 | ||
12162 | /* don't try this for absolute or relative paths */ | 12605 | /* don't try this for absolute or relative paths */ |
12163 | if (strchr(name, '/')) | 12606 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) |
12164 | return name; | 12607 | return name; |
12165 | 12608 | ||
12166 | /* IIRC standards do not say whether . is to be searched. | 12609 | /* IIRC standards do not say whether . is to be searched. |
@@ -12275,10 +12718,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12275 | struct stat statb; | 12718 | struct stat statb; |
12276 | int e; | 12719 | int e; |
12277 | int updatetbl; | 12720 | int updatetbl; |
12721 | IF_PLATFORM_MINGW32(int len;) | ||
12278 | struct builtincmd *bcmd; | 12722 | struct builtincmd *bcmd; |
12279 | 12723 | ||
12280 | /* If name contains a slash, don't use PATH or hash table */ | 12724 | /* If name contains a slash, don't use PATH or hash table */ |
12281 | if (strchr(name, '/') != NULL) { | 12725 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) { |
12282 | entry->u.index = -1; | 12726 | entry->u.index = -1; |
12283 | if (act & DO_ABS) { | 12727 | if (act & DO_ABS) { |
12284 | while (stat(name, &statb) < 0) { | 12728 | while (stat(name, &statb) < 0) { |
@@ -12294,6 +12738,14 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12294 | return; | 12738 | return; |
12295 | } | 12739 | } |
12296 | 12740 | ||
12741 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
12742 | if (busybox_cmd_and_exe(name)) { | ||
12743 | entry->u.index = -1; | ||
12744 | entry->cmdtype = CMDNORMAL; | ||
12745 | return; | ||
12746 | } | ||
12747 | #endif | ||
12748 | |||
12297 | /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ | 12749 | /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ |
12298 | 12750 | ||
12299 | updatetbl = (path == pathval()); | 12751 | updatetbl = (path == pathval()); |
@@ -12385,12 +12837,48 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12385 | } | 12837 | } |
12386 | } | 12838 | } |
12387 | /* if rehash, don't redo absolute path names */ | 12839 | /* if rehash, don't redo absolute path names */ |
12388 | if (fullname[0] == '/' && idx <= prev) { | 12840 | if (is_absolute_path(fullname) && idx <= prev) { |
12389 | if (idx < prev) | 12841 | if (idx < prev) |
12390 | continue; | 12842 | continue; |
12391 | TRACE(("searchexec \"%s\": no change\n", name)); | 12843 | TRACE(("searchexec \"%s\": no change\n", name)); |
12392 | goto success; | 12844 | goto success; |
12393 | } | 12845 | } |
12846 | #if ENABLE_PLATFORM_MINGW32 | ||
12847 | len = strlen(fullname); | ||
12848 | if (len > 4 && | ||
12849 | (!strcasecmp(fullname+len-4, ".exe") || | ||
12850 | !strcasecmp(fullname+len-4, ".com"))) { | ||
12851 | if (stat(fullname, &statb) < 0) { | ||
12852 | if (errno != ENOENT && errno != ENOTDIR) | ||
12853 | e = errno; | ||
12854 | goto loop; | ||
12855 | } | ||
12856 | } | ||
12857 | else { | ||
12858 | /* path_advance() has reserved space for .exe */ | ||
12859 | memcpy(fullname+len, ".exe", 5); | ||
12860 | if (stat(fullname, &statb) < 0) { | ||
12861 | if (errno != ENOENT && errno != ENOTDIR) | ||
12862 | e = errno; | ||
12863 | memcpy(fullname+len, ".com", 5); | ||
12864 | if (stat(fullname, &statb) < 0) { | ||
12865 | if (errno != ENOENT && errno != ENOTDIR) | ||
12866 | e = errno; | ||
12867 | fullname[len] = '\0'; | ||
12868 | if (stat(fullname, &statb) < 0) { | ||
12869 | if (errno != ENOENT && errno != ENOTDIR) | ||
12870 | e = errno; | ||
12871 | goto loop; | ||
12872 | } | ||
12873 | if (!file_is_executable(fullname)) { | ||
12874 | e = ENOEXEC; | ||
12875 | goto loop; | ||
12876 | } | ||
12877 | } | ||
12878 | } | ||
12879 | fullname[len] = '\0'; | ||
12880 | } | ||
12881 | #else | ||
12394 | while (stat(fullname, &statb) < 0) { | 12882 | while (stat(fullname, &statb) < 0) { |
12395 | #ifdef SYSV | 12883 | #ifdef SYSV |
12396 | if (errno == EINTR) | 12884 | if (errno == EINTR) |
@@ -12400,6 +12888,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12400 | e = errno; | 12888 | e = errno; |
12401 | goto loop; | 12889 | goto loop; |
12402 | } | 12890 | } |
12891 | #endif | ||
12403 | e = EACCES; /* if we fail, this will be the error */ | 12892 | e = EACCES; /* if we fail, this will be the error */ |
12404 | if (!S_ISREG(statb.st_mode)) | 12893 | if (!S_ISREG(statb.st_mode)) |
12405 | continue; | 12894 | continue; |
@@ -12908,7 +13397,11 @@ exitshell(void) | |||
12908 | } | 13397 | } |
12909 | 13398 | ||
12910 | static void | 13399 | static void |
13400 | #if ENABLE_PLATFORM_MINGW32 | ||
13401 | init(int xp) | ||
13402 | #else | ||
12911 | init(void) | 13403 | init(void) |
13404 | #endif | ||
12912 | { | 13405 | { |
12913 | /* from input.c: */ | 13406 | /* from input.c: */ |
12914 | /* we will never free this */ | 13407 | /* we will never free this */ |
@@ -12928,6 +13421,86 @@ init(void) | |||
12928 | struct stat st1, st2; | 13421 | struct stat st1, st2; |
12929 | 13422 | ||
12930 | initvar(); | 13423 | initvar(); |
13424 | |||
13425 | #if ENABLE_PLATFORM_MINGW32 | ||
13426 | /* | ||
13427 | * case insensitive env names from Windows world | ||
13428 | * | ||
13429 | * Some standard env names such as PATH is named Path and so on | ||
13430 | * ash itself is case sensitive, so "Path" will confuse it, as | ||
13431 | * MSVC getenv() is case insensitive. | ||
13432 | * | ||
13433 | * We may end up having both Path and PATH. Then Path will be chosen | ||
13434 | * because it appears first. | ||
13435 | */ | ||
13436 | for (envp = environ; envp && *envp; envp++) { | ||
13437 | if (strncasecmp(*envp, "PATH=", 5) == 0 && | ||
13438 | strncmp(*envp, "PATH=", 5) != 0) { | ||
13439 | break; | ||
13440 | } | ||
13441 | } | ||
13442 | |||
13443 | if (envp && *envp) { | ||
13444 | /* | ||
13445 | * If we get here it's because the environment contains a path | ||
13446 | * variable called something other than PATH. This suggests we | ||
13447 | * haven't been invoked from an earlier instance of BusyBox. | ||
13448 | */ | ||
13449 | char *start, *end; | ||
13450 | struct passwd *pw; | ||
13451 | |||
13452 | for (envp = environ; envp && *envp; envp++) { | ||
13453 | if (!(end=strchr(*envp, '='))) | ||
13454 | continue; | ||
13455 | |||
13456 | /* make all variable names uppercase */ | ||
13457 | for (start = *envp;start < end;start++) | ||
13458 | *start = toupper(*start); | ||
13459 | |||
13460 | /* skip conversion of variables known to cause problems */ | ||
13461 | if ( strncmp(*envp, "SYSTEMROOT=", 11) == 0 || | ||
13462 | strncmp(*envp, "COMSPEC=", 8) == 0 ) { | ||
13463 | continue; | ||
13464 | } | ||
13465 | |||
13466 | /* convert backslashes to forward slashes */ | ||
13467 | if (!xp) { | ||
13468 | for ( ++end; *end; ++end ) { | ||
13469 | if ( *end == '\\' ) { | ||
13470 | *end = '/'; | ||
13471 | } | ||
13472 | } | ||
13473 | } | ||
13474 | |||
13475 | /* check for invalid characters */ | ||
13476 | for (start = *envp;start < end;start++) { | ||
13477 | if (!isdigit(*start) && !isalpha(*start) && *start != '_') { | ||
13478 | break; | ||
13479 | } | ||
13480 | } | ||
13481 | |||
13482 | if (start != end) { | ||
13483 | /* | ||
13484 | * Make a copy of the variable, replacing invalid | ||
13485 | * characters in the name with underscores. | ||
13486 | */ | ||
13487 | char *var = xstrdup(*envp); | ||
13488 | |||
13489 | for (start = var;*start != '=';start++) { | ||
13490 | if (!isdigit(*start) && !isalpha(*start)) { | ||
13491 | *start = '_'; | ||
13492 | } | ||
13493 | } | ||
13494 | setvareq(var, VEXPORT|VNOSAVE); | ||
13495 | } | ||
13496 | } | ||
13497 | |||
13498 | /* some initialisation normally performed at login */ | ||
13499 | pw = xgetpwuid(getuid()); | ||
13500 | setup_environment(pw->pw_shell, | ||
13501 | SETUP_ENV_CHANGEENV|SETUP_ENV_NO_CHDIR, pw); | ||
13502 | } | ||
13503 | #endif | ||
12931 | for (envp = environ; envp && *envp; envp++) { | 13504 | for (envp = environ; envp && *envp; envp++) { |
12932 | if (strchr(*envp, '=')) { | 13505 | if (strchr(*envp, '=')) { |
12933 | setvareq(*envp, VEXPORT|VTEXTFIXED); | 13506 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
@@ -13143,15 +13716,40 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13143 | #endif | 13716 | #endif |
13144 | rootpid = getpid(); | 13717 | rootpid = getpid(); |
13145 | 13718 | ||
13146 | init(); | 13719 | init(IF_PLATFORM_MINGW32(argc >= 2 && strcmp(argv[1], "-X") == 0)); |
13147 | setstackmark(&smark); | 13720 | setstackmark(&smark); |
13721 | |||
13722 | #if ENABLE_PLATFORM_MINGW32 | ||
13723 | hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL); | ||
13724 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
13725 | if (argc == 3 && !strcmp(argv[1], "--forkshell")) { | ||
13726 | forkshell_init(argv[2]); | ||
13727 | |||
13728 | /* NOTREACHED */ | ||
13729 | bb_error_msg_and_die("subshell ended unexpectedly"); | ||
13730 | } | ||
13731 | #endif | ||
13148 | procargs(argv); | 13732 | procargs(argv); |
13733 | #if ENABLE_PLATFORM_MINGW32 | ||
13734 | if ( noconsole ) { | ||
13735 | DWORD dummy; | ||
13736 | |||
13737 | if ( GetConsoleProcessList(&dummy, 1) == 1 ) { | ||
13738 | ShowWindow(GetConsoleWindow(), SW_HIDE); | ||
13739 | } | ||
13740 | } | ||
13741 | #endif | ||
13149 | 13742 | ||
13150 | if (argv[0] && argv[0][0] == '-') | 13743 | if (argv[0] && argv[0][0] == '-') |
13151 | isloginsh = 1; | 13744 | isloginsh = 1; |
13152 | if (isloginsh) { | 13745 | if (isloginsh) { |
13153 | const char *hp; | 13746 | const char *hp; |
13154 | 13747 | ||
13748 | #if ENABLE_PLATFORM_MINGW32 | ||
13749 | chdir(xgetpwuid(getuid())->pw_dir); | ||
13750 | setpwd(NULL, 0); | ||
13751 | #endif | ||
13752 | |||
13155 | state = 1; | 13753 | state = 1; |
13156 | read_profile("/etc/profile"); | 13754 | read_profile("/etc/profile"); |
13157 | state1: | 13755 | state1: |
@@ -13227,6 +13825,644 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13227 | /* NOTREACHED */ | 13825 | /* NOTREACHED */ |
13228 | } | 13826 | } |
13229 | 13827 | ||
13828 | #if ENABLE_PLATFORM_MINGW32 | ||
13829 | static void | ||
13830 | forkshell_openhere(struct forkshell *fs) | ||
13831 | { | ||
13832 | union node *redir = fs->n; | ||
13833 | int pip[2]; | ||
13834 | |||
13835 | pip[0] = fs->fd[0]; | ||
13836 | pip[1] = fs->fd[1]; | ||
13837 | |||
13838 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
13839 | |||
13840 | close(pip[0]); | ||
13841 | ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); | ||
13842 | ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); | ||
13843 | ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); | ||
13844 | ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); | ||
13845 | signal(SIGPIPE, SIG_DFL); | ||
13846 | if (redir->type == NHERE) { | ||
13847 | size_t len = strlen(redir->nhere.doc->narg.text); | ||
13848 | full_write(pip[1], redir->nhere.doc->narg.text, len); | ||
13849 | } else /* NXHERE */ | ||
13850 | expandhere(redir->nhere.doc, pip[1]); | ||
13851 | _exit(EXIT_SUCCESS); | ||
13852 | } | ||
13853 | |||
13854 | static void | ||
13855 | forkshell_evalbackcmd(struct forkshell *fs) | ||
13856 | { | ||
13857 | union node *n = fs->n; | ||
13858 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
13859 | |||
13860 | FORCE_INT_ON; | ||
13861 | close(pip[0]); | ||
13862 | if (pip[1] != 1) { | ||
13863 | /*close(1);*/ | ||
13864 | copyfd(pip[1], 1 | COPYFD_EXACT); | ||
13865 | close(pip[1]); | ||
13866 | } | ||
13867 | eflag = 0; | ||
13868 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ | ||
13869 | /* NOTREACHED */ | ||
13870 | } | ||
13871 | |||
13872 | static void | ||
13873 | forkshell_evalsubshell(struct forkshell *fs) | ||
13874 | { | ||
13875 | union node *n = fs->n; | ||
13876 | int flags = fs->flags; | ||
13877 | |||
13878 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
13879 | INT_ON; | ||
13880 | flags |= EV_EXIT; | ||
13881 | expredir(n->nredir.redirect); | ||
13882 | redirect(n->nredir.redirect, 0); | ||
13883 | evaltreenr(n->nredir.n, flags); | ||
13884 | /* never returns */ | ||
13885 | } | ||
13886 | |||
13887 | static void | ||
13888 | forkshell_evalpipe(struct forkshell *fs) | ||
13889 | { | ||
13890 | union node *n = fs->n; | ||
13891 | int flags = fs->flags; | ||
13892 | int prevfd = fs->fd[2]; | ||
13893 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
13894 | |||
13895 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
13896 | INT_ON; | ||
13897 | if (pip[1] >= 0) { | ||
13898 | close(pip[0]); | ||
13899 | } | ||
13900 | if (prevfd > 0) { | ||
13901 | dup2(prevfd, 0); | ||
13902 | close(prevfd); | ||
13903 | } | ||
13904 | if (pip[1] > 1) { | ||
13905 | dup2(pip[1], 1); | ||
13906 | close(pip[1]); | ||
13907 | } | ||
13908 | evaltreenr(n, flags); | ||
13909 | } | ||
13910 | |||
13911 | static void | ||
13912 | forkshell_shellexec(struct forkshell *fs) | ||
13913 | { | ||
13914 | int idx = fs->fd[0]; | ||
13915 | struct strlist *varlist = fs->strlist; | ||
13916 | char **argv = fs->argv; | ||
13917 | char *path = fs->string; | ||
13918 | |||
13919 | listsetvar(varlist, VEXPORT|VSTACK); | ||
13920 | shellexec(argv, path, idx); | ||
13921 | } | ||
13922 | |||
13923 | static void | ||
13924 | forkshell_child(struct forkshell *fs) | ||
13925 | { | ||
13926 | switch ( fs->fpid ) { | ||
13927 | case FS_OPENHERE: | ||
13928 | forkshell_openhere(fs); | ||
13929 | break; | ||
13930 | case FS_EVALBACKCMD: | ||
13931 | forkshell_evalbackcmd(fs); | ||
13932 | break; | ||
13933 | case FS_EVALSUBSHELL: | ||
13934 | forkshell_evalsubshell(fs); | ||
13935 | break; | ||
13936 | case FS_EVALPIPE: | ||
13937 | forkshell_evalpipe(fs); | ||
13938 | break; | ||
13939 | case FS_SHELLEXEC: | ||
13940 | forkshell_shellexec(fs); | ||
13941 | break; | ||
13942 | } | ||
13943 | } | ||
13944 | |||
13945 | /* | ||
13946 | * Reset the pointers to the builtin environment variables in the hash | ||
13947 | * table to point to varinit rather than the bogus copy created during | ||
13948 | * forkshell_prepare. | ||
13949 | */ | ||
13950 | static void | ||
13951 | reinitvar(void) | ||
13952 | { | ||
13953 | struct var *vp; | ||
13954 | struct var *end; | ||
13955 | struct var **vpp; | ||
13956 | struct var **old; | ||
13957 | |||
13958 | vp = varinit; | ||
13959 | end = vp + ARRAY_SIZE(varinit); | ||
13960 | do { | ||
13961 | vpp = hashvar(vp->var_text); | ||
13962 | if ( (old=findvar(vpp, vp->var_text)) != NULL ) { | ||
13963 | vp->next = (*old)->next; | ||
13964 | *old = vp; | ||
13965 | } | ||
13966 | } while (++vp < end); | ||
13967 | } | ||
13968 | |||
13969 | /* FIXME: should consider running forkparent() and forkchild() */ | ||
13970 | static int | ||
13971 | spawn_forkshell(struct job *jp, struct forkshell *fs, int mode) | ||
13972 | { | ||
13973 | struct forkshell *new; | ||
13974 | char buf[16]; | ||
13975 | const char *argv[] = { "sh", "--forkshell", NULL, NULL }; | ||
13976 | pid_t pid; | ||
13977 | |||
13978 | new = forkshell_prepare(fs); | ||
13979 | sprintf(buf, "%x", (unsigned int)new->hMapFile); | ||
13980 | argv[2] = buf; | ||
13981 | pid = mingw_spawn_applet(P_NOWAIT, "sh", argv, | ||
13982 | (const char *const *)environ); | ||
13983 | CloseHandle(new->hMapFile); | ||
13984 | UnmapViewOfFile(new); | ||
13985 | if (pid == -1) { | ||
13986 | free(jp); | ||
13987 | return -1; | ||
13988 | } | ||
13989 | forkparent(jp, fs->node, mode, pid); | ||
13990 | return pid; | ||
13991 | } | ||
13992 | |||
13993 | /* | ||
13994 | * forkshell_prepare() and friends | ||
13995 | * | ||
13996 | * The sequence is as follows: | ||
13997 | * - funcblocksize, funcstringsize, nodeptrsize are initialized | ||
13998 | * - forkshell_size(fs) is called to calculate the exact memory needed | ||
13999 | * - a new struct is allocated | ||
14000 | * - funcblock, funcstring, nodeptr are initialized from the new block | ||
14001 | * - forkshell_copy(fs) is called to copy recursively everything over | ||
14002 | * it will record all pointers along the way, to nodeptr | ||
14003 | * | ||
14004 | * When this memory is mapped elsewhere, pointer fixup will be needed | ||
14005 | */ | ||
14006 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
14007 | static void \ | ||
14008 | name(type *p) \ | ||
14009 | { \ | ||
14010 | while (p) { \ | ||
14011 | funcblocksize += sizeof(type); | ||
14012 | /* do something here with p */ | ||
14013 | #define SLIST_SIZE_END() \ | ||
14014 | nodeptrsize++; \ | ||
14015 | p = p->next; \ | ||
14016 | } \ | ||
14017 | } | ||
14018 | |||
14019 | #define SLIST_COPY_BEGIN(name,type) \ | ||
14020 | static type * \ | ||
14021 | name(type *vp) \ | ||
14022 | { \ | ||
14023 | type *start; \ | ||
14024 | type **vpp; \ | ||
14025 | vpp = &start; \ | ||
14026 | while (vp) { \ | ||
14027 | *vpp = funcblock; \ | ||
14028 | funcblock = (char *) funcblock + sizeof(type); | ||
14029 | /* do something here with vpp and vp */ | ||
14030 | #define SLIST_COPY_END() \ | ||
14031 | SAVE_PTR((*vpp)->next); \ | ||
14032 | vp = vp->next; \ | ||
14033 | vpp = &(*vpp)->next; \ | ||
14034 | } \ | ||
14035 | *vpp = NULL; \ | ||
14036 | return start; \ | ||
14037 | } | ||
14038 | |||
14039 | /* | ||
14040 | * struct var | ||
14041 | */ | ||
14042 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
14043 | funcstringsize += strlen(p->var_text) + 1; | ||
14044 | nodeptrsize++; /* p->text */ | ||
14045 | SLIST_SIZE_END() | ||
14046 | |||
14047 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
14048 | (*vpp)->var_text = nodeckstrdup(vp->var_text); | ||
14049 | (*vpp)->flags = vp->flags; | ||
14050 | /* | ||
14051 | * The only place that can set struct var#func is varinit[], | ||
14052 | * which will be fixed by forkshell_init() | ||
14053 | */ | ||
14054 | (*vpp)->var_func = NULL; | ||
14055 | SAVE_PTR((*vpp)->var_text); | ||
14056 | SLIST_COPY_END() | ||
14057 | |||
14058 | /* | ||
14059 | * struct strlist | ||
14060 | */ | ||
14061 | SLIST_SIZE_BEGIN(strlist_size,struct strlist) | ||
14062 | funcstringsize += strlen(p->text) + 1; | ||
14063 | nodeptrsize++; /* p->text */ | ||
14064 | SLIST_SIZE_END() | ||
14065 | |||
14066 | SLIST_COPY_BEGIN(strlist_copy,struct strlist) | ||
14067 | (*vpp)->text = nodeckstrdup(vp->text); | ||
14068 | SAVE_PTR((*vpp)->text); | ||
14069 | SLIST_COPY_END() | ||
14070 | |||
14071 | /* | ||
14072 | * struct tblentry | ||
14073 | */ | ||
14074 | static void | ||
14075 | tblentry_size(struct tblentry *tep) | ||
14076 | { | ||
14077 | while (tep) { | ||
14078 | funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
14079 | /* CMDBUILTIN, e->param.cmd needs no pointer relocation */ | ||
14080 | if (tep->cmdtype == CMDFUNCTION) { | ||
14081 | funcblocksize += offsetof(struct funcnode, n); | ||
14082 | calcsize(&tep->param.func->n); | ||
14083 | nodeptrsize++; /* tep->param.func */ | ||
14084 | } | ||
14085 | nodeptrsize++; /* tep->next */ | ||
14086 | tep = tep->next; | ||
14087 | } | ||
14088 | } | ||
14089 | |||
14090 | static struct tblentry * | ||
14091 | tblentry_copy(struct tblentry *tep) | ||
14092 | { | ||
14093 | struct tblentry *start; | ||
14094 | struct tblentry **newp; | ||
14095 | int size; | ||
14096 | |||
14097 | newp = &start; | ||
14098 | while (tep) { | ||
14099 | *newp = funcblock; | ||
14100 | size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
14101 | |||
14102 | funcblock = (char *) funcblock + size; | ||
14103 | memcpy(*newp, tep, size); | ||
14104 | switch (tep->cmdtype) { | ||
14105 | case CMDBUILTIN: | ||
14106 | /* No pointer saving, this field must be fixed by forkshell_init() */ | ||
14107 | (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab); | ||
14108 | break; | ||
14109 | case CMDFUNCTION: | ||
14110 | (*newp)->param.func = funcblock; | ||
14111 | funcblock = (char *) funcblock + offsetof(struct funcnode, n); | ||
14112 | copynode(&tep->param.func->n); | ||
14113 | SAVE_PTR((*newp)->param.func); | ||
14114 | break; | ||
14115 | default: | ||
14116 | break; | ||
14117 | } | ||
14118 | SAVE_PTR((*newp)->next); | ||
14119 | tep = tep->next; | ||
14120 | newp = &(*newp)->next; | ||
14121 | } | ||
14122 | *newp = NULL; | ||
14123 | return start; | ||
14124 | } | ||
14125 | |||
14126 | static void | ||
14127 | cmdtable_size(struct tblentry **cmdtablep) | ||
14128 | { | ||
14129 | int i; | ||
14130 | nodeptrsize += CMDTABLESIZE; | ||
14131 | funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE; | ||
14132 | for (i = 0; i < CMDTABLESIZE; i++) | ||
14133 | tblentry_size(cmdtablep[i]); | ||
14134 | } | ||
14135 | |||
14136 | static struct tblentry ** | ||
14137 | cmdtable_copy(struct tblentry **cmdtablep) | ||
14138 | { | ||
14139 | struct tblentry **new = funcblock; | ||
14140 | int i; | ||
14141 | |||
14142 | funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE; | ||
14143 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
14144 | new[i] = tblentry_copy(cmdtablep[i]); | ||
14145 | SAVE_PTR(new[i]); | ||
14146 | } | ||
14147 | return new; | ||
14148 | } | ||
14149 | |||
14150 | /* | ||
14151 | * char ** | ||
14152 | */ | ||
14153 | static void | ||
14154 | argv_size(char **p) | ||
14155 | { | ||
14156 | while (p && *p) { | ||
14157 | funcblocksize += sizeof(char *); | ||
14158 | funcstringsize += strlen(*p)+1; | ||
14159 | nodeptrsize++; | ||
14160 | p++; | ||
14161 | } | ||
14162 | funcblocksize += sizeof(char *); | ||
14163 | } | ||
14164 | |||
14165 | static char ** | ||
14166 | argv_copy(char **p) | ||
14167 | { | ||
14168 | char **new, **start = funcblock; | ||
14169 | |||
14170 | while (p && *p) { | ||
14171 | new = funcblock; | ||
14172 | funcblock = (char *) funcblock + sizeof(char *); | ||
14173 | *new = nodeckstrdup(*p); | ||
14174 | SAVE_PTR(*new); | ||
14175 | p++; | ||
14176 | new++; | ||
14177 | } | ||
14178 | new = funcblock; | ||
14179 | funcblock = (char *) funcblock + sizeof(char *); | ||
14180 | *new = NULL; | ||
14181 | return start; | ||
14182 | } | ||
14183 | |||
14184 | /* | ||
14185 | * struct redirtab | ||
14186 | */ | ||
14187 | static void | ||
14188 | redirtab_size(struct redirtab *rdtp) | ||
14189 | { | ||
14190 | while (rdtp) { | ||
14191 | funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
14192 | rdtp = rdtp->next; | ||
14193 | nodeptrsize++; /* rdtp->next */ | ||
14194 | } | ||
14195 | } | ||
14196 | |||
14197 | static struct redirtab * | ||
14198 | redirtab_copy(struct redirtab *rdtp) | ||
14199 | { | ||
14200 | struct redirtab *start; | ||
14201 | struct redirtab **vpp; | ||
14202 | |||
14203 | vpp = &start; | ||
14204 | while (rdtp) { | ||
14205 | int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
14206 | *vpp = funcblock; | ||
14207 | funcblock = (char *) funcblock + size; | ||
14208 | memcpy(*vpp, rdtp, size); | ||
14209 | SAVE_PTR((*vpp)->next); | ||
14210 | rdtp = rdtp->next; | ||
14211 | vpp = &(*vpp)->next; | ||
14212 | } | ||
14213 | *vpp = NULL; | ||
14214 | return start; | ||
14215 | } | ||
14216 | |||
14217 | #undef shellparam | ||
14218 | #undef redirlist | ||
14219 | #undef varinit | ||
14220 | #undef vartab | ||
14221 | static void | ||
14222 | globals_var_size(struct globals_var *gvp) | ||
14223 | { | ||
14224 | int i; | ||
14225 | |||
14226 | funcblocksize += sizeof(struct globals_var); | ||
14227 | argv_size(gvp->shellparam.p); | ||
14228 | redirtab_size(gvp->redirlist); | ||
14229 | for (i = 0; i < VTABSIZE; i++) | ||
14230 | var_size(gvp->vartab[i]); | ||
14231 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
14232 | var_size(gvp->varinit+i); | ||
14233 | nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */ | ||
14234 | } | ||
14235 | |||
14236 | #undef g_nullredirs | ||
14237 | #undef preverrout_fd | ||
14238 | static struct globals_var * | ||
14239 | globals_var_copy(struct globals_var *gvp) | ||
14240 | { | ||
14241 | int i; | ||
14242 | struct globals_var *new; | ||
14243 | |||
14244 | new = funcblock; | ||
14245 | funcblock = (char *) funcblock + sizeof(struct globals_var); | ||
14246 | |||
14247 | /* shparam */ | ||
14248 | memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam)); | ||
14249 | new->shellparam.malloced = 0; | ||
14250 | new->shellparam.p = argv_copy(gvp->shellparam.p); | ||
14251 | SAVE_PTR(new->shellparam.p); | ||
14252 | |||
14253 | new->redirlist = redirtab_copy(gvp->redirlist); | ||
14254 | SAVE_PTR(new->redirlist); | ||
14255 | |||
14256 | new->g_nullredirs = gvp->g_nullredirs; | ||
14257 | new->preverrout_fd = gvp->preverrout_fd; | ||
14258 | for (i = 0; i < VTABSIZE; i++) { | ||
14259 | new->vartab[i] = var_copy(gvp->vartab[i]); | ||
14260 | SAVE_PTR(new->vartab[i]); | ||
14261 | } | ||
14262 | |||
14263 | /* Can't use var_copy because varinit is already allocated */ | ||
14264 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { | ||
14265 | new->varinit[i].next = NULL; | ||
14266 | new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text); | ||
14267 | SAVE_PTR(new->varinit[i].var_text); | ||
14268 | new->varinit[i].flags = gvp->varinit[i].flags; | ||
14269 | new->varinit[i].var_func = gvp->varinit[i].var_func; | ||
14270 | } | ||
14271 | return new; | ||
14272 | } | ||
14273 | |||
14274 | #undef minusc | ||
14275 | #undef curdir | ||
14276 | #undef physdir | ||
14277 | #undef arg0 | ||
14278 | #undef nullstr | ||
14279 | static void | ||
14280 | globals_misc_size(struct globals_misc *p) | ||
14281 | { | ||
14282 | funcblocksize += sizeof(struct globals_misc); | ||
14283 | funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1; | ||
14284 | if (p->curdir != p->nullstr) | ||
14285 | funcstringsize += strlen(p->curdir) + 1; | ||
14286 | if (p->physdir != p->nullstr) | ||
14287 | funcstringsize += strlen(p->physdir) + 1; | ||
14288 | funcstringsize += strlen(p->arg0) + 1; | ||
14289 | nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */ | ||
14290 | } | ||
14291 | |||
14292 | static struct globals_misc * | ||
14293 | globals_misc_copy(struct globals_misc *p) | ||
14294 | { | ||
14295 | struct globals_misc *new = funcblock; | ||
14296 | |||
14297 | funcblock = (char *) funcblock + sizeof(struct globals_misc); | ||
14298 | memcpy(new, p, sizeof(struct globals_misc)); | ||
14299 | |||
14300 | new->minusc = nodeckstrdup(p->minusc); | ||
14301 | new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr; | ||
14302 | new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr; | ||
14303 | new->arg0 = nodeckstrdup(p->arg0); | ||
14304 | SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0); | ||
14305 | return new; | ||
14306 | } | ||
14307 | |||
14308 | static void | ||
14309 | forkshell_size(struct forkshell *fs) | ||
14310 | { | ||
14311 | funcblocksize += sizeof(struct forkshell); | ||
14312 | globals_var_size(fs->gvp); | ||
14313 | globals_misc_size(fs->gmp); | ||
14314 | cmdtable_size(fs->cmdtable); | ||
14315 | /* optlist_transfer(sending, fd); */ | ||
14316 | /* misc_transfer(sending, fd); */ | ||
14317 | |||
14318 | calcsize(fs->n); | ||
14319 | argv_size(fs->argv); | ||
14320 | funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1; | ||
14321 | strlist_size(fs->strlist); | ||
14322 | |||
14323 | nodeptrsize += 7; /* gvp, gmp, cmdtable, n, argv, string, strlist */ | ||
14324 | } | ||
14325 | |||
14326 | static struct forkshell * | ||
14327 | forkshell_copy(struct forkshell *fs) | ||
14328 | { | ||
14329 | struct forkshell *new; | ||
14330 | |||
14331 | new = funcblock; | ||
14332 | funcblock = (char *) funcblock + sizeof(struct forkshell); | ||
14333 | |||
14334 | memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */ | ||
14335 | new->gvp = globals_var_copy(fs->gvp); | ||
14336 | new->gmp = globals_misc_copy(fs->gmp); | ||
14337 | new->cmdtable = cmdtable_copy(fs->cmdtable); | ||
14338 | SAVE_PTR3(new->gvp, new->gmp, new->cmdtable); | ||
14339 | |||
14340 | new->n = copynode(fs->n); | ||
14341 | new->argv = argv_copy(fs->argv); | ||
14342 | new->string = nodeckstrdup(fs->string); | ||
14343 | new->strlist = strlist_copy(fs->strlist); | ||
14344 | SAVE_PTR4(new->n, new->argv, new->string, new->strlist); | ||
14345 | return new; | ||
14346 | } | ||
14347 | |||
14348 | static struct forkshell * | ||
14349 | forkshell_prepare(struct forkshell *fs) | ||
14350 | { | ||
14351 | struct forkshell *new; | ||
14352 | int size, nodeptr_offset; | ||
14353 | HANDLE h; | ||
14354 | SECURITY_ATTRIBUTES sa; | ||
14355 | |||
14356 | /* Calculate size of "new" */ | ||
14357 | fs->gvp = ash_ptr_to_globals_var; | ||
14358 | fs->gmp = ash_ptr_to_globals_misc; | ||
14359 | fs->cmdtable = cmdtable; | ||
14360 | |||
14361 | nodeptrsize = 1; /* NULL terminated */ | ||
14362 | funcblocksize = 0; | ||
14363 | funcstringsize = 0; | ||
14364 | forkshell_size(fs); | ||
14365 | size = funcblocksize + funcstringsize + nodeptrsize*sizeof(char *); | ||
14366 | |||
14367 | /* Allocate, initialize pointers */ | ||
14368 | memset(&sa, 0, sizeof(sa)); | ||
14369 | sa.nLength = sizeof(sa); | ||
14370 | sa.lpSecurityDescriptor = NULL; | ||
14371 | sa.bInheritHandle = TRUE; | ||
14372 | h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL); | ||
14373 | new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
14374 | /* new = ckmalloc(size); */ | ||
14375 | funcblock = new; | ||
14376 | funcstring = (char *) funcblock + funcblocksize; | ||
14377 | nodeptr = (char **)((char *)funcstring + funcstringsize); | ||
14378 | nodeptr_offset = (char *)nodeptr - (char *)new; | ||
14379 | |||
14380 | /* Now pack them all */ | ||
14381 | forkshell_copy(fs); | ||
14382 | |||
14383 | /* Finish it up */ | ||
14384 | *nodeptr = NULL; | ||
14385 | new->size = size; | ||
14386 | new->nodeptr_offset = nodeptr_offset; | ||
14387 | new->old_base = new; | ||
14388 | new->hMapFile = h; | ||
14389 | return new; | ||
14390 | } | ||
14391 | |||
14392 | #undef exception_handler | ||
14393 | #undef trap | ||
14394 | #undef trap_ptr | ||
14395 | static void *sticky_mem_start, *sticky_mem_end; | ||
14396 | static void | ||
14397 | forkshell_init(const char *idstr) | ||
14398 | { | ||
14399 | struct forkshell *fs; | ||
14400 | int map_handle; | ||
14401 | HANDLE h; | ||
14402 | struct globals_var **gvpp; | ||
14403 | struct globals_misc **gmpp; | ||
14404 | int i; | ||
14405 | char **ptr; | ||
14406 | |||
14407 | if (sscanf(idstr, "%x", &map_handle) != 1) | ||
14408 | bb_error_msg_and_die("invalid forkshell ID"); | ||
14409 | |||
14410 | h = (HANDLE)map_handle; | ||
14411 | fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
14412 | if (!fs) | ||
14413 | bb_error_msg_and_die("Invalid forkshell memory"); | ||
14414 | |||
14415 | /* this memory can't be freed */ | ||
14416 | sticky_mem_start = fs; | ||
14417 | sticky_mem_end = (char *) fs + fs->size; | ||
14418 | |||
14419 | /* pointer fixup */ | ||
14420 | nodeptr = (char **)((char *)fs + fs->nodeptr_offset); | ||
14421 | for ( i=0; nodeptr[i]; ++i ) { | ||
14422 | ptr = (char **)((char *)fs + (nodeptr[i] - (char *)fs->old_base)); | ||
14423 | if (*ptr) | ||
14424 | *ptr = (char *)fs + (*ptr - (char *)fs->old_base); | ||
14425 | } | ||
14426 | |||
14427 | /* Now fix up stuff that can't be transferred */ | ||
14428 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
14429 | fs->gvp->varinit[i].var_func = varinit_data[i].var_func; | ||
14430 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
14431 | struct tblentry *e = fs->cmdtable[i]; | ||
14432 | while (e) { | ||
14433 | if (e->cmdtype == CMDBUILTIN) | ||
14434 | e->param.cmd = builtintab + (int)e->param.cmd; | ||
14435 | e = e->next; | ||
14436 | } | ||
14437 | } | ||
14438 | fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler; | ||
14439 | for (i = 0; i < NSIG; i++) | ||
14440 | fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i]; | ||
14441 | fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr; | ||
14442 | |||
14443 | /* Switch global variables */ | ||
14444 | gvpp = (struct globals_var **)&ash_ptr_to_globals_var; | ||
14445 | *gvpp = fs->gvp; | ||
14446 | gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc; | ||
14447 | *gmpp = fs->gmp; | ||
14448 | cmdtable = fs->cmdtable; | ||
14449 | |||
14450 | CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */ | ||
14451 | |||
14452 | reinitvar(); | ||
14453 | |||
14454 | forkshell_child(fs); | ||
14455 | } | ||
14456 | |||
14457 | #undef free | ||
14458 | static void | ||
14459 | sticky_free(void *base) | ||
14460 | { | ||
14461 | if (base >= sticky_mem_start && base < sticky_mem_end) | ||
14462 | return; | ||
14463 | free(base); | ||
14464 | } | ||
14465 | #endif | ||
13230 | 14466 | ||
13231 | /*- | 14467 | /*- |
13232 | * Copyright (c) 1989, 1991, 1993, 1994 | 14468 | * Copyright (c) 1989, 1991, 1993, 1994 |