diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 1197 |
1 files changed, 1186 insertions, 11 deletions
diff --git a/shell/ash.c b/shell/ash.c index 90fb00fbd..b95356034 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,9 @@ 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 | #endif | ||
236 | }; | 301 | }; |
237 | 302 | ||
238 | #define optletters(n) optletters_optnames[n][0] | 303 | #define optletters(n) optletters_optnames[n][0] |
@@ -313,6 +378,9 @@ struct globals_misc { | |||
313 | # define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] | 378 | # define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] |
314 | # define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] | 379 | # define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] |
315 | #endif | 380 | #endif |
381 | #if ENABLE_PLATFORM_MINGW32 | ||
382 | # define noconsole optlist[14 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG] | ||
383 | #endif | ||
316 | 384 | ||
317 | /* trap handler commands */ | 385 | /* trap handler commands */ |
318 | /* | 386 | /* |
@@ -2393,10 +2461,22 @@ path_advance(const char **path, const char *name) | |||
2393 | if (*path == NULL) | 2461 | if (*path == NULL) |
2394 | return NULL; | 2462 | return NULL; |
2395 | start = *path; | 2463 | start = *path; |
2464 | #if ENABLE_PLATFORM_MINGW32 | ||
2465 | p = next_path_sep(start); | ||
2466 | q = strchr(start, '%'); | ||
2467 | if ((p && q && q < p) || (!p && q)) | ||
2468 | p = q; | ||
2469 | if (!p) | ||
2470 | for (p = start; *p; p++) | ||
2471 | continue; | ||
2472 | #else | ||
2396 | for (p = start; *p && *p != ':' && *p != '%'; p++) | 2473 | for (p = start; *p && *p != ':' && *p != '%'; p++) |
2397 | continue; | 2474 | continue; |
2475 | #endif | ||
2398 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ | 2476 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ |
2399 | while (stackblocksize() < len) | 2477 | |
2478 | /* preserve space for .exe too */ | ||
2479 | while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len)) | ||
2400 | growstackblock(); | 2480 | growstackblock(); |
2401 | q = stackblock(); | 2481 | q = stackblock(); |
2402 | if (p != start) { | 2482 | if (p != start) { |
@@ -2408,10 +2488,19 @@ path_advance(const char **path, const char *name) | |||
2408 | pathopt = NULL; | 2488 | pathopt = NULL; |
2409 | if (*p == '%') { | 2489 | if (*p == '%') { |
2410 | pathopt = ++p; | 2490 | pathopt = ++p; |
2491 | #if ENABLE_PLATFORM_MINGW32 | ||
2492 | p = next_path_sep(start); | ||
2493 | |||
2494 | /* *p != ':' and '*' would suffice */ | ||
2495 | if (!p) | ||
2496 | p = pathopt - 1; | ||
2497 | #else | ||
2411 | while (*p && *p != ':') | 2498 | while (*p && *p != ':') |
2412 | p++; | 2499 | p++; |
2500 | #endif | ||
2413 | } | 2501 | } |
2414 | if (*p == ':') | 2502 | if (*p == ':' || |
2503 | (ENABLE_PLATFORM_MINGW32 && *p == ';')) | ||
2415 | *path = p + 1; | 2504 | *path = p + 1; |
2416 | else | 2505 | else |
2417 | *path = NULL; | 2506 | *path = NULL; |
@@ -2513,6 +2602,106 @@ cdopt(void) | |||
2513 | static const char * | 2602 | static const char * |
2514 | updatepwd(const char *dir) | 2603 | updatepwd(const char *dir) |
2515 | { | 2604 | { |
2605 | #if ENABLE_PLATFORM_MINGW32 | ||
2606 | #define is_path_sep(x) ((x) == '/' || (x) == '\\') | ||
2607 | #define is_unc_path(x) (is_path_sep(x[0]) && is_path_sep(x[1])) | ||
2608 | /* | ||
2609 | * Due to Windows drive notion, getting pwd is a completely | ||
2610 | * different thing. Handle it in a separate routine | ||
2611 | */ | ||
2612 | |||
2613 | char *new; | ||
2614 | char *p; | ||
2615 | char *cdcomppath; | ||
2616 | const char *lim; | ||
2617 | /* | ||
2618 | * There are five cases that make some kind of sense | ||
2619 | * absdrive + abspath: c:/path | ||
2620 | * absdrive + !abspath: c:path | ||
2621 | * !absdrive + abspath: /path | ||
2622 | * !absdrive + uncpath: //host/share | ||
2623 | * !absdrive + !abspath: path | ||
2624 | * | ||
2625 | * Damn DOS! | ||
2626 | * c:path behaviour is "undefined" | ||
2627 | * To properly handle this case, I have to keep track of cwd | ||
2628 | * of every drive, which is too painful to do. | ||
2629 | * So when c:path is given, I assume it's c:${curdir}path | ||
2630 | * with ${curdir} comes from the current drive | ||
2631 | */ | ||
2632 | int absdrive = *dir && dir[1] == ':'; | ||
2633 | int abspath = absdrive ? is_path_sep(dir[2]) : is_path_sep(*dir); | ||
2634 | |||
2635 | cdcomppath = ststrdup(dir); | ||
2636 | STARTSTACKSTR(new); | ||
2637 | if (!absdrive && curdir == nullstr) | ||
2638 | return 0; | ||
2639 | if (!abspath) { | ||
2640 | if (curdir == nullstr) | ||
2641 | return 0; | ||
2642 | new = stack_putstr(curdir, new); | ||
2643 | } | ||
2644 | new = makestrspace(strlen(dir) + 2, new); | ||
2645 | |||
2646 | if ( is_unc_path(dir) || (!absdrive && !abspath && is_unc_path(curdir)) ) { | ||
2647 | lim = (char *)stackblock() + 1; | ||
2648 | } | ||
2649 | else { | ||
2650 | char *drive = stackblock(); | ||
2651 | if (absdrive) { | ||
2652 | *drive = *dir; | ||
2653 | cdcomppath += 2; | ||
2654 | dir += 2; | ||
2655 | } else { | ||
2656 | *drive = *curdir; | ||
2657 | } | ||
2658 | drive[1] = ':'; /* in case of absolute drive+path */ | ||
2659 | |||
2660 | if (abspath) | ||
2661 | new = drive + 2; | ||
2662 | lim = drive + 3; | ||
2663 | } | ||
2664 | |||
2665 | if (!abspath) { | ||
2666 | if (!is_path_sep(new[-1])) | ||
2667 | USTPUTC('/', new); | ||
2668 | if (new > lim && is_path_sep(*lim)) | ||
2669 | lim++; | ||
2670 | } else { | ||
2671 | USTPUTC('/', new); | ||
2672 | cdcomppath ++; | ||
2673 | if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) { | ||
2674 | USTPUTC('/', new); | ||
2675 | cdcomppath++; | ||
2676 | lim++; | ||
2677 | } | ||
2678 | } | ||
2679 | p = strtok(cdcomppath, "/\\"); | ||
2680 | while (p) { | ||
2681 | switch (*p) { | ||
2682 | case '.': | ||
2683 | if (p[1] == '.' && p[2] == '\0') { | ||
2684 | while (new > lim) { | ||
2685 | STUNPUTC(new); | ||
2686 | if (is_path_sep(new[-1])) | ||
2687 | break; | ||
2688 | } | ||
2689 | break; | ||
2690 | } | ||
2691 | if (p[1] == '\0') | ||
2692 | break; | ||
2693 | /* fall through */ | ||
2694 | default: | ||
2695 | new = stack_putstr(p, new); | ||
2696 | USTPUTC('/', new); | ||
2697 | } | ||
2698 | p = strtok(0, "/\\"); | ||
2699 | } | ||
2700 | if (new > lim) | ||
2701 | STUNPUTC(new); | ||
2702 | *new = 0; | ||
2703 | return stackblock(); | ||
2704 | #else | ||
2516 | char *new; | 2705 | char *new; |
2517 | char *p; | 2706 | char *p; |
2518 | char *cdcomppath; | 2707 | char *cdcomppath; |
@@ -2566,6 +2755,7 @@ updatepwd(const char *dir) | |||
2566 | STUNPUTC(new); | 2755 | STUNPUTC(new); |
2567 | *new = 0; | 2756 | *new = 0; |
2568 | return stackblock(); | 2757 | return stackblock(); |
2758 | #endif | ||
2569 | } | 2759 | } |
2570 | 2760 | ||
2571 | /* | 2761 | /* |
@@ -2660,7 +2850,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2660 | } | 2850 | } |
2661 | if (!dest) | 2851 | if (!dest) |
2662 | dest = nullstr; | 2852 | dest = nullstr; |
2663 | if (*dest == '/') | 2853 | if (is_absolute_path(dest)) |
2664 | goto step7; | 2854 | goto step7; |
2665 | if (*dest == '.') { | 2855 | if (*dest == '.') { |
2666 | c = dest[1]; | 2856 | c = dest[1]; |
@@ -3377,7 +3567,9 @@ struct job { | |||
3377 | }; | 3567 | }; |
3378 | 3568 | ||
3379 | static struct job *makejob(/*union node *,*/ int); | 3569 | static struct job *makejob(/*union node *,*/ int); |
3570 | #if !ENABLE_PLATFORM_MINGW32 | ||
3380 | static int forkshell(struct job *, union node *, int); | 3571 | static int forkshell(struct job *, union node *, int); |
3572 | #endif | ||
3381 | static int waitforjob(struct job *); | 3573 | static int waitforjob(struct job *); |
3382 | 3574 | ||
3383 | #if !JOBS | 3575 | #if !JOBS |
@@ -3432,6 +3624,8 @@ setsignal(int signo) | |||
3432 | char cur_act, new_act; | 3624 | char cur_act, new_act; |
3433 | struct sigaction act; | 3625 | struct sigaction act; |
3434 | 3626 | ||
3627 | if (ENABLE_PLATFORM_MINGW32) | ||
3628 | return; | ||
3435 | t = trap[signo]; | 3629 | t = trap[signo]; |
3436 | new_act = S_DFL; | 3630 | new_act = S_DFL; |
3437 | if (t != NULL) { /* trap for this sig is set */ | 3631 | if (t != NULL) { /* trap for this sig is set */ |
@@ -3953,6 +4147,79 @@ sprint_status(char *s, int status, int sigonly) | |||
3953 | return col; | 4147 | return col; |
3954 | } | 4148 | } |
3955 | 4149 | ||
4150 | #if ENABLE_PLATFORM_MINGW32 | ||
4151 | |||
4152 | HANDLE hSIGINT; /* Ctrl-C is pressed */ | ||
4153 | |||
4154 | static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) | ||
4155 | { | ||
4156 | if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { | ||
4157 | SetEvent(hSIGINT); | ||
4158 | return TRUE; | ||
4159 | } | ||
4160 | return FALSE; | ||
4161 | } | ||
4162 | |||
4163 | /* | ||
4164 | * Windows does not know about parent-child relationship | ||
4165 | * They don't support waitpid(-1) | ||
4166 | */ | ||
4167 | static pid_t | ||
4168 | waitpid_child(int *status, int wait_flags) | ||
4169 | { | ||
4170 | HANDLE *pidlist, *pidp; | ||
4171 | int pid_nr = 0; | ||
4172 | pid_t pid; | ||
4173 | DWORD win_status, idx; | ||
4174 | struct job *jb; | ||
4175 | |||
4176 | #define LOOP(stmt) \ | ||
4177 | for (jb = curjob; jb; jb = jb->prev_job) { \ | ||
4178 | struct procstat *ps, *psend; \ | ||
4179 | if (jb->state == JOBDONE) \ | ||
4180 | continue; \ | ||
4181 | ps = jb->ps; \ | ||
4182 | psend = ps + jb->nprocs; \ | ||
4183 | while (ps < psend) { \ | ||
4184 | if (ps->ps_pid != -1) { \ | ||
4185 | stmt; \ | ||
4186 | } \ | ||
4187 | ps++; \ | ||
4188 | } \ | ||
4189 | } | ||
4190 | |||
4191 | LOOP(pid_nr++); | ||
4192 | if (!pid_nr) | ||
4193 | return -1; | ||
4194 | pid_nr++; | ||
4195 | pidp = pidlist = ckmalloc(sizeof(*pidlist)*pid_nr); | ||
4196 | *pidp++ = hSIGINT; | ||
4197 | LOOP(*pidp++ = (HANDLE)ps->ps_pid); | ||
4198 | #undef LOOP | ||
4199 | |||
4200 | idx = WaitForMultipleObjects(pid_nr, pidlist, FALSE, | ||
4201 | wait_flags|WNOHANG ? 1 : INFINITE); | ||
4202 | if (idx >= pid_nr) { | ||
4203 | free(pidlist); | ||
4204 | return -1; | ||
4205 | } | ||
4206 | if (!idx) { /* hSIGINT */ | ||
4207 | int i; | ||
4208 | ResetEvent(hSIGINT); | ||
4209 | for (i = 1; i < pid_nr; i++) | ||
4210 | TerminateProcess(pidlist[i], 1); | ||
4211 | free(pidlist); | ||
4212 | *status = 260; /* terminated by a signal */ | ||
4213 | return pidlist[1]; | ||
4214 | } | ||
4215 | GetExitCodeProcess(pidlist[idx], &win_status); | ||
4216 | pid = (int)pidlist[idx]; | ||
4217 | free(pidlist); | ||
4218 | *status = (int)win_status; | ||
4219 | return pid; | ||
4220 | } | ||
4221 | #endif | ||
4222 | |||
3956 | static int | 4223 | static int |
3957 | dowait(int wait_flags, struct job *job) | 4224 | dowait(int wait_flags, struct job *job) |
3958 | { | 4225 | { |
@@ -3969,7 +4236,11 @@ dowait(int wait_flags, struct job *job) | |||
3969 | * NB: _not_ safe_waitpid, we need to detect EINTR */ | 4236 | * NB: _not_ safe_waitpid, we need to detect EINTR */ |
3970 | if (doing_jobctl) | 4237 | if (doing_jobctl) |
3971 | wait_flags |= WUNTRACED; | 4238 | wait_flags |= WUNTRACED; |
4239 | #if ENABLE_PLATFORM_MINGW32 | ||
4240 | pid = waitpid_child(&status, wait_flags); | ||
4241 | #else | ||
3972 | pid = waitpid(-1, &status, wait_flags); | 4242 | pid = waitpid(-1, &status, wait_flags); |
4243 | #endif | ||
3973 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", | 4244 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", |
3974 | pid, status, errno, strerror(errno))); | 4245 | pid, status, errno, strerror(errno))); |
3975 | if (pid <= 0) | 4246 | if (pid <= 0) |
@@ -3992,6 +4263,8 @@ dowait(int wait_flags, struct job *job) | |||
3992 | jobno(jp), pid, ps->ps_status, status)); | 4263 | jobno(jp), pid, ps->ps_status, status)); |
3993 | ps->ps_status = status; | 4264 | ps->ps_status = status; |
3994 | thisjob = jp; | 4265 | thisjob = jp; |
4266 | if (ENABLE_PLATFORM_MINGW32) | ||
4267 | ps->ps_pid = -1; | ||
3995 | } | 4268 | } |
3996 | if (ps->ps_status == -1) | 4269 | if (ps->ps_status == -1) |
3997 | state = JOBRUNNING; | 4270 | state = JOBRUNNING; |
@@ -4223,6 +4496,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
4223 | int retval; | 4496 | int retval; |
4224 | struct job *jp; | 4497 | struct job *jp; |
4225 | 4498 | ||
4499 | if (ENABLE_PLATFORM_MINGW32) | ||
4500 | return 0; | ||
4501 | |||
4226 | if (pending_sig) | 4502 | if (pending_sig) |
4227 | raise_exception(EXSIG); | 4503 | raise_exception(EXSIG); |
4228 | 4504 | ||
@@ -4678,6 +4954,7 @@ commandtext(union node *n) | |||
4678 | * | 4954 | * |
4679 | * Called with interrupts off. | 4955 | * Called with interrupts off. |
4680 | */ | 4956 | */ |
4957 | #if !ENABLE_PLATFORM_MINGW32 | ||
4681 | /* | 4958 | /* |
4682 | * Clear traps on a fork. | 4959 | * Clear traps on a fork. |
4683 | */ | 4960 | */ |
@@ -4826,6 +5103,7 @@ forkchild(struct job *jp, union node *n, int mode) | |||
4826 | freejob(jp); | 5103 | freejob(jp); |
4827 | jobless = 0; | 5104 | jobless = 0; |
4828 | } | 5105 | } |
5106 | #endif | ||
4829 | 5107 | ||
4830 | /* Called after fork(), in parent */ | 5108 | /* Called after fork(), in parent */ |
4831 | #if !JOBS | 5109 | #if !JOBS |
@@ -4835,7 +5113,7 @@ static void | |||
4835 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 5113 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
4836 | { | 5114 | { |
4837 | TRACE(("In parent shell: child = %d\n", pid)); | 5115 | TRACE(("In parent shell: child = %d\n", pid)); |
4838 | if (!jp) { | 5116 | if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */ |
4839 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) | 5117 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) |
4840 | continue; | 5118 | continue; |
4841 | jobless++; | 5119 | jobless++; |
@@ -4869,12 +5147,14 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) | |||
4869 | } | 5147 | } |
4870 | } | 5148 | } |
4871 | 5149 | ||
5150 | #if !ENABLE_PLATFORM_MINGW32 | ||
4872 | static int | 5151 | static int |
4873 | forkshell(struct job *jp, union node *n, int mode) | 5152 | forkshell(struct job *jp, union node *n, int mode) |
4874 | { | 5153 | { |
4875 | int pid; | 5154 | int pid; |
4876 | 5155 | ||
4877 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); | 5156 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); |
5157 | |||
4878 | pid = fork(); | 5158 | pid = fork(); |
4879 | if (pid < 0) { | 5159 | if (pid < 0) { |
4880 | TRACE(("Fork failed, errno=%d", errno)); | 5160 | TRACE(("Fork failed, errno=%d", errno)); |
@@ -4890,6 +5170,7 @@ forkshell(struct job *jp, union node *n, int mode) | |||
4890 | } | 5170 | } |
4891 | return pid; | 5171 | return pid; |
4892 | } | 5172 | } |
5173 | #endif | ||
4893 | 5174 | ||
4894 | /* | 5175 | /* |
4895 | * Wait for job to finish. | 5176 | * Wait for job to finish. |
@@ -5082,6 +5363,7 @@ openhere(union node *redir) | |||
5082 | { | 5363 | { |
5083 | int pip[2]; | 5364 | int pip[2]; |
5084 | size_t len = 0; | 5365 | size_t len = 0; |
5366 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5085 | 5367 | ||
5086 | if (pipe(pip) < 0) | 5368 | if (pipe(pip) < 0) |
5087 | ash_msg_and_raise_error("pipe call failed"); | 5369 | ash_msg_and_raise_error("pipe call failed"); |
@@ -5092,6 +5374,15 @@ openhere(union node *redir) | |||
5092 | goto out; | 5374 | goto out; |
5093 | } | 5375 | } |
5094 | } | 5376 | } |
5377 | #if ENABLE_PLATFORM_MINGW32 | ||
5378 | memset(&fs, 0, sizeof(fs)); | ||
5379 | fs.fpid = FS_OPENHERE; | ||
5380 | fs.n = redir; | ||
5381 | fs.fd[0] = pip[0]; | ||
5382 | fs.fd[1] = pip[1]; | ||
5383 | if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0) | ||
5384 | ash_msg_and_raise_error("unable to spawn shell"); | ||
5385 | #else | ||
5095 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | 5386 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { |
5096 | /* child */ | 5387 | /* child */ |
5097 | close(pip[0]); | 5388 | close(pip[0]); |
@@ -5106,6 +5397,7 @@ openhere(union node *redir) | |||
5106 | expandhere(redir->nhere.doc, pip[1]); | 5397 | expandhere(redir->nhere.doc, pip[1]); |
5107 | _exit(EXIT_SUCCESS); | 5398 | _exit(EXIT_SUCCESS); |
5108 | } | 5399 | } |
5400 | #endif | ||
5109 | out: | 5401 | out: |
5110 | close(pip[1]); | 5402 | close(pip[1]); |
5111 | return pip[0]; | 5403 | return pip[0]; |
@@ -5118,6 +5410,31 @@ openredirect(union node *redir) | |||
5118 | int f; | 5410 | int f; |
5119 | 5411 | ||
5120 | fname = redir->nfile.expfname; | 5412 | fname = redir->nfile.expfname; |
5413 | #if ENABLE_PLATFORM_MINGW32 | ||
5414 | /* Support for /dev/null */ | ||
5415 | switch (redir->nfile.type) { | ||
5416 | case NFROM: | ||
5417 | if (!strcmp(fname, "/dev/null")) | ||
5418 | return open("nul",O_RDWR); | ||
5419 | if (!strncmp(fname, "/dev/", 5)) { | ||
5420 | ash_msg("Unhandled device %s\n", fname); | ||
5421 | return -1; | ||
5422 | } | ||
5423 | break; | ||
5424 | |||
5425 | case NFROMTO: | ||
5426 | case NTO: | ||
5427 | case NCLOBBER: | ||
5428 | case NAPPEND: | ||
5429 | if (!strcmp(fname, "/dev/null")) | ||
5430 | return open("nul",O_RDWR); | ||
5431 | if (!strncmp(fname, "/dev/", 5)) { | ||
5432 | ash_msg("Unhandled device %s\n", fname); | ||
5433 | return -1; | ||
5434 | } | ||
5435 | break; | ||
5436 | } | ||
5437 | #endif | ||
5121 | switch (redir->nfile.type) { | 5438 | switch (redir->nfile.type) { |
5122 | case NFROM: | 5439 | case NFROM: |
5123 | f = open(fname, O_RDONLY); | 5440 | f = open(fname, O_RDONLY); |
@@ -5842,6 +6159,7 @@ struct backcmd { /* result of evalbackcmd */ | |||
5842 | int fd; /* file descriptor to read from */ | 6159 | int fd; /* file descriptor to read from */ |
5843 | int nleft; /* number of chars in buffer */ | 6160 | int nleft; /* number of chars in buffer */ |
5844 | char *buf; /* buffer */ | 6161 | char *buf; /* buffer */ |
6162 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5845 | struct job *jp; /* job structure for command */ | 6163 | struct job *jp; /* job structure for command */ |
5846 | }; | 6164 | }; |
5847 | 6165 | ||
@@ -5858,6 +6176,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5858 | result->fd = -1; | 6176 | result->fd = -1; |
5859 | result->buf = NULL; | 6177 | result->buf = NULL; |
5860 | result->nleft = 0; | 6178 | result->nleft = 0; |
6179 | IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs))); | ||
5861 | result->jp = NULL; | 6180 | result->jp = NULL; |
5862 | if (n == NULL) | 6181 | if (n == NULL) |
5863 | goto out; | 6182 | goto out; |
@@ -5872,6 +6191,14 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5872 | if (pipe(pip) < 0) | 6191 | if (pipe(pip) < 0) |
5873 | ash_msg_and_raise_error("pipe call failed"); | 6192 | ash_msg_and_raise_error("pipe call failed"); |
5874 | jp = makejob(/*n,*/ 1); | 6193 | jp = makejob(/*n,*/ 1); |
6194 | #if ENABLE_PLATFORM_MINGW32 | ||
6195 | result->fs.fpid = FS_EVALBACKCMD; | ||
6196 | result->fs.n = n; | ||
6197 | result->fs.fd[0] = pip[0]; | ||
6198 | result->fs.fd[1] = pip[1]; | ||
6199 | if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0) | ||
6200 | ash_msg_and_raise_error("unable to spawn shell"); | ||
6201 | #else | ||
5875 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 6202 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
5876 | FORCE_INT_ON; | 6203 | FORCE_INT_ON; |
5877 | close(pip[0]); | 6204 | close(pip[0]); |
@@ -5884,6 +6211,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5884 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ | 6211 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ |
5885 | /* NOTREACHED */ | 6212 | /* NOTREACHED */ |
5886 | } | 6213 | } |
6214 | #endif | ||
5887 | close(pip[1]); | 6215 | close(pip[1]); |
5888 | result->fd = pip[0]; | 6216 | result->fd = pip[0]; |
5889 | result->jp = jp; | 6217 | result->jp = jp; |
@@ -5942,7 +6270,8 @@ expbackq(union node *cmd, int quoted, int quotes) | |||
5942 | 6270 | ||
5943 | /* Eat all trailing newlines */ | 6271 | /* Eat all trailing newlines */ |
5944 | dest = expdest; | 6272 | dest = expdest; |
5945 | for (; dest > (char *)stackblock() && dest[-1] == '\n';) | 6273 | for (; dest > (char *)stackblock() && (dest[-1] == '\n' || |
6274 | (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));) | ||
5946 | STUNPUTC(dest); | 6275 | STUNPUTC(dest); |
5947 | expdest = dest; | 6276 | expdest = dest; |
5948 | 6277 | ||
@@ -7505,7 +7834,7 @@ shellexec(char **argv, const char *path, int idx) | |||
7505 | 7834 | ||
7506 | clearredir(/*drop:*/ 1); | 7835 | clearredir(/*drop:*/ 1); |
7507 | envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); | 7836 | envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); |
7508 | if (strchr(argv[0], '/') != NULL | 7837 | if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\'))) |
7509 | #if ENABLE_FEATURE_SH_STANDALONE | 7838 | #if ENABLE_FEATURE_SH_STANDALONE |
7510 | || (applet_no = find_applet_by_name(argv[0])) >= 0 | 7839 | || (applet_no = find_applet_by_name(argv[0])) >= 0 |
7511 | #endif | 7840 | #endif |
@@ -8016,6 +8345,10 @@ static int funcblocksize; /* size of structures in function */ | |||
8016 | static int funcstringsize; /* size of strings in node */ | 8345 | static int funcstringsize; /* size of strings in node */ |
8017 | static void *funcblock; /* block to allocate function from */ | 8346 | static void *funcblock; /* block to allocate function from */ |
8018 | static char *funcstring; /* block to allocate strings from */ | 8347 | static char *funcstring; /* block to allocate strings from */ |
8348 | #if ENABLE_PLATFORM_MINGW32 | ||
8349 | static int nodeptrsize; | ||
8350 | static int *nodeptr; | ||
8351 | #endif | ||
8019 | 8352 | ||
8020 | /* flags in argument to evaltree */ | 8353 | /* flags in argument to evaltree */ |
8021 | #define EV_EXIT 01 /* exit after evaluating tree */ | 8354 | #define EV_EXIT 01 /* exit after evaluating tree */ |
@@ -8061,6 +8394,7 @@ sizenodelist(struct nodelist *lp) | |||
8061 | { | 8394 | { |
8062 | while (lp) { | 8395 | while (lp) { |
8063 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); | 8396 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); |
8397 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8064 | calcsize(lp->n); | 8398 | calcsize(lp->n); |
8065 | lp = lp->next; | 8399 | lp = lp->next; |
8066 | } | 8400 | } |
@@ -8077,15 +8411,18 @@ calcsize(union node *n) | |||
8077 | calcsize(n->ncmd.redirect); | 8411 | calcsize(n->ncmd.redirect); |
8078 | calcsize(n->ncmd.args); | 8412 | calcsize(n->ncmd.args); |
8079 | calcsize(n->ncmd.assign); | 8413 | calcsize(n->ncmd.assign); |
8414 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8080 | break; | 8415 | break; |
8081 | case NPIPE: | 8416 | case NPIPE: |
8082 | sizenodelist(n->npipe.cmdlist); | 8417 | sizenodelist(n->npipe.cmdlist); |
8418 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
8083 | break; | 8419 | break; |
8084 | case NREDIR: | 8420 | case NREDIR: |
8085 | case NBACKGND: | 8421 | case NBACKGND: |
8086 | case NSUBSHELL: | 8422 | case NSUBSHELL: |
8087 | calcsize(n->nredir.redirect); | 8423 | calcsize(n->nredir.redirect); |
8088 | calcsize(n->nredir.n); | 8424 | calcsize(n->nredir.n); |
8425 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8089 | break; | 8426 | break; |
8090 | case NAND: | 8427 | case NAND: |
8091 | case NOR: | 8428 | case NOR: |
@@ -8094,31 +8431,37 @@ calcsize(union node *n) | |||
8094 | case NUNTIL: | 8431 | case NUNTIL: |
8095 | calcsize(n->nbinary.ch2); | 8432 | calcsize(n->nbinary.ch2); |
8096 | calcsize(n->nbinary.ch1); | 8433 | calcsize(n->nbinary.ch1); |
8434 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8097 | break; | 8435 | break; |
8098 | case NIF: | 8436 | case NIF: |
8099 | calcsize(n->nif.elsepart); | 8437 | calcsize(n->nif.elsepart); |
8100 | calcsize(n->nif.ifpart); | 8438 | calcsize(n->nif.ifpart); |
8101 | calcsize(n->nif.test); | 8439 | calcsize(n->nif.test); |
8440 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8102 | break; | 8441 | break; |
8103 | case NFOR: | 8442 | case NFOR: |
8104 | funcstringsize += strlen(n->nfor.var) + 1; | 8443 | funcstringsize += strlen(n->nfor.var) + 1; |
8105 | calcsize(n->nfor.body); | 8444 | calcsize(n->nfor.body); |
8106 | calcsize(n->nfor.args); | 8445 | calcsize(n->nfor.args); |
8446 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8107 | break; | 8447 | break; |
8108 | case NCASE: | 8448 | case NCASE: |
8109 | calcsize(n->ncase.cases); | 8449 | calcsize(n->ncase.cases); |
8110 | calcsize(n->ncase.expr); | 8450 | calcsize(n->ncase.expr); |
8451 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8111 | break; | 8452 | break; |
8112 | case NCLIST: | 8453 | case NCLIST: |
8113 | calcsize(n->nclist.body); | 8454 | calcsize(n->nclist.body); |
8114 | calcsize(n->nclist.pattern); | 8455 | calcsize(n->nclist.pattern); |
8115 | calcsize(n->nclist.next); | 8456 | calcsize(n->nclist.next); |
8457 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8116 | break; | 8458 | break; |
8117 | case NDEFUN: | 8459 | case NDEFUN: |
8118 | case NARG: | 8460 | case NARG: |
8119 | sizenodelist(n->narg.backquote); | 8461 | sizenodelist(n->narg.backquote); |
8120 | funcstringsize += strlen(n->narg.text) + 1; | 8462 | funcstringsize += strlen(n->narg.text) + 1; |
8121 | calcsize(n->narg.next); | 8463 | calcsize(n->narg.next); |
8464 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8122 | break; | 8465 | break; |
8123 | case NTO: | 8466 | case NTO: |
8124 | #if ENABLE_ASH_BASH_COMPAT | 8467 | #if ENABLE_ASH_BASH_COMPAT |
@@ -8130,28 +8473,34 @@ calcsize(union node *n) | |||
8130 | case NAPPEND: | 8473 | case NAPPEND: |
8131 | calcsize(n->nfile.fname); | 8474 | calcsize(n->nfile.fname); |
8132 | calcsize(n->nfile.next); | 8475 | calcsize(n->nfile.next); |
8476 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8133 | break; | 8477 | break; |
8134 | case NTOFD: | 8478 | case NTOFD: |
8135 | case NFROMFD: | 8479 | case NFROMFD: |
8136 | calcsize(n->ndup.vname); | 8480 | calcsize(n->ndup.vname); |
8137 | calcsize(n->ndup.next); | 8481 | calcsize(n->ndup.next); |
8482 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8138 | break; | 8483 | break; |
8139 | case NHERE: | 8484 | case NHERE: |
8140 | case NXHERE: | 8485 | case NXHERE: |
8141 | calcsize(n->nhere.doc); | 8486 | calcsize(n->nhere.doc); |
8142 | calcsize(n->nhere.next); | 8487 | calcsize(n->nhere.next); |
8488 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8143 | break; | 8489 | break; |
8144 | case NNOT: | 8490 | case NNOT: |
8145 | calcsize(n->nnot.com); | 8491 | calcsize(n->nnot.com); |
8492 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
8146 | break; | 8493 | break; |
8147 | }; | 8494 | }; |
8148 | } | 8495 | } |
8149 | 8496 | ||
8150 | static char * | 8497 | static char * |
8151 | nodeckstrdup(char *s) | 8498 | nodeckstrdup(const char *s) |
8152 | { | 8499 | { |
8153 | char *rtn = funcstring; | 8500 | char *rtn = funcstring; |
8154 | 8501 | ||
8502 | if (!s) | ||
8503 | return NULL; | ||
8155 | strcpy(funcstring, s); | 8504 | strcpy(funcstring, s); |
8156 | funcstring += strlen(s) + 1; | 8505 | funcstring += strlen(s) + 1; |
8157 | return rtn; | 8506 | return rtn; |
@@ -8159,6 +8508,18 @@ nodeckstrdup(char *s) | |||
8159 | 8508 | ||
8160 | static union node *copynode(union node *); | 8509 | static union node *copynode(union node *); |
8161 | 8510 | ||
8511 | #if ENABLE_PLATFORM_MINGW32 | ||
8512 | # define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (int)&(dst);} | ||
8513 | # define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);}} | ||
8514 | # define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);}} | ||
8515 | # define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);*nodeptr++ = (int)&(dst4);}} | ||
8516 | #else | ||
8517 | # define SAVE_PTR(dst) | ||
8518 | # define SAVE_PTR2(dst,dst2) | ||
8519 | # define SAVE_PTR3(dst,dst2,dst3) | ||
8520 | # define SAVE_PTR4(dst,dst2,dst3,dst4) | ||
8521 | #endif | ||
8522 | |||
8162 | static struct nodelist * | 8523 | static struct nodelist * |
8163 | copynodelist(struct nodelist *lp) | 8524 | copynodelist(struct nodelist *lp) |
8164 | { | 8525 | { |
@@ -8170,6 +8531,7 @@ copynodelist(struct nodelist *lp) | |||
8170 | *lpp = funcblock; | 8531 | *lpp = funcblock; |
8171 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); | 8532 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); |
8172 | (*lpp)->n = copynode(lp->n); | 8533 | (*lpp)->n = copynode(lp->n); |
8534 | SAVE_PTR2((*lpp)->n, (*lpp)->next); | ||
8173 | lp = lp->next; | 8535 | lp = lp->next; |
8174 | lpp = &(*lpp)->next; | 8536 | lpp = &(*lpp)->next; |
8175 | } | 8537 | } |
@@ -8192,16 +8554,19 @@ copynode(union node *n) | |||
8192 | new->ncmd.redirect = copynode(n->ncmd.redirect); | 8554 | new->ncmd.redirect = copynode(n->ncmd.redirect); |
8193 | new->ncmd.args = copynode(n->ncmd.args); | 8555 | new->ncmd.args = copynode(n->ncmd.args); |
8194 | new->ncmd.assign = copynode(n->ncmd.assign); | 8556 | new->ncmd.assign = copynode(n->ncmd.assign); |
8557 | SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign); | ||
8195 | break; | 8558 | break; |
8196 | case NPIPE: | 8559 | case NPIPE: |
8197 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | 8560 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); |
8198 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; | 8561 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; |
8562 | SAVE_PTR(new->npipe.cmdlist); | ||
8199 | break; | 8563 | break; |
8200 | case NREDIR: | 8564 | case NREDIR: |
8201 | case NBACKGND: | 8565 | case NBACKGND: |
8202 | case NSUBSHELL: | 8566 | case NSUBSHELL: |
8203 | new->nredir.redirect = copynode(n->nredir.redirect); | 8567 | new->nredir.redirect = copynode(n->nredir.redirect); |
8204 | new->nredir.n = copynode(n->nredir.n); | 8568 | new->nredir.n = copynode(n->nredir.n); |
8569 | SAVE_PTR2(new->nredir.redirect,new->nredir.n); | ||
8205 | break; | 8570 | break; |
8206 | case NAND: | 8571 | case NAND: |
8207 | case NOR: | 8572 | case NOR: |
@@ -8210,31 +8575,37 @@ copynode(union node *n) | |||
8210 | case NUNTIL: | 8575 | case NUNTIL: |
8211 | new->nbinary.ch2 = copynode(n->nbinary.ch2); | 8576 | new->nbinary.ch2 = copynode(n->nbinary.ch2); |
8212 | new->nbinary.ch1 = copynode(n->nbinary.ch1); | 8577 | new->nbinary.ch1 = copynode(n->nbinary.ch1); |
8578 | SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2); | ||
8213 | break; | 8579 | break; |
8214 | case NIF: | 8580 | case NIF: |
8215 | new->nif.elsepart = copynode(n->nif.elsepart); | 8581 | new->nif.elsepart = copynode(n->nif.elsepart); |
8216 | new->nif.ifpart = copynode(n->nif.ifpart); | 8582 | new->nif.ifpart = copynode(n->nif.ifpart); |
8217 | new->nif.test = copynode(n->nif.test); | 8583 | new->nif.test = copynode(n->nif.test); |
8584 | SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test); | ||
8218 | break; | 8585 | break; |
8219 | case NFOR: | 8586 | case NFOR: |
8220 | new->nfor.var = nodeckstrdup(n->nfor.var); | 8587 | new->nfor.var = nodeckstrdup(n->nfor.var); |
8221 | new->nfor.body = copynode(n->nfor.body); | 8588 | new->nfor.body = copynode(n->nfor.body); |
8222 | new->nfor.args = copynode(n->nfor.args); | 8589 | new->nfor.args = copynode(n->nfor.args); |
8590 | SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args); | ||
8223 | break; | 8591 | break; |
8224 | case NCASE: | 8592 | case NCASE: |
8225 | new->ncase.cases = copynode(n->ncase.cases); | 8593 | new->ncase.cases = copynode(n->ncase.cases); |
8226 | new->ncase.expr = copynode(n->ncase.expr); | 8594 | new->ncase.expr = copynode(n->ncase.expr); |
8595 | SAVE_PTR2(new->ncase.cases,new->ncase.expr); | ||
8227 | break; | 8596 | break; |
8228 | case NCLIST: | 8597 | case NCLIST: |
8229 | new->nclist.body = copynode(n->nclist.body); | 8598 | new->nclist.body = copynode(n->nclist.body); |
8230 | new->nclist.pattern = copynode(n->nclist.pattern); | 8599 | new->nclist.pattern = copynode(n->nclist.pattern); |
8231 | new->nclist.next = copynode(n->nclist.next); | 8600 | new->nclist.next = copynode(n->nclist.next); |
8601 | SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next); | ||
8232 | break; | 8602 | break; |
8233 | case NDEFUN: | 8603 | case NDEFUN: |
8234 | case NARG: | 8604 | case NARG: |
8235 | new->narg.backquote = copynodelist(n->narg.backquote); | 8605 | new->narg.backquote = copynodelist(n->narg.backquote); |
8236 | new->narg.text = nodeckstrdup(n->narg.text); | 8606 | new->narg.text = nodeckstrdup(n->narg.text); |
8237 | new->narg.next = copynode(n->narg.next); | 8607 | new->narg.next = copynode(n->narg.next); |
8608 | SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next); | ||
8238 | break; | 8609 | break; |
8239 | case NTO: | 8610 | case NTO: |
8240 | #if ENABLE_ASH_BASH_COMPAT | 8611 | #if ENABLE_ASH_BASH_COMPAT |
@@ -8247,6 +8618,7 @@ copynode(union node *n) | |||
8247 | new->nfile.fname = copynode(n->nfile.fname); | 8618 | new->nfile.fname = copynode(n->nfile.fname); |
8248 | new->nfile.fd = n->nfile.fd; | 8619 | new->nfile.fd = n->nfile.fd; |
8249 | new->nfile.next = copynode(n->nfile.next); | 8620 | new->nfile.next = copynode(n->nfile.next); |
8621 | SAVE_PTR2(new->nfile.fname,new->nfile.next); | ||
8250 | break; | 8622 | break; |
8251 | case NTOFD: | 8623 | case NTOFD: |
8252 | case NFROMFD: | 8624 | case NFROMFD: |
@@ -8254,15 +8626,18 @@ copynode(union node *n) | |||
8254 | new->ndup.dupfd = n->ndup.dupfd; | 8626 | new->ndup.dupfd = n->ndup.dupfd; |
8255 | new->ndup.fd = n->ndup.fd; | 8627 | new->ndup.fd = n->ndup.fd; |
8256 | new->ndup.next = copynode(n->ndup.next); | 8628 | new->ndup.next = copynode(n->ndup.next); |
8629 | SAVE_PTR2(new->ndup.vname,new->ndup.next); | ||
8257 | break; | 8630 | break; |
8258 | case NHERE: | 8631 | case NHERE: |
8259 | case NXHERE: | 8632 | case NXHERE: |
8260 | new->nhere.doc = copynode(n->nhere.doc); | 8633 | new->nhere.doc = copynode(n->nhere.doc); |
8261 | new->nhere.fd = n->nhere.fd; | 8634 | new->nhere.fd = n->nhere.fd; |
8262 | new->nhere.next = copynode(n->nhere.next); | 8635 | new->nhere.next = copynode(n->nhere.next); |
8636 | SAVE_PTR2(new->nhere.doc,new->nhere.next); | ||
8263 | break; | 8637 | break; |
8264 | case NNOT: | 8638 | case NNOT: |
8265 | new->nnot.com = copynode(n->nnot.com); | 8639 | new->nnot.com = copynode(n->nnot.com); |
8640 | SAVE_PTR(new->nnot.com); | ||
8266 | break; | 8641 | break; |
8267 | }; | 8642 | }; |
8268 | new->type = n->type; | 8643 | new->type = n->type; |
@@ -8285,6 +8660,7 @@ copyfunc(union node *n) | |||
8285 | f = ckmalloc(blocksize + funcstringsize); | 8660 | f = ckmalloc(blocksize + funcstringsize); |
8286 | funcblock = (char *) f + offsetof(struct funcnode, n); | 8661 | funcblock = (char *) f + offsetof(struct funcnode, n); |
8287 | funcstring = (char *) f + blocksize; | 8662 | funcstring = (char *) f + blocksize; |
8663 | IF_PLATFORM_MINGW32(nodeptr = NULL); | ||
8288 | copynode(n); | 8664 | copynode(n); |
8289 | f->count = 0; | 8665 | f->count = 0; |
8290 | return f; | 8666 | return f; |
@@ -8644,6 +9020,7 @@ evalcase(union node *n, int flags) | |||
8644 | static void | 9020 | static void |
8645 | evalsubshell(union node *n, int flags) | 9021 | evalsubshell(union node *n, int flags) |
8646 | { | 9022 | { |
9023 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
8647 | struct job *jp; | 9024 | struct job *jp; |
8648 | int backgnd = (n->type == NBACKGND); | 9025 | int backgnd = (n->type == NBACKGND); |
8649 | int status; | 9026 | int status; |
@@ -8653,12 +9030,22 @@ evalsubshell(union node *n, int flags) | |||
8653 | goto nofork; | 9030 | goto nofork; |
8654 | INT_OFF; | 9031 | INT_OFF; |
8655 | jp = makejob(/*n,*/ 1); | 9032 | jp = makejob(/*n,*/ 1); |
9033 | #if ENABLE_PLATFORM_MINGW32 | ||
9034 | memset(&fs, 0, sizeof(fs)); | ||
9035 | fs.fpid = FS_EVALSUBSHELL; | ||
9036 | fs.n = n; | ||
9037 | fs.flags = flags; | ||
9038 | if (spawn_forkshell(jp, &fs, backgnd) < 0) | ||
9039 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9040 | if ( 0 ) { | ||
9041 | #else | ||
8656 | if (forkshell(jp, n, backgnd) == 0) { | 9042 | if (forkshell(jp, n, backgnd) == 0) { |
8657 | /* child */ | 9043 | /* child */ |
8658 | INT_ON; | 9044 | INT_ON; |
8659 | flags |= EV_EXIT; | 9045 | flags |= EV_EXIT; |
8660 | if (backgnd) | 9046 | if (backgnd) |
8661 | flags &= ~EV_TESTED; | 9047 | flags &= ~EV_TESTED; |
9048 | #endif | ||
8662 | nofork: | 9049 | nofork: |
8663 | redirect(n->nredir.redirect, 0); | 9050 | redirect(n->nredir.redirect, 0); |
8664 | evaltreenr(n->nredir.n, flags); | 9051 | evaltreenr(n->nredir.n, flags); |
@@ -8744,6 +9131,7 @@ expredir(union node *n) | |||
8744 | static void | 9131 | static void |
8745 | evalpipe(union node *n, int flags) | 9132 | evalpipe(union node *n, int flags) |
8746 | { | 9133 | { |
9134 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
8747 | struct job *jp; | 9135 | struct job *jp; |
8748 | struct nodelist *lp; | 9136 | struct nodelist *lp; |
8749 | int pipelen; | 9137 | int pipelen; |
@@ -8767,6 +9155,17 @@ evalpipe(union node *n, int flags) | |||
8767 | ash_msg_and_raise_error("pipe call failed"); | 9155 | ash_msg_and_raise_error("pipe call failed"); |
8768 | } | 9156 | } |
8769 | } | 9157 | } |
9158 | #if ENABLE_PLATFORM_MINGW32 | ||
9159 | memset(&fs, 0, sizeof(fs)); | ||
9160 | fs.fpid = FS_EVALPIPE; | ||
9161 | fs.flags = flags; | ||
9162 | fs.n = lp->n; | ||
9163 | fs.fd[0] = pip[0]; | ||
9164 | fs.fd[1] = pip[1]; | ||
9165 | fs.fd[2] = prevfd; | ||
9166 | if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0) | ||
9167 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9168 | #else | ||
8770 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { | 9169 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { |
8771 | INT_ON; | 9170 | INT_ON; |
8772 | if (pip[1] >= 0) { | 9171 | if (pip[1] >= 0) { |
@@ -8783,6 +9182,7 @@ evalpipe(union node *n, int flags) | |||
8783 | evaltreenr(lp->n, flags); | 9182 | evaltreenr(lp->n, flags); |
8784 | /* never returns */ | 9183 | /* never returns */ |
8785 | } | 9184 | } |
9185 | #endif | ||
8786 | if (prevfd >= 0) | 9186 | if (prevfd >= 0) |
8787 | close(prevfd); | 9187 | close(prevfd); |
8788 | prevfd = pip[0]; | 9188 | prevfd = pip[0]; |
@@ -9244,6 +9644,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
9244 | * as POSIX mandates */ | 9644 | * as POSIX mandates */ |
9245 | return back_exitstatus; | 9645 | return back_exitstatus; |
9246 | } | 9646 | } |
9647 | |||
9247 | static void | 9648 | static void |
9248 | evalcommand(union node *cmd, int flags) | 9649 | evalcommand(union node *cmd, int flags) |
9249 | { | 9650 | { |
@@ -9421,6 +9822,27 @@ evalcommand(union node *cmd, int flags) | |||
9421 | * in a script or a subshell does not need forking, | 9822 | * in a script or a subshell does not need forking, |
9422 | * we can just exec it. | 9823 | * we can just exec it. |
9423 | */ | 9824 | */ |
9825 | #if ENABLE_PLATFORM_MINGW32 | ||
9826 | if (!(flags & EV_EXIT) || trap[0]) { | ||
9827 | /* No, forking off a child is necessary */ | ||
9828 | struct forkshell fs; | ||
9829 | |||
9830 | memset(&fs, 0, sizeof(fs)); | ||
9831 | fs.fpid = FS_SHELLEXEC; | ||
9832 | fs.argv = argv; | ||
9833 | fs.string = (char*)path; | ||
9834 | fs.fd[0] = cmdentry.u.index; | ||
9835 | fs.strlist = varlist.list; | ||
9836 | jp = makejob(/*cmd,*/ 1); | ||
9837 | if (spawn_forkshell(jp, &fs, FORK_FG) < 0) | ||
9838 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9839 | exitstatus = waitforjob(jp); | ||
9840 | INT_ON; | ||
9841 | TRACE(("forked child exited with %d\n", exitstatus)); | ||
9842 | break; | ||
9843 | } | ||
9844 | /* goes through to shellexec() */ | ||
9845 | #else | ||
9424 | if (!(flags & EV_EXIT) || may_have_traps) { | 9846 | if (!(flags & EV_EXIT) || may_have_traps) { |
9425 | /* No, forking off a child is necessary */ | 9847 | /* No, forking off a child is necessary */ |
9426 | INT_OFF; | 9848 | INT_OFF; |
@@ -9436,6 +9858,7 @@ evalcommand(union node *cmd, int flags) | |||
9436 | FORCE_INT_ON; | 9858 | FORCE_INT_ON; |
9437 | /* fall through to exec'ing external program */ | 9859 | /* fall through to exec'ing external program */ |
9438 | } | 9860 | } |
9861 | #endif | ||
9439 | listsetvar(varlist.list, VEXPORT|VSTACK); | 9862 | listsetvar(varlist.list, VEXPORT|VSTACK); |
9440 | shellexec(argv, path, cmdentry.u.index); | 9863 | shellexec(argv, path, cmdentry.u.index); |
9441 | /* NOTREACHED */ | 9864 | /* NOTREACHED */ |
@@ -9824,7 +10247,7 @@ preadbuffer(void) | |||
9824 | more--; | 10247 | more--; |
9825 | 10248 | ||
9826 | c = *q; | 10249 | c = *q; |
9827 | if (c == '\0') { | 10250 | if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) { |
9828 | memmove(q, q + 1, more); | 10251 | memmove(q, q + 1, more); |
9829 | } else { | 10252 | } else { |
9830 | q++; | 10253 | q++; |
@@ -9980,6 +10403,7 @@ popallfiles(void) | |||
9980 | popfile(); | 10403 | popfile(); |
9981 | } | 10404 | } |
9982 | 10405 | ||
10406 | #if !ENABLE_PLATFORM_MINGW32 | ||
9983 | /* | 10407 | /* |
9984 | * Close the file(s) that the shell is reading commands from. Called | 10408 | * Close the file(s) that the shell is reading commands from. Called |
9985 | * after a fork is done. | 10409 | * after a fork is done. |
@@ -9993,6 +10417,7 @@ closescript(void) | |||
9993 | g_parsefile->pf_fd = 0; | 10417 | g_parsefile->pf_fd = 0; |
9994 | } | 10418 | } |
9995 | } | 10419 | } |
10420 | #endif | ||
9996 | 10421 | ||
9997 | /* | 10422 | /* |
9998 | * Like setinputfile, but takes an open file descriptor. Call this with | 10423 | * Like setinputfile, but takes an open file descriptor. Call this with |
@@ -12256,7 +12681,7 @@ find_dot_file(char *name) | |||
12256 | struct stat statb; | 12681 | struct stat statb; |
12257 | 12682 | ||
12258 | /* don't try this for absolute or relative paths */ | 12683 | /* don't try this for absolute or relative paths */ |
12259 | if (strchr(name, '/')) | 12684 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) |
12260 | return name; | 12685 | return name; |
12261 | 12686 | ||
12262 | /* IIRC standards do not say whether . is to be searched. | 12687 | /* IIRC standards do not say whether . is to be searched. |
@@ -12371,10 +12796,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12371 | struct stat statb; | 12796 | struct stat statb; |
12372 | int e; | 12797 | int e; |
12373 | int updatetbl; | 12798 | int updatetbl; |
12799 | IF_PLATFORM_MINGW32(int len;) | ||
12374 | struct builtincmd *bcmd; | 12800 | struct builtincmd *bcmd; |
12375 | 12801 | ||
12376 | /* If name contains a slash, don't use PATH or hash table */ | 12802 | /* If name contains a slash, don't use PATH or hash table */ |
12377 | if (strchr(name, '/') != NULL) { | 12803 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) { |
12378 | entry->u.index = -1; | 12804 | entry->u.index = -1; |
12379 | if (act & DO_ABS) { | 12805 | if (act & DO_ABS) { |
12380 | while (stat(name, &statb) < 0) { | 12806 | while (stat(name, &statb) < 0) { |
@@ -12481,12 +12907,48 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12481 | } | 12907 | } |
12482 | } | 12908 | } |
12483 | /* if rehash, don't redo absolute path names */ | 12909 | /* if rehash, don't redo absolute path names */ |
12484 | if (fullname[0] == '/' && idx <= prev) { | 12910 | if (is_absolute_path(fullname) && idx <= prev) { |
12485 | if (idx < prev) | 12911 | if (idx < prev) |
12486 | continue; | 12912 | continue; |
12487 | TRACE(("searchexec \"%s\": no change\n", name)); | 12913 | TRACE(("searchexec \"%s\": no change\n", name)); |
12488 | goto success; | 12914 | goto success; |
12489 | } | 12915 | } |
12916 | #if ENABLE_PLATFORM_MINGW32 | ||
12917 | len = strlen(fullname); | ||
12918 | if (len > 4 && | ||
12919 | (!strcasecmp(fullname+len-4, ".exe") || | ||
12920 | !strcasecmp(fullname+len-4, ".com"))) { | ||
12921 | if (stat(fullname, &statb) < 0) { | ||
12922 | if (errno != ENOENT && errno != ENOTDIR) | ||
12923 | e = errno; | ||
12924 | goto loop; | ||
12925 | } | ||
12926 | } | ||
12927 | else { | ||
12928 | /* path_advance() has reserved space for .exe */ | ||
12929 | memcpy(fullname+len, ".exe", 5); | ||
12930 | if (stat(fullname, &statb) < 0) { | ||
12931 | if (errno != ENOENT && errno != ENOTDIR) | ||
12932 | e = errno; | ||
12933 | memcpy(fullname+len, ".com", 5); | ||
12934 | if (stat(fullname, &statb) < 0) { | ||
12935 | if (errno != ENOENT && errno != ENOTDIR) | ||
12936 | e = errno; | ||
12937 | fullname[len] = '\0'; | ||
12938 | if (stat(fullname, &statb) < 0) { | ||
12939 | if (errno != ENOENT && errno != ENOTDIR) | ||
12940 | e = errno; | ||
12941 | goto loop; | ||
12942 | } | ||
12943 | if (!file_is_executable(fullname)) { | ||
12944 | e = ENOEXEC; | ||
12945 | goto loop; | ||
12946 | } | ||
12947 | } | ||
12948 | } | ||
12949 | fullname[len] = '\0'; | ||
12950 | } | ||
12951 | #else | ||
12490 | while (stat(fullname, &statb) < 0) { | 12952 | while (stat(fullname, &statb) < 0) { |
12491 | #ifdef SYSV | 12953 | #ifdef SYSV |
12492 | if (errno == EINTR) | 12954 | if (errno == EINTR) |
@@ -12496,6 +12958,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12496 | e = errno; | 12958 | e = errno; |
12497 | goto loop; | 12959 | goto loop; |
12498 | } | 12960 | } |
12961 | #endif | ||
12499 | e = EACCES; /* if we fail, this will be the error */ | 12962 | e = EACCES; /* if we fail, this will be the error */ |
12500 | if (!S_ISREG(statb.st_mode)) | 12963 | if (!S_ISREG(statb.st_mode)) |
12501 | continue; | 12964 | continue; |
@@ -13036,6 +13499,57 @@ init(void) | |||
13036 | struct stat st1, st2; | 13499 | struct stat st1, st2; |
13037 | 13500 | ||
13038 | initvar(); | 13501 | initvar(); |
13502 | |||
13503 | #if ENABLE_PLATFORM_MINGW32 | ||
13504 | /* | ||
13505 | * case insensitive env names from Windows world | ||
13506 | * | ||
13507 | * Some standard env names such as PATH is named Path and so on | ||
13508 | * ash itself is case sensitive, so "Path" will confuse it, as | ||
13509 | * MSVC getenv() is case insensitive. | ||
13510 | * | ||
13511 | * We may end up having both Path and PATH. Then Path will be chosen | ||
13512 | * because it appears first. | ||
13513 | */ | ||
13514 | for (envp = environ; envp && *envp; envp++) { | ||
13515 | if (strncasecmp(*envp, "PATH=", 5) == 0 && | ||
13516 | strncmp(*envp, "PATH=", 5) != 0) { | ||
13517 | break; | ||
13518 | } | ||
13519 | } | ||
13520 | |||
13521 | if (envp && *envp) { | ||
13522 | /* | ||
13523 | * If we get here it's because the environment contains a path | ||
13524 | * variable called something other than PATH. This suggests we | ||
13525 | * haven't been invoked from an earlier instance of BusyBox. | ||
13526 | */ | ||
13527 | char *start, *end; | ||
13528 | struct passwd *pw; | ||
13529 | |||
13530 | for (envp = environ; envp && *envp; envp++) { | ||
13531 | end = strchr(*envp, '='); | ||
13532 | if (!end) | ||
13533 | continue; | ||
13534 | |||
13535 | /* make all variable names uppercase */ | ||
13536 | for (start = *envp;start < end;start++) | ||
13537 | *start = toupper(*start); | ||
13538 | |||
13539 | /* convert backslashes to forward slashes */ | ||
13540 | for ( ++end; *end; ++end ) { | ||
13541 | if ( *end == '\\' ) { | ||
13542 | *end = '/'; | ||
13543 | } | ||
13544 | } | ||
13545 | } | ||
13546 | |||
13547 | /* some initialisation normally performed at login */ | ||
13548 | pw = xgetpwuid(getuid()); | ||
13549 | setup_environment(pw->pw_shell, | ||
13550 | SETUP_ENV_CHANGEENV|SETUP_ENV_NO_CHDIR, pw); | ||
13551 | } | ||
13552 | #endif | ||
13039 | for (envp = environ; envp && *envp; envp++) { | 13553 | for (envp = environ; envp && *envp; envp++) { |
13040 | if (strchr(*envp, '=')) { | 13554 | if (strchr(*envp, '=')) { |
13041 | setvareq(*envp, VEXPORT|VTEXTFIXED); | 13555 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
@@ -13253,13 +13767,38 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13253 | 13767 | ||
13254 | init(); | 13768 | init(); |
13255 | setstackmark(&smark); | 13769 | setstackmark(&smark); |
13770 | |||
13771 | #if ENABLE_PLATFORM_MINGW32 | ||
13772 | hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL); | ||
13773 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
13774 | if (argc == 3 && !strcmp(argv[1], "--forkshell")) { | ||
13775 | forkshell_init(argv[2]); | ||
13776 | |||
13777 | /* NOTREACHED */ | ||
13778 | bb_error_msg_and_die("subshell ended unexpectedly"); | ||
13779 | } | ||
13780 | #endif | ||
13256 | procargs(argv); | 13781 | procargs(argv); |
13782 | #if ENABLE_PLATFORM_MINGW32 | ||
13783 | if ( noconsole ) { | ||
13784 | DWORD dummy; | ||
13785 | |||
13786 | if ( GetConsoleProcessList(&dummy, 1) == 1 ) { | ||
13787 | ShowWindow(GetConsoleWindow(), SW_HIDE); | ||
13788 | } | ||
13789 | } | ||
13790 | #endif | ||
13257 | 13791 | ||
13258 | if (argv[0] && argv[0][0] == '-') | 13792 | if (argv[0] && argv[0][0] == '-') |
13259 | isloginsh = 1; | 13793 | isloginsh = 1; |
13260 | if (isloginsh) { | 13794 | if (isloginsh) { |
13261 | const char *hp; | 13795 | const char *hp; |
13262 | 13796 | ||
13797 | #if ENABLE_PLATFORM_MINGW32 | ||
13798 | chdir(xgetpwuid(getuid())->pw_dir); | ||
13799 | setpwd(NULL, 0); | ||
13800 | #endif | ||
13801 | |||
13263 | state = 1; | 13802 | state = 1; |
13264 | read_profile("/etc/profile"); | 13803 | read_profile("/etc/profile"); |
13265 | state1: | 13804 | state1: |
@@ -13335,6 +13874,642 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13335 | /* NOTREACHED */ | 13874 | /* NOTREACHED */ |
13336 | } | 13875 | } |
13337 | 13876 | ||
13877 | #if ENABLE_PLATFORM_MINGW32 | ||
13878 | static void | ||
13879 | forkshell_openhere(struct forkshell *fs) | ||
13880 | { | ||
13881 | union node *redir = fs->n; | ||
13882 | int pip[2]; | ||
13883 | |||
13884 | pip[0] = fs->fd[0]; | ||
13885 | pip[1] = fs->fd[1]; | ||
13886 | |||
13887 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
13888 | |||
13889 | close(pip[0]); | ||
13890 | ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); | ||
13891 | ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); | ||
13892 | ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); | ||
13893 | ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); | ||
13894 | signal(SIGPIPE, SIG_DFL); | ||
13895 | if (redir->type == NHERE) { | ||
13896 | size_t len = strlen(redir->nhere.doc->narg.text); | ||
13897 | full_write(pip[1], redir->nhere.doc->narg.text, len); | ||
13898 | } else /* NXHERE */ | ||
13899 | expandhere(redir->nhere.doc, pip[1]); | ||
13900 | _exit(EXIT_SUCCESS); | ||
13901 | } | ||
13902 | |||
13903 | static void | ||
13904 | forkshell_evalbackcmd(struct forkshell *fs) | ||
13905 | { | ||
13906 | union node *n = fs->n; | ||
13907 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
13908 | |||
13909 | FORCE_INT_ON; | ||
13910 | close(pip[0]); | ||
13911 | if (pip[1] != 1) { | ||
13912 | /*close(1);*/ | ||
13913 | copyfd(pip[1], 1 | COPYFD_EXACT); | ||
13914 | close(pip[1]); | ||
13915 | } | ||
13916 | eflag = 0; | ||
13917 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ | ||
13918 | /* NOTREACHED */ | ||
13919 | } | ||
13920 | |||
13921 | static void | ||
13922 | forkshell_evalsubshell(struct forkshell *fs) | ||
13923 | { | ||
13924 | union node *n = fs->n; | ||
13925 | int flags = fs->flags; | ||
13926 | |||
13927 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
13928 | INT_ON; | ||
13929 | flags |= EV_EXIT; | ||
13930 | expredir(n->nredir.redirect); | ||
13931 | redirect(n->nredir.redirect, 0); | ||
13932 | evaltreenr(n->nredir.n, flags); | ||
13933 | /* never returns */ | ||
13934 | } | ||
13935 | |||
13936 | static void | ||
13937 | forkshell_evalpipe(struct forkshell *fs) | ||
13938 | { | ||
13939 | union node *n = fs->n; | ||
13940 | int flags = fs->flags; | ||
13941 | int prevfd = fs->fd[2]; | ||
13942 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
13943 | |||
13944 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
13945 | INT_ON; | ||
13946 | if (pip[1] >= 0) { | ||
13947 | close(pip[0]); | ||
13948 | } | ||
13949 | if (prevfd > 0) { | ||
13950 | dup2(prevfd, 0); | ||
13951 | close(prevfd); | ||
13952 | } | ||
13953 | if (pip[1] > 1) { | ||
13954 | dup2(pip[1], 1); | ||
13955 | close(pip[1]); | ||
13956 | } | ||
13957 | evaltreenr(n, flags); | ||
13958 | } | ||
13959 | |||
13960 | static void | ||
13961 | forkshell_shellexec(struct forkshell *fs) | ||
13962 | { | ||
13963 | int idx = fs->fd[0]; | ||
13964 | struct strlist *varlist = fs->strlist; | ||
13965 | char **argv = fs->argv; | ||
13966 | char *path = fs->string; | ||
13967 | |||
13968 | listsetvar(varlist, VEXPORT|VSTACK); | ||
13969 | shellexec(argv, path, idx); | ||
13970 | } | ||
13971 | |||
13972 | static void | ||
13973 | forkshell_child(struct forkshell *fs) | ||
13974 | { | ||
13975 | switch ( fs->fpid ) { | ||
13976 | case FS_OPENHERE: | ||
13977 | forkshell_openhere(fs); | ||
13978 | break; | ||
13979 | case FS_EVALBACKCMD: | ||
13980 | forkshell_evalbackcmd(fs); | ||
13981 | break; | ||
13982 | case FS_EVALSUBSHELL: | ||
13983 | forkshell_evalsubshell(fs); | ||
13984 | break; | ||
13985 | case FS_EVALPIPE: | ||
13986 | forkshell_evalpipe(fs); | ||
13987 | break; | ||
13988 | case FS_SHELLEXEC: | ||
13989 | forkshell_shellexec(fs); | ||
13990 | break; | ||
13991 | } | ||
13992 | } | ||
13993 | |||
13994 | /* | ||
13995 | * Reset the pointers to the builtin environment variables in the hash | ||
13996 | * table to point to varinit rather than the bogus copy created during | ||
13997 | * forkshell_prepare. | ||
13998 | */ | ||
13999 | static void | ||
14000 | reinitvar(void) | ||
14001 | { | ||
14002 | struct var *vp; | ||
14003 | struct var *end; | ||
14004 | struct var **vpp; | ||
14005 | struct var **old; | ||
14006 | |||
14007 | vp = varinit; | ||
14008 | end = vp + ARRAY_SIZE(varinit); | ||
14009 | do { | ||
14010 | vpp = hashvar(vp->var_text); | ||
14011 | if ( (old=findvar(vpp, vp->var_text)) != NULL ) { | ||
14012 | vp->next = (*old)->next; | ||
14013 | *old = vp; | ||
14014 | } | ||
14015 | } while (++vp < end); | ||
14016 | } | ||
14017 | |||
14018 | /* FIXME: should consider running forkparent() and forkchild() */ | ||
14019 | static int | ||
14020 | spawn_forkshell(struct job *jp, struct forkshell *fs, int mode) | ||
14021 | { | ||
14022 | struct forkshell *new; | ||
14023 | char buf[16]; | ||
14024 | const char *argv[] = { "sh", "--forkshell", NULL, NULL }; | ||
14025 | pid_t pid; | ||
14026 | |||
14027 | new = forkshell_prepare(fs); | ||
14028 | sprintf(buf, "%x", (unsigned int)new->hMapFile); | ||
14029 | argv[2] = buf; | ||
14030 | pid = mingw_spawn_applet(P_NOWAIT, "sh", argv, | ||
14031 | (const char *const *)environ); | ||
14032 | CloseHandle(new->hMapFile); | ||
14033 | UnmapViewOfFile(new); | ||
14034 | if (pid == -1) { | ||
14035 | free(jp); | ||
14036 | return -1; | ||
14037 | } | ||
14038 | forkparent(jp, fs->node, mode, pid); | ||
14039 | return pid; | ||
14040 | } | ||
14041 | |||
14042 | /* | ||
14043 | * forkshell_prepare() and friends | ||
14044 | * | ||
14045 | * The sequence is as follows: | ||
14046 | * - funcblocksize, funcstringsize, nodeptrsize are initialized | ||
14047 | * - forkshell_size(fs) is called to calculate the exact memory needed | ||
14048 | * - a new struct is allocated | ||
14049 | * - funcblock, funcstring, nodeptr are initialized from the new block | ||
14050 | * - forkshell_copy(fs) is called to copy recursively everything over | ||
14051 | * it will record all pointers along the way, to nodeptr | ||
14052 | * | ||
14053 | * When this memory is mapped elsewhere, pointer fixup will be needed | ||
14054 | */ | ||
14055 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
14056 | static void \ | ||
14057 | name(type *p) \ | ||
14058 | { \ | ||
14059 | while (p) { \ | ||
14060 | funcblocksize += sizeof(type); | ||
14061 | /* do something here with p */ | ||
14062 | #define SLIST_SIZE_END() \ | ||
14063 | nodeptrsize++; \ | ||
14064 | p = p->next; \ | ||
14065 | } \ | ||
14066 | } | ||
14067 | |||
14068 | #define SLIST_COPY_BEGIN(name,type) \ | ||
14069 | static type * \ | ||
14070 | name(type *vp) \ | ||
14071 | { \ | ||
14072 | type *start; \ | ||
14073 | type **vpp; \ | ||
14074 | vpp = &start; \ | ||
14075 | while (vp) { \ | ||
14076 | *vpp = funcblock; \ | ||
14077 | funcblock = (char *) funcblock + sizeof(type); | ||
14078 | /* do something here with vpp and vp */ | ||
14079 | #define SLIST_COPY_END() \ | ||
14080 | SAVE_PTR((*vpp)->next); \ | ||
14081 | vp = vp->next; \ | ||
14082 | vpp = &(*vpp)->next; \ | ||
14083 | } \ | ||
14084 | *vpp = NULL; \ | ||
14085 | return start; \ | ||
14086 | } | ||
14087 | |||
14088 | /* | ||
14089 | * struct var | ||
14090 | */ | ||
14091 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
14092 | funcstringsize += strlen(p->var_text) + 1; | ||
14093 | nodeptrsize++; /* p->text */ | ||
14094 | SLIST_SIZE_END() | ||
14095 | |||
14096 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
14097 | (*vpp)->var_text = nodeckstrdup(vp->var_text); | ||
14098 | (*vpp)->flags = vp->flags; | ||
14099 | /* | ||
14100 | * The only place that can set struct var#func is varinit[], | ||
14101 | * which will be fixed by forkshell_init() | ||
14102 | */ | ||
14103 | (*vpp)->var_func = NULL; | ||
14104 | SAVE_PTR((*vpp)->var_text); | ||
14105 | SLIST_COPY_END() | ||
14106 | |||
14107 | /* | ||
14108 | * struct strlist | ||
14109 | */ | ||
14110 | SLIST_SIZE_BEGIN(strlist_size,struct strlist) | ||
14111 | funcstringsize += strlen(p->text) + 1; | ||
14112 | nodeptrsize++; /* p->text */ | ||
14113 | SLIST_SIZE_END() | ||
14114 | |||
14115 | SLIST_COPY_BEGIN(strlist_copy,struct strlist) | ||
14116 | (*vpp)->text = nodeckstrdup(vp->text); | ||
14117 | SAVE_PTR((*vpp)->text); | ||
14118 | SLIST_COPY_END() | ||
14119 | |||
14120 | /* | ||
14121 | * struct tblentry | ||
14122 | */ | ||
14123 | static void | ||
14124 | tblentry_size(struct tblentry *tep) | ||
14125 | { | ||
14126 | while (tep) { | ||
14127 | funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
14128 | /* CMDBUILTIN, e->param.cmd needs no pointer relocation */ | ||
14129 | if (tep->cmdtype == CMDFUNCTION) { | ||
14130 | funcblocksize += offsetof(struct funcnode, n); | ||
14131 | calcsize(&tep->param.func->n); | ||
14132 | nodeptrsize++; /* tep->param.func */ | ||
14133 | } | ||
14134 | nodeptrsize++; /* tep->next */ | ||
14135 | tep = tep->next; | ||
14136 | } | ||
14137 | } | ||
14138 | |||
14139 | static struct tblentry * | ||
14140 | tblentry_copy(struct tblentry *tep) | ||
14141 | { | ||
14142 | struct tblentry *start; | ||
14143 | struct tblentry **newp; | ||
14144 | int size; | ||
14145 | |||
14146 | newp = &start; | ||
14147 | while (tep) { | ||
14148 | *newp = funcblock; | ||
14149 | size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
14150 | |||
14151 | funcblock = (char *) funcblock + size; | ||
14152 | memcpy(*newp, tep, size); | ||
14153 | switch (tep->cmdtype) { | ||
14154 | case CMDBUILTIN: | ||
14155 | /* No pointer saving, this field must be fixed by forkshell_init() */ | ||
14156 | (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab); | ||
14157 | break; | ||
14158 | case CMDFUNCTION: | ||
14159 | (*newp)->param.func = funcblock; | ||
14160 | funcblock = (char *) funcblock + offsetof(struct funcnode, n); | ||
14161 | copynode(&tep->param.func->n); | ||
14162 | SAVE_PTR((*newp)->param.func); | ||
14163 | break; | ||
14164 | default: | ||
14165 | break; | ||
14166 | } | ||
14167 | SAVE_PTR((*newp)->next); | ||
14168 | tep = tep->next; | ||
14169 | newp = &(*newp)->next; | ||
14170 | } | ||
14171 | *newp = NULL; | ||
14172 | return start; | ||
14173 | } | ||
14174 | |||
14175 | static void | ||
14176 | cmdtable_size(struct tblentry **cmdtablep) | ||
14177 | { | ||
14178 | int i; | ||
14179 | nodeptrsize += CMDTABLESIZE; | ||
14180 | funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE; | ||
14181 | for (i = 0; i < CMDTABLESIZE; i++) | ||
14182 | tblentry_size(cmdtablep[i]); | ||
14183 | } | ||
14184 | |||
14185 | static struct tblentry ** | ||
14186 | cmdtable_copy(struct tblentry **cmdtablep) | ||
14187 | { | ||
14188 | struct tblentry **new = funcblock; | ||
14189 | int i; | ||
14190 | |||
14191 | funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE; | ||
14192 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
14193 | new[i] = tblentry_copy(cmdtablep[i]); | ||
14194 | SAVE_PTR(new[i]); | ||
14195 | } | ||
14196 | return new; | ||
14197 | } | ||
14198 | |||
14199 | /* | ||
14200 | * char ** | ||
14201 | */ | ||
14202 | static void | ||
14203 | argv_size(char **p) | ||
14204 | { | ||
14205 | while (p && *p) { | ||
14206 | funcblocksize += sizeof(char *); | ||
14207 | funcstringsize += strlen(*p)+1; | ||
14208 | nodeptrsize++; | ||
14209 | p++; | ||
14210 | } | ||
14211 | funcblocksize += sizeof(char *); | ||
14212 | } | ||
14213 | |||
14214 | static char ** | ||
14215 | argv_copy(char **p) | ||
14216 | { | ||
14217 | char **new, **start = funcblock; | ||
14218 | |||
14219 | while (p && *p) { | ||
14220 | new = funcblock; | ||
14221 | funcblock = (char *) funcblock + sizeof(char *); | ||
14222 | *new = nodeckstrdup(*p); | ||
14223 | SAVE_PTR(*new); | ||
14224 | p++; | ||
14225 | new++; | ||
14226 | } | ||
14227 | new = funcblock; | ||
14228 | funcblock = (char *) funcblock + sizeof(char *); | ||
14229 | *new = NULL; | ||
14230 | return start; | ||
14231 | } | ||
14232 | |||
14233 | /* | ||
14234 | * struct redirtab | ||
14235 | */ | ||
14236 | static void | ||
14237 | redirtab_size(struct redirtab *rdtp) | ||
14238 | { | ||
14239 | while (rdtp) { | ||
14240 | funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
14241 | rdtp = rdtp->next; | ||
14242 | nodeptrsize++; /* rdtp->next */ | ||
14243 | } | ||
14244 | } | ||
14245 | |||
14246 | static struct redirtab * | ||
14247 | redirtab_copy(struct redirtab *rdtp) | ||
14248 | { | ||
14249 | struct redirtab *start; | ||
14250 | struct redirtab **vpp; | ||
14251 | |||
14252 | vpp = &start; | ||
14253 | while (rdtp) { | ||
14254 | int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
14255 | *vpp = funcblock; | ||
14256 | funcblock = (char *) funcblock + size; | ||
14257 | memcpy(*vpp, rdtp, size); | ||
14258 | SAVE_PTR((*vpp)->next); | ||
14259 | rdtp = rdtp->next; | ||
14260 | vpp = &(*vpp)->next; | ||
14261 | } | ||
14262 | *vpp = NULL; | ||
14263 | return start; | ||
14264 | } | ||
14265 | |||
14266 | #undef shellparam | ||
14267 | #undef redirlist | ||
14268 | #undef varinit | ||
14269 | #undef vartab | ||
14270 | static void | ||
14271 | globals_var_size(struct globals_var *gvp) | ||
14272 | { | ||
14273 | int i; | ||
14274 | |||
14275 | funcblocksize += sizeof(struct globals_var); | ||
14276 | argv_size(gvp->shellparam.p); | ||
14277 | redirtab_size(gvp->redirlist); | ||
14278 | for (i = 0; i < VTABSIZE; i++) | ||
14279 | var_size(gvp->vartab[i]); | ||
14280 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
14281 | var_size(gvp->varinit+i); | ||
14282 | nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */ | ||
14283 | } | ||
14284 | |||
14285 | #undef g_nullredirs | ||
14286 | #undef preverrout_fd | ||
14287 | static struct globals_var * | ||
14288 | globals_var_copy(struct globals_var *gvp) | ||
14289 | { | ||
14290 | int i; | ||
14291 | struct globals_var *new; | ||
14292 | |||
14293 | new = funcblock; | ||
14294 | funcblock = (char *) funcblock + sizeof(struct globals_var); | ||
14295 | |||
14296 | /* shparam */ | ||
14297 | memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam)); | ||
14298 | new->shellparam.malloced = 0; | ||
14299 | new->shellparam.p = argv_copy(gvp->shellparam.p); | ||
14300 | SAVE_PTR(new->shellparam.p); | ||
14301 | |||
14302 | new->redirlist = redirtab_copy(gvp->redirlist); | ||
14303 | SAVE_PTR(new->redirlist); | ||
14304 | |||
14305 | new->g_nullredirs = gvp->g_nullredirs; | ||
14306 | new->preverrout_fd = gvp->preverrout_fd; | ||
14307 | for (i = 0; i < VTABSIZE; i++) { | ||
14308 | new->vartab[i] = var_copy(gvp->vartab[i]); | ||
14309 | SAVE_PTR(new->vartab[i]); | ||
14310 | } | ||
14311 | |||
14312 | /* Can't use var_copy because varinit is already allocated */ | ||
14313 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { | ||
14314 | new->varinit[i].next = NULL; | ||
14315 | new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text); | ||
14316 | SAVE_PTR(new->varinit[i].var_text); | ||
14317 | new->varinit[i].flags = gvp->varinit[i].flags; | ||
14318 | new->varinit[i].var_func = gvp->varinit[i].var_func; | ||
14319 | } | ||
14320 | return new; | ||
14321 | } | ||
14322 | |||
14323 | #undef minusc | ||
14324 | #undef curdir | ||
14325 | #undef physdir | ||
14326 | #undef arg0 | ||
14327 | #undef nullstr | ||
14328 | static void | ||
14329 | globals_misc_size(struct globals_misc *p) | ||
14330 | { | ||
14331 | funcblocksize += sizeof(struct globals_misc); | ||
14332 | funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1; | ||
14333 | if (p->curdir != p->nullstr) | ||
14334 | funcstringsize += strlen(p->curdir) + 1; | ||
14335 | if (p->physdir != p->nullstr) | ||
14336 | funcstringsize += strlen(p->physdir) + 1; | ||
14337 | funcstringsize += strlen(p->arg0) + 1; | ||
14338 | nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */ | ||
14339 | } | ||
14340 | |||
14341 | static struct globals_misc * | ||
14342 | globals_misc_copy(struct globals_misc *p) | ||
14343 | { | ||
14344 | struct globals_misc *new = funcblock; | ||
14345 | |||
14346 | funcblock = (char *) funcblock + sizeof(struct globals_misc); | ||
14347 | memcpy(new, p, sizeof(struct globals_misc)); | ||
14348 | |||
14349 | new->minusc = nodeckstrdup(p->minusc); | ||
14350 | new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr; | ||
14351 | new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr; | ||
14352 | new->arg0 = nodeckstrdup(p->arg0); | ||
14353 | SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0); | ||
14354 | return new; | ||
14355 | } | ||
14356 | |||
14357 | static void | ||
14358 | forkshell_size(struct forkshell *fs) | ||
14359 | { | ||
14360 | funcblocksize += sizeof(struct forkshell); | ||
14361 | globals_var_size(fs->gvp); | ||
14362 | globals_misc_size(fs->gmp); | ||
14363 | cmdtable_size(fs->cmdtable); | ||
14364 | /* optlist_transfer(sending, fd); */ | ||
14365 | /* misc_transfer(sending, fd); */ | ||
14366 | |||
14367 | calcsize(fs->n); | ||
14368 | argv_size(fs->argv); | ||
14369 | funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1; | ||
14370 | strlist_size(fs->strlist); | ||
14371 | |||
14372 | nodeptrsize += 7; /* gvp, gmp, cmdtable, n, argv, string, strlist */ | ||
14373 | } | ||
14374 | |||
14375 | static struct forkshell * | ||
14376 | forkshell_copy(struct forkshell *fs) | ||
14377 | { | ||
14378 | struct forkshell *new; | ||
14379 | |||
14380 | new = funcblock; | ||
14381 | funcblock = (char *) funcblock + sizeof(struct forkshell); | ||
14382 | |||
14383 | memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */ | ||
14384 | new->gvp = globals_var_copy(fs->gvp); | ||
14385 | new->gmp = globals_misc_copy(fs->gmp); | ||
14386 | new->cmdtable = cmdtable_copy(fs->cmdtable); | ||
14387 | SAVE_PTR3(new->gvp, new->gmp, new->cmdtable); | ||
14388 | |||
14389 | new->n = copynode(fs->n); | ||
14390 | new->argv = argv_copy(fs->argv); | ||
14391 | new->string = nodeckstrdup(fs->string); | ||
14392 | new->strlist = strlist_copy(fs->strlist); | ||
14393 | SAVE_PTR4(new->n, new->argv, new->string, new->strlist); | ||
14394 | return new; | ||
14395 | } | ||
14396 | |||
14397 | static struct forkshell * | ||
14398 | forkshell_prepare(struct forkshell *fs) | ||
14399 | { | ||
14400 | struct forkshell *new; | ||
14401 | int size, nodeptr_offset; | ||
14402 | HANDLE h; | ||
14403 | SECURITY_ATTRIBUTES sa; | ||
14404 | |||
14405 | /* Calculate size of "new" */ | ||
14406 | fs->gvp = ash_ptr_to_globals_var; | ||
14407 | fs->gmp = ash_ptr_to_globals_misc; | ||
14408 | fs->cmdtable = cmdtable; | ||
14409 | |||
14410 | nodeptrsize = 1; /* NULL terminated */ | ||
14411 | funcblocksize = 0; | ||
14412 | funcstringsize = 0; | ||
14413 | forkshell_size(fs); | ||
14414 | size = funcblocksize + funcstringsize + nodeptrsize*sizeof(int); | ||
14415 | |||
14416 | /* Allocate, initialize pointers */ | ||
14417 | memset(&sa, 0, sizeof(sa)); | ||
14418 | sa.nLength = sizeof(sa); | ||
14419 | sa.lpSecurityDescriptor = NULL; | ||
14420 | sa.bInheritHandle = TRUE; | ||
14421 | h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL); | ||
14422 | new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
14423 | /* new = ckmalloc(size); */ | ||
14424 | funcblock = new; | ||
14425 | funcstring = (char *) funcblock + funcblocksize; | ||
14426 | nodeptr = (int*)((char *) funcstring + funcstringsize); | ||
14427 | nodeptr_offset = (int) nodeptr - (int) new; | ||
14428 | |||
14429 | /* Now pack them all */ | ||
14430 | forkshell_copy(fs); | ||
14431 | |||
14432 | /* Finish it up */ | ||
14433 | *nodeptr = 0; | ||
14434 | new->size = size; | ||
14435 | new->nodeptr_offset = nodeptr_offset; | ||
14436 | new->old_base = new; | ||
14437 | new->hMapFile = h; | ||
14438 | return new; | ||
14439 | } | ||
14440 | |||
14441 | #undef exception_handler | ||
14442 | #undef trap | ||
14443 | #undef trap_ptr | ||
14444 | static void *sticky_mem_start, *sticky_mem_end; | ||
14445 | static void | ||
14446 | forkshell_init(const char *idstr) | ||
14447 | { | ||
14448 | struct forkshell *fs; | ||
14449 | int map_handle; | ||
14450 | HANDLE h; | ||
14451 | struct globals_var **gvpp; | ||
14452 | struct globals_misc **gmpp; | ||
14453 | int i; | ||
14454 | |||
14455 | if (sscanf(idstr, "%x", &map_handle) != 1) | ||
14456 | bb_error_msg_and_die("invalid forkshell ID"); | ||
14457 | |||
14458 | h = (HANDLE)map_handle; | ||
14459 | fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
14460 | if (!fs) | ||
14461 | bb_error_msg_and_die("Invalid forkshell memory"); | ||
14462 | |||
14463 | /* this memory can't be freed */ | ||
14464 | sticky_mem_start = fs; | ||
14465 | sticky_mem_end = (char *) fs + fs->size; | ||
14466 | /* pointer fixup */ | ||
14467 | nodeptr = (int*)((char*)fs + fs->nodeptr_offset); | ||
14468 | while (*nodeptr) { | ||
14469 | int *ptr = (int*)((char*)fs + (*nodeptr - (int)fs->old_base)); | ||
14470 | if (*ptr) | ||
14471 | *ptr -= ((int)fs->old_base - (int)fs); | ||
14472 | nodeptr++; | ||
14473 | } | ||
14474 | /* Now fix up stuff that can't be transferred */ | ||
14475 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
14476 | fs->gvp->varinit[i].var_func = varinit_data[i].var_func; | ||
14477 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
14478 | struct tblentry *e = fs->cmdtable[i]; | ||
14479 | while (e) { | ||
14480 | if (e->cmdtype == CMDBUILTIN) | ||
14481 | e->param.cmd = builtintab + (int)e->param.cmd; | ||
14482 | e = e->next; | ||
14483 | } | ||
14484 | } | ||
14485 | fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler; | ||
14486 | for (i = 0; i < NSIG; i++) | ||
14487 | fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i]; | ||
14488 | fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr; | ||
14489 | |||
14490 | /* Switch global variables */ | ||
14491 | gvpp = (struct globals_var **)&ash_ptr_to_globals_var; | ||
14492 | *gvpp = fs->gvp; | ||
14493 | gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc; | ||
14494 | *gmpp = fs->gmp; | ||
14495 | cmdtable = fs->cmdtable; | ||
14496 | |||
14497 | CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */ | ||
14498 | |||
14499 | reinitvar(); | ||
14500 | |||
14501 | forkshell_child(fs); | ||
14502 | } | ||
14503 | |||
14504 | #undef free | ||
14505 | static void | ||
14506 | sticky_free(void *base) | ||
14507 | { | ||
14508 | if (base >= sticky_mem_start && base < sticky_mem_end) | ||
14509 | return; | ||
14510 | free(base); | ||
14511 | } | ||
14512 | #endif | ||
13338 | 14513 | ||
13339 | /*- | 14514 | /*- |
13340 | * Copyright (c) 1989, 1991, 1993, 1994 | 14515 | * Copyright (c) 1989, 1991, 1993, 1994 |