diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 1172 |
1 files changed, 1156 insertions, 16 deletions
diff --git a/shell/ash.c b/shell/ash.c index b50e0952e..eaaa71967 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -17,6 +17,18 @@ | |||
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" is still understood as executable (option to turn off?) | ||
25 | * - both / and \ are supported in PATH. Usually you must use / | ||
26 | * - trap/job does not work | ||
27 | * - /dev/null is supported for redirection | ||
28 | * - no $PPID | ||
29 | */ | ||
30 | |||
31 | /* | ||
20 | * The following should be set to reflect the type of system you have: | 32 | * The following should be set to reflect the type of system you have: |
21 | * JOBS -> 1 if you have Berkeley job control, 0 otherwise. | 33 | * JOBS -> 1 if you have Berkeley job control, 0 otherwise. |
22 | * define SYSV if you are running under System V. | 34 | * define SYSV if you are running under System V. |
@@ -36,7 +48,10 @@ | |||
36 | 48 | ||
37 | #define JOBS ENABLE_ASH_JOB_CONTROL | 49 | #define JOBS ENABLE_ASH_JOB_CONTROL |
38 | 50 | ||
51 | #include "busybox.h" /* for applet_names */ | ||
52 | #ifndef __MINGW32__ | ||
39 | #include <paths.h> | 53 | #include <paths.h> |
54 | #endif | ||
40 | #include <setjmp.h> | 55 | #include <setjmp.h> |
41 | #include <fnmatch.h> | 56 | #include <fnmatch.h> |
42 | #include <sys/times.h> | 57 | #include <sys/times.h> |
@@ -192,6 +207,41 @@ | |||
192 | //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o | 207 | //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o |
193 | //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o | 208 | //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o |
194 | 209 | ||
210 | #if ENABLE_PLATFORM_MINGW32 | ||
211 | struct forkshell; | ||
212 | union node; | ||
213 | struct strlist; | ||
214 | struct job; | ||
215 | |||
216 | typedef void (*forkpoint_fn)(struct forkshell *fs); | ||
217 | struct forkshell { | ||
218 | /* filled by forkshell_copy() */ | ||
219 | struct globals_var *gvp; | ||
220 | struct globals_misc *gmp; | ||
221 | struct tblentry **cmdtable; | ||
222 | struct localvar *localvars; | ||
223 | /* struct alias **atab; */ | ||
224 | /* struct parsefile *g_parsefile; */ | ||
225 | int fpid; | ||
226 | HANDLE hMapFile; | ||
227 | void *old_base; | ||
228 | int nodeptr_offset; | ||
229 | int size; | ||
230 | |||
231 | forkpoint_fn fp; | ||
232 | /* optional data, used by forkpoint_fn */ | ||
233 | int flags; | ||
234 | int fd[10]; | ||
235 | union node *n; | ||
236 | char **argv; | ||
237 | char *string; | ||
238 | struct strlist *strlist; | ||
239 | pid_t pid; | ||
240 | }; | ||
241 | static void sticky_free(void *p); | ||
242 | #define free(p) sticky_free(p) | ||
243 | static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode); | ||
244 | #endif | ||
195 | 245 | ||
196 | /* ============ Hash table sizes. Configurable. */ | 246 | /* ============ Hash table sizes. Configurable. */ |
197 | 247 | ||
@@ -896,7 +946,7 @@ static void | |||
896 | opentrace(void) | 946 | opentrace(void) |
897 | { | 947 | { |
898 | char s[100]; | 948 | char s[100]; |
899 | #ifdef O_APPEND | 949 | #if defined(O_APPEND) && !ENABLE_PLATFORM_MINGW32 |
900 | int flags; | 950 | int flags; |
901 | #endif | 951 | #endif |
902 | 952 | ||
@@ -921,7 +971,7 @@ opentrace(void) | |||
921 | return; | 971 | return; |
922 | } | 972 | } |
923 | } | 973 | } |
924 | #ifdef O_APPEND | 974 | #if defined(O_APPEND) && !ENABLE_PLATFORM_MINGW32 |
925 | flags = fcntl(fileno(tracefile), F_GETFL); | 975 | flags = fcntl(fileno(tracefile), F_GETFL); |
926 | if (flags >= 0) | 976 | if (flags >= 0) |
927 | fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); | 977 | fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); |
@@ -2382,10 +2432,22 @@ path_advance(const char **path, const char *name) | |||
2382 | if (*path == NULL) | 2432 | if (*path == NULL) |
2383 | return NULL; | 2433 | return NULL; |
2384 | start = *path; | 2434 | start = *path; |
2435 | #if ENABLE_PLATFORM_MINGW32 | ||
2436 | p = next_path_sep(start); | ||
2437 | q = strchr(start, '%'); | ||
2438 | if ((p && q && q < p) || (!p && q)) | ||
2439 | p = q; | ||
2440 | if (!p) | ||
2441 | for (p = start; *p; p++) | ||
2442 | continue; | ||
2443 | #else | ||
2385 | for (p = start; *p && *p != ':' && *p != '%'; p++) | 2444 | for (p = start; *p && *p != ':' && *p != '%'; p++) |
2386 | continue; | 2445 | continue; |
2446 | #endif | ||
2387 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ | 2447 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ |
2388 | while (stackblocksize() < len) | 2448 | |
2449 | /* preserve space for .exe too */ | ||
2450 | while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len)) | ||
2389 | growstackblock(); | 2451 | growstackblock(); |
2390 | q = stackblock(); | 2452 | q = stackblock(); |
2391 | if (p != start) { | 2453 | if (p != start) { |
@@ -2397,10 +2459,19 @@ path_advance(const char **path, const char *name) | |||
2397 | pathopt = NULL; | 2459 | pathopt = NULL; |
2398 | if (*p == '%') { | 2460 | if (*p == '%') { |
2399 | pathopt = ++p; | 2461 | pathopt = ++p; |
2462 | #if ENABLE_PLATFORM_MINGW32 | ||
2463 | p = next_path_sep(start); | ||
2464 | |||
2465 | /* *p != ':' and '*' would suffice */ | ||
2466 | if (!p) | ||
2467 | p = pathopt - 1; | ||
2468 | #else | ||
2400 | while (*p && *p != ':') | 2469 | while (*p && *p != ':') |
2401 | p++; | 2470 | p++; |
2471 | #endif | ||
2402 | } | 2472 | } |
2403 | if (*p == ':') | 2473 | if (*p == ':' || |
2474 | (ENABLE_PLATFORM_MINGW32 && *p == ';')) | ||
2404 | *path = p + 1; | 2475 | *path = p + 1; |
2405 | else | 2476 | else |
2406 | *path = NULL; | 2477 | *path = NULL; |
@@ -2502,6 +2573,99 @@ cdopt(void) | |||
2502 | static const char * | 2573 | static const char * |
2503 | updatepwd(const char *dir) | 2574 | updatepwd(const char *dir) |
2504 | { | 2575 | { |
2576 | #if ENABLE_PLATFORM_MINGW32 | ||
2577 | #define is_path_sep(x) ((x) == '/' || (x) == '\\') | ||
2578 | /* | ||
2579 | * Due to Windows drive notion, getting pwd is a completely | ||
2580 | * different thing. Handle it in a separate routine | ||
2581 | */ | ||
2582 | |||
2583 | char *new; | ||
2584 | char *p; | ||
2585 | char *cdcomppath; | ||
2586 | const char *lim; | ||
2587 | /* | ||
2588 | * There are four cases | ||
2589 | * absdrive + abspath: c:/path | ||
2590 | * absdrive + !abspath: c:path | ||
2591 | * !absdrive + abspath: /path | ||
2592 | * !absdrive + !abspath: path | ||
2593 | * | ||
2594 | * Damn DOS! | ||
2595 | * c:path behaviour is "undefined" | ||
2596 | * To properly handle this case, I have to keep track of cwd | ||
2597 | * of every drive, which is too painful to do. | ||
2598 | * So when c:path is given, I assume it's c:${curdir}path | ||
2599 | * with ${curdir} comes from the current drive | ||
2600 | */ | ||
2601 | int absdrive = *dir && dir[1] == ':'; | ||
2602 | int abspath = absdrive ? is_path_sep(dir[2]) : is_path_sep(*dir); | ||
2603 | char *drive; | ||
2604 | |||
2605 | cdcomppath = ststrdup(dir); | ||
2606 | STARTSTACKSTR(new); | ||
2607 | if (!absdrive && curdir == nullstr) | ||
2608 | return 0; | ||
2609 | if (!abspath) { | ||
2610 | if (curdir == nullstr) | ||
2611 | return 0; | ||
2612 | new = stack_putstr(curdir, new); | ||
2613 | } | ||
2614 | new = makestrspace(strlen(dir) + 2, new); | ||
2615 | |||
2616 | drive = stackblock(); | ||
2617 | if (absdrive) { | ||
2618 | *drive = *dir; | ||
2619 | cdcomppath += 2; | ||
2620 | dir += 2; | ||
2621 | } else { | ||
2622 | *drive = *curdir; | ||
2623 | } | ||
2624 | drive[1] = ':'; /* in case of absolute drive+path */ | ||
2625 | |||
2626 | if (abspath) | ||
2627 | new = drive + 2; | ||
2628 | lim = drive + 3; | ||
2629 | if (!abspath) { | ||
2630 | if (!is_path_sep(new[-1])) | ||
2631 | USTPUTC('/', new); | ||
2632 | if (new > lim && is_path_sep(*lim)) | ||
2633 | lim++; | ||
2634 | } else { | ||
2635 | USTPUTC('/', new); | ||
2636 | cdcomppath ++; | ||
2637 | if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) { | ||
2638 | USTPUTC('/', new); | ||
2639 | cdcomppath++; | ||
2640 | lim++; | ||
2641 | } | ||
2642 | } | ||
2643 | p = strtok(cdcomppath, "/\\"); | ||
2644 | while (p) { | ||
2645 | switch (*p) { | ||
2646 | case '.': | ||
2647 | if (p[1] == '.' && p[2] == '\0') { | ||
2648 | while (new > lim) { | ||
2649 | STUNPUTC(new); | ||
2650 | if (is_path_sep(new[-1])) | ||
2651 | break; | ||
2652 | } | ||
2653 | break; | ||
2654 | } | ||
2655 | if (p[1] == '\0') | ||
2656 | break; | ||
2657 | /* fall through */ | ||
2658 | default: | ||
2659 | new = stack_putstr(p, new); | ||
2660 | USTPUTC('/', new); | ||
2661 | } | ||
2662 | p = strtok(0, "/\\"); | ||
2663 | } | ||
2664 | if (new > lim) | ||
2665 | STUNPUTC(new); | ||
2666 | *new = 0; | ||
2667 | return stackblock(); | ||
2668 | #else | ||
2505 | char *new; | 2669 | char *new; |
2506 | char *p; | 2670 | char *p; |
2507 | char *cdcomppath; | 2671 | char *cdcomppath; |
@@ -2555,6 +2719,7 @@ updatepwd(const char *dir) | |||
2555 | STUNPUTC(new); | 2719 | STUNPUTC(new); |
2556 | *new = 0; | 2720 | *new = 0; |
2557 | return stackblock(); | 2721 | return stackblock(); |
2722 | #endif | ||
2558 | } | 2723 | } |
2559 | 2724 | ||
2560 | /* | 2725 | /* |
@@ -2649,7 +2814,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2649 | } | 2814 | } |
2650 | if (!dest) | 2815 | if (!dest) |
2651 | dest = nullstr; | 2816 | dest = nullstr; |
2652 | if (*dest == '/') | 2817 | if (is_absolute_path(dest)) |
2653 | goto step7; | 2818 | goto step7; |
2654 | if (*dest == '.') { | 2819 | if (*dest == '.') { |
2655 | c = dest[1]; | 2820 | c = dest[1]; |
@@ -3421,6 +3586,8 @@ setsignal(int signo) | |||
3421 | char cur_act, new_act; | 3586 | char cur_act, new_act; |
3422 | struct sigaction act; | 3587 | struct sigaction act; |
3423 | 3588 | ||
3589 | if (ENABLE_PLATFORM_MINGW32) | ||
3590 | return; | ||
3424 | t = trap[signo]; | 3591 | t = trap[signo]; |
3425 | new_act = S_DFL; | 3592 | new_act = S_DFL; |
3426 | if (t != NULL) { /* trap for this sig is set */ | 3593 | if (t != NULL) { /* trap for this sig is set */ |
@@ -3733,7 +3900,7 @@ setjobctl(int on) | |||
3733 | if (--fd < 0) | 3900 | if (--fd < 0) |
3734 | goto out; | 3901 | goto out; |
3735 | } | 3902 | } |
3736 | fd = fcntl(fd, F_DUPFD, 10); | 3903 | fd = copyfd(fd, 10); |
3737 | if (ofd >= 0) | 3904 | if (ofd >= 0) |
3738 | close(ofd); | 3905 | close(ofd); |
3739 | if (fd < 0) | 3906 | if (fd < 0) |
@@ -3941,6 +4108,79 @@ sprint_status(char *s, int status, int sigonly) | |||
3941 | return col; | 4108 | return col; |
3942 | } | 4109 | } |
3943 | 4110 | ||
4111 | #if ENABLE_PLATFORM_MINGW32 | ||
4112 | |||
4113 | HANDLE hSIGINT; /* Ctrl-C is pressed */ | ||
4114 | |||
4115 | static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) | ||
4116 | { | ||
4117 | if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { | ||
4118 | SetEvent(hSIGINT); | ||
4119 | return TRUE; | ||
4120 | } | ||
4121 | return FALSE; | ||
4122 | } | ||
4123 | |||
4124 | /* | ||
4125 | * Windows does not know about parent-child relationship | ||
4126 | * They don't support waitpid(-1) | ||
4127 | */ | ||
4128 | static pid_t | ||
4129 | waitpid_child(int *status, int wait_flags) | ||
4130 | { | ||
4131 | HANDLE *pidlist, *pidp; | ||
4132 | int pid_nr = 0; | ||
4133 | pid_t pid; | ||
4134 | DWORD win_status, idx; | ||
4135 | struct job *jb; | ||
4136 | |||
4137 | #define LOOP(stmt) \ | ||
4138 | for (jb = curjob; jb; jb = jb->prev_job) { \ | ||
4139 | struct procstat *ps, *psend; \ | ||
4140 | if (jb->state == JOBDONE) \ | ||
4141 | continue; \ | ||
4142 | ps = jb->ps; \ | ||
4143 | psend = ps + jb->nprocs; \ | ||
4144 | while (ps < psend) { \ | ||
4145 | if (ps->ps_pid != -1) { \ | ||
4146 | stmt; \ | ||
4147 | } \ | ||
4148 | ps++; \ | ||
4149 | } \ | ||
4150 | } | ||
4151 | |||
4152 | LOOP(pid_nr++); | ||
4153 | if (!pid_nr) | ||
4154 | return -1; | ||
4155 | pid_nr++; | ||
4156 | pidp = pidlist = ckmalloc(sizeof(*pidlist)*pid_nr); | ||
4157 | *pidp++ = hSIGINT; | ||
4158 | LOOP(*pidp++ = (HANDLE)ps->ps_pid); | ||
4159 | #undef LOOP | ||
4160 | |||
4161 | idx = WaitForMultipleObjects(pid_nr, pidlist, FALSE, | ||
4162 | wait_flags|WNOHANG ? 0 : INFINITE); | ||
4163 | if (idx >= pid_nr) { | ||
4164 | free(pidlist); | ||
4165 | return -1; | ||
4166 | } | ||
4167 | if (!idx) { /* hSIGINT */ | ||
4168 | int i; | ||
4169 | ResetEvent(hSIGINT); | ||
4170 | for (i = 1; i < pid_nr; i++) | ||
4171 | TerminateProcess(pidlist[i], 1); | ||
4172 | free(pidlist); | ||
4173 | *status = 260; /* terminated by a signal */ | ||
4174 | return pidlist[1]; | ||
4175 | } | ||
4176 | GetExitCodeProcess(pidlist[idx], &win_status); | ||
4177 | pid = (int)pidlist[idx]; | ||
4178 | free(pidlist); | ||
4179 | *status = (int)win_status; | ||
4180 | return pid; | ||
4181 | } | ||
4182 | #endif | ||
4183 | |||
3944 | static int | 4184 | static int |
3945 | dowait(int wait_flags, struct job *job) | 4185 | dowait(int wait_flags, struct job *job) |
3946 | { | 4186 | { |
@@ -3957,7 +4197,11 @@ dowait(int wait_flags, struct job *job) | |||
3957 | * NB: _not_ safe_waitpid, we need to detect EINTR */ | 4197 | * NB: _not_ safe_waitpid, we need to detect EINTR */ |
3958 | if (doing_jobctl) | 4198 | if (doing_jobctl) |
3959 | wait_flags |= WUNTRACED; | 4199 | wait_flags |= WUNTRACED; |
4200 | #if ENABLE_PLATFORM_MINGW32 | ||
4201 | pid = waitpid_child(&status, wait_flags); | ||
4202 | #else | ||
3960 | pid = waitpid(-1, &status, wait_flags); | 4203 | pid = waitpid(-1, &status, wait_flags); |
4204 | #endif | ||
3961 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", | 4205 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", |
3962 | pid, status, errno, strerror(errno))); | 4206 | pid, status, errno, strerror(errno))); |
3963 | if (pid <= 0) | 4207 | if (pid <= 0) |
@@ -3980,6 +4224,8 @@ dowait(int wait_flags, struct job *job) | |||
3980 | jobno(jp), pid, ps->ps_status, status)); | 4224 | jobno(jp), pid, ps->ps_status, status)); |
3981 | ps->ps_status = status; | 4225 | ps->ps_status = status; |
3982 | thisjob = jp; | 4226 | thisjob = jp; |
4227 | if (ENABLE_PLATFORM_MINGW32) | ||
4228 | ps->ps_pid = -1; | ||
3983 | } | 4229 | } |
3984 | if (ps->ps_status == -1) | 4230 | if (ps->ps_status == -1) |
3985 | state = JOBRUNNING; | 4231 | state = JOBRUNNING; |
@@ -4211,6 +4457,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
4211 | int retval; | 4457 | int retval; |
4212 | struct job *jp; | 4458 | struct job *jp; |
4213 | 4459 | ||
4460 | if (ENABLE_PLATFORM_MINGW32) | ||
4461 | return 0; | ||
4462 | |||
4214 | if (pending_sig) | 4463 | if (pending_sig) |
4215 | raise_exception(EXSIG); | 4464 | raise_exception(EXSIG); |
4216 | 4465 | ||
@@ -4823,7 +5072,7 @@ static void | |||
4823 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 5072 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
4824 | { | 5073 | { |
4825 | TRACE(("In parent shell: child = %d\n", pid)); | 5074 | TRACE(("In parent shell: child = %d\n", pid)); |
4826 | if (!jp) { | 5075 | if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */ |
4827 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) | 5076 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) |
4828 | continue; | 5077 | continue; |
4829 | jobless++; | 5078 | jobless++; |
@@ -4863,6 +5112,9 @@ forkshell(struct job *jp, union node *n, int mode) | |||
4863 | int pid; | 5112 | int pid; |
4864 | 5113 | ||
4865 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); | 5114 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); |
5115 | if (ENABLE_PLATFORM_MINGW32) | ||
5116 | return -1; | ||
5117 | |||
4866 | pid = fork(); | 5118 | pid = fork(); |
4867 | if (pid < 0) { | 5119 | if (pid < 0) { |
4868 | TRACE(("Fork failed, errno=%d", errno)); | 5120 | TRACE(("Fork failed, errno=%d", errno)); |
@@ -5065,11 +5317,39 @@ noclobberopen(const char *fname) | |||
5065 | */ | 5317 | */ |
5066 | /* openhere needs this forward reference */ | 5318 | /* openhere needs this forward reference */ |
5067 | static void expandhere(union node *arg, int fd); | 5319 | static void expandhere(union node *arg, int fd); |
5320 | #if ENABLE_PLATFORM_MINGW32 | ||
5321 | static void | ||
5322 | forkshell_openhere(struct forkshell *fs) | ||
5323 | { | ||
5324 | union node *redir = fs->n; | ||
5325 | int pip[2]; | ||
5326 | |||
5327 | pip[0] = fs->fd[0]; | ||
5328 | pip[1] = fs->fd[1]; | ||
5329 | |||
5330 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
5331 | |||
5332 | close(pip[0]); | ||
5333 | ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); | ||
5334 | ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); | ||
5335 | ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); | ||
5336 | ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); | ||
5337 | signal(SIGPIPE, SIG_DFL); | ||
5338 | if (redir->type == NHERE) { | ||
5339 | size_t len = strlen(redir->nhere.doc->narg.text); | ||
5340 | full_write(pip[1], redir->nhere.doc->narg.text, len); | ||
5341 | } else /* NXHERE */ | ||
5342 | expandhere(redir->nhere.doc, pip[1]); | ||
5343 | _exit(EXIT_SUCCESS); | ||
5344 | } | ||
5345 | #endif | ||
5346 | |||
5068 | static int | 5347 | static int |
5069 | openhere(union node *redir) | 5348 | openhere(union node *redir) |
5070 | { | 5349 | { |
5071 | int pip[2]; | 5350 | int pip[2]; |
5072 | size_t len = 0; | 5351 | size_t len = 0; |
5352 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5073 | 5353 | ||
5074 | if (pipe(pip) < 0) | 5354 | if (pipe(pip) < 0) |
5075 | ash_msg_and_raise_error("pipe call failed"); | 5355 | ash_msg_and_raise_error("pipe call failed"); |
@@ -5080,6 +5360,16 @@ openhere(union node *redir) | |||
5080 | goto out; | 5360 | goto out; |
5081 | } | 5361 | } |
5082 | } | 5362 | } |
5363 | #if ENABLE_PLATFORM_MINGW32 | ||
5364 | memset(&fs, 0, sizeof(fs)); | ||
5365 | fs.fp = forkshell_openhere; | ||
5366 | fs.flags = 0; | ||
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 | #endif | ||
5083 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | 5373 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { |
5084 | /* child */ | 5374 | /* child */ |
5085 | close(pip[0]); | 5375 | close(pip[0]); |
@@ -5105,6 +5395,31 @@ openredirect(union node *redir) | |||
5105 | char *fname; | 5395 | char *fname; |
5106 | int f; | 5396 | int f; |
5107 | 5397 | ||
5398 | #if ENABLE_PLATFORM_MINGW32 | ||
5399 | /* Support for /dev/null */ | ||
5400 | switch (redir->nfile.type) { | ||
5401 | case NFROM: | ||
5402 | if (!strcmp(redir->nfile.expfname, "/dev/null")) | ||
5403 | return open("nul",O_RDWR); | ||
5404 | if (!strncmp(redir->nfile.expfname, "/dev/", 5)) { | ||
5405 | ash_msg("Unhandled device %s\n", redir->nfile.expfname); | ||
5406 | return -1; | ||
5407 | } | ||
5408 | break; | ||
5409 | |||
5410 | case NFROMTO: | ||
5411 | case NTO: | ||
5412 | case NCLOBBER: | ||
5413 | case NAPPEND: | ||
5414 | if (!strcmp(redir->nfile.expfname, "/dev/null")) | ||
5415 | return open("nul",O_RDWR); | ||
5416 | if (!strncmp(redir->nfile.expfname, "/dev/", 5)) { | ||
5417 | ash_msg("Unhandled device %s\n", redir->nfile.expfname); | ||
5418 | return -1; | ||
5419 | } | ||
5420 | break; | ||
5421 | } | ||
5422 | #endif | ||
5108 | switch (redir->nfile.type) { | 5423 | switch (redir->nfile.type) { |
5109 | case NFROM: | 5424 | case NFROM: |
5110 | fname = redir->nfile.expfname; | 5425 | fname = redir->nfile.expfname; |
@@ -5187,6 +5502,18 @@ copyfd(int from, int to) | |||
5187 | /*if (from != to)*/ | 5502 | /*if (from != to)*/ |
5188 | newfd = dup2(from, to); | 5503 | newfd = dup2(from, to); |
5189 | } else { | 5504 | } else { |
5505 | if (ENABLE_PLATFORM_MINGW32) { | ||
5506 | char* fds = ckmalloc(to); | ||
5507 | int i,fd; | ||
5508 | memset(fds,0,to); | ||
5509 | while ((fd = dup(from)) < to && fd >= 0) | ||
5510 | fds[fd] = 1; | ||
5511 | for (i = 0;i < to;i ++) | ||
5512 | if (fds[i]) | ||
5513 | close(i); | ||
5514 | free(fds); | ||
5515 | return fd; | ||
5516 | } | ||
5190 | newfd = fcntl(from, F_DUPFD, to); | 5517 | newfd = fcntl(from, F_DUPFD, to); |
5191 | } | 5518 | } |
5192 | if (newfd < 0) { | 5519 | if (newfd < 0) { |
@@ -5345,7 +5672,7 @@ redirect(union node *redir, int flags) | |||
5345 | /* Careful to not accidentally "save" | 5672 | /* Careful to not accidentally "save" |
5346 | * to the same fd as right side fd in N>&M */ | 5673 | * to the same fd as right side fd in N>&M */ |
5347 | int minfd = right_fd < 10 ? 10 : right_fd + 1; | 5674 | int minfd = right_fd < 10 ? 10 : right_fd + 1; |
5348 | i = fcntl(fd, F_DUPFD, minfd); | 5675 | i = copyfd(fd, minfd); |
5349 | /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds | 5676 | /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds |
5350 | * are closed in popredir() in the child, preventing them from leaking | 5677 | * are closed in popredir() in the child, preventing them from leaking |
5351 | * into child. (popredir() also cleans up the mess in case of failures) | 5678 | * into child. (popredir() also cleans up the mess in case of failures) |
@@ -5807,6 +6134,8 @@ exptilde(char *startp, char *p, int flags) | |||
5807 | if (*name == '\0') { | 6134 | if (*name == '\0') { |
5808 | home = lookupvar("HOME"); | 6135 | home = lookupvar("HOME"); |
5809 | } else { | 6136 | } else { |
6137 | if (ENABLE_PLATFORM_MINGW32) | ||
6138 | goto lose; | ||
5810 | pw = getpwnam(name); | 6139 | pw = getpwnam(name); |
5811 | if (pw == NULL) | 6140 | if (pw == NULL) |
5812 | goto lose; | 6141 | goto lose; |
@@ -5834,6 +6163,7 @@ struct backcmd { /* result of evalbackcmd */ | |||
5834 | int fd; /* file descriptor to read from */ | 6163 | int fd; /* file descriptor to read from */ |
5835 | int nleft; /* number of chars in buffer */ | 6164 | int nleft; /* number of chars in buffer */ |
5836 | char *buf; /* buffer */ | 6165 | char *buf; /* buffer */ |
6166 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5837 | struct job *jp; /* job structure for command */ | 6167 | struct job *jp; /* job structure for command */ |
5838 | }; | 6168 | }; |
5839 | 6169 | ||
@@ -5842,6 +6172,25 @@ static uint8_t back_exitstatus; /* exit status of backquoted command */ | |||
5842 | #define EV_EXIT 01 /* exit after evaluating tree */ | 6172 | #define EV_EXIT 01 /* exit after evaluating tree */ |
5843 | static void evaltree(union node *, int); | 6173 | static void evaltree(union node *, int); |
5844 | 6174 | ||
6175 | #if ENABLE_PLATFORM_MINGW32 | ||
6176 | static void | ||
6177 | forkshell_evalbackcmd(struct forkshell *fs) | ||
6178 | { | ||
6179 | union node *n = fs->n; | ||
6180 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
6181 | |||
6182 | FORCE_INT_ON; | ||
6183 | close(pip[0]); | ||
6184 | if (pip[1] != 1) { | ||
6185 | /*close(1);*/ | ||
6186 | copyfd(pip[1], 1 | COPYFD_EXACT); | ||
6187 | close(pip[1]); | ||
6188 | } | ||
6189 | eflag = 0; | ||
6190 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ | ||
6191 | /* NOTREACHED */ | ||
6192 | } | ||
6193 | #endif | ||
5845 | static void FAST_FUNC | 6194 | static void FAST_FUNC |
5846 | evalbackcmd(union node *n, struct backcmd *result) | 6195 | evalbackcmd(union node *n, struct backcmd *result) |
5847 | { | 6196 | { |
@@ -5850,6 +6199,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5850 | result->fd = -1; | 6199 | result->fd = -1; |
5851 | result->buf = NULL; | 6200 | result->buf = NULL; |
5852 | result->nleft = 0; | 6201 | result->nleft = 0; |
6202 | IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs))); | ||
5853 | result->jp = NULL; | 6203 | result->jp = NULL; |
5854 | if (n == NULL) | 6204 | if (n == NULL) |
5855 | goto out; | 6205 | goto out; |
@@ -5864,6 +6214,14 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5864 | if (pipe(pip) < 0) | 6214 | if (pipe(pip) < 0) |
5865 | ash_msg_and_raise_error("pipe call failed"); | 6215 | ash_msg_and_raise_error("pipe call failed"); |
5866 | jp = makejob(/*n,*/ 1); | 6216 | jp = makejob(/*n,*/ 1); |
6217 | #if ENABLE_PLATFORM_MINGW32 | ||
6218 | result->fs.fp = forkshell_evalbackcmd; | ||
6219 | result->fs.n = n; | ||
6220 | result->fs.fd[0] = pip[0]; | ||
6221 | result->fs.fd[1] = pip[1]; | ||
6222 | if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0) | ||
6223 | ash_msg_and_raise_error("unable to spawn shell"); | ||
6224 | #endif | ||
5867 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 6225 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
5868 | FORCE_INT_ON; | 6226 | FORCE_INT_ON; |
5869 | close(pip[0]); | 6227 | close(pip[0]); |
@@ -5934,7 +6292,8 @@ expbackq(union node *cmd, int quoted, int quotes) | |||
5934 | 6292 | ||
5935 | /* Eat all trailing newlines */ | 6293 | /* Eat all trailing newlines */ |
5936 | dest = expdest; | 6294 | dest = expdest; |
5937 | for (; dest > (char *)stackblock() && dest[-1] == '\n';) | 6295 | for (; dest > (char *)stackblock() && (dest[-1] == '\n' || |
6296 | (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));) | ||
5938 | STUNPUTC(dest); | 6297 | STUNPUTC(dest); |
5939 | expdest = dest; | 6298 | expdest = dest; |
5940 | 6299 | ||
@@ -7471,7 +7830,7 @@ shellexec(char **argv, const char *path, int idx) | |||
7471 | 7830 | ||
7472 | clearredir(/*drop:*/ 1); | 7831 | clearredir(/*drop:*/ 1); |
7473 | envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); | 7832 | envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); |
7474 | if (strchr(argv[0], '/') != NULL | 7833 | if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\'))) |
7475 | #if ENABLE_FEATURE_SH_STANDALONE | 7834 | #if ENABLE_FEATURE_SH_STANDALONE |
7476 | || (applet_no = find_applet_by_name(argv[0])) >= 0 | 7835 | || (applet_no = find_applet_by_name(argv[0])) >= 0 |
7477 | #endif | 7836 | #endif |
@@ -7974,6 +8333,10 @@ static int funcblocksize; /* size of structures in function */ | |||
7974 | static int funcstringsize; /* size of strings in node */ | 8333 | static int funcstringsize; /* size of strings in node */ |
7975 | static void *funcblock; /* block to allocate function from */ | 8334 | static void *funcblock; /* block to allocate function from */ |
7976 | static char *funcstring; /* block to allocate strings from */ | 8335 | static char *funcstring; /* block to allocate strings from */ |
8336 | #if ENABLE_PLATFORM_MINGW32 | ||
8337 | static int nodeptrsize; | ||
8338 | static int *nodeptr; | ||
8339 | #endif | ||
7977 | 8340 | ||
7978 | /* flags in argument to evaltree */ | 8341 | /* flags in argument to evaltree */ |
7979 | #define EV_EXIT 01 /* exit after evaluating tree */ | 8342 | #define EV_EXIT 01 /* exit after evaluating tree */ |
@@ -8019,6 +8382,7 @@ sizenodelist(struct nodelist *lp) | |||
8019 | { | 8382 | { |
8020 | while (lp) { | 8383 | while (lp) { |
8021 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); | 8384 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); |
8385 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8022 | calcsize(lp->n); | 8386 | calcsize(lp->n); |
8023 | lp = lp->next; | 8387 | lp = lp->next; |
8024 | } | 8388 | } |
@@ -8035,15 +8399,18 @@ calcsize(union node *n) | |||
8035 | calcsize(n->ncmd.redirect); | 8399 | calcsize(n->ncmd.redirect); |
8036 | calcsize(n->ncmd.args); | 8400 | calcsize(n->ncmd.args); |
8037 | calcsize(n->ncmd.assign); | 8401 | calcsize(n->ncmd.assign); |
8402 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8038 | break; | 8403 | break; |
8039 | case NPIPE: | 8404 | case NPIPE: |
8040 | sizenodelist(n->npipe.cmdlist); | 8405 | sizenodelist(n->npipe.cmdlist); |
8406 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
8041 | break; | 8407 | break; |
8042 | case NREDIR: | 8408 | case NREDIR: |
8043 | case NBACKGND: | 8409 | case NBACKGND: |
8044 | case NSUBSHELL: | 8410 | case NSUBSHELL: |
8045 | calcsize(n->nredir.redirect); | 8411 | calcsize(n->nredir.redirect); |
8046 | calcsize(n->nredir.n); | 8412 | calcsize(n->nredir.n); |
8413 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8047 | break; | 8414 | break; |
8048 | case NAND: | 8415 | case NAND: |
8049 | case NOR: | 8416 | case NOR: |
@@ -8052,31 +8419,37 @@ calcsize(union node *n) | |||
8052 | case NUNTIL: | 8419 | case NUNTIL: |
8053 | calcsize(n->nbinary.ch2); | 8420 | calcsize(n->nbinary.ch2); |
8054 | calcsize(n->nbinary.ch1); | 8421 | calcsize(n->nbinary.ch1); |
8422 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8055 | break; | 8423 | break; |
8056 | case NIF: | 8424 | case NIF: |
8057 | calcsize(n->nif.elsepart); | 8425 | calcsize(n->nif.elsepart); |
8058 | calcsize(n->nif.ifpart); | 8426 | calcsize(n->nif.ifpart); |
8059 | calcsize(n->nif.test); | 8427 | calcsize(n->nif.test); |
8428 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8060 | break; | 8429 | break; |
8061 | case NFOR: | 8430 | case NFOR: |
8062 | funcstringsize += strlen(n->nfor.var) + 1; | 8431 | funcstringsize += strlen(n->nfor.var) + 1; |
8063 | calcsize(n->nfor.body); | 8432 | calcsize(n->nfor.body); |
8064 | calcsize(n->nfor.args); | 8433 | calcsize(n->nfor.args); |
8434 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8065 | break; | 8435 | break; |
8066 | case NCASE: | 8436 | case NCASE: |
8067 | calcsize(n->ncase.cases); | 8437 | calcsize(n->ncase.cases); |
8068 | calcsize(n->ncase.expr); | 8438 | calcsize(n->ncase.expr); |
8439 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8069 | break; | 8440 | break; |
8070 | case NCLIST: | 8441 | case NCLIST: |
8071 | calcsize(n->nclist.body); | 8442 | calcsize(n->nclist.body); |
8072 | calcsize(n->nclist.pattern); | 8443 | calcsize(n->nclist.pattern); |
8073 | calcsize(n->nclist.next); | 8444 | calcsize(n->nclist.next); |
8445 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8074 | break; | 8446 | break; |
8075 | case NDEFUN: | 8447 | case NDEFUN: |
8076 | case NARG: | 8448 | case NARG: |
8077 | sizenodelist(n->narg.backquote); | 8449 | sizenodelist(n->narg.backquote); |
8078 | funcstringsize += strlen(n->narg.text) + 1; | 8450 | funcstringsize += strlen(n->narg.text) + 1; |
8079 | calcsize(n->narg.next); | 8451 | calcsize(n->narg.next); |
8452 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8080 | break; | 8453 | break; |
8081 | case NTO: | 8454 | case NTO: |
8082 | #if ENABLE_ASH_BASH_COMPAT | 8455 | #if ENABLE_ASH_BASH_COMPAT |
@@ -8088,28 +8461,34 @@ calcsize(union node *n) | |||
8088 | case NAPPEND: | 8461 | case NAPPEND: |
8089 | calcsize(n->nfile.fname); | 8462 | calcsize(n->nfile.fname); |
8090 | calcsize(n->nfile.next); | 8463 | calcsize(n->nfile.next); |
8464 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8091 | break; | 8465 | break; |
8092 | case NTOFD: | 8466 | case NTOFD: |
8093 | case NFROMFD: | 8467 | case NFROMFD: |
8094 | calcsize(n->ndup.vname); | 8468 | calcsize(n->ndup.vname); |
8095 | calcsize(n->ndup.next); | 8469 | calcsize(n->ndup.next); |
8470 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8096 | break; | 8471 | break; |
8097 | case NHERE: | 8472 | case NHERE: |
8098 | case NXHERE: | 8473 | case NXHERE: |
8099 | calcsize(n->nhere.doc); | 8474 | calcsize(n->nhere.doc); |
8100 | calcsize(n->nhere.next); | 8475 | calcsize(n->nhere.next); |
8476 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8101 | break; | 8477 | break; |
8102 | case NNOT: | 8478 | case NNOT: |
8103 | calcsize(n->nnot.com); | 8479 | calcsize(n->nnot.com); |
8480 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
8104 | break; | 8481 | break; |
8105 | }; | 8482 | }; |
8106 | } | 8483 | } |
8107 | 8484 | ||
8108 | static char * | 8485 | static char * |
8109 | nodeckstrdup(char *s) | 8486 | nodeckstrdup(const char *s) |
8110 | { | 8487 | { |
8111 | char *rtn = funcstring; | 8488 | char *rtn = funcstring; |
8112 | 8489 | ||
8490 | if (!s) | ||
8491 | return NULL; | ||
8113 | strcpy(funcstring, s); | 8492 | strcpy(funcstring, s); |
8114 | funcstring += strlen(s) + 1; | 8493 | funcstring += strlen(s) + 1; |
8115 | return rtn; | 8494 | return rtn; |
@@ -8117,6 +8496,18 @@ nodeckstrdup(char *s) | |||
8117 | 8496 | ||
8118 | static union node *copynode(union node *); | 8497 | static union node *copynode(union node *); |
8119 | 8498 | ||
8499 | #if ENABLE_PLATFORM_MINGW32 | ||
8500 | # define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (int)&(dst);} | ||
8501 | # define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);}} | ||
8502 | # define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);}} | ||
8503 | # define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);*nodeptr++ = (int)&(dst4);}} | ||
8504 | #else | ||
8505 | # define SAVE_PTR(dst) | ||
8506 | # define SAVE_PTR2(dst,dst2) | ||
8507 | # define SAVE_PTR3(dst,dst2,dst3) | ||
8508 | # define SAVE_PTR4(dst,dst2,dst3,dst4) | ||
8509 | #endif | ||
8510 | |||
8120 | static struct nodelist * | 8511 | static struct nodelist * |
8121 | copynodelist(struct nodelist *lp) | 8512 | copynodelist(struct nodelist *lp) |
8122 | { | 8513 | { |
@@ -8128,6 +8519,7 @@ copynodelist(struct nodelist *lp) | |||
8128 | *lpp = funcblock; | 8519 | *lpp = funcblock; |
8129 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); | 8520 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); |
8130 | (*lpp)->n = copynode(lp->n); | 8521 | (*lpp)->n = copynode(lp->n); |
8522 | SAVE_PTR2((*lpp)->n, (*lpp)->next); | ||
8131 | lp = lp->next; | 8523 | lp = lp->next; |
8132 | lpp = &(*lpp)->next; | 8524 | lpp = &(*lpp)->next; |
8133 | } | 8525 | } |
@@ -8150,16 +8542,19 @@ copynode(union node *n) | |||
8150 | new->ncmd.redirect = copynode(n->ncmd.redirect); | 8542 | new->ncmd.redirect = copynode(n->ncmd.redirect); |
8151 | new->ncmd.args = copynode(n->ncmd.args); | 8543 | new->ncmd.args = copynode(n->ncmd.args); |
8152 | new->ncmd.assign = copynode(n->ncmd.assign); | 8544 | new->ncmd.assign = copynode(n->ncmd.assign); |
8545 | SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign); | ||
8153 | break; | 8546 | break; |
8154 | case NPIPE: | 8547 | case NPIPE: |
8155 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | 8548 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); |
8156 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; | 8549 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; |
8550 | SAVE_PTR(new->npipe.cmdlist); | ||
8157 | break; | 8551 | break; |
8158 | case NREDIR: | 8552 | case NREDIR: |
8159 | case NBACKGND: | 8553 | case NBACKGND: |
8160 | case NSUBSHELL: | 8554 | case NSUBSHELL: |
8161 | new->nredir.redirect = copynode(n->nredir.redirect); | 8555 | new->nredir.redirect = copynode(n->nredir.redirect); |
8162 | new->nredir.n = copynode(n->nredir.n); | 8556 | new->nredir.n = copynode(n->nredir.n); |
8557 | SAVE_PTR2(new->nredir.redirect,new->nredir.n); | ||
8163 | break; | 8558 | break; |
8164 | case NAND: | 8559 | case NAND: |
8165 | case NOR: | 8560 | case NOR: |
@@ -8168,31 +8563,37 @@ copynode(union node *n) | |||
8168 | case NUNTIL: | 8563 | case NUNTIL: |
8169 | new->nbinary.ch2 = copynode(n->nbinary.ch2); | 8564 | new->nbinary.ch2 = copynode(n->nbinary.ch2); |
8170 | new->nbinary.ch1 = copynode(n->nbinary.ch1); | 8565 | new->nbinary.ch1 = copynode(n->nbinary.ch1); |
8566 | SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2); | ||
8171 | break; | 8567 | break; |
8172 | case NIF: | 8568 | case NIF: |
8173 | new->nif.elsepart = copynode(n->nif.elsepart); | 8569 | new->nif.elsepart = copynode(n->nif.elsepart); |
8174 | new->nif.ifpart = copynode(n->nif.ifpart); | 8570 | new->nif.ifpart = copynode(n->nif.ifpart); |
8175 | new->nif.test = copynode(n->nif.test); | 8571 | new->nif.test = copynode(n->nif.test); |
8572 | SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test); | ||
8176 | break; | 8573 | break; |
8177 | case NFOR: | 8574 | case NFOR: |
8178 | new->nfor.var = nodeckstrdup(n->nfor.var); | 8575 | new->nfor.var = nodeckstrdup(n->nfor.var); |
8179 | new->nfor.body = copynode(n->nfor.body); | 8576 | new->nfor.body = copynode(n->nfor.body); |
8180 | new->nfor.args = copynode(n->nfor.args); | 8577 | new->nfor.args = copynode(n->nfor.args); |
8578 | SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args); | ||
8181 | break; | 8579 | break; |
8182 | case NCASE: | 8580 | case NCASE: |
8183 | new->ncase.cases = copynode(n->ncase.cases); | 8581 | new->ncase.cases = copynode(n->ncase.cases); |
8184 | new->ncase.expr = copynode(n->ncase.expr); | 8582 | new->ncase.expr = copynode(n->ncase.expr); |
8583 | SAVE_PTR2(new->ncase.cases,new->ncase.expr); | ||
8185 | break; | 8584 | break; |
8186 | case NCLIST: | 8585 | case NCLIST: |
8187 | new->nclist.body = copynode(n->nclist.body); | 8586 | new->nclist.body = copynode(n->nclist.body); |
8188 | new->nclist.pattern = copynode(n->nclist.pattern); | 8587 | new->nclist.pattern = copynode(n->nclist.pattern); |
8189 | new->nclist.next = copynode(n->nclist.next); | 8588 | new->nclist.next = copynode(n->nclist.next); |
8589 | SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next); | ||
8190 | break; | 8590 | break; |
8191 | case NDEFUN: | 8591 | case NDEFUN: |
8192 | case NARG: | 8592 | case NARG: |
8193 | new->narg.backquote = copynodelist(n->narg.backquote); | 8593 | new->narg.backquote = copynodelist(n->narg.backquote); |
8194 | new->narg.text = nodeckstrdup(n->narg.text); | 8594 | new->narg.text = nodeckstrdup(n->narg.text); |
8195 | new->narg.next = copynode(n->narg.next); | 8595 | new->narg.next = copynode(n->narg.next); |
8596 | SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next); | ||
8196 | break; | 8597 | break; |
8197 | case NTO: | 8598 | case NTO: |
8198 | #if ENABLE_ASH_BASH_COMPAT | 8599 | #if ENABLE_ASH_BASH_COMPAT |
@@ -8205,6 +8606,7 @@ copynode(union node *n) | |||
8205 | new->nfile.fname = copynode(n->nfile.fname); | 8606 | new->nfile.fname = copynode(n->nfile.fname); |
8206 | new->nfile.fd = n->nfile.fd; | 8607 | new->nfile.fd = n->nfile.fd; |
8207 | new->nfile.next = copynode(n->nfile.next); | 8608 | new->nfile.next = copynode(n->nfile.next); |
8609 | SAVE_PTR2(new->nfile.fname,new->nfile.next); | ||
8208 | break; | 8610 | break; |
8209 | case NTOFD: | 8611 | case NTOFD: |
8210 | case NFROMFD: | 8612 | case NFROMFD: |
@@ -8212,15 +8614,18 @@ copynode(union node *n) | |||
8212 | new->ndup.dupfd = n->ndup.dupfd; | 8614 | new->ndup.dupfd = n->ndup.dupfd; |
8213 | new->ndup.fd = n->ndup.fd; | 8615 | new->ndup.fd = n->ndup.fd; |
8214 | new->ndup.next = copynode(n->ndup.next); | 8616 | new->ndup.next = copynode(n->ndup.next); |
8617 | SAVE_PTR2(new->ndup.vname,new->ndup.next); | ||
8215 | break; | 8618 | break; |
8216 | case NHERE: | 8619 | case NHERE: |
8217 | case NXHERE: | 8620 | case NXHERE: |
8218 | new->nhere.doc = copynode(n->nhere.doc); | 8621 | new->nhere.doc = copynode(n->nhere.doc); |
8219 | new->nhere.fd = n->nhere.fd; | 8622 | new->nhere.fd = n->nhere.fd; |
8220 | new->nhere.next = copynode(n->nhere.next); | 8623 | new->nhere.next = copynode(n->nhere.next); |
8624 | SAVE_PTR2(new->nhere.doc,new->nhere.next); | ||
8221 | break; | 8625 | break; |
8222 | case NNOT: | 8626 | case NNOT: |
8223 | new->nnot.com = copynode(n->nnot.com); | 8627 | new->nnot.com = copynode(n->nnot.com); |
8628 | SAVE_PTR(new->nnot.com); | ||
8224 | break; | 8629 | break; |
8225 | }; | 8630 | }; |
8226 | new->type = n->type; | 8631 | new->type = n->type; |
@@ -8243,6 +8648,7 @@ copyfunc(union node *n) | |||
8243 | f = ckmalloc(blocksize + funcstringsize); | 8648 | f = ckmalloc(blocksize + funcstringsize); |
8244 | funcblock = (char *) f + offsetof(struct funcnode, n); | 8649 | funcblock = (char *) f + offsetof(struct funcnode, n); |
8245 | funcstring = (char *) f + blocksize; | 8650 | funcstring = (char *) f + blocksize; |
8651 | IF_PLATFORM_MINGW32(nodeptr = NULL); | ||
8246 | copynode(n); | 8652 | copynode(n); |
8247 | f->count = 0; | 8653 | f->count = 0; |
8248 | return f; | 8654 | return f; |
@@ -8599,9 +9005,26 @@ evalcase(union node *n, int flags) | |||
8599 | /* | 9005 | /* |
8600 | * Kick off a subshell to evaluate a tree. | 9006 | * Kick off a subshell to evaluate a tree. |
8601 | */ | 9007 | */ |
9008 | #if ENABLE_PLATFORM_MINGW32 | ||
9009 | static void | ||
9010 | forkshell_evalsubshell(struct forkshell *fs) | ||
9011 | { | ||
9012 | union node *n = fs->n; | ||
9013 | int flags = fs->flags; | ||
9014 | |||
9015 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
9016 | INT_ON; | ||
9017 | flags |= EV_EXIT; | ||
9018 | expredir(n->nredir.redirect); | ||
9019 | redirect(n->nredir.redirect, 0); | ||
9020 | evaltreenr(n->nredir.n, flags); | ||
9021 | /* never returns */ | ||
9022 | } | ||
9023 | #endif | ||
8602 | static void | 9024 | static void |
8603 | evalsubshell(union node *n, int flags) | 9025 | evalsubshell(union node *n, int flags) |
8604 | { | 9026 | { |
9027 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
8605 | struct job *jp; | 9028 | struct job *jp; |
8606 | int backgnd = (n->type == NBACKGND); | 9029 | int backgnd = (n->type == NBACKGND); |
8607 | int status; | 9030 | int status; |
@@ -8611,6 +9034,14 @@ evalsubshell(union node *n, int flags) | |||
8611 | goto nofork; | 9034 | goto nofork; |
8612 | INT_OFF; | 9035 | INT_OFF; |
8613 | jp = makejob(/*n,*/ 1); | 9036 | jp = makejob(/*n,*/ 1); |
9037 | #if ENABLE_PLATFORM_MINGW32 | ||
9038 | memset(&fs, 0, sizeof(fs)); | ||
9039 | fs.fp = forkshell_evalsubshell; | ||
9040 | fs.n = n; | ||
9041 | fs.flags = flags; | ||
9042 | if (spawn_forkshell(jp, &fs, backgnd) < 0) | ||
9043 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9044 | #endif | ||
8614 | if (forkshell(jp, n, backgnd) == 0) { | 9045 | if (forkshell(jp, n, backgnd) == 0) { |
8615 | /* child */ | 9046 | /* child */ |
8616 | INT_ON; | 9047 | INT_ON; |
@@ -8687,9 +9118,35 @@ expredir(union node *n) | |||
8687 | * of the shell, which make the last process in a pipeline the parent | 9118 | * of the shell, which make the last process in a pipeline the parent |
8688 | * of all the rest.) | 9119 | * of all the rest.) |
8689 | */ | 9120 | */ |
9121 | #if ENABLE_PLATFORM_MINGW32 | ||
9122 | static void | ||
9123 | forkshell_evalpipe(struct forkshell *fs) | ||
9124 | { | ||
9125 | union node *n = fs->n; | ||
9126 | int flags = fs->flags; | ||
9127 | int prevfd = fs->fd[2]; | ||
9128 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
9129 | |||
9130 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
9131 | INT_ON; | ||
9132 | if (pip[1] >= 0) { | ||
9133 | close(pip[0]); | ||
9134 | } | ||
9135 | if (prevfd > 0) { | ||
9136 | dup2(prevfd, 0); | ||
9137 | close(prevfd); | ||
9138 | } | ||
9139 | if (pip[1] > 1) { | ||
9140 | dup2(pip[1], 1); | ||
9141 | close(pip[1]); | ||
9142 | } | ||
9143 | evaltreenr(n, flags); | ||
9144 | } | ||
9145 | #endif | ||
8690 | static void | 9146 | static void |
8691 | evalpipe(union node *n, int flags) | 9147 | evalpipe(union node *n, int flags) |
8692 | { | 9148 | { |
9149 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
8693 | struct job *jp; | 9150 | struct job *jp; |
8694 | struct nodelist *lp; | 9151 | struct nodelist *lp; |
8695 | int pipelen; | 9152 | int pipelen; |
@@ -8713,6 +9170,17 @@ evalpipe(union node *n, int flags) | |||
8713 | ash_msg_and_raise_error("pipe call failed"); | 9170 | ash_msg_and_raise_error("pipe call failed"); |
8714 | } | 9171 | } |
8715 | } | 9172 | } |
9173 | #if ENABLE_PLATFORM_MINGW32 | ||
9174 | memset(&fs, 0, sizeof(fs)); | ||
9175 | fs.fp = forkshell_evalpipe; | ||
9176 | fs.flags = flags; | ||
9177 | fs.n = lp->n; | ||
9178 | fs.fd[0] = pip[0]; | ||
9179 | fs.fd[1] = pip[1]; | ||
9180 | fs.fd[2] = prevfd; | ||
9181 | if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0) | ||
9182 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9183 | #endif | ||
8716 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { | 9184 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { |
8717 | INT_ON; | 9185 | INT_ON; |
8718 | if (pip[1] >= 0) { | 9186 | if (pip[1] >= 0) { |
@@ -9181,6 +9649,20 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
9181 | * as POSIX mandates */ | 9649 | * as POSIX mandates */ |
9182 | return back_exitstatus; | 9650 | return back_exitstatus; |
9183 | } | 9651 | } |
9652 | |||
9653 | #if ENABLE_PLATFORM_MINGW32 | ||
9654 | static void | ||
9655 | forkshell_shellexec(struct forkshell *fs) | ||
9656 | { | ||
9657 | int idx = fs->fd[0]; | ||
9658 | struct strlist *varlist = fs->strlist; | ||
9659 | char **argv = fs->argv; | ||
9660 | char *path = fs->string; | ||
9661 | |||
9662 | listsetvar(varlist, VEXPORT|VSTACK); | ||
9663 | shellexec(argv, path, idx); | ||
9664 | } | ||
9665 | #endif | ||
9184 | static void | 9666 | static void |
9185 | evalcommand(union node *cmd, int flags) | 9667 | evalcommand(union node *cmd, int flags) |
9186 | { | 9668 | { |
@@ -9358,6 +9840,27 @@ evalcommand(union node *cmd, int flags) | |||
9358 | * in a script or a subshell does not need forking, | 9840 | * in a script or a subshell does not need forking, |
9359 | * we can just exec it. | 9841 | * we can just exec it. |
9360 | */ | 9842 | */ |
9843 | #if ENABLE_PLATFORM_MINGW32 | ||
9844 | if (!(flags & EV_EXIT) || trap[0]) { | ||
9845 | /* No, forking off a child is necessary */ | ||
9846 | struct forkshell fs; | ||
9847 | |||
9848 | memset(&fs, 0, sizeof(fs)); | ||
9849 | fs.fp = forkshell_shellexec; | ||
9850 | fs.argv = argv; | ||
9851 | fs.string = (char*)path; | ||
9852 | fs.fd[0] = cmdentry.u.index; | ||
9853 | fs.strlist = varlist.list; | ||
9854 | jp = makejob(/*cmd,*/ 1); | ||
9855 | if (spawn_forkshell(jp, &fs, FORK_FG) < 0) | ||
9856 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9857 | exitstatus = waitforjob(jp); | ||
9858 | INT_ON; | ||
9859 | TRACE(("forked child exited with %d\n", exitstatus)); | ||
9860 | break; | ||
9861 | } | ||
9862 | /* goes through to shellexec() */ | ||
9863 | #endif | ||
9361 | if (!(flags & EV_EXIT) || may_have_traps) { | 9864 | if (!(flags & EV_EXIT) || may_have_traps) { |
9362 | /* No, forking off a child is necessary */ | 9865 | /* No, forking off a child is necessary */ |
9363 | INT_OFF; | 9866 | INT_OFF; |
@@ -9765,7 +10268,7 @@ preadbuffer(void) | |||
9765 | more--; | 10268 | more--; |
9766 | 10269 | ||
9767 | c = *q; | 10270 | c = *q; |
9768 | if (c == '\0') { | 10271 | if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) { |
9769 | memmove(q, q + 1, more); | 10272 | memmove(q, q + 1, more); |
9770 | } else { | 10273 | } else { |
9771 | q++; | 10274 | q++; |
@@ -12196,7 +12699,7 @@ find_dot_file(char *name) | |||
12196 | struct stat statb; | 12699 | struct stat statb; |
12197 | 12700 | ||
12198 | /* don't try this for absolute or relative paths */ | 12701 | /* don't try this for absolute or relative paths */ |
12199 | if (strchr(name, '/')) | 12702 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) |
12200 | return name; | 12703 | return name; |
12201 | 12704 | ||
12202 | /* IIRC standards do not say whether . is to be searched. | 12705 | /* IIRC standards do not say whether . is to be searched. |
@@ -12306,10 +12809,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12306 | struct stat statb; | 12809 | struct stat statb; |
12307 | int e; | 12810 | int e; |
12308 | int updatetbl; | 12811 | int updatetbl; |
12812 | IF_PLATFORM_MINGW32(int len); | ||
12309 | struct builtincmd *bcmd; | 12813 | struct builtincmd *bcmd; |
12310 | 12814 | ||
12311 | /* If name contains a slash, don't use PATH or hash table */ | 12815 | /* If name contains a slash, don't use PATH or hash table */ |
12312 | if (strchr(name, '/') != NULL) { | 12816 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) { |
12313 | entry->u.index = -1; | 12817 | entry->u.index = -1; |
12314 | if (act & DO_ABS) { | 12818 | if (act & DO_ABS) { |
12315 | while (stat(name, &statb) < 0) { | 12819 | while (stat(name, &statb) < 0) { |
@@ -12416,12 +12920,39 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12416 | } | 12920 | } |
12417 | } | 12921 | } |
12418 | /* if rehash, don't redo absolute path names */ | 12922 | /* if rehash, don't redo absolute path names */ |
12419 | if (fullname[0] == '/' && idx <= prev) { | 12923 | if (is_absolute_path(fullname) && idx <= prev) { |
12420 | if (idx < prev) | 12924 | if (idx < prev) |
12421 | continue; | 12925 | continue; |
12422 | TRACE(("searchexec \"%s\": no change\n", name)); | 12926 | TRACE(("searchexec \"%s\": no change\n", name)); |
12423 | goto success; | 12927 | goto success; |
12424 | } | 12928 | } |
12929 | #if ENABLE_PLATFORM_MINGW32 | ||
12930 | len = strlen(fullname); | ||
12931 | if (len > 4 && | ||
12932 | (!strcasecmp(fullname+len-4, ".exe") || | ||
12933 | !strcasecmp(fullname+len-4, ".com"))) { | ||
12934 | if (stat(fullname, &statb) < 0) { | ||
12935 | if (errno != ENOENT && errno != ENOTDIR) | ||
12936 | e = errno; | ||
12937 | goto loop; | ||
12938 | } | ||
12939 | } | ||
12940 | else { | ||
12941 | /* path_advance() has reserved space for .exe */ | ||
12942 | memcpy(fullname+len, ".exe", 5); | ||
12943 | if (stat(fullname, &statb) < 0) { | ||
12944 | if (errno != ENOENT && errno != ENOTDIR) | ||
12945 | e = errno; | ||
12946 | memcpy(fullname+len, ".com", 5); | ||
12947 | if (stat(fullname, &statb) < 0) { | ||
12948 | if (errno != ENOENT && errno != ENOTDIR) | ||
12949 | e = errno; | ||
12950 | goto loop; | ||
12951 | } | ||
12952 | } | ||
12953 | fullname[len] = '\0'; | ||
12954 | } | ||
12955 | #else | ||
12425 | while (stat(fullname, &statb) < 0) { | 12956 | while (stat(fullname, &statb) < 0) { |
12426 | #ifdef SYSV | 12957 | #ifdef SYSV |
12427 | if (errno == EINTR) | 12958 | if (errno == EINTR) |
@@ -12431,6 +12962,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12431 | e = errno; | 12962 | e = errno; |
12432 | goto loop; | 12963 | goto loop; |
12433 | } | 12964 | } |
12965 | #endif | ||
12434 | e = EACCES; /* if we fail, this will be the error */ | 12966 | e = EACCES; /* if we fail, this will be the error */ |
12435 | if (!S_ISREG(statb.st_mode)) | 12967 | if (!S_ISREG(statb.st_mode)) |
12436 | continue; | 12968 | continue; |
@@ -12679,6 +13211,10 @@ unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12679 | return ret & 1; | 13211 | return ret & 1; |
12680 | } | 13212 | } |
12681 | 13213 | ||
13214 | /* setmode.c */ | ||
13215 | |||
13216 | #if !ENABLE_PLATFORM_MINGW32 | ||
13217 | |||
12682 | static const unsigned char timescmd_str[] ALIGN1 = { | 13218 | static const unsigned char timescmd_str[] ALIGN1 = { |
12683 | ' ', offsetof(struct tms, tms_utime), | 13219 | ' ', offsetof(struct tms, tms_utime), |
12684 | '\n', offsetof(struct tms, tms_stime), | 13220 | '\n', offsetof(struct tms, tms_stime), |
@@ -12710,6 +13246,13 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12710 | 13246 | ||
12711 | return 0; | 13247 | return 0; |
12712 | } | 13248 | } |
13249 | #else | ||
13250 | static int FAST_FUNC | ||
13251 | timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | ||
13252 | { | ||
13253 | return 0; | ||
13254 | } | ||
13255 | #endif | ||
12713 | 13256 | ||
12714 | #if ENABLE_SH_MATH_SUPPORT | 13257 | #if ENABLE_SH_MATH_SUPPORT |
12715 | /* | 13258 | /* |
@@ -12934,13 +13477,67 @@ init(void) | |||
12934 | struct stat st1, st2; | 13477 | struct stat st1, st2; |
12935 | 13478 | ||
12936 | initvar(); | 13479 | initvar(); |
13480 | |||
13481 | #if ENABLE_PLATFORM_MINGW32 | ||
13482 | /* | ||
13483 | * case insensitive env names from Windows world | ||
13484 | * | ||
13485 | * Some standard env names such as PATH is named Path and so on | ||
13486 | * ash itself is case sensitive, so "Path" will confuse it, as | ||
13487 | * MSVC getenv() is case insensitive. | ||
13488 | * | ||
13489 | * We may end up having both Path and PATH. Then Path will be chosen | ||
13490 | * because it appears first. | ||
13491 | */ | ||
13492 | for (envp = environ; envp && *envp; envp++) | ||
13493 | if (!strncasecmp(*envp, "PATH=", 5) && | ||
13494 | strncmp(*envp, "PATH=", 5)) | ||
13495 | break; | ||
13496 | if (envp && *envp) { | ||
13497 | char *start, *end; | ||
13498 | for (envp = environ; envp && *envp; envp++) { | ||
13499 | end = strchr(*envp, '='); | ||
13500 | if (!end) | ||
13501 | continue; | ||
13502 | for (start = *envp;start < end;start++) | ||
13503 | *start = toupper(*start); | ||
13504 | } | ||
13505 | } | ||
13506 | #endif | ||
12937 | for (envp = environ; envp && *envp; envp++) { | 13507 | for (envp = environ; envp && *envp; envp++) { |
13508 | #if ENABLE_PLATFORM_MINGW32 | ||
13509 | char *s; | ||
13510 | |||
13511 | while ((s=strchr(*envp, '\\'))) { | ||
13512 | *s = '/'; | ||
13513 | } | ||
13514 | #endif | ||
12938 | if (strchr(*envp, '=')) { | 13515 | if (strchr(*envp, '=')) { |
12939 | setvareq(*envp, VEXPORT|VTEXTFIXED); | 13516 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
12940 | } | 13517 | } |
12941 | } | 13518 | } |
12942 | 13519 | ||
12943 | setvar("PPID", utoa(getppid()), 0); | 13520 | #if ENABLE_PLATFORM_MINGW32 |
13521 | p = lookupvar("HOME"); | ||
13522 | if (!p) { | ||
13523 | const char *hd, *hp; | ||
13524 | |||
13525 | hd = lookupvar("HOMEDRIVE"); | ||
13526 | hp = lookupvar("HOMEPATH"); | ||
13527 | if (hd && hp) { | ||
13528 | char *s; | ||
13529 | |||
13530 | if ((s=malloc(strlen(hd) + strlen(hp) + 1)) != NULL) { | ||
13531 | strcat(strcpy(s, hd), hp); | ||
13532 | setvar("HOME", s, VEXPORT); | ||
13533 | free(s); | ||
13534 | } | ||
13535 | } | ||
13536 | } | ||
13537 | #endif | ||
13538 | |||
13539 | if (!ENABLE_PLATFORM_MINGW32) | ||
13540 | setvar("PPID", utoa(getppid()), 0); | ||
12944 | 13541 | ||
12945 | p = lookupvar("PWD"); | 13542 | p = lookupvar("PWD"); |
12946 | if (p) { | 13543 | if (p) { |
@@ -13074,6 +13671,20 @@ static short profile_buf[16384]; | |||
13074 | extern int etext(); | 13671 | extern int etext(); |
13075 | #endif | 13672 | #endif |
13076 | 13673 | ||
13674 | #if ENABLE_PLATFORM_MINGW32 | ||
13675 | static const forkpoint_fn forkpoints[] = { | ||
13676 | forkshell_openhere, | ||
13677 | forkshell_evalbackcmd, | ||
13678 | forkshell_evalsubshell, | ||
13679 | forkshell_evalpipe, | ||
13680 | forkshell_shellexec, | ||
13681 | NULL | ||
13682 | }; | ||
13683 | |||
13684 | static struct forkshell* forkshell_prepare(struct forkshell *fs); | ||
13685 | static void forkshell_init(const char *idstr); | ||
13686 | #endif | ||
13687 | |||
13077 | /* | 13688 | /* |
13078 | * Main routine. We initialize things, parse the arguments, execute | 13689 | * Main routine. We initialize things, parse the arguments, execute |
13079 | * profiles if we're a login shell, and then call cmdloop to execute | 13690 | * profiles if we're a login shell, and then call cmdloop to execute |
@@ -13143,6 +13754,17 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13143 | 13754 | ||
13144 | init(); | 13755 | init(); |
13145 | setstackmark(&smark); | 13756 | setstackmark(&smark); |
13757 | |||
13758 | #if ENABLE_PLATFORM_MINGW32 | ||
13759 | hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL); | ||
13760 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
13761 | if (argc == 3 && !strcmp(argv[1], "--forkshell")) { | ||
13762 | forkshell_init(argv[2]); | ||
13763 | |||
13764 | /* NOTREACHED */ | ||
13765 | bb_error_msg_and_die("subshell ended unexpectedly"); | ||
13766 | } | ||
13767 | #endif | ||
13146 | procargs(argv); | 13768 | procargs(argv); |
13147 | 13769 | ||
13148 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 13770 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY |
@@ -13222,6 +13844,524 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13222 | /* NOTREACHED */ | 13844 | /* NOTREACHED */ |
13223 | } | 13845 | } |
13224 | 13846 | ||
13847 | /* FIXME: should consider running forkparent() and forkchild() */ | ||
13848 | static int | ||
13849 | spawn_forkshell(struct job *jp, struct forkshell *fs, int mode) | ||
13850 | { | ||
13851 | const char *argv[] = { "sh", "--forkshell", NULL, NULL }; | ||
13852 | char buf[16]; | ||
13853 | |||
13854 | struct forkshell *new; | ||
13855 | new = forkshell_prepare(fs); | ||
13856 | sprintf(buf, "%x", (unsigned int)new->hMapFile); | ||
13857 | argv[2] = buf; | ||
13858 | fs->pid = mingw_spawn_applet(P_NOWAIT, "sh", argv, | ||
13859 | (const char *const *)environ); | ||
13860 | CloseHandle(new->hMapFile); | ||
13861 | UnmapViewOfFile(new); | ||
13862 | if (fs->pid == -1) { | ||
13863 | free(jp); | ||
13864 | return -1; | ||
13865 | } | ||
13866 | forkparent(jp, fs->node, mode, fs->pid); | ||
13867 | return fs->pid; | ||
13868 | } | ||
13869 | |||
13870 | /* | ||
13871 | * forkshell_prepare() and friends | ||
13872 | * | ||
13873 | * The sequence is as follows: | ||
13874 | * - funcblocksize, funcstringsize, nodeptrsize are initialized | ||
13875 | * - forkshell_size(fs) is called to calculate the exact memory needed | ||
13876 | * - a new struct is allocated | ||
13877 | * - funcblock, funcstring, nodeptr are initialized from the new block | ||
13878 | * - forkshell_copy(fs) is called to copy recursively everything over | ||
13879 | * it will record all pointers along the way, to nodeptr | ||
13880 | * | ||
13881 | * When this memory is mapped elsewhere, pointer fixup will be needed | ||
13882 | */ | ||
13883 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
13884 | static void \ | ||
13885 | name(type *p) \ | ||
13886 | { \ | ||
13887 | while (p) { \ | ||
13888 | funcblocksize += sizeof(type); | ||
13889 | /* do something here with p */ | ||
13890 | #define SLIST_SIZE_END() \ | ||
13891 | nodeptrsize++; \ | ||
13892 | p = p->next; \ | ||
13893 | } \ | ||
13894 | } | ||
13895 | |||
13896 | #define SLIST_COPY_BEGIN(name,type) \ | ||
13897 | static type * \ | ||
13898 | name(type *vp) \ | ||
13899 | { \ | ||
13900 | type *start; \ | ||
13901 | type **vpp; \ | ||
13902 | vpp = &start; \ | ||
13903 | while (vp) { \ | ||
13904 | *vpp = funcblock; \ | ||
13905 | funcblock = (char *) funcblock + sizeof(type); | ||
13906 | /* do something here with vpp and vp */ | ||
13907 | #define SLIST_COPY_END() \ | ||
13908 | SAVE_PTR((*vpp)->next); \ | ||
13909 | vp = vp->next; \ | ||
13910 | vpp = &(*vpp)->next; \ | ||
13911 | } \ | ||
13912 | *vpp = NULL; \ | ||
13913 | return start; \ | ||
13914 | } | ||
13915 | |||
13916 | /* | ||
13917 | * struct var | ||
13918 | */ | ||
13919 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
13920 | funcstringsize += strlen(p->var_text) + 1; | ||
13921 | nodeptrsize++; /* p->text */ | ||
13922 | SLIST_SIZE_END() | ||
13923 | |||
13924 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
13925 | (*vpp)->var_text = nodeckstrdup(vp->var_text); | ||
13926 | (*vpp)->flags = vp->flags; | ||
13927 | /* | ||
13928 | * The only place that can set struct var#func is varinit[], | ||
13929 | * which will be fixed by forkshell_init() | ||
13930 | */ | ||
13931 | (*vpp)->var_func = NULL; | ||
13932 | SAVE_PTR((*vpp)->var_text); | ||
13933 | SLIST_COPY_END() | ||
13934 | |||
13935 | /* | ||
13936 | * struct localvar | ||
13937 | */ | ||
13938 | SLIST_SIZE_BEGIN(localvar_size,struct localvar) | ||
13939 | var_size(p->vp); | ||
13940 | funcstringsize += strlen(p->text) + 1; | ||
13941 | nodeptrsize += 2; /* p->vp, p->text */ | ||
13942 | SLIST_SIZE_END() | ||
13943 | |||
13944 | SLIST_COPY_BEGIN(localvar_copy,struct localvar) | ||
13945 | (*vpp)->text = nodeckstrdup(vp->text); | ||
13946 | (*vpp)->flags = vp->flags; | ||
13947 | (*vpp)->vp = var_copy(vp->vp); | ||
13948 | SAVE_PTR2((*vpp)->vp, (*vpp)->text); | ||
13949 | SLIST_COPY_END() | ||
13950 | |||
13951 | /* | ||
13952 | * struct strlist | ||
13953 | */ | ||
13954 | SLIST_SIZE_BEGIN(strlist_size,struct strlist) | ||
13955 | funcstringsize += strlen(p->text) + 1; | ||
13956 | nodeptrsize++; /* p->text */ | ||
13957 | SLIST_SIZE_END() | ||
13958 | |||
13959 | SLIST_COPY_BEGIN(strlist_copy,struct strlist) | ||
13960 | (*vpp)->text = nodeckstrdup(vp->text); | ||
13961 | SAVE_PTR((*vpp)->text); | ||
13962 | SLIST_COPY_END() | ||
13963 | |||
13964 | /* | ||
13965 | * struct tblentry | ||
13966 | */ | ||
13967 | static void | ||
13968 | tblentry_size(struct tblentry *tep) | ||
13969 | { | ||
13970 | while (tep) { | ||
13971 | funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
13972 | /* CMDBUILTIN, e->param.cmd needs no pointer relocation */ | ||
13973 | if (tep->cmdtype == CMDFUNCTION) { | ||
13974 | funcblocksize += offsetof(struct funcnode, n); | ||
13975 | calcsize(&tep->param.func->n); | ||
13976 | nodeptrsize++; /* tep->param.func */ | ||
13977 | } | ||
13978 | nodeptrsize++; /* tep->next */ | ||
13979 | tep = tep->next; | ||
13980 | } | ||
13981 | } | ||
13982 | |||
13983 | static struct tblentry * | ||
13984 | tblentry_copy(struct tblentry *tep) | ||
13985 | { | ||
13986 | struct tblentry *start; | ||
13987 | struct tblentry **newp; | ||
13988 | int size; | ||
13989 | |||
13990 | newp = &start; | ||
13991 | while (tep) { | ||
13992 | *newp = funcblock; | ||
13993 | size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
13994 | |||
13995 | funcblock = (char *) funcblock + size; | ||
13996 | memcpy(*newp, tep, size); | ||
13997 | switch (tep->cmdtype) { | ||
13998 | case CMDBUILTIN: | ||
13999 | /* No pointer saving, this field must be fixed by forkshell_init() */ | ||
14000 | (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab); | ||
14001 | break; | ||
14002 | case CMDFUNCTION: | ||
14003 | (*newp)->param.func = funcblock; | ||
14004 | funcblock = (char *) funcblock + offsetof(struct funcnode, n); | ||
14005 | copynode(&tep->param.func->n); | ||
14006 | SAVE_PTR((*newp)->param.func); | ||
14007 | break; | ||
14008 | default: | ||
14009 | break; | ||
14010 | } | ||
14011 | SAVE_PTR((*newp)->next); | ||
14012 | tep = tep->next; | ||
14013 | newp = &(*newp)->next; | ||
14014 | } | ||
14015 | *newp = NULL; | ||
14016 | return start; | ||
14017 | } | ||
14018 | |||
14019 | static void | ||
14020 | cmdtable_size(struct tblentry **cmdtablep) | ||
14021 | { | ||
14022 | int i; | ||
14023 | nodeptrsize += CMDTABLESIZE; | ||
14024 | funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE; | ||
14025 | for (i = 0; i < CMDTABLESIZE; i++) | ||
14026 | tblentry_size(cmdtablep[i]); | ||
14027 | } | ||
14028 | |||
14029 | static struct tblentry ** | ||
14030 | cmdtable_copy(struct tblentry **cmdtablep) | ||
14031 | { | ||
14032 | struct tblentry **new = funcblock; | ||
14033 | int i; | ||
14034 | |||
14035 | funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE; | ||
14036 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
14037 | new[i] = tblentry_copy(cmdtablep[i]); | ||
14038 | SAVE_PTR(new[i]); | ||
14039 | } | ||
14040 | return new; | ||
14041 | } | ||
14042 | |||
14043 | /* | ||
14044 | * char ** | ||
14045 | */ | ||
14046 | static void | ||
14047 | argv_size(char **p) | ||
14048 | { | ||
14049 | while (p && *p) { | ||
14050 | funcblocksize += sizeof(char *); | ||
14051 | funcstringsize += strlen(*p)+1; | ||
14052 | nodeptrsize++; | ||
14053 | p++; | ||
14054 | } | ||
14055 | funcblocksize += sizeof(char *); | ||
14056 | } | ||
14057 | |||
14058 | static char ** | ||
14059 | argv_copy(char **p) | ||
14060 | { | ||
14061 | char **new, **start = funcblock; | ||
14062 | |||
14063 | while (p && *p) { | ||
14064 | new = funcblock; | ||
14065 | funcblock = (char *) funcblock + sizeof(char *); | ||
14066 | *new = nodeckstrdup(*p); | ||
14067 | SAVE_PTR(*new); | ||
14068 | p++; | ||
14069 | new++; | ||
14070 | } | ||
14071 | new = funcblock; | ||
14072 | funcblock = (char *) funcblock + sizeof(char *); | ||
14073 | *new = NULL; | ||
14074 | return start; | ||
14075 | } | ||
14076 | |||
14077 | /* | ||
14078 | * struct redirtab | ||
14079 | */ | ||
14080 | static void | ||
14081 | redirtab_size(struct redirtab *rdtp) | ||
14082 | { | ||
14083 | while (rdtp) { | ||
14084 | funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
14085 | rdtp = rdtp->next; | ||
14086 | nodeptrsize++; /* rdtp->next */ | ||
14087 | } | ||
14088 | } | ||
14089 | |||
14090 | static struct redirtab * | ||
14091 | redirtab_copy(struct redirtab *rdtp) | ||
14092 | { | ||
14093 | struct redirtab *start; | ||
14094 | struct redirtab **vpp; | ||
14095 | |||
14096 | vpp = &start; | ||
14097 | while (rdtp) { | ||
14098 | int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
14099 | *vpp = funcblock; | ||
14100 | funcblock = (char *) funcblock + size; | ||
14101 | memcpy(*vpp, rdtp, size); | ||
14102 | SAVE_PTR((*vpp)->next); | ||
14103 | rdtp = rdtp->next; | ||
14104 | vpp = &(*vpp)->next; | ||
14105 | } | ||
14106 | *vpp = NULL; | ||
14107 | return start; | ||
14108 | } | ||
14109 | |||
14110 | #undef shellparam | ||
14111 | #undef redirlist | ||
14112 | #undef varinit | ||
14113 | #undef vartab | ||
14114 | static void | ||
14115 | globals_var_size(struct globals_var *gvp) | ||
14116 | { | ||
14117 | int i; | ||
14118 | |||
14119 | funcblocksize += sizeof(struct globals_var); | ||
14120 | argv_size(gvp->shellparam.p); | ||
14121 | redirtab_size(gvp->redirlist); | ||
14122 | for (i = 0; i < VTABSIZE; i++) | ||
14123 | var_size(gvp->vartab[i]); | ||
14124 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
14125 | var_size(gvp->varinit+i); | ||
14126 | nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */ | ||
14127 | } | ||
14128 | |||
14129 | #undef g_nullredirs | ||
14130 | #undef preverrout_fd | ||
14131 | static struct globals_var * | ||
14132 | globals_var_copy(struct globals_var *gvp) | ||
14133 | { | ||
14134 | int i; | ||
14135 | struct globals_var *new; | ||
14136 | |||
14137 | new = funcblock; | ||
14138 | funcblock = (char *) funcblock + sizeof(struct globals_var); | ||
14139 | |||
14140 | /* shparam */ | ||
14141 | memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam)); | ||
14142 | new->shellparam.malloced = 0; | ||
14143 | new->shellparam.p = argv_copy(gvp->shellparam.p); | ||
14144 | SAVE_PTR(new->shellparam.p); | ||
14145 | |||
14146 | new->redirlist = redirtab_copy(gvp->redirlist); | ||
14147 | SAVE_PTR(new->redirlist); | ||
14148 | |||
14149 | new->g_nullredirs = gvp->g_nullredirs; | ||
14150 | new->preverrout_fd = gvp->preverrout_fd; | ||
14151 | for (i = 0; i < VTABSIZE; i++) { | ||
14152 | new->vartab[i] = var_copy(gvp->vartab[i]); | ||
14153 | SAVE_PTR(new->vartab[i]); | ||
14154 | } | ||
14155 | |||
14156 | /* Can't use var_copy because varinit is already allocated */ | ||
14157 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { | ||
14158 | new->varinit[i].next = NULL; | ||
14159 | new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text); | ||
14160 | SAVE_PTR(new->varinit[i].var_text); | ||
14161 | new->varinit[i].flags = gvp->varinit[i].flags; | ||
14162 | new->varinit[i].var_func = gvp->varinit[i].var_func; | ||
14163 | } | ||
14164 | return new; | ||
14165 | } | ||
14166 | |||
14167 | #undef minusc | ||
14168 | #undef curdir | ||
14169 | #undef physdir | ||
14170 | #undef arg0 | ||
14171 | #undef nullstr | ||
14172 | static void | ||
14173 | globals_misc_size(struct globals_misc *p) | ||
14174 | { | ||
14175 | funcblocksize += sizeof(struct globals_misc); | ||
14176 | funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1; | ||
14177 | if (p->curdir != p->nullstr) | ||
14178 | funcstringsize += strlen(p->curdir) + 1; | ||
14179 | if (p->physdir != p->nullstr) | ||
14180 | funcstringsize += strlen(p->physdir) + 1; | ||
14181 | funcstringsize += strlen(p->arg0) + 1; | ||
14182 | nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */ | ||
14183 | } | ||
14184 | |||
14185 | static struct globals_misc * | ||
14186 | globals_misc_copy(struct globals_misc *p) | ||
14187 | { | ||
14188 | struct globals_misc *new = funcblock; | ||
14189 | |||
14190 | funcblock = (char *) funcblock + sizeof(struct globals_misc); | ||
14191 | memcpy(new, p, sizeof(struct globals_misc)); | ||
14192 | |||
14193 | new->minusc = nodeckstrdup(p->minusc); | ||
14194 | new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr; | ||
14195 | new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr; | ||
14196 | new->arg0 = nodeckstrdup(p->arg0); | ||
14197 | SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0); | ||
14198 | return new; | ||
14199 | } | ||
14200 | |||
14201 | static void | ||
14202 | forkshell_size(struct forkshell *fs) | ||
14203 | { | ||
14204 | funcblocksize += sizeof(struct forkshell); | ||
14205 | globals_var_size(fs->gvp); | ||
14206 | globals_misc_size(fs->gmp); | ||
14207 | cmdtable_size(fs->cmdtable); | ||
14208 | localvar_size(fs->localvars); | ||
14209 | /* optlist_transfer(sending, fd); */ | ||
14210 | /* misc_transfer(sending, fd); */ | ||
14211 | |||
14212 | calcsize(fs->n); | ||
14213 | argv_size(fs->argv); | ||
14214 | funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1; | ||
14215 | strlist_size(fs->strlist); | ||
14216 | |||
14217 | nodeptrsize += 8; /* gvp, gmp, cmdtable, localvars, n, argv, string, strlist */ | ||
14218 | } | ||
14219 | |||
14220 | static struct forkshell * | ||
14221 | forkshell_copy(struct forkshell *fs) | ||
14222 | { | ||
14223 | struct forkshell *new; | ||
14224 | |||
14225 | new = funcblock; | ||
14226 | funcblock = (char *) funcblock + sizeof(struct forkshell); | ||
14227 | |||
14228 | memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */ | ||
14229 | new->gvp = globals_var_copy(fs->gvp); | ||
14230 | new->gmp = globals_misc_copy(fs->gmp); | ||
14231 | new->cmdtable = cmdtable_copy(fs->cmdtable); | ||
14232 | new->localvars = localvar_copy(fs->localvars); | ||
14233 | SAVE_PTR4(new->gvp, new->gmp, new->cmdtable, new->localvars); | ||
14234 | |||
14235 | /* new->fs will be reconstructed from new->fpid */ | ||
14236 | new->n = copynode(fs->n); | ||
14237 | new->argv = argv_copy(fs->argv); | ||
14238 | new->string = nodeckstrdup(fs->string); | ||
14239 | new->strlist = strlist_copy(fs->strlist); | ||
14240 | SAVE_PTR4(new->n, new->argv, new->string, new->strlist); | ||
14241 | return new; | ||
14242 | } | ||
14243 | |||
14244 | static struct forkshell * | ||
14245 | forkshell_prepare(struct forkshell *fs) | ||
14246 | { | ||
14247 | struct forkshell *new; | ||
14248 | int size, fp, nodeptr_offset; | ||
14249 | HANDLE h; | ||
14250 | SECURITY_ATTRIBUTES sa; | ||
14251 | |||
14252 | for (fp = 0; forkpoints[fp] && forkpoints[fp] != fs->fp; fp++) | ||
14253 | ; | ||
14254 | |||
14255 | if (!forkpoints[fp]) | ||
14256 | bb_error_msg_and_die("invalid forkpoint %08x", (int)fs->fp); | ||
14257 | fs->fpid = fp; | ||
14258 | |||
14259 | /* Calculate size of "new" */ | ||
14260 | fs->gvp = ash_ptr_to_globals_var; | ||
14261 | fs->gmp = ash_ptr_to_globals_misc; | ||
14262 | fs->cmdtable = cmdtable; | ||
14263 | fs->localvars = localvars; | ||
14264 | |||
14265 | nodeptrsize = 1; /* NULL terminated */ | ||
14266 | funcblocksize = 0; | ||
14267 | funcstringsize = 0; | ||
14268 | forkshell_size(fs); | ||
14269 | size = funcblocksize + funcstringsize + nodeptrsize*sizeof(int); | ||
14270 | |||
14271 | /* Allocate, initialize pointers */ | ||
14272 | memset(&sa, 0, sizeof(sa)); | ||
14273 | sa.nLength = sizeof(sa); | ||
14274 | sa.lpSecurityDescriptor = NULL; | ||
14275 | sa.bInheritHandle = TRUE; | ||
14276 | h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL); | ||
14277 | new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
14278 | /* new = ckmalloc(size); */ | ||
14279 | funcblock = new; | ||
14280 | funcstring = (char *) funcblock + funcblocksize; | ||
14281 | nodeptr = (int*)((char *) funcstring + funcstringsize); | ||
14282 | nodeptr_offset = (int) nodeptr - (int) new; | ||
14283 | |||
14284 | /* Now pack them all */ | ||
14285 | forkshell_copy(fs); | ||
14286 | |||
14287 | /* Finish it up */ | ||
14288 | *nodeptr = 0; | ||
14289 | new->size = size; | ||
14290 | new->nodeptr_offset = nodeptr_offset; | ||
14291 | new->old_base = new; | ||
14292 | new->hMapFile = h; | ||
14293 | return new; | ||
14294 | } | ||
14295 | |||
14296 | #undef exception_handler | ||
14297 | #undef trap | ||
14298 | #undef trap_ptr | ||
14299 | static void *sticky_mem_start, *sticky_mem_end; | ||
14300 | static void | ||
14301 | forkshell_init(const char *idstr) | ||
14302 | { | ||
14303 | struct forkshell *fs; | ||
14304 | int map_handle; | ||
14305 | HANDLE h; | ||
14306 | struct globals_var **gvpp; | ||
14307 | struct globals_misc **gmpp; | ||
14308 | int i; | ||
14309 | |||
14310 | if (sscanf(idstr, "%x", &map_handle) != 1) | ||
14311 | bb_error_msg_and_die("invalid forkshell ID"); | ||
14312 | |||
14313 | h = (HANDLE)map_handle; | ||
14314 | fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
14315 | if (!fs) | ||
14316 | bb_error_msg_and_die("Invalid forkshell memory"); | ||
14317 | |||
14318 | /* this memory can't be freed */ | ||
14319 | sticky_mem_start = fs; | ||
14320 | sticky_mem_end = (char *) fs + fs->size; | ||
14321 | /* pointer fixup */ | ||
14322 | nodeptr = (int*)((char*)fs + fs->nodeptr_offset); | ||
14323 | while (*nodeptr) { | ||
14324 | int *ptr = (int*)((char*)fs + (*nodeptr - (int)fs->old_base)); | ||
14325 | if (*ptr) | ||
14326 | *ptr -= ((int)fs->old_base - (int)fs); | ||
14327 | nodeptr++; | ||
14328 | } | ||
14329 | /* Now fix up stuff that can't be transferred */ | ||
14330 | fs->fp = forkpoints[fs->fpid]; | ||
14331 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
14332 | fs->gvp->varinit[i].var_func = varinit_data[i].var_func; | ||
14333 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
14334 | struct tblentry *e = fs->cmdtable[i]; | ||
14335 | while (e) { | ||
14336 | if (e->cmdtype == CMDBUILTIN) | ||
14337 | e->param.cmd = builtintab + (int)e->param.cmd; | ||
14338 | e = e->next; | ||
14339 | } | ||
14340 | } | ||
14341 | fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler; | ||
14342 | for (i = 0; i < NSIG; i++) | ||
14343 | fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i]; | ||
14344 | fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr; | ||
14345 | |||
14346 | /* Switch global variables */ | ||
14347 | gvpp = (struct globals_var **)&ash_ptr_to_globals_var; | ||
14348 | *gvpp = fs->gvp; | ||
14349 | gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc; | ||
14350 | *gmpp = fs->gmp; | ||
14351 | localvars = fs->localvars; | ||
14352 | cmdtable = fs->cmdtable; | ||
14353 | |||
14354 | fs->fp(fs); | ||
14355 | } | ||
14356 | |||
14357 | #undef free | ||
14358 | static void | ||
14359 | sticky_free(void *base) | ||
14360 | { | ||
14361 | if (base >= sticky_mem_start && base < sticky_mem_end) | ||
14362 | return; | ||
14363 | free(base); | ||
14364 | } | ||
13225 | 14365 | ||
13226 | /*- | 14366 | /*- |
13227 | * Copyright (c) 1989, 1991, 1993, 1994 | 14367 | * Copyright (c) 1989, 1991, 1993, 1994 |