diff options
| author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-09-14 11:06:35 +1000 |
|---|---|---|
| committer | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-09-14 11:06:35 +1000 |
| commit | 87911f4fcd86f7abc0aefba8e9cbec2ac9d127e4 (patch) | |
| tree | c91a4a9a048f3cc2bdae47fa61a02db7a108170d /shell | |
| parent | ba3cea41689d211093d914212de048cc06d976ce (diff) | |
| parent | 9375ca983262075d8420fd0d88d00a088916fc10 (diff) | |
| download | busybox-w32-87911f4fcd86f7abc0aefba8e9cbec2ac9d127e4.tar.gz busybox-w32-87911f4fcd86f7abc0aefba8e9cbec2ac9d127e4.tar.bz2 busybox-w32-87911f4fcd86f7abc0aefba8e9cbec2ac9d127e4.zip | |
Merge branch 'ash'
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/ash.c | 1088 |
1 files changed, 1074 insertions, 14 deletions
diff --git a/shell/ash.c b/shell/ash.c index ab935e72a..5d8415a79 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. |
| @@ -81,6 +93,41 @@ | |||
| 81 | # error "Do not even bother, ash will not run on NOMMU machine" | 93 | # error "Do not even bother, ash will not run on NOMMU machine" |
| 82 | #endif | 94 | #endif |
| 83 | 95 | ||
| 96 | #if ENABLE_PLATFORM_MINGW32 | ||
| 97 | struct forkshell; | ||
| 98 | union node; | ||
| 99 | struct strlist; | ||
| 100 | struct job; | ||
| 101 | |||
| 102 | typedef void (*forkpoint_fn)(struct forkshell *fs); | ||
| 103 | struct forkshell { | ||
| 104 | /* filled by forkshell_copy() */ | ||
| 105 | struct globals_var *gvp; | ||
| 106 | struct globals_misc *gmp; | ||
| 107 | struct tblentry **cmdtable; | ||
| 108 | struct localvar *localvars; | ||
| 109 | /* struct alias **atab; */ | ||
| 110 | /* struct parsefile *g_parsefile; */ | ||
| 111 | int fpid; | ||
| 112 | HANDLE hMapFile; | ||
| 113 | void *old_base; | ||
| 114 | int nodeptr_offset; | ||
| 115 | int size; | ||
| 116 | |||
| 117 | forkpoint_fn fp; | ||
| 118 | /* optional data, used by forkpoint_fn */ | ||
| 119 | int flags; | ||
| 120 | int fd[10]; | ||
| 121 | union node *n; | ||
| 122 | char **argv; | ||
| 123 | char *string; | ||
| 124 | struct strlist *strlist; | ||
| 125 | pid_t pid; | ||
| 126 | }; | ||
| 127 | static void sticky_free(void *p); | ||
| 128 | #define free(p) sticky_free(p) | ||
| 129 | static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode); | ||
| 130 | #endif | ||
| 84 | 131 | ||
| 85 | /* ============ Hash table sizes. Configurable. */ | 132 | /* ============ Hash table sizes. Configurable. */ |
| 86 | 133 | ||
| @@ -774,7 +821,7 @@ static void | |||
| 774 | opentrace(void) | 821 | opentrace(void) |
| 775 | { | 822 | { |
| 776 | char s[100]; | 823 | char s[100]; |
| 777 | #ifdef O_APPEND | 824 | #if defined(O_APPEND) && !ENABLE_PLATFORM_MINGW32 |
| 778 | int flags; | 825 | int flags; |
| 779 | #endif | 826 | #endif |
| 780 | 827 | ||
| @@ -799,7 +846,7 @@ opentrace(void) | |||
| 799 | return; | 846 | return; |
| 800 | } | 847 | } |
| 801 | } | 848 | } |
| 802 | #ifdef O_APPEND | 849 | #if defined(O_APPEND) && !ENABLE_PLATFORM_MINGW32 |
| 803 | flags = fcntl(fileno(tracefile), F_GETFL); | 850 | flags = fcntl(fileno(tracefile), F_GETFL); |
| 804 | if (flags >= 0) | 851 | if (flags >= 0) |
| 805 | fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); | 852 | fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); |
| @@ -2261,10 +2308,22 @@ path_advance(const char **path, const char *name) | |||
| 2261 | if (*path == NULL) | 2308 | if (*path == NULL) |
| 2262 | return NULL; | 2309 | return NULL; |
| 2263 | start = *path; | 2310 | start = *path; |
| 2311 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2312 | p = next_path_sep(start); | ||
| 2313 | q = strchr(start, '%'); | ||
| 2314 | if ((p && q && q < p) || (!p && q)) | ||
| 2315 | p = q; | ||
| 2316 | if (!p) | ||
| 2317 | for (p = start; *p; p++) | ||
| 2318 | continue; | ||
| 2319 | #else | ||
| 2264 | for (p = start; *p && *p != ':' && *p != '%'; p++) | 2320 | for (p = start; *p && *p != ':' && *p != '%'; p++) |
| 2265 | continue; | 2321 | continue; |
| 2322 | #endif | ||
| 2266 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ | 2323 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ |
| 2267 | while (stackblocksize() < len) | 2324 | |
| 2325 | /* preserve space for .exe too */ | ||
| 2326 | while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len)) | ||
| 2268 | growstackblock(); | 2327 | growstackblock(); |
| 2269 | q = stackblock(); | 2328 | q = stackblock(); |
| 2270 | if (p != start) { | 2329 | if (p != start) { |
| @@ -2380,6 +2439,98 @@ cdopt(void) | |||
| 2380 | static const char * | 2439 | static const char * |
| 2381 | updatepwd(const char *dir) | 2440 | updatepwd(const char *dir) |
| 2382 | { | 2441 | { |
| 2442 | #if ENABLE_PLATFORM_MINGW32 | ||
| 2443 | /* | ||
| 2444 | * Due to Windows drive notion, getting pwd is a completely | ||
| 2445 | * different thing. Handle it in a separate routine | ||
| 2446 | */ | ||
| 2447 | |||
| 2448 | char *new; | ||
| 2449 | char *p; | ||
| 2450 | char *cdcomppath; | ||
| 2451 | const char *lim; | ||
| 2452 | /* | ||
| 2453 | * There are four cases | ||
| 2454 | * absdrive + abspath: c:/path | ||
| 2455 | * absdrive + !abspath: c:path | ||
| 2456 | * !absdrive + abspath: /path | ||
| 2457 | * !absdrive + !abspath: path | ||
| 2458 | * | ||
| 2459 | * Damn DOS! | ||
| 2460 | * c:path behaviour is "undefined" | ||
| 2461 | * To properly handle this case, I have to keep track of cwd | ||
| 2462 | * of every drive, which is too painful to do. | ||
| 2463 | * So when c:path is given, I assume it's c:${curdir}path | ||
| 2464 | * with ${curdir} comes from the current drive | ||
| 2465 | */ | ||
| 2466 | int absdrive = *dir && dir[1] == ':'; | ||
| 2467 | int abspath = absdrive ? dir[2] == '/' : *dir == '/'; | ||
| 2468 | char *drive; | ||
| 2469 | |||
| 2470 | cdcomppath = ststrdup(dir); | ||
| 2471 | STARTSTACKSTR(new); | ||
| 2472 | if (!absdrive && curdir == nullstr) | ||
| 2473 | return 0; | ||
| 2474 | if (!abspath) { | ||
| 2475 | if (curdir == nullstr) | ||
| 2476 | return 0; | ||
| 2477 | new = stack_putstr(curdir, new); | ||
| 2478 | } | ||
| 2479 | new = makestrspace(strlen(dir) + 2, new); | ||
| 2480 | |||
| 2481 | drive = stackblock(); | ||
| 2482 | if (absdrive) { | ||
| 2483 | *drive = *dir; | ||
| 2484 | cdcomppath += 2; | ||
| 2485 | dir += 2; | ||
| 2486 | } else { | ||
| 2487 | *drive = *curdir; | ||
| 2488 | } | ||
| 2489 | drive[1] = ':'; /* in case of absolute drive+path */ | ||
| 2490 | |||
| 2491 | if (abspath) | ||
| 2492 | new = drive + 2; | ||
| 2493 | lim = drive + 3; | ||
| 2494 | if (!abspath) { | ||
| 2495 | if (new[-1] != '/') | ||
| 2496 | USTPUTC('/', new); | ||
| 2497 | if (new > lim && *lim == '/') | ||
| 2498 | lim++; | ||
| 2499 | } else { | ||
| 2500 | USTPUTC('/', new); | ||
| 2501 | cdcomppath ++; | ||
| 2502 | if (dir[1] == '/' && dir[2] != '/') { | ||
| 2503 | USTPUTC('/', new); | ||
| 2504 | cdcomppath++; | ||
| 2505 | lim++; | ||
| 2506 | } | ||
| 2507 | } | ||
| 2508 | p = strtok(cdcomppath, "/"); | ||
| 2509 | while (p) { | ||
| 2510 | switch (*p) { | ||
| 2511 | case '.': | ||
| 2512 | if (p[1] == '.' && p[2] == '\0') { | ||
| 2513 | while (new > lim) { | ||
| 2514 | STUNPUTC(new); | ||
| 2515 | if (new[-1] == '/') | ||
| 2516 | break; | ||
| 2517 | } | ||
| 2518 | break; | ||
| 2519 | } | ||
| 2520 | if (p[1] == '\0') | ||
| 2521 | break; | ||
| 2522 | /* fall through */ | ||
| 2523 | default: | ||
| 2524 | new = stack_putstr(p, new); | ||
| 2525 | USTPUTC('/', new); | ||
| 2526 | } | ||
| 2527 | p = strtok(0, "/"); | ||
| 2528 | } | ||
| 2529 | if (new > lim) | ||
| 2530 | STUNPUTC(new); | ||
| 2531 | *new = 0; | ||
| 2532 | return stackblock(); | ||
| 2533 | #else | ||
| 2383 | char *new; | 2534 | char *new; |
| 2384 | char *p; | 2535 | char *p; |
| 2385 | char *cdcomppath; | 2536 | char *cdcomppath; |
| @@ -2433,6 +2584,7 @@ updatepwd(const char *dir) | |||
| 2433 | STUNPUTC(new); | 2584 | STUNPUTC(new); |
| 2434 | *new = 0; | 2585 | *new = 0; |
| 2435 | return stackblock(); | 2586 | return stackblock(); |
| 2587 | #endif | ||
| 2436 | } | 2588 | } |
| 2437 | 2589 | ||
| 2438 | /* | 2590 | /* |
| @@ -2527,7 +2679,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 2527 | } | 2679 | } |
| 2528 | if (!dest) | 2680 | if (!dest) |
| 2529 | dest = nullstr; | 2681 | dest = nullstr; |
| 2530 | if (*dest == '/') | 2682 | if (is_absolute_path(dest)) |
| 2531 | goto step7; | 2683 | goto step7; |
| 2532 | if (*dest == '.') { | 2684 | if (*dest == '.') { |
| 2533 | c = dest[1]; | 2685 | c = dest[1]; |
| @@ -3301,6 +3453,8 @@ setsignal(int signo) | |||
| 3301 | char cur_act, new_act; | 3453 | char cur_act, new_act; |
| 3302 | struct sigaction act; | 3454 | struct sigaction act; |
| 3303 | 3455 | ||
| 3456 | if (ENABLE_PLATFORM_MINGW32) | ||
| 3457 | return; | ||
| 3304 | t = trap[signo]; | 3458 | t = trap[signo]; |
| 3305 | new_act = S_DFL; | 3459 | new_act = S_DFL; |
| 3306 | if (t != NULL) { /* trap for this sig is set */ | 3460 | if (t != NULL) { /* trap for this sig is set */ |
| @@ -3608,7 +3762,7 @@ setjobctl(int on) | |||
| 3608 | if (--fd < 0) | 3762 | if (--fd < 0) |
| 3609 | goto out; | 3763 | goto out; |
| 3610 | } | 3764 | } |
| 3611 | fd = fcntl(fd, F_DUPFD, 10); | 3765 | fd = copyfd(fd, 10); |
| 3612 | if (ofd >= 0) | 3766 | if (ofd >= 0) |
| 3613 | close(ofd); | 3767 | close(ofd); |
| 3614 | if (fd < 0) | 3768 | if (fd < 0) |
| @@ -3782,6 +3936,53 @@ sprint_status(char *s, int status, int sigonly) | |||
| 3782 | return col; | 3936 | return col; |
| 3783 | } | 3937 | } |
| 3784 | 3938 | ||
| 3939 | #if ENABLE_PLATFORM_MINGW32 | ||
| 3940 | /* | ||
| 3941 | * Windows does not know about parent-child relationship | ||
| 3942 | * They don't support waitpid(-1) | ||
| 3943 | */ | ||
| 3944 | static pid_t | ||
| 3945 | waitpid_child(int *status) | ||
| 3946 | { | ||
| 3947 | HANDLE *pidlist, *pidp; | ||
| 3948 | int pid_nr = 0; | ||
| 3949 | pid_t pid; | ||
| 3950 | DWORD win_status, idx; | ||
| 3951 | struct job *jb; | ||
| 3952 | |||
| 3953 | #define LOOP(stmt) \ | ||
| 3954 | for (jb = curjob; jb; jb = jb->prev_job) { \ | ||
| 3955 | struct procstat *ps, *psend; \ | ||
| 3956 | if (jb->state == JOBDONE) \ | ||
| 3957 | continue; \ | ||
| 3958 | ps = jb->ps; \ | ||
| 3959 | psend = ps + jb->nprocs; \ | ||
| 3960 | while (ps < psend) { \ | ||
| 3961 | if (ps->ps_pid != -1) { \ | ||
| 3962 | stmt; \ | ||
| 3963 | } \ | ||
| 3964 | ps++; \ | ||
| 3965 | } \ | ||
| 3966 | } | ||
| 3967 | |||
| 3968 | LOOP(pid_nr++); | ||
| 3969 | pidp = pidlist = ckmalloc(sizeof(*pidlist)*pid_nr); | ||
| 3970 | LOOP(*pidp++ = (HANDLE)ps->ps_pid); | ||
| 3971 | #undef LOOP | ||
| 3972 | |||
| 3973 | idx = WaitForMultipleObjects(pid_nr, pidlist, FALSE, INFINITE); | ||
| 3974 | if (idx >= pid_nr) { | ||
| 3975 | free(pidlist); | ||
| 3976 | return -1; | ||
| 3977 | } | ||
| 3978 | GetExitCodeProcess(pidlist[idx], &win_status); | ||
| 3979 | pid = (int)pidlist[idx]; | ||
| 3980 | free(pidlist); | ||
| 3981 | *status = (int)win_status; | ||
| 3982 | return pid; | ||
| 3983 | } | ||
| 3984 | #endif | ||
| 3985 | |||
| 3785 | static int | 3986 | static int |
| 3786 | dowait(int wait_flags, struct job *job) | 3987 | dowait(int wait_flags, struct job *job) |
| 3787 | { | 3988 | { |
| @@ -3798,7 +3999,11 @@ dowait(int wait_flags, struct job *job) | |||
| 3798 | * NB: _not_ safe_waitpid, we need to detect EINTR */ | 3999 | * NB: _not_ safe_waitpid, we need to detect EINTR */ |
| 3799 | if (doing_jobctl) | 4000 | if (doing_jobctl) |
| 3800 | wait_flags |= WUNTRACED; | 4001 | wait_flags |= WUNTRACED; |
| 4002 | #if ENABLE_PLATFORM_MINGW32 | ||
| 4003 | pid = waitpid_child(&status); | ||
| 4004 | #else | ||
| 3801 | pid = waitpid(-1, &status, wait_flags); | 4005 | pid = waitpid(-1, &status, wait_flags); |
| 4006 | #endif | ||
| 3802 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", | 4007 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", |
| 3803 | pid, status, errno, strerror(errno))); | 4008 | pid, status, errno, strerror(errno))); |
| 3804 | if (pid <= 0) | 4009 | if (pid <= 0) |
| @@ -3821,6 +4026,8 @@ dowait(int wait_flags, struct job *job) | |||
| 3821 | jobno(jp), pid, ps->ps_status, status)); | 4026 | jobno(jp), pid, ps->ps_status, status)); |
| 3822 | ps->ps_status = status; | 4027 | ps->ps_status = status; |
| 3823 | thisjob = jp; | 4028 | thisjob = jp; |
| 4029 | if (ENABLE_PLATFORM_MINGW32) | ||
| 4030 | ps->ps_pid = -1; | ||
| 3824 | } | 4031 | } |
| 3825 | if (ps->ps_status == -1) | 4032 | if (ps->ps_status == -1) |
| 3826 | state = JOBRUNNING; | 4033 | state = JOBRUNNING; |
| @@ -4052,6 +4259,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
| 4052 | int retval; | 4259 | int retval; |
| 4053 | struct job *jp; | 4260 | struct job *jp; |
| 4054 | 4261 | ||
| 4262 | if (ENABLE_PLATFORM_MINGW32) | ||
| 4263 | return 0; | ||
| 4264 | |||
| 4055 | if (pending_sig) | 4265 | if (pending_sig) |
| 4056 | raise_exception(EXSIG); | 4266 | raise_exception(EXSIG); |
| 4057 | 4267 | ||
| @@ -4655,7 +4865,7 @@ static void | |||
| 4655 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 4865 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
| 4656 | { | 4866 | { |
| 4657 | TRACE(("In parent shell: child = %d\n", pid)); | 4867 | TRACE(("In parent shell: child = %d\n", pid)); |
| 4658 | if (!jp) { | 4868 | if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */ |
| 4659 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) | 4869 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) |
| 4660 | continue; | 4870 | continue; |
| 4661 | jobless++; | 4871 | jobless++; |
| @@ -4695,6 +4905,9 @@ forkshell(struct job *jp, union node *n, int mode) | |||
| 4695 | int pid; | 4905 | int pid; |
| 4696 | 4906 | ||
| 4697 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); | 4907 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); |
| 4908 | if (ENABLE_PLATFORM_MINGW32) | ||
| 4909 | return -1; | ||
| 4910 | |||
| 4698 | pid = fork(); | 4911 | pid = fork(); |
| 4699 | if (pid < 0) { | 4912 | if (pid < 0) { |
| 4700 | TRACE(("Fork failed, errno=%d", errno)); | 4913 | TRACE(("Fork failed, errno=%d", errno)); |
| @@ -4891,11 +5104,39 @@ noclobberopen(const char *fname) | |||
| 4891 | */ | 5104 | */ |
| 4892 | /* openhere needs this forward reference */ | 5105 | /* openhere needs this forward reference */ |
| 4893 | static void expandhere(union node *arg, int fd); | 5106 | static void expandhere(union node *arg, int fd); |
| 5107 | #if ENABLE_PLATFORM_MINGW32 | ||
| 5108 | static void | ||
| 5109 | forkshell_openhere(struct forkshell *fs) | ||
| 5110 | { | ||
| 5111 | union node *redir = fs->n; | ||
| 5112 | int pip[2]; | ||
| 5113 | |||
| 5114 | pip[0] = fs->fd[0]; | ||
| 5115 | pip[1] = fs->fd[1]; | ||
| 5116 | |||
| 5117 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
| 5118 | |||
| 5119 | close(pip[0]); | ||
| 5120 | ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); | ||
| 5121 | ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); | ||
| 5122 | ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); | ||
| 5123 | ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); | ||
| 5124 | signal(SIGPIPE, SIG_DFL); | ||
| 5125 | if (redir->type == NHERE) { | ||
| 5126 | size_t len = strlen(redir->nhere.doc->narg.text); | ||
| 5127 | full_write(pip[1], redir->nhere.doc->narg.text, len); | ||
| 5128 | } else /* NXHERE */ | ||
| 5129 | expandhere(redir->nhere.doc, pip[1]); | ||
| 5130 | _exit(EXIT_SUCCESS); | ||
| 5131 | } | ||
| 5132 | #endif | ||
| 5133 | |||
| 4894 | static int | 5134 | static int |
| 4895 | openhere(union node *redir) | 5135 | openhere(union node *redir) |
| 4896 | { | 5136 | { |
| 4897 | int pip[2]; | 5137 | int pip[2]; |
| 4898 | size_t len = 0; | 5138 | size_t len = 0; |
| 5139 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
| 4899 | 5140 | ||
| 4900 | if (pipe(pip) < 0) | 5141 | if (pipe(pip) < 0) |
| 4901 | ash_msg_and_raise_error("pipe call failed"); | 5142 | ash_msg_and_raise_error("pipe call failed"); |
| @@ -4906,6 +5147,16 @@ openhere(union node *redir) | |||
| 4906 | goto out; | 5147 | goto out; |
| 4907 | } | 5148 | } |
| 4908 | } | 5149 | } |
| 5150 | #if ENABLE_PLATFORM_MINGW32 | ||
| 5151 | memset(&fs, 0, sizeof(fs)); | ||
| 5152 | fs.fp = forkshell_openhere; | ||
| 5153 | fs.flags = 0; | ||
| 5154 | fs.n = redir; | ||
| 5155 | fs.fd[0] = pip[0]; | ||
| 5156 | fs.fd[1] = pip[1]; | ||
| 5157 | if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0) | ||
| 5158 | ash_msg_and_raise_error("unable to spawn shell"); | ||
| 5159 | #endif | ||
| 4909 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | 5160 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { |
| 4910 | /* child */ | 5161 | /* child */ |
| 4911 | close(pip[0]); | 5162 | close(pip[0]); |
| @@ -4931,6 +5182,31 @@ openredirect(union node *redir) | |||
| 4931 | char *fname; | 5182 | char *fname; |
| 4932 | int f; | 5183 | int f; |
| 4933 | 5184 | ||
| 5185 | #if ENABLE_PLATFORM_MINGW32 | ||
| 5186 | /* Support for /dev/null */ | ||
| 5187 | switch (redir->nfile.type) { | ||
| 5188 | case NFROM: | ||
| 5189 | if (!strcmp(redir->nfile.expfname, "/dev/null")) | ||
| 5190 | return open("nul",O_RDWR); | ||
| 5191 | if (!strncmp(redir->nfile.expfname, "/dev/", 5)) { | ||
| 5192 | ash_msg("Unhandled device %s\n", redir->nfile.expfname); | ||
| 5193 | return -1; | ||
| 5194 | } | ||
| 5195 | break; | ||
| 5196 | |||
| 5197 | case NFROMTO: | ||
| 5198 | case NTO: | ||
| 5199 | case NCLOBBER: | ||
| 5200 | case NAPPEND: | ||
| 5201 | if (!strcmp(redir->nfile.expfname, "/dev/null")) | ||
| 5202 | return open("nul",O_RDWR); | ||
| 5203 | if (!strncmp(redir->nfile.expfname, "/dev/", 5)) { | ||
| 5204 | ash_msg("Unhandled device %s\n", redir->nfile.expfname); | ||
| 5205 | return -1; | ||
| 5206 | } | ||
| 5207 | break; | ||
| 5208 | } | ||
| 5209 | #endif | ||
| 4934 | switch (redir->nfile.type) { | 5210 | switch (redir->nfile.type) { |
| 4935 | case NFROM: | 5211 | case NFROM: |
| 4936 | fname = redir->nfile.expfname; | 5212 | fname = redir->nfile.expfname; |
| @@ -5013,6 +5289,18 @@ copyfd(int from, int to) | |||
| 5013 | /*if (from != to)*/ | 5289 | /*if (from != to)*/ |
| 5014 | newfd = dup2(from, to); | 5290 | newfd = dup2(from, to); |
| 5015 | } else { | 5291 | } else { |
| 5292 | if (ENABLE_PLATFORM_MINGW32) { | ||
| 5293 | char* fds = ckmalloc(to); | ||
| 5294 | int i,fd; | ||
| 5295 | memset(fds,0,to); | ||
| 5296 | while ((fd = dup(from)) < to && fd >= 0) | ||
| 5297 | fds[fd] = 1; | ||
| 5298 | for (i = 0;i < to;i ++) | ||
| 5299 | if (fds[i]) | ||
| 5300 | close(i); | ||
| 5301 | free(fds); | ||
| 5302 | return fd; | ||
| 5303 | } | ||
| 5016 | newfd = fcntl(from, F_DUPFD, to); | 5304 | newfd = fcntl(from, F_DUPFD, to); |
| 5017 | } | 5305 | } |
| 5018 | if (newfd < 0) { | 5306 | if (newfd < 0) { |
| @@ -5157,7 +5445,7 @@ redirect(union node *redir, int flags) | |||
| 5157 | #endif | 5445 | #endif |
| 5158 | if (need_to_remember(sv, fd)) { | 5446 | if (need_to_remember(sv, fd)) { |
| 5159 | /* Copy old descriptor */ | 5447 | /* Copy old descriptor */ |
| 5160 | i = fcntl(fd, F_DUPFD, 10); | 5448 | i = copyfd(fd, 10); |
| 5161 | /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds | 5449 | /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds |
| 5162 | * are closed in popredir() in the child, preventing them from leaking | 5450 | * are closed in popredir() in the child, preventing them from leaking |
| 5163 | * into child. (popredir() also cleans up the mess in case of failures) | 5451 | * into child. (popredir() also cleans up the mess in case of failures) |
| @@ -5618,6 +5906,8 @@ exptilde(char *startp, char *p, int flags) | |||
| 5618 | if (*name == '\0') { | 5906 | if (*name == '\0') { |
| 5619 | home = lookupvar(homestr); | 5907 | home = lookupvar(homestr); |
| 5620 | } else { | 5908 | } else { |
| 5909 | if (ENABLE_PLATFORM_MINGW32) | ||
| 5910 | goto lose; | ||
| 5621 | pw = getpwnam(name); | 5911 | pw = getpwnam(name); |
| 5622 | if (pw == NULL) | 5912 | if (pw == NULL) |
| 5623 | goto lose; | 5913 | goto lose; |
| @@ -5645,6 +5935,7 @@ struct backcmd { /* result of evalbackcmd */ | |||
| 5645 | int fd; /* file descriptor to read from */ | 5935 | int fd; /* file descriptor to read from */ |
| 5646 | int nleft; /* number of chars in buffer */ | 5936 | int nleft; /* number of chars in buffer */ |
| 5647 | char *buf; /* buffer */ | 5937 | char *buf; /* buffer */ |
| 5938 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
| 5648 | struct job *jp; /* job structure for command */ | 5939 | struct job *jp; /* job structure for command */ |
| 5649 | }; | 5940 | }; |
| 5650 | 5941 | ||
| @@ -5653,6 +5944,25 @@ static uint8_t back_exitstatus; /* exit status of backquoted command */ | |||
| 5653 | #define EV_EXIT 01 /* exit after evaluating tree */ | 5944 | #define EV_EXIT 01 /* exit after evaluating tree */ |
| 5654 | static void evaltree(union node *, int); | 5945 | static void evaltree(union node *, int); |
| 5655 | 5946 | ||
| 5947 | #if ENABLE_PLATFORM_MINGW32 | ||
| 5948 | static void | ||
| 5949 | forkshell_evalbackcmd(struct forkshell *fs) | ||
| 5950 | { | ||
| 5951 | union node *n = fs->n; | ||
| 5952 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
| 5953 | |||
| 5954 | FORCE_INT_ON; | ||
| 5955 | close(pip[0]); | ||
| 5956 | if (pip[1] != 1) { | ||
| 5957 | /*close(1);*/ | ||
| 5958 | copyfd(pip[1], 1 | COPYFD_EXACT); | ||
| 5959 | close(pip[1]); | ||
| 5960 | } | ||
| 5961 | eflag = 0; | ||
| 5962 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ | ||
| 5963 | /* NOTREACHED */ | ||
| 5964 | } | ||
| 5965 | #endif | ||
| 5656 | static void FAST_FUNC | 5966 | static void FAST_FUNC |
| 5657 | evalbackcmd(union node *n, struct backcmd *result) | 5967 | evalbackcmd(union node *n, struct backcmd *result) |
| 5658 | { | 5968 | { |
| @@ -5661,6 +5971,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
| 5661 | result->fd = -1; | 5971 | result->fd = -1; |
| 5662 | result->buf = NULL; | 5972 | result->buf = NULL; |
| 5663 | result->nleft = 0; | 5973 | result->nleft = 0; |
| 5974 | IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs))); | ||
| 5664 | result->jp = NULL; | 5975 | result->jp = NULL; |
| 5665 | if (n == NULL) | 5976 | if (n == NULL) |
| 5666 | goto out; | 5977 | goto out; |
| @@ -5675,6 +5986,14 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
| 5675 | if (pipe(pip) < 0) | 5986 | if (pipe(pip) < 0) |
| 5676 | ash_msg_and_raise_error("pipe call failed"); | 5987 | ash_msg_and_raise_error("pipe call failed"); |
| 5677 | jp = makejob(/*n,*/ 1); | 5988 | jp = makejob(/*n,*/ 1); |
| 5989 | #if ENABLE_PLATFORM_MINGW32 | ||
| 5990 | result->fs.fp = forkshell_evalbackcmd; | ||
| 5991 | result->fs.n = n; | ||
| 5992 | result->fs.fd[0] = pip[0]; | ||
| 5993 | result->fs.fd[1] = pip[1]; | ||
| 5994 | if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0) | ||
| 5995 | ash_msg_and_raise_error("unable to spawn shell"); | ||
| 5996 | #endif | ||
| 5678 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 5997 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
| 5679 | FORCE_INT_ON; | 5998 | FORCE_INT_ON; |
| 5680 | close(pip[0]); | 5999 | close(pip[0]); |
| @@ -7290,7 +7609,7 @@ shellexec(char **argv, const char *path, int idx) | |||
| 7290 | 7609 | ||
| 7291 | clearredir(/*drop:*/ 1); | 7610 | clearredir(/*drop:*/ 1); |
| 7292 | envp = listvars(VEXPORT, VUNSET, 0); | 7611 | envp = listvars(VEXPORT, VUNSET, 0); |
| 7293 | if (strchr(argv[0], '/') != NULL | 7612 | if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\'))) |
| 7294 | #if ENABLE_FEATURE_SH_STANDALONE | 7613 | #if ENABLE_FEATURE_SH_STANDALONE |
| 7295 | || (applet_no = find_applet_by_name(argv[0])) >= 0 | 7614 | || (applet_no = find_applet_by_name(argv[0])) >= 0 |
| 7296 | #endif | 7615 | #endif |
| @@ -7807,6 +8126,10 @@ static int funcblocksize; /* size of structures in function */ | |||
| 7807 | static int funcstringsize; /* size of strings in node */ | 8126 | static int funcstringsize; /* size of strings in node */ |
| 7808 | static void *funcblock; /* block to allocate function from */ | 8127 | static void *funcblock; /* block to allocate function from */ |
| 7809 | static char *funcstring; /* block to allocate strings from */ | 8128 | static char *funcstring; /* block to allocate strings from */ |
| 8129 | #if ENABLE_PLATFORM_MINGW32 | ||
| 8130 | static int nodeptrsize; | ||
| 8131 | static int *nodeptr; | ||
| 8132 | #endif | ||
| 7810 | 8133 | ||
| 7811 | /* flags in argument to evaltree */ | 8134 | /* flags in argument to evaltree */ |
| 7812 | #define EV_EXIT 01 /* exit after evaluating tree */ | 8135 | #define EV_EXIT 01 /* exit after evaluating tree */ |
| @@ -7852,6 +8175,7 @@ sizenodelist(struct nodelist *lp) | |||
| 7852 | { | 8175 | { |
| 7853 | while (lp) { | 8176 | while (lp) { |
| 7854 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); | 8177 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); |
| 8178 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
| 7855 | calcsize(lp->n); | 8179 | calcsize(lp->n); |
| 7856 | lp = lp->next; | 8180 | lp = lp->next; |
| 7857 | } | 8181 | } |
| @@ -7868,15 +8192,18 @@ calcsize(union node *n) | |||
| 7868 | calcsize(n->ncmd.redirect); | 8192 | calcsize(n->ncmd.redirect); |
| 7869 | calcsize(n->ncmd.args); | 8193 | calcsize(n->ncmd.args); |
| 7870 | calcsize(n->ncmd.assign); | 8194 | calcsize(n->ncmd.assign); |
| 8195 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
| 7871 | break; | 8196 | break; |
| 7872 | case NPIPE: | 8197 | case NPIPE: |
| 7873 | sizenodelist(n->npipe.cmdlist); | 8198 | sizenodelist(n->npipe.cmdlist); |
| 8199 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
| 7874 | break; | 8200 | break; |
| 7875 | case NREDIR: | 8201 | case NREDIR: |
| 7876 | case NBACKGND: | 8202 | case NBACKGND: |
| 7877 | case NSUBSHELL: | 8203 | case NSUBSHELL: |
| 7878 | calcsize(n->nredir.redirect); | 8204 | calcsize(n->nredir.redirect); |
| 7879 | calcsize(n->nredir.n); | 8205 | calcsize(n->nredir.n); |
| 8206 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
| 7880 | break; | 8207 | break; |
| 7881 | case NAND: | 8208 | case NAND: |
| 7882 | case NOR: | 8209 | case NOR: |
| @@ -7885,31 +8212,37 @@ calcsize(union node *n) | |||
| 7885 | case NUNTIL: | 8212 | case NUNTIL: |
| 7886 | calcsize(n->nbinary.ch2); | 8213 | calcsize(n->nbinary.ch2); |
| 7887 | calcsize(n->nbinary.ch1); | 8214 | calcsize(n->nbinary.ch1); |
| 8215 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
| 7888 | break; | 8216 | break; |
| 7889 | case NIF: | 8217 | case NIF: |
| 7890 | calcsize(n->nif.elsepart); | 8218 | calcsize(n->nif.elsepart); |
| 7891 | calcsize(n->nif.ifpart); | 8219 | calcsize(n->nif.ifpart); |
| 7892 | calcsize(n->nif.test); | 8220 | calcsize(n->nif.test); |
| 8221 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
| 7893 | break; | 8222 | break; |
| 7894 | case NFOR: | 8223 | case NFOR: |
| 7895 | funcstringsize += strlen(n->nfor.var) + 1; | 8224 | funcstringsize += strlen(n->nfor.var) + 1; |
| 7896 | calcsize(n->nfor.body); | 8225 | calcsize(n->nfor.body); |
| 7897 | calcsize(n->nfor.args); | 8226 | calcsize(n->nfor.args); |
| 8227 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
| 7898 | break; | 8228 | break; |
| 7899 | case NCASE: | 8229 | case NCASE: |
| 7900 | calcsize(n->ncase.cases); | 8230 | calcsize(n->ncase.cases); |
| 7901 | calcsize(n->ncase.expr); | 8231 | calcsize(n->ncase.expr); |
| 8232 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
| 7902 | break; | 8233 | break; |
| 7903 | case NCLIST: | 8234 | case NCLIST: |
| 7904 | calcsize(n->nclist.body); | 8235 | calcsize(n->nclist.body); |
| 7905 | calcsize(n->nclist.pattern); | 8236 | calcsize(n->nclist.pattern); |
| 7906 | calcsize(n->nclist.next); | 8237 | calcsize(n->nclist.next); |
| 8238 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
| 7907 | break; | 8239 | break; |
| 7908 | case NDEFUN: | 8240 | case NDEFUN: |
| 7909 | case NARG: | 8241 | case NARG: |
| 7910 | sizenodelist(n->narg.backquote); | 8242 | sizenodelist(n->narg.backquote); |
| 7911 | funcstringsize += strlen(n->narg.text) + 1; | 8243 | funcstringsize += strlen(n->narg.text) + 1; |
| 7912 | calcsize(n->narg.next); | 8244 | calcsize(n->narg.next); |
| 8245 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
| 7913 | break; | 8246 | break; |
| 7914 | case NTO: | 8247 | case NTO: |
| 7915 | #if ENABLE_ASH_BASH_COMPAT | 8248 | #if ENABLE_ASH_BASH_COMPAT |
| @@ -7921,28 +8254,34 @@ calcsize(union node *n) | |||
| 7921 | case NAPPEND: | 8254 | case NAPPEND: |
| 7922 | calcsize(n->nfile.fname); | 8255 | calcsize(n->nfile.fname); |
| 7923 | calcsize(n->nfile.next); | 8256 | calcsize(n->nfile.next); |
| 8257 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
| 7924 | break; | 8258 | break; |
| 7925 | case NTOFD: | 8259 | case NTOFD: |
| 7926 | case NFROMFD: | 8260 | case NFROMFD: |
| 7927 | calcsize(n->ndup.vname); | 8261 | calcsize(n->ndup.vname); |
| 7928 | calcsize(n->ndup.next); | 8262 | calcsize(n->ndup.next); |
| 8263 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
| 7929 | break; | 8264 | break; |
| 7930 | case NHERE: | 8265 | case NHERE: |
| 7931 | case NXHERE: | 8266 | case NXHERE: |
| 7932 | calcsize(n->nhere.doc); | 8267 | calcsize(n->nhere.doc); |
| 7933 | calcsize(n->nhere.next); | 8268 | calcsize(n->nhere.next); |
| 8269 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
| 7934 | break; | 8270 | break; |
| 7935 | case NNOT: | 8271 | case NNOT: |
| 7936 | calcsize(n->nnot.com); | 8272 | calcsize(n->nnot.com); |
| 8273 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
| 7937 | break; | 8274 | break; |
| 7938 | }; | 8275 | }; |
| 7939 | } | 8276 | } |
| 7940 | 8277 | ||
| 7941 | static char * | 8278 | static char * |
| 7942 | nodeckstrdup(char *s) | 8279 | nodeckstrdup(const char *s) |
| 7943 | { | 8280 | { |
| 7944 | char *rtn = funcstring; | 8281 | char *rtn = funcstring; |
| 7945 | 8282 | ||
| 8283 | if (!s) | ||
| 8284 | return NULL; | ||
| 7946 | strcpy(funcstring, s); | 8285 | strcpy(funcstring, s); |
| 7947 | funcstring += strlen(s) + 1; | 8286 | funcstring += strlen(s) + 1; |
| 7948 | return rtn; | 8287 | return rtn; |
| @@ -7950,6 +8289,18 @@ nodeckstrdup(char *s) | |||
| 7950 | 8289 | ||
| 7951 | static union node *copynode(union node *); | 8290 | static union node *copynode(union node *); |
| 7952 | 8291 | ||
| 8292 | #if ENABLE_PLATFORM_MINGW32 | ||
| 8293 | # define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (int)&(dst);} | ||
| 8294 | # define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);}} | ||
| 8295 | # define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);}} | ||
| 8296 | # define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);*nodeptr++ = (int)&(dst4);}} | ||
| 8297 | #else | ||
| 8298 | # define SAVE_PTR(dst) | ||
| 8299 | # define SAVE_PTR2(dst,dst2) | ||
| 8300 | # define SAVE_PTR3(dst,dst2,dst3) | ||
| 8301 | # define SAVE_PTR4(dst,dst2,dst3,dst4) | ||
| 8302 | #endif | ||
| 8303 | |||
| 7953 | static struct nodelist * | 8304 | static struct nodelist * |
| 7954 | copynodelist(struct nodelist *lp) | 8305 | copynodelist(struct nodelist *lp) |
| 7955 | { | 8306 | { |
| @@ -7961,6 +8312,7 @@ copynodelist(struct nodelist *lp) | |||
| 7961 | *lpp = funcblock; | 8312 | *lpp = funcblock; |
| 7962 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); | 8313 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); |
| 7963 | (*lpp)->n = copynode(lp->n); | 8314 | (*lpp)->n = copynode(lp->n); |
| 8315 | SAVE_PTR2((*lpp)->n, (*lpp)->next); | ||
| 7964 | lp = lp->next; | 8316 | lp = lp->next; |
| 7965 | lpp = &(*lpp)->next; | 8317 | lpp = &(*lpp)->next; |
| 7966 | } | 8318 | } |
| @@ -7983,16 +8335,19 @@ copynode(union node *n) | |||
| 7983 | new->ncmd.redirect = copynode(n->ncmd.redirect); | 8335 | new->ncmd.redirect = copynode(n->ncmd.redirect); |
| 7984 | new->ncmd.args = copynode(n->ncmd.args); | 8336 | new->ncmd.args = copynode(n->ncmd.args); |
| 7985 | new->ncmd.assign = copynode(n->ncmd.assign); | 8337 | new->ncmd.assign = copynode(n->ncmd.assign); |
| 8338 | SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign); | ||
| 7986 | break; | 8339 | break; |
| 7987 | case NPIPE: | 8340 | case NPIPE: |
| 7988 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | 8341 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); |
| 7989 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; | 8342 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; |
| 8343 | SAVE_PTR(new->npipe.cmdlist); | ||
| 7990 | break; | 8344 | break; |
| 7991 | case NREDIR: | 8345 | case NREDIR: |
| 7992 | case NBACKGND: | 8346 | case NBACKGND: |
| 7993 | case NSUBSHELL: | 8347 | case NSUBSHELL: |
| 7994 | new->nredir.redirect = copynode(n->nredir.redirect); | 8348 | new->nredir.redirect = copynode(n->nredir.redirect); |
| 7995 | new->nredir.n = copynode(n->nredir.n); | 8349 | new->nredir.n = copynode(n->nredir.n); |
| 8350 | SAVE_PTR2(new->nredir.redirect,new->nredir.n); | ||
| 7996 | break; | 8351 | break; |
| 7997 | case NAND: | 8352 | case NAND: |
| 7998 | case NOR: | 8353 | case NOR: |
| @@ -8001,31 +8356,37 @@ copynode(union node *n) | |||
| 8001 | case NUNTIL: | 8356 | case NUNTIL: |
| 8002 | new->nbinary.ch2 = copynode(n->nbinary.ch2); | 8357 | new->nbinary.ch2 = copynode(n->nbinary.ch2); |
| 8003 | new->nbinary.ch1 = copynode(n->nbinary.ch1); | 8358 | new->nbinary.ch1 = copynode(n->nbinary.ch1); |
| 8359 | SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2); | ||
| 8004 | break; | 8360 | break; |
| 8005 | case NIF: | 8361 | case NIF: |
| 8006 | new->nif.elsepart = copynode(n->nif.elsepart); | 8362 | new->nif.elsepart = copynode(n->nif.elsepart); |
| 8007 | new->nif.ifpart = copynode(n->nif.ifpart); | 8363 | new->nif.ifpart = copynode(n->nif.ifpart); |
| 8008 | new->nif.test = copynode(n->nif.test); | 8364 | new->nif.test = copynode(n->nif.test); |
| 8365 | SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test); | ||
| 8009 | break; | 8366 | break; |
| 8010 | case NFOR: | 8367 | case NFOR: |
| 8011 | new->nfor.var = nodeckstrdup(n->nfor.var); | 8368 | new->nfor.var = nodeckstrdup(n->nfor.var); |
| 8012 | new->nfor.body = copynode(n->nfor.body); | 8369 | new->nfor.body = copynode(n->nfor.body); |
| 8013 | new->nfor.args = copynode(n->nfor.args); | 8370 | new->nfor.args = copynode(n->nfor.args); |
| 8371 | SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args); | ||
| 8014 | break; | 8372 | break; |
| 8015 | case NCASE: | 8373 | case NCASE: |
| 8016 | new->ncase.cases = copynode(n->ncase.cases); | 8374 | new->ncase.cases = copynode(n->ncase.cases); |
| 8017 | new->ncase.expr = copynode(n->ncase.expr); | 8375 | new->ncase.expr = copynode(n->ncase.expr); |
| 8376 | SAVE_PTR2(new->ncase.cases,new->ncase.expr); | ||
| 8018 | break; | 8377 | break; |
| 8019 | case NCLIST: | 8378 | case NCLIST: |
| 8020 | new->nclist.body = copynode(n->nclist.body); | 8379 | new->nclist.body = copynode(n->nclist.body); |
| 8021 | new->nclist.pattern = copynode(n->nclist.pattern); | 8380 | new->nclist.pattern = copynode(n->nclist.pattern); |
| 8022 | new->nclist.next = copynode(n->nclist.next); | 8381 | new->nclist.next = copynode(n->nclist.next); |
| 8382 | SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next); | ||
| 8023 | break; | 8383 | break; |
| 8024 | case NDEFUN: | 8384 | case NDEFUN: |
| 8025 | case NARG: | 8385 | case NARG: |
| 8026 | new->narg.backquote = copynodelist(n->narg.backquote); | 8386 | new->narg.backquote = copynodelist(n->narg.backquote); |
| 8027 | new->narg.text = nodeckstrdup(n->narg.text); | 8387 | new->narg.text = nodeckstrdup(n->narg.text); |
| 8028 | new->narg.next = copynode(n->narg.next); | 8388 | new->narg.next = copynode(n->narg.next); |
| 8389 | SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next); | ||
| 8029 | break; | 8390 | break; |
| 8030 | case NTO: | 8391 | case NTO: |
| 8031 | #if ENABLE_ASH_BASH_COMPAT | 8392 | #if ENABLE_ASH_BASH_COMPAT |
| @@ -8038,6 +8399,7 @@ copynode(union node *n) | |||
| 8038 | new->nfile.fname = copynode(n->nfile.fname); | 8399 | new->nfile.fname = copynode(n->nfile.fname); |
| 8039 | new->nfile.fd = n->nfile.fd; | 8400 | new->nfile.fd = n->nfile.fd; |
| 8040 | new->nfile.next = copynode(n->nfile.next); | 8401 | new->nfile.next = copynode(n->nfile.next); |
| 8402 | SAVE_PTR2(new->nfile.fname,new->nfile.next); | ||
| 8041 | break; | 8403 | break; |
| 8042 | case NTOFD: | 8404 | case NTOFD: |
| 8043 | case NFROMFD: | 8405 | case NFROMFD: |
| @@ -8045,15 +8407,18 @@ copynode(union node *n) | |||
| 8045 | new->ndup.dupfd = n->ndup.dupfd; | 8407 | new->ndup.dupfd = n->ndup.dupfd; |
| 8046 | new->ndup.fd = n->ndup.fd; | 8408 | new->ndup.fd = n->ndup.fd; |
| 8047 | new->ndup.next = copynode(n->ndup.next); | 8409 | new->ndup.next = copynode(n->ndup.next); |
| 8410 | SAVE_PTR2(new->ndup.vname,new->ndup.next); | ||
| 8048 | break; | 8411 | break; |
| 8049 | case NHERE: | 8412 | case NHERE: |
| 8050 | case NXHERE: | 8413 | case NXHERE: |
| 8051 | new->nhere.doc = copynode(n->nhere.doc); | 8414 | new->nhere.doc = copynode(n->nhere.doc); |
| 8052 | new->nhere.fd = n->nhere.fd; | 8415 | new->nhere.fd = n->nhere.fd; |
| 8053 | new->nhere.next = copynode(n->nhere.next); | 8416 | new->nhere.next = copynode(n->nhere.next); |
| 8417 | SAVE_PTR2(new->nhere.doc,new->nhere.next); | ||
| 8054 | break; | 8418 | break; |
| 8055 | case NNOT: | 8419 | case NNOT: |
| 8056 | new->nnot.com = copynode(n->nnot.com); | 8420 | new->nnot.com = copynode(n->nnot.com); |
| 8421 | SAVE_PTR(new->nnot.com); | ||
| 8057 | break; | 8422 | break; |
| 8058 | }; | 8423 | }; |
| 8059 | new->type = n->type; | 8424 | new->type = n->type; |
| @@ -8076,6 +8441,7 @@ copyfunc(union node *n) | |||
| 8076 | f = ckmalloc(blocksize + funcstringsize); | 8441 | f = ckmalloc(blocksize + funcstringsize); |
| 8077 | funcblock = (char *) f + offsetof(struct funcnode, n); | 8442 | funcblock = (char *) f + offsetof(struct funcnode, n); |
| 8078 | funcstring = (char *) f + blocksize; | 8443 | funcstring = (char *) f + blocksize; |
| 8444 | IF_PLATFORM_MINGW32(nodeptr = NULL); | ||
| 8079 | copynode(n); | 8445 | copynode(n); |
| 8080 | f->count = 0; | 8446 | f->count = 0; |
| 8081 | return f; | 8447 | return f; |
| @@ -8428,9 +8794,26 @@ evalcase(union node *n, int flags) | |||
| 8428 | /* | 8794 | /* |
| 8429 | * Kick off a subshell to evaluate a tree. | 8795 | * Kick off a subshell to evaluate a tree. |
| 8430 | */ | 8796 | */ |
| 8797 | #if ENABLE_PLATFORM_MINGW32 | ||
| 8798 | static void | ||
| 8799 | forkshell_evalsubshell(struct forkshell *fs) | ||
| 8800 | { | ||
| 8801 | union node *n = fs->n; | ||
| 8802 | int flags = fs->flags; | ||
| 8803 | |||
| 8804 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
| 8805 | INT_ON; | ||
| 8806 | flags |= EV_EXIT; | ||
| 8807 | expredir(n->nredir.redirect); | ||
| 8808 | redirect(n->nredir.redirect, 0); | ||
| 8809 | evaltreenr(n->nredir.n, flags); | ||
| 8810 | /* never returns */ | ||
| 8811 | } | ||
| 8812 | #endif | ||
| 8431 | static void | 8813 | static void |
| 8432 | evalsubshell(union node *n, int flags) | 8814 | evalsubshell(union node *n, int flags) |
| 8433 | { | 8815 | { |
| 8816 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
| 8434 | struct job *jp; | 8817 | struct job *jp; |
| 8435 | int backgnd = (n->type == NBACKGND); | 8818 | int backgnd = (n->type == NBACKGND); |
| 8436 | int status; | 8819 | int status; |
| @@ -8440,6 +8823,14 @@ evalsubshell(union node *n, int flags) | |||
| 8440 | goto nofork; | 8823 | goto nofork; |
| 8441 | INT_OFF; | 8824 | INT_OFF; |
| 8442 | jp = makejob(/*n,*/ 1); | 8825 | jp = makejob(/*n,*/ 1); |
| 8826 | #if ENABLE_PLATFORM_MINGW32 | ||
| 8827 | memset(&fs, 0, sizeof(fs)); | ||
| 8828 | fs.fp = forkshell_evalsubshell; | ||
| 8829 | fs.n = n; | ||
| 8830 | fs.flags = flags; | ||
| 8831 | if (spawn_forkshell(jp, &fs, backgnd) < 0) | ||
| 8832 | ash_msg_and_raise_error("unable to spawn shell"); | ||
| 8833 | #endif | ||
| 8443 | if (forkshell(jp, n, backgnd) == 0) { | 8834 | if (forkshell(jp, n, backgnd) == 0) { |
| 8444 | INT_ON; | 8835 | INT_ON; |
| 8445 | flags |= EV_EXIT; | 8836 | flags |= EV_EXIT; |
| @@ -8515,9 +8906,35 @@ expredir(union node *n) | |||
| 8515 | * of the shell, which make the last process in a pipeline the parent | 8906 | * of the shell, which make the last process in a pipeline the parent |
| 8516 | * of all the rest.) | 8907 | * of all the rest.) |
| 8517 | */ | 8908 | */ |
| 8909 | #if ENABLE_PLATFORM_MINGW32 | ||
| 8910 | static void | ||
| 8911 | forkshell_evalpipe(struct forkshell *fs) | ||
| 8912 | { | ||
| 8913 | union node *n = fs->n; | ||
| 8914 | int flags = fs->flags; | ||
| 8915 | int prevfd = fs->fd[2]; | ||
| 8916 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
| 8917 | |||
| 8918 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
| 8919 | INT_ON; | ||
| 8920 | if (pip[1] >= 0) { | ||
| 8921 | close(pip[0]); | ||
| 8922 | } | ||
| 8923 | if (prevfd > 0) { | ||
| 8924 | dup2(prevfd, 0); | ||
| 8925 | close(prevfd); | ||
| 8926 | } | ||
| 8927 | if (pip[1] > 1) { | ||
| 8928 | dup2(pip[1], 1); | ||
| 8929 | close(pip[1]); | ||
| 8930 | } | ||
| 8931 | evaltreenr(n, flags); | ||
| 8932 | } | ||
| 8933 | #endif | ||
| 8518 | static void | 8934 | static void |
| 8519 | evalpipe(union node *n, int flags) | 8935 | evalpipe(union node *n, int flags) |
| 8520 | { | 8936 | { |
| 8937 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
| 8521 | struct job *jp; | 8938 | struct job *jp; |
| 8522 | struct nodelist *lp; | 8939 | struct nodelist *lp; |
| 8523 | int pipelen; | 8940 | int pipelen; |
| @@ -8541,6 +8958,17 @@ evalpipe(union node *n, int flags) | |||
| 8541 | ash_msg_and_raise_error("pipe call failed"); | 8958 | ash_msg_and_raise_error("pipe call failed"); |
| 8542 | } | 8959 | } |
| 8543 | } | 8960 | } |
| 8961 | #if ENABLE_PLATFORM_MINGW32 | ||
| 8962 | memset(&fs, 0, sizeof(fs)); | ||
| 8963 | fs.fp = forkshell_evalpipe; | ||
| 8964 | fs.flags = flags; | ||
| 8965 | fs.n = lp->n; | ||
| 8966 | fs.fd[0] = pip[0]; | ||
| 8967 | fs.fd[1] = pip[1]; | ||
| 8968 | fs.fd[2] = prevfd; | ||
| 8969 | if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0) | ||
| 8970 | ash_msg_and_raise_error("unable to spawn shell"); | ||
| 8971 | #endif | ||
| 8544 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { | 8972 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { |
| 8545 | INT_ON; | 8973 | INT_ON; |
| 8546 | if (pip[1] >= 0) { | 8974 | if (pip[1] >= 0) { |
| @@ -9007,6 +9435,20 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 9007 | * as POSIX mandates */ | 9435 | * as POSIX mandates */ |
| 9008 | return back_exitstatus; | 9436 | return back_exitstatus; |
| 9009 | } | 9437 | } |
| 9438 | |||
| 9439 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9440 | static void | ||
| 9441 | forkshell_shellexec(struct forkshell *fs) | ||
| 9442 | { | ||
| 9443 | int idx = fs->fd[0]; | ||
| 9444 | struct strlist *varlist = fs->strlist; | ||
| 9445 | char **argv = fs->argv; | ||
| 9446 | char *path = fs->string; | ||
| 9447 | |||
| 9448 | listsetvar(varlist, VEXPORT|VSTACK); | ||
| 9449 | shellexec(argv, path, idx); | ||
| 9450 | } | ||
| 9451 | #endif | ||
| 9010 | static void | 9452 | static void |
| 9011 | evalcommand(union node *cmd, int flags) | 9453 | evalcommand(union node *cmd, int flags) |
| 9012 | { | 9454 | { |
| @@ -9183,6 +9625,26 @@ evalcommand(union node *cmd, int flags) | |||
| 9183 | } | 9625 | } |
| 9184 | } | 9626 | } |
| 9185 | #endif | 9627 | #endif |
| 9628 | #if ENABLE_PLATFORM_MINGW32 | ||
| 9629 | if (!(flags & EV_EXIT) || trap[0]) { | ||
| 9630 | struct forkshell fs; | ||
| 9631 | |||
| 9632 | memset(&fs, 0, sizeof(fs)); | ||
| 9633 | fs.fp = forkshell_shellexec; | ||
| 9634 | fs.argv = argv; | ||
| 9635 | fs.string = (char*)path; | ||
| 9636 | fs.fd[0] = cmdentry.u.index; | ||
| 9637 | fs.strlist = varlist.list; | ||
| 9638 | jp = makejob(/*cmd,*/ 1); | ||
| 9639 | if (spawn_forkshell(jp, &fs, FORK_FG) < 0) | ||
| 9640 | ash_msg_and_raise_error("unable to spawn shell"); | ||
| 9641 | exitstatus = waitforjob(jp); | ||
| 9642 | INT_ON; | ||
| 9643 | TRACE(("forked child exited with %d\n", exitstatus)); | ||
| 9644 | break; | ||
| 9645 | } | ||
| 9646 | /* goes through to shellexec() */ | ||
| 9647 | #endif | ||
| 9186 | /* Fork off a child process if necessary. */ | 9648 | /* Fork off a child process if necessary. */ |
| 9187 | if (!(flags & EV_EXIT) || trap[0]) { | 9649 | if (!(flags & EV_EXIT) || trap[0]) { |
| 9188 | INT_OFF; | 9650 | INT_OFF; |
| @@ -9563,7 +10025,7 @@ preadbuffer(void) | |||
| 9563 | more--; | 10025 | more--; |
| 9564 | 10026 | ||
| 9565 | c = *q; | 10027 | c = *q; |
| 9566 | if (c == '\0') { | 10028 | if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) { |
| 9567 | memmove(q, q + 1, more); | 10029 | memmove(q, q + 1, more); |
| 9568 | } else { | 10030 | } else { |
| 9569 | q++; | 10031 | q++; |
| @@ -11990,7 +12452,7 @@ find_dot_file(char *name) | |||
| 11990 | struct stat statb; | 12452 | struct stat statb; |
| 11991 | 12453 | ||
| 11992 | /* don't try this for absolute or relative paths */ | 12454 | /* don't try this for absolute or relative paths */ |
| 11993 | if (strchr(name, '/')) | 12455 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) |
| 11994 | return name; | 12456 | return name; |
| 11995 | 12457 | ||
| 11996 | /* IIRC standards do not say whether . is to be searched. | 12458 | /* IIRC standards do not say whether . is to be searched. |
| @@ -12093,10 +12555,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
| 12093 | struct stat statb; | 12555 | struct stat statb; |
| 12094 | int e; | 12556 | int e; |
| 12095 | int updatetbl; | 12557 | int updatetbl; |
| 12558 | IF_PLATFORM_MINGW32(int len); | ||
| 12096 | struct builtincmd *bcmd; | 12559 | struct builtincmd *bcmd; |
| 12097 | 12560 | ||
| 12098 | /* If name contains a slash, don't use PATH or hash table */ | 12561 | /* If name contains a slash, don't use PATH or hash table */ |
| 12099 | if (strchr(name, '/') != NULL) { | 12562 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) { |
| 12100 | entry->u.index = -1; | 12563 | entry->u.index = -1; |
| 12101 | if (act & DO_ABS) { | 12564 | if (act & DO_ABS) { |
| 12102 | while (stat(name, &statb) < 0) { | 12565 | while (stat(name, &statb) < 0) { |
| @@ -12203,12 +12666,39 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
| 12203 | } | 12666 | } |
| 12204 | } | 12667 | } |
| 12205 | /* if rehash, don't redo absolute path names */ | 12668 | /* if rehash, don't redo absolute path names */ |
| 12206 | if (fullname[0] == '/' && idx <= prev) { | 12669 | if (is_absolute_path(fullname) && idx <= prev) { |
| 12207 | if (idx < prev) | 12670 | if (idx < prev) |
| 12208 | continue; | 12671 | continue; |
| 12209 | TRACE(("searchexec \"%s\": no change\n", name)); | 12672 | TRACE(("searchexec \"%s\": no change\n", name)); |
| 12210 | goto success; | 12673 | goto success; |
| 12211 | } | 12674 | } |
| 12675 | #if ENABLE_PLATFORM_MINGW32 | ||
| 12676 | len = strlen(fullname); | ||
| 12677 | if (len > 4 && | ||
| 12678 | (!strcasecmp(fullname+len-4, ".exe") || | ||
| 12679 | !strcasecmp(fullname+len-4, ".com"))) { | ||
| 12680 | if (stat(fullname, &statb) < 0) { | ||
| 12681 | if (errno != ENOENT && errno != ENOTDIR) | ||
| 12682 | e = errno; | ||
| 12683 | goto loop; | ||
| 12684 | } | ||
| 12685 | } | ||
| 12686 | else { | ||
| 12687 | /* path_advance() has reserved space for .exe */ | ||
| 12688 | memcpy(fullname+len, ".exe", 5); | ||
| 12689 | if (stat(fullname, &statb) < 0) { | ||
| 12690 | if (errno != ENOENT && errno != ENOTDIR) | ||
| 12691 | e = errno; | ||
| 12692 | memcpy(fullname+len, ".com", 5); | ||
| 12693 | if (stat(fullname, &statb) < 0) { | ||
| 12694 | if (errno != ENOENT && errno != ENOTDIR) | ||
| 12695 | e = errno; | ||
| 12696 | goto loop; | ||
| 12697 | } | ||
| 12698 | } | ||
| 12699 | fullname[len] = '\0'; | ||
| 12700 | } | ||
| 12701 | #else | ||
| 12212 | while (stat(fullname, &statb) < 0) { | 12702 | while (stat(fullname, &statb) < 0) { |
| 12213 | #ifdef SYSV | 12703 | #ifdef SYSV |
| 12214 | if (errno == EINTR) | 12704 | if (errno == EINTR) |
| @@ -12218,6 +12708,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
| 12218 | e = errno; | 12708 | e = errno; |
| 12219 | goto loop; | 12709 | goto loop; |
| 12220 | } | 12710 | } |
| 12711 | #endif | ||
| 12221 | e = EACCES; /* if we fail, this will be the error */ | 12712 | e = EACCES; /* if we fail, this will be the error */ |
| 12222 | if (!S_ISREG(statb.st_mode)) | 12713 | if (!S_ISREG(statb.st_mode)) |
| 12223 | continue; | 12714 | continue; |
| @@ -12744,13 +13235,41 @@ init(void) | |||
| 12744 | struct stat st1, st2; | 13235 | struct stat st1, st2; |
| 12745 | 13236 | ||
| 12746 | initvar(); | 13237 | initvar(); |
| 13238 | |||
| 13239 | #if ENABLE_PLATFORM_MINGW32 | ||
| 13240 | /* | ||
| 13241 | * case insensitive env names from Windows world | ||
| 13242 | * | ||
| 13243 | * Some standard env names such as PATH is named Path and so on | ||
| 13244 | * ash itself is case sensitive, so "Path" will confuse it, as | ||
| 13245 | * MSVC getenv() is case insensitive. | ||
| 13246 | * | ||
| 13247 | * We may end up having both Path and PATH. Then Path will be chosen | ||
| 13248 | * because it appears first. | ||
| 13249 | */ | ||
| 13250 | for (envp = environ; envp && *envp; envp++) | ||
| 13251 | if (!strncasecmp(*envp, "PATH=", 5) && | ||
| 13252 | strncmp(*envp, "PATH=", 5)) | ||
| 13253 | break; | ||
| 13254 | if (envp && *envp) { | ||
| 13255 | char *start, *end; | ||
| 13256 | for (envp = environ; envp && *envp; envp++) { | ||
| 13257 | end = strchr(*envp, '='); | ||
| 13258 | if (!end) | ||
| 13259 | continue; | ||
| 13260 | for (start = *envp;start < end;start++) | ||
| 13261 | *start = toupper(*start); | ||
| 13262 | } | ||
| 13263 | } | ||
| 13264 | #endif | ||
| 12747 | for (envp = environ; envp && *envp; envp++) { | 13265 | for (envp = environ; envp && *envp; envp++) { |
| 12748 | if (strchr(*envp, '=')) { | 13266 | if (strchr(*envp, '=')) { |
| 12749 | setvareq(*envp, VEXPORT|VTEXTFIXED); | 13267 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
| 12750 | } | 13268 | } |
| 12751 | } | 13269 | } |
| 12752 | 13270 | ||
| 12753 | setvar("PPID", utoa(getppid()), 0); | 13271 | if (!ENABLE_PLATFORM_MINGW32) |
| 13272 | setvar("PPID", utoa(getppid()), 0); | ||
| 12754 | 13273 | ||
| 12755 | p = lookupvar("PWD"); | 13274 | p = lookupvar("PWD"); |
| 12756 | if (p) | 13275 | if (p) |
| @@ -12866,6 +13385,20 @@ static short profile_buf[16384]; | |||
| 12866 | extern int etext(); | 13385 | extern int etext(); |
| 12867 | #endif | 13386 | #endif |
| 12868 | 13387 | ||
| 13388 | #if ENABLE_PLATFORM_MINGW32 | ||
| 13389 | static const forkpoint_fn forkpoints[] = { | ||
| 13390 | forkshell_openhere, | ||
| 13391 | forkshell_evalbackcmd, | ||
| 13392 | forkshell_evalsubshell, | ||
| 13393 | forkshell_evalpipe, | ||
| 13394 | forkshell_shellexec, | ||
| 13395 | NULL | ||
| 13396 | }; | ||
| 13397 | |||
| 13398 | static struct forkshell* forkshell_prepare(struct forkshell *fs); | ||
| 13399 | static void forkshell_init(const char *idstr); | ||
| 13400 | #endif | ||
| 13401 | |||
| 12869 | /* | 13402 | /* |
| 12870 | * Main routine. We initialize things, parse the arguments, execute | 13403 | * Main routine. We initialize things, parse the arguments, execute |
| 12871 | * profiles if we're a login shell, and then call cmdloop to execute | 13404 | * profiles if we're a login shell, and then call cmdloop to execute |
| @@ -12933,6 +13466,15 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 12933 | 13466 | ||
| 12934 | init(); | 13467 | init(); |
| 12935 | setstackmark(&smark); | 13468 | setstackmark(&smark); |
| 13469 | |||
| 13470 | #if ENABLE_PLATFORM_MINGW32 | ||
| 13471 | if (argc == 3 && !strcmp(argv[1], "--forkshell")) { | ||
| 13472 | forkshell_init(argv[2]); | ||
| 13473 | |||
| 13474 | /* NOTREACHED */ | ||
| 13475 | bb_error_msg_and_die("subshell ended unexpectedly"); | ||
| 13476 | } | ||
| 13477 | #endif | ||
| 12936 | procargs(argv); | 13478 | procargs(argv); |
| 12937 | 13479 | ||
| 12938 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 13480 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY |
| @@ -13007,6 +13549,524 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 13007 | /* NOTREACHED */ | 13549 | /* NOTREACHED */ |
| 13008 | } | 13550 | } |
| 13009 | 13551 | ||
| 13552 | /* FIXME: should consider running forkparent() and forkchild() */ | ||
| 13553 | static int | ||
| 13554 | spawn_forkshell(struct job *jp, struct forkshell *fs, int mode) | ||
| 13555 | { | ||
| 13556 | const char *argv[] = { "sh", "--forkshell", NULL, NULL }; | ||
| 13557 | char buf[16]; | ||
| 13558 | |||
| 13559 | struct forkshell *new; | ||
| 13560 | new = forkshell_prepare(fs); | ||
| 13561 | sprintf(buf, "%x", (unsigned int)new->hMapFile); | ||
| 13562 | argv[2] = buf; | ||
| 13563 | fs->pid = mingw_spawn_applet(P_NOWAIT, "sh", argv, | ||
| 13564 | (const char *const *)environ); | ||
| 13565 | CloseHandle(new->hMapFile); | ||
| 13566 | UnmapViewOfFile(new); | ||
| 13567 | if (fs->pid == -1) { | ||
| 13568 | free(jp); | ||
| 13569 | return -1; | ||
| 13570 | } | ||
| 13571 | forkparent(jp, fs->node, mode, fs->pid); | ||
| 13572 | return fs->pid; | ||
| 13573 | } | ||
| 13574 | |||
| 13575 | /* | ||
| 13576 | * forkshell_prepare() and friends | ||
| 13577 | * | ||
| 13578 | * The sequence is as follows: | ||
| 13579 | * - funcblocksize, funcstringsize, nodeptrsize are initialized | ||
| 13580 | * - forkshell_size(fs) is called to calculate the exact memory needed | ||
| 13581 | * - a new struct is allocated | ||
| 13582 | * - funcblock, funcstring, nodeptr are initialized from the new block | ||
| 13583 | * - forkshell_copy(fs) is called to copy recursively everything over | ||
| 13584 | * it will record all pointers along the way, to nodeptr | ||
| 13585 | * | ||
| 13586 | * When this memory is mapped elsewhere, pointer fixup will be needed | ||
| 13587 | */ | ||
| 13588 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
| 13589 | static void \ | ||
| 13590 | name(type *p) \ | ||
| 13591 | { \ | ||
| 13592 | while (p) { \ | ||
| 13593 | funcblocksize += sizeof(type); | ||
| 13594 | /* do something here with p */ | ||
| 13595 | #define SLIST_SIZE_END() \ | ||
| 13596 | nodeptrsize++; \ | ||
| 13597 | p = p->next; \ | ||
| 13598 | } \ | ||
| 13599 | } | ||
| 13600 | |||
| 13601 | #define SLIST_COPY_BEGIN(name,type) \ | ||
| 13602 | static type * \ | ||
| 13603 | name(type *vp) \ | ||
| 13604 | { \ | ||
| 13605 | type *start; \ | ||
| 13606 | type **vpp; \ | ||
| 13607 | vpp = &start; \ | ||
| 13608 | while (vp) { \ | ||
| 13609 | *vpp = funcblock; \ | ||
| 13610 | funcblock = (char *) funcblock + sizeof(type); | ||
| 13611 | /* do something here with vpp and vp */ | ||
| 13612 | #define SLIST_COPY_END() \ | ||
| 13613 | SAVE_PTR((*vpp)->next); \ | ||
| 13614 | vp = vp->next; \ | ||
| 13615 | vpp = &(*vpp)->next; \ | ||
| 13616 | } \ | ||
| 13617 | *vpp = NULL; \ | ||
| 13618 | return start; \ | ||
| 13619 | } | ||
| 13620 | |||
| 13621 | /* | ||
| 13622 | * struct var | ||
| 13623 | */ | ||
| 13624 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
| 13625 | funcstringsize += strlen(p->text) + 1; | ||
| 13626 | nodeptrsize++; /* p->text */ | ||
| 13627 | SLIST_SIZE_END() | ||
| 13628 | |||
| 13629 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
| 13630 | (*vpp)->text = nodeckstrdup(vp->text); | ||
| 13631 | (*vpp)->flags = vp->flags; | ||
| 13632 | /* | ||
| 13633 | * The only place that can set struct var#func is varinit[], | ||
| 13634 | * which will be fixed by forkshell_init() | ||
| 13635 | */ | ||
| 13636 | (*vpp)->func = NULL; | ||
| 13637 | SAVE_PTR((*vpp)->text); | ||
| 13638 | SLIST_COPY_END() | ||
| 13639 | |||
| 13640 | /* | ||
| 13641 | * struct localvar | ||
| 13642 | */ | ||
| 13643 | SLIST_SIZE_BEGIN(localvar_size,struct localvar) | ||
| 13644 | var_size(p->vp); | ||
| 13645 | funcstringsize += strlen(p->text) + 1; | ||
| 13646 | nodeptrsize += 2; /* p->vp, p->text */ | ||
| 13647 | SLIST_SIZE_END() | ||
| 13648 | |||
| 13649 | SLIST_COPY_BEGIN(localvar_copy,struct localvar) | ||
| 13650 | (*vpp)->text = nodeckstrdup(vp->text); | ||
| 13651 | (*vpp)->flags = vp->flags; | ||
| 13652 | (*vpp)->vp = var_copy(vp->vp); | ||
| 13653 | SAVE_PTR2((*vpp)->vp, (*vpp)->text); | ||
| 13654 | SLIST_COPY_END() | ||
| 13655 | |||
| 13656 | /* | ||
| 13657 | * struct strlist | ||
| 13658 | */ | ||
| 13659 | SLIST_SIZE_BEGIN(strlist_size,struct strlist) | ||
| 13660 | funcstringsize += strlen(p->text) + 1; | ||
| 13661 | nodeptrsize++; /* p->text */ | ||
| 13662 | SLIST_SIZE_END() | ||
| 13663 | |||
| 13664 | SLIST_COPY_BEGIN(strlist_copy,struct strlist) | ||
| 13665 | (*vpp)->text = nodeckstrdup(vp->text); | ||
| 13666 | SAVE_PTR((*vpp)->text); | ||
| 13667 | SLIST_COPY_END() | ||
| 13668 | |||
| 13669 | /* | ||
| 13670 | * struct tblentry | ||
| 13671 | */ | ||
| 13672 | static void | ||
| 13673 | tblentry_size(struct tblentry *tep) | ||
| 13674 | { | ||
| 13675 | while (tep) { | ||
| 13676 | funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
| 13677 | /* CMDBUILTIN, e->param.cmd needs no pointer relocation */ | ||
| 13678 | if (tep->cmdtype == CMDFUNCTION) { | ||
| 13679 | funcblocksize += offsetof(struct funcnode, n); | ||
| 13680 | calcsize(&tep->param.func->n); | ||
| 13681 | nodeptrsize++; /* tep->param.func */ | ||
| 13682 | } | ||
| 13683 | nodeptrsize++; /* tep->next */ | ||
| 13684 | tep = tep->next; | ||
| 13685 | } | ||
| 13686 | } | ||
| 13687 | |||
| 13688 | static struct tblentry * | ||
| 13689 | tblentry_copy(struct tblentry *tep) | ||
| 13690 | { | ||
| 13691 | struct tblentry *start; | ||
| 13692 | struct tblentry **newp; | ||
| 13693 | int size; | ||
| 13694 | |||
| 13695 | newp = &start; | ||
| 13696 | while (tep) { | ||
| 13697 | *newp = funcblock; | ||
| 13698 | size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
| 13699 | |||
| 13700 | funcblock = (char *) funcblock + size; | ||
| 13701 | memcpy(*newp, tep, size); | ||
| 13702 | switch (tep->cmdtype) { | ||
| 13703 | case CMDBUILTIN: | ||
| 13704 | /* No pointer saving, this field must be fixed by forkshell_init() */ | ||
| 13705 | (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab); | ||
| 13706 | break; | ||
| 13707 | case CMDFUNCTION: | ||
| 13708 | (*newp)->param.func = funcblock; | ||
| 13709 | funcblock = (char *) funcblock + offsetof(struct funcnode, n); | ||
| 13710 | copynode(&tep->param.func->n); | ||
| 13711 | SAVE_PTR((*newp)->param.func); | ||
| 13712 | break; | ||
| 13713 | default: | ||
| 13714 | break; | ||
| 13715 | } | ||
| 13716 | SAVE_PTR((*newp)->next); | ||
| 13717 | tep = tep->next; | ||
| 13718 | newp = &(*newp)->next; | ||
| 13719 | } | ||
| 13720 | *newp = NULL; | ||
| 13721 | return start; | ||
| 13722 | } | ||
| 13723 | |||
| 13724 | static void | ||
| 13725 | cmdtable_size(struct tblentry **cmdtablep) | ||
| 13726 | { | ||
| 13727 | int i; | ||
| 13728 | nodeptrsize += CMDTABLESIZE; | ||
| 13729 | funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE; | ||
| 13730 | for (i = 0; i < CMDTABLESIZE; i++) | ||
| 13731 | tblentry_size(cmdtablep[i]); | ||
| 13732 | } | ||
| 13733 | |||
| 13734 | static struct tblentry ** | ||
| 13735 | cmdtable_copy(struct tblentry **cmdtablep) | ||
| 13736 | { | ||
| 13737 | struct tblentry **new = funcblock; | ||
| 13738 | int i; | ||
| 13739 | |||
| 13740 | funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE; | ||
| 13741 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
| 13742 | new[i] = tblentry_copy(cmdtablep[i]); | ||
| 13743 | SAVE_PTR(new[i]); | ||
| 13744 | } | ||
| 13745 | return new; | ||
| 13746 | } | ||
| 13747 | |||
| 13748 | /* | ||
| 13749 | * char ** | ||
| 13750 | */ | ||
| 13751 | static void | ||
| 13752 | argv_size(char **p) | ||
| 13753 | { | ||
| 13754 | while (p && *p) { | ||
| 13755 | funcblocksize += sizeof(char *); | ||
| 13756 | funcstringsize += strlen(*p)+1; | ||
| 13757 | nodeptrsize++; | ||
| 13758 | p++; | ||
| 13759 | } | ||
| 13760 | funcblocksize += sizeof(char *); | ||
| 13761 | } | ||
| 13762 | |||
| 13763 | static char ** | ||
| 13764 | argv_copy(char **p) | ||
| 13765 | { | ||
| 13766 | char **new, **start = funcblock; | ||
| 13767 | |||
| 13768 | while (p && *p) { | ||
| 13769 | new = funcblock; | ||
| 13770 | funcblock = (char *) funcblock + sizeof(char *); | ||
| 13771 | *new = nodeckstrdup(*p); | ||
| 13772 | SAVE_PTR(*new); | ||
| 13773 | p++; | ||
| 13774 | new++; | ||
| 13775 | } | ||
| 13776 | new = funcblock; | ||
| 13777 | funcblock = (char *) funcblock + sizeof(char *); | ||
| 13778 | *new = NULL; | ||
| 13779 | return start; | ||
| 13780 | } | ||
| 13781 | |||
| 13782 | /* | ||
| 13783 | * struct redirtab | ||
| 13784 | */ | ||
| 13785 | static void | ||
| 13786 | redirtab_size(struct redirtab *rdtp) | ||
| 13787 | { | ||
| 13788 | while (rdtp) { | ||
| 13789 | funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
| 13790 | rdtp = rdtp->next; | ||
| 13791 | nodeptrsize++; /* rdtp->next */ | ||
| 13792 | } | ||
| 13793 | } | ||
| 13794 | |||
| 13795 | static struct redirtab * | ||
| 13796 | redirtab_copy(struct redirtab *rdtp) | ||
| 13797 | { | ||
| 13798 | struct redirtab *start; | ||
| 13799 | struct redirtab **vpp; | ||
| 13800 | |||
| 13801 | vpp = &start; | ||
| 13802 | while (rdtp) { | ||
| 13803 | int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
| 13804 | *vpp = funcblock; | ||
| 13805 | funcblock = (char *) funcblock + size; | ||
| 13806 | memcpy(*vpp, rdtp, size); | ||
| 13807 | SAVE_PTR((*vpp)->next); | ||
| 13808 | rdtp = rdtp->next; | ||
| 13809 | vpp = &(*vpp)->next; | ||
| 13810 | } | ||
| 13811 | *vpp = NULL; | ||
| 13812 | return start; | ||
| 13813 | } | ||
| 13814 | |||
| 13815 | #undef shellparam | ||
| 13816 | #undef redirlist | ||
| 13817 | #undef varinit | ||
| 13818 | #undef vartab | ||
| 13819 | static void | ||
| 13820 | globals_var_size(struct globals_var *gvp) | ||
| 13821 | { | ||
| 13822 | int i; | ||
| 13823 | |||
| 13824 | funcblocksize += sizeof(struct globals_var); | ||
| 13825 | argv_size(gvp->shellparam.p); | ||
| 13826 | redirtab_size(gvp->redirlist); | ||
| 13827 | for (i = 0; i < VTABSIZE; i++) | ||
| 13828 | var_size(gvp->vartab[i]); | ||
| 13829 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
| 13830 | var_size(gvp->varinit+i); | ||
| 13831 | nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */ | ||
| 13832 | } | ||
| 13833 | |||
| 13834 | #undef g_nullredirs | ||
| 13835 | #undef preverrout_fd | ||
| 13836 | static struct globals_var * | ||
| 13837 | globals_var_copy(struct globals_var *gvp) | ||
| 13838 | { | ||
| 13839 | int i; | ||
| 13840 | struct globals_var *new; | ||
| 13841 | |||
| 13842 | new = funcblock; | ||
| 13843 | funcblock = (char *) funcblock + sizeof(struct globals_var); | ||
| 13844 | |||
| 13845 | /* shparam */ | ||
| 13846 | memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam)); | ||
| 13847 | new->shellparam.malloced = 0; | ||
| 13848 | new->shellparam.p = argv_copy(gvp->shellparam.p); | ||
| 13849 | SAVE_PTR(new->shellparam.p); | ||
| 13850 | |||
| 13851 | new->redirlist = redirtab_copy(gvp->redirlist); | ||
| 13852 | SAVE_PTR(new->redirlist); | ||
| 13853 | |||
| 13854 | new->g_nullredirs = gvp->g_nullredirs; | ||
| 13855 | new->preverrout_fd = gvp->preverrout_fd; | ||
| 13856 | for (i = 0; i < VTABSIZE; i++) { | ||
| 13857 | new->vartab[i] = var_copy(gvp->vartab[i]); | ||
| 13858 | SAVE_PTR(new->vartab[i]); | ||
| 13859 | } | ||
| 13860 | |||
| 13861 | /* Can't use var_copy because varinit is already allocated */ | ||
| 13862 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { | ||
| 13863 | new->varinit[i].next = NULL; | ||
| 13864 | new->varinit[i].text = nodeckstrdup(gvp->varinit[i].text); | ||
| 13865 | SAVE_PTR(new->varinit[i].text); | ||
| 13866 | new->varinit[i].flags = gvp->varinit[i].flags; | ||
| 13867 | new->varinit[i].func = gvp->varinit[i].func; | ||
| 13868 | } | ||
| 13869 | return new; | ||
| 13870 | } | ||
| 13871 | |||
| 13872 | #undef minusc | ||
| 13873 | #undef curdir | ||
| 13874 | #undef physdir | ||
| 13875 | #undef arg0 | ||
| 13876 | #undef nullstr | ||
| 13877 | static void | ||
| 13878 | globals_misc_size(struct globals_misc *p) | ||
| 13879 | { | ||
| 13880 | funcblocksize += sizeof(struct globals_misc); | ||
| 13881 | funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1; | ||
| 13882 | if (p->curdir != p->nullstr) | ||
| 13883 | funcstringsize += strlen(p->curdir) + 1; | ||
| 13884 | if (p->physdir != p->nullstr) | ||
| 13885 | funcstringsize += strlen(p->physdir) + 1; | ||
| 13886 | funcstringsize += strlen(p->arg0) + 1; | ||
| 13887 | nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */ | ||
| 13888 | } | ||
| 13889 | |||
| 13890 | static struct globals_misc * | ||
| 13891 | globals_misc_copy(struct globals_misc *p) | ||
| 13892 | { | ||
| 13893 | struct globals_misc *new = funcblock; | ||
| 13894 | |||
| 13895 | funcblock = (char *) funcblock + sizeof(struct globals_misc); | ||
| 13896 | memcpy(new, p, sizeof(struct globals_misc)); | ||
| 13897 | |||
| 13898 | new->minusc = nodeckstrdup(p->minusc); | ||
| 13899 | new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr; | ||
| 13900 | new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr; | ||
| 13901 | new->arg0 = nodeckstrdup(p->arg0); | ||
| 13902 | SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0); | ||
| 13903 | return new; | ||
| 13904 | } | ||
| 13905 | |||
| 13906 | static void | ||
| 13907 | forkshell_size(struct forkshell *fs) | ||
| 13908 | { | ||
| 13909 | funcblocksize += sizeof(struct forkshell); | ||
| 13910 | globals_var_size(fs->gvp); | ||
| 13911 | globals_misc_size(fs->gmp); | ||
| 13912 | cmdtable_size(fs->cmdtable); | ||
| 13913 | localvar_size(fs->localvars); | ||
| 13914 | /* optlist_transfer(sending, fd); */ | ||
| 13915 | /* misc_transfer(sending, fd); */ | ||
| 13916 | |||
| 13917 | calcsize(fs->n); | ||
| 13918 | argv_size(fs->argv); | ||
| 13919 | funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1; | ||
| 13920 | strlist_size(fs->strlist); | ||
| 13921 | |||
| 13922 | nodeptrsize += 8; /* gvp, gmp, cmdtable, localvars, n, argv, string, strlist */ | ||
| 13923 | } | ||
| 13924 | |||
| 13925 | static struct forkshell * | ||
| 13926 | forkshell_copy(struct forkshell *fs) | ||
| 13927 | { | ||
| 13928 | struct forkshell *new; | ||
| 13929 | |||
| 13930 | new = funcblock; | ||
| 13931 | funcblock = (char *) funcblock + sizeof(struct forkshell); | ||
| 13932 | |||
| 13933 | memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */ | ||
| 13934 | new->gvp = globals_var_copy(fs->gvp); | ||
| 13935 | new->gmp = globals_misc_copy(fs->gmp); | ||
| 13936 | new->cmdtable = cmdtable_copy(fs->cmdtable); | ||
| 13937 | new->localvars = localvar_copy(fs->localvars); | ||
| 13938 | SAVE_PTR4(new->gvp, new->gmp, new->cmdtable, new->localvars); | ||
| 13939 | |||
| 13940 | /* new->fs will be reconstructed from new->fpid */ | ||
| 13941 | new->n = copynode(fs->n); | ||
| 13942 | new->argv = argv_copy(fs->argv); | ||
| 13943 | new->string = nodeckstrdup(fs->string); | ||
| 13944 | new->strlist = strlist_copy(fs->strlist); | ||
| 13945 | SAVE_PTR4(new->n, new->argv, new->string, new->strlist); | ||
| 13946 | return new; | ||
| 13947 | } | ||
| 13948 | |||
| 13949 | static struct forkshell * | ||
| 13950 | forkshell_prepare(struct forkshell *fs) | ||
| 13951 | { | ||
| 13952 | struct forkshell *new; | ||
| 13953 | int size, fp, nodeptr_offset; | ||
| 13954 | HANDLE h; | ||
| 13955 | SECURITY_ATTRIBUTES sa; | ||
| 13956 | |||
| 13957 | for (fp = 0; forkpoints[fp] && forkpoints[fp] != fs->fp; fp++) | ||
| 13958 | ; | ||
| 13959 | |||
| 13960 | if (!forkpoints[fp]) | ||
| 13961 | bb_error_msg_and_die("invalid forkpoint %08x", (int)fs->fp); | ||
| 13962 | fs->fpid = fp; | ||
| 13963 | |||
| 13964 | /* Calculate size of "new" */ | ||
| 13965 | fs->gvp = ash_ptr_to_globals_var; | ||
| 13966 | fs->gmp = ash_ptr_to_globals_misc; | ||
| 13967 | fs->cmdtable = cmdtable; | ||
| 13968 | fs->localvars = localvars; | ||
| 13969 | |||
| 13970 | nodeptrsize = 1; /* NULL terminated */ | ||
| 13971 | funcblocksize = 0; | ||
| 13972 | funcstringsize = 0; | ||
| 13973 | forkshell_size(fs); | ||
| 13974 | size = funcblocksize + funcstringsize + nodeptrsize*sizeof(int); | ||
| 13975 | |||
| 13976 | /* Allocate, initialize pointers */ | ||
| 13977 | memset(&sa, 0, sizeof(sa)); | ||
| 13978 | sa.nLength = sizeof(sa); | ||
| 13979 | sa.lpSecurityDescriptor = NULL; | ||
| 13980 | sa.bInheritHandle = TRUE; | ||
| 13981 | h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL); | ||
| 13982 | new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
| 13983 | /* new = ckmalloc(size); */ | ||
| 13984 | funcblock = new; | ||
| 13985 | funcstring = (char *) funcblock + funcblocksize; | ||
| 13986 | nodeptr = (int*)((char *) funcstring + funcstringsize); | ||
| 13987 | nodeptr_offset = (int) nodeptr - (int) new; | ||
| 13988 | |||
| 13989 | /* Now pack them all */ | ||
| 13990 | forkshell_copy(fs); | ||
| 13991 | |||
| 13992 | /* Finish it up */ | ||
| 13993 | *nodeptr = 0; | ||
| 13994 | new->size = size; | ||
| 13995 | new->nodeptr_offset = nodeptr_offset; | ||
| 13996 | new->old_base = new; | ||
| 13997 | new->hMapFile = h; | ||
| 13998 | return new; | ||
| 13999 | } | ||
| 14000 | |||
| 14001 | #undef exception_handler | ||
| 14002 | #undef trap | ||
| 14003 | #undef trap_ptr | ||
| 14004 | static void *sticky_mem_start, *sticky_mem_end; | ||
| 14005 | static void | ||
| 14006 | forkshell_init(const char *idstr) | ||
| 14007 | { | ||
| 14008 | struct forkshell *fs; | ||
| 14009 | int map_handle; | ||
| 14010 | HANDLE h; | ||
| 14011 | struct globals_var **gvpp; | ||
| 14012 | struct globals_misc **gmpp; | ||
| 14013 | int i; | ||
| 14014 | |||
| 14015 | if (sscanf(idstr, "%x", &map_handle) != 1) | ||
| 14016 | bb_error_msg_and_die("invalid forkshell ID"); | ||
| 14017 | |||
| 14018 | h = (HANDLE)map_handle; | ||
| 14019 | fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
| 14020 | if (!fs) | ||
| 14021 | bb_error_msg_and_die("Invalid forkshell memory"); | ||
| 14022 | |||
| 14023 | /* this memory can't be freed */ | ||
| 14024 | sticky_mem_start = fs; | ||
| 14025 | sticky_mem_end = (char *) fs + fs->size; | ||
| 14026 | /* pointer fixup */ | ||
| 14027 | nodeptr = (int*)((char*)fs + fs->nodeptr_offset); | ||
| 14028 | while (*nodeptr) { | ||
| 14029 | int *ptr = (int*)((char*)fs + (*nodeptr - (int)fs->old_base)); | ||
| 14030 | if (*ptr) | ||
| 14031 | *ptr -= ((int)fs->old_base - (int)fs); | ||
| 14032 | nodeptr++; | ||
| 14033 | } | ||
| 14034 | /* Now fix up stuff that can't be transferred */ | ||
| 14035 | fs->fp = forkpoints[fs->fpid]; | ||
| 14036 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
| 14037 | fs->gvp->varinit[i].func = varinit_data[i].func; | ||
| 14038 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
| 14039 | struct tblentry *e = fs->cmdtable[i]; | ||
| 14040 | while (e) { | ||
| 14041 | if (e->cmdtype == CMDBUILTIN) | ||
| 14042 | e->param.cmd = builtintab + (int)e->param.cmd; | ||
| 14043 | e = e->next; | ||
| 14044 | } | ||
| 14045 | } | ||
| 14046 | fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler; | ||
| 14047 | for (i = 0; i < NSIG; i++) | ||
| 14048 | fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i]; | ||
| 14049 | fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr; | ||
| 14050 | |||
| 14051 | /* Switch global variables */ | ||
| 14052 | gvpp = (struct globals_var **)&ash_ptr_to_globals_var; | ||
| 14053 | *gvpp = fs->gvp; | ||
| 14054 | gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc; | ||
| 14055 | *gmpp = fs->gmp; | ||
| 14056 | localvars = fs->localvars; | ||
| 14057 | cmdtable = fs->cmdtable; | ||
| 14058 | |||
| 14059 | fs->fp(fs); | ||
| 14060 | } | ||
| 14061 | |||
| 14062 | #undef free | ||
| 14063 | static void | ||
| 14064 | sticky_free(void *base) | ||
| 14065 | { | ||
| 14066 | if (base >= sticky_mem_start && base < sticky_mem_end) | ||
| 14067 | return; | ||
| 14068 | free(base); | ||
| 14069 | } | ||
| 13010 | 14070 | ||
| 13011 | /*- | 14071 | /*- |
| 13012 | * Copyright (c) 1989, 1991, 1993, 1994 | 14072 | * Copyright (c) 1989, 1991, 1993, 1994 |
