diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 1102 |
1 files changed, 1088 insertions, 14 deletions
diff --git a/shell/ash.c b/shell/ash.c index 4fbae2498..f7fad88cd 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. |
@@ -37,7 +49,9 @@ | |||
37 | #define JOBS ENABLE_ASH_JOB_CONTROL | 49 | #define JOBS ENABLE_ASH_JOB_CONTROL |
38 | 50 | ||
39 | #include "busybox.h" /* for applet_names */ | 51 | #include "busybox.h" /* for applet_names */ |
52 | #ifndef __MINGW32__ | ||
40 | #include <paths.h> | 53 | #include <paths.h> |
54 | #endif | ||
41 | #include <setjmp.h> | 55 | #include <setjmp.h> |
42 | #include <fnmatch.h> | 56 | #include <fnmatch.h> |
43 | #include <sys/times.h> | 57 | #include <sys/times.h> |
@@ -188,6 +202,41 @@ | |||
188 | //usage:#define bash_trivial_usage NOUSAGE_STR | 202 | //usage:#define bash_trivial_usage NOUSAGE_STR |
189 | //usage:#define bash_full_usage "" | 203 | //usage:#define bash_full_usage "" |
190 | 204 | ||
205 | #if ENABLE_PLATFORM_MINGW32 | ||
206 | struct forkshell; | ||
207 | union node; | ||
208 | struct strlist; | ||
209 | struct job; | ||
210 | |||
211 | typedef void (*forkpoint_fn)(struct forkshell *fs); | ||
212 | struct forkshell { | ||
213 | /* filled by forkshell_copy() */ | ||
214 | struct globals_var *gvp; | ||
215 | struct globals_misc *gmp; | ||
216 | struct tblentry **cmdtable; | ||
217 | struct localvar *localvars; | ||
218 | /* struct alias **atab; */ | ||
219 | /* struct parsefile *g_parsefile; */ | ||
220 | int fpid; | ||
221 | HANDLE hMapFile; | ||
222 | void *old_base; | ||
223 | int nodeptr_offset; | ||
224 | int size; | ||
225 | |||
226 | forkpoint_fn fp; | ||
227 | /* optional data, used by forkpoint_fn */ | ||
228 | int flags; | ||
229 | int fd[10]; | ||
230 | union node *n; | ||
231 | char **argv; | ||
232 | char *string; | ||
233 | struct strlist *strlist; | ||
234 | pid_t pid; | ||
235 | }; | ||
236 | static void sticky_free(void *p); | ||
237 | #define free(p) sticky_free(p) | ||
238 | static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode); | ||
239 | #endif | ||
191 | 240 | ||
192 | /* ============ Hash table sizes. Configurable. */ | 241 | /* ============ Hash table sizes. Configurable. */ |
193 | 242 | ||
@@ -889,7 +938,7 @@ static void | |||
889 | opentrace(void) | 938 | opentrace(void) |
890 | { | 939 | { |
891 | char s[100]; | 940 | char s[100]; |
892 | #ifdef O_APPEND | 941 | #if defined(O_APPEND) && !ENABLE_PLATFORM_MINGW32 |
893 | int flags; | 942 | int flags; |
894 | #endif | 943 | #endif |
895 | 944 | ||
@@ -914,7 +963,7 @@ opentrace(void) | |||
914 | return; | 963 | return; |
915 | } | 964 | } |
916 | } | 965 | } |
917 | #ifdef O_APPEND | 966 | #if defined(O_APPEND) && !ENABLE_PLATFORM_MINGW32 |
918 | flags = fcntl(fileno(tracefile), F_GETFL); | 967 | flags = fcntl(fileno(tracefile), F_GETFL); |
919 | if (flags >= 0) | 968 | if (flags >= 0) |
920 | fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); | 969 | fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); |
@@ -2370,10 +2419,22 @@ path_advance(const char **path, const char *name) | |||
2370 | if (*path == NULL) | 2419 | if (*path == NULL) |
2371 | return NULL; | 2420 | return NULL; |
2372 | start = *path; | 2421 | start = *path; |
2422 | #if ENABLE_PLATFORM_MINGW32 | ||
2423 | p = next_path_sep(start); | ||
2424 | q = strchr(start, '%'); | ||
2425 | if ((p && q && q < p) || (!p && q)) | ||
2426 | p = q; | ||
2427 | if (!p) | ||
2428 | for (p = start; *p; p++) | ||
2429 | continue; | ||
2430 | #else | ||
2373 | for (p = start; *p && *p != ':' && *p != '%'; p++) | 2431 | for (p = start; *p && *p != ':' && *p != '%'; p++) |
2374 | continue; | 2432 | continue; |
2433 | #endif | ||
2375 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ | 2434 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ |
2376 | while (stackblocksize() < len) | 2435 | |
2436 | /* preserve space for .exe too */ | ||
2437 | while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len)) | ||
2377 | growstackblock(); | 2438 | growstackblock(); |
2378 | q = stackblock(); | 2439 | q = stackblock(); |
2379 | if (p != start) { | 2440 | if (p != start) { |
@@ -2489,6 +2550,98 @@ cdopt(void) | |||
2489 | static const char * | 2550 | static const char * |
2490 | updatepwd(const char *dir) | 2551 | updatepwd(const char *dir) |
2491 | { | 2552 | { |
2553 | #if ENABLE_PLATFORM_MINGW32 | ||
2554 | /* | ||
2555 | * Due to Windows drive notion, getting pwd is a completely | ||
2556 | * different thing. Handle it in a separate routine | ||
2557 | */ | ||
2558 | |||
2559 | char *new; | ||
2560 | char *p; | ||
2561 | char *cdcomppath; | ||
2562 | const char *lim; | ||
2563 | /* | ||
2564 | * There are four cases | ||
2565 | * absdrive + abspath: c:/path | ||
2566 | * absdrive + !abspath: c:path | ||
2567 | * !absdrive + abspath: /path | ||
2568 | * !absdrive + !abspath: path | ||
2569 | * | ||
2570 | * Damn DOS! | ||
2571 | * c:path behaviour is "undefined" | ||
2572 | * To properly handle this case, I have to keep track of cwd | ||
2573 | * of every drive, which is too painful to do. | ||
2574 | * So when c:path is given, I assume it's c:${curdir}path | ||
2575 | * with ${curdir} comes from the current drive | ||
2576 | */ | ||
2577 | int absdrive = *dir && dir[1] == ':'; | ||
2578 | int abspath = absdrive ? dir[2] == '/' : *dir == '/'; | ||
2579 | char *drive; | ||
2580 | |||
2581 | cdcomppath = ststrdup(dir); | ||
2582 | STARTSTACKSTR(new); | ||
2583 | if (!absdrive && curdir == nullstr) | ||
2584 | return 0; | ||
2585 | if (!abspath) { | ||
2586 | if (curdir == nullstr) | ||
2587 | return 0; | ||
2588 | new = stack_putstr(curdir, new); | ||
2589 | } | ||
2590 | new = makestrspace(strlen(dir) + 2, new); | ||
2591 | |||
2592 | drive = stackblock(); | ||
2593 | if (absdrive) { | ||
2594 | *drive = *dir; | ||
2595 | cdcomppath += 2; | ||
2596 | dir += 2; | ||
2597 | } else { | ||
2598 | *drive = *curdir; | ||
2599 | } | ||
2600 | drive[1] = ':'; /* in case of absolute drive+path */ | ||
2601 | |||
2602 | if (abspath) | ||
2603 | new = drive + 2; | ||
2604 | lim = drive + 3; | ||
2605 | if (!abspath) { | ||
2606 | if (new[-1] != '/') | ||
2607 | USTPUTC('/', new); | ||
2608 | if (new > lim && *lim == '/') | ||
2609 | lim++; | ||
2610 | } else { | ||
2611 | USTPUTC('/', new); | ||
2612 | cdcomppath ++; | ||
2613 | if (dir[1] == '/' && dir[2] != '/') { | ||
2614 | USTPUTC('/', new); | ||
2615 | cdcomppath++; | ||
2616 | lim++; | ||
2617 | } | ||
2618 | } | ||
2619 | p = strtok(cdcomppath, "/"); | ||
2620 | while (p) { | ||
2621 | switch (*p) { | ||
2622 | case '.': | ||
2623 | if (p[1] == '.' && p[2] == '\0') { | ||
2624 | while (new > lim) { | ||
2625 | STUNPUTC(new); | ||
2626 | if (new[-1] == '/') | ||
2627 | break; | ||
2628 | } | ||
2629 | break; | ||
2630 | } | ||
2631 | if (p[1] == '\0') | ||
2632 | break; | ||
2633 | /* fall through */ | ||
2634 | default: | ||
2635 | new = stack_putstr(p, new); | ||
2636 | USTPUTC('/', new); | ||
2637 | } | ||
2638 | p = strtok(0, "/"); | ||
2639 | } | ||
2640 | if (new > lim) | ||
2641 | STUNPUTC(new); | ||
2642 | *new = 0; | ||
2643 | return stackblock(); | ||
2644 | #else | ||
2492 | char *new; | 2645 | char *new; |
2493 | char *p; | 2646 | char *p; |
2494 | char *cdcomppath; | 2647 | char *cdcomppath; |
@@ -2542,6 +2695,7 @@ updatepwd(const char *dir) | |||
2542 | STUNPUTC(new); | 2695 | STUNPUTC(new); |
2543 | *new = 0; | 2696 | *new = 0; |
2544 | return stackblock(); | 2697 | return stackblock(); |
2698 | #endif | ||
2545 | } | 2699 | } |
2546 | 2700 | ||
2547 | /* | 2701 | /* |
@@ -2636,7 +2790,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2636 | } | 2790 | } |
2637 | if (!dest) | 2791 | if (!dest) |
2638 | dest = nullstr; | 2792 | dest = nullstr; |
2639 | if (*dest == '/') | 2793 | if (is_absolute_path(dest)) |
2640 | goto step7; | 2794 | goto step7; |
2641 | if (*dest == '.') { | 2795 | if (*dest == '.') { |
2642 | c = dest[1]; | 2796 | c = dest[1]; |
@@ -3408,6 +3562,8 @@ setsignal(int signo) | |||
3408 | char cur_act, new_act; | 3562 | char cur_act, new_act; |
3409 | struct sigaction act; | 3563 | struct sigaction act; |
3410 | 3564 | ||
3565 | if (ENABLE_PLATFORM_MINGW32) | ||
3566 | return; | ||
3411 | t = trap[signo]; | 3567 | t = trap[signo]; |
3412 | new_act = S_DFL; | 3568 | new_act = S_DFL; |
3413 | if (t != NULL) { /* trap for this sig is set */ | 3569 | if (t != NULL) { /* trap for this sig is set */ |
@@ -3715,7 +3871,7 @@ setjobctl(int on) | |||
3715 | if (--fd < 0) | 3871 | if (--fd < 0) |
3716 | goto out; | 3872 | goto out; |
3717 | } | 3873 | } |
3718 | fd = fcntl(fd, F_DUPFD, 10); | 3874 | fd = copyfd(fd, 10); |
3719 | if (ofd >= 0) | 3875 | if (ofd >= 0) |
3720 | close(ofd); | 3876 | close(ofd); |
3721 | if (fd < 0) | 3877 | if (fd < 0) |
@@ -3889,6 +4045,53 @@ sprint_status(char *s, int status, int sigonly) | |||
3889 | return col; | 4045 | return col; |
3890 | } | 4046 | } |
3891 | 4047 | ||
4048 | #if ENABLE_PLATFORM_MINGW32 | ||
4049 | /* | ||
4050 | * Windows does not know about parent-child relationship | ||
4051 | * They don't support waitpid(-1) | ||
4052 | */ | ||
4053 | static pid_t | ||
4054 | waitpid_child(int *status) | ||
4055 | { | ||
4056 | HANDLE *pidlist, *pidp; | ||
4057 | int pid_nr = 0; | ||
4058 | pid_t pid; | ||
4059 | DWORD win_status, idx; | ||
4060 | struct job *jb; | ||
4061 | |||
4062 | #define LOOP(stmt) \ | ||
4063 | for (jb = curjob; jb; jb = jb->prev_job) { \ | ||
4064 | struct procstat *ps, *psend; \ | ||
4065 | if (jb->state == JOBDONE) \ | ||
4066 | continue; \ | ||
4067 | ps = jb->ps; \ | ||
4068 | psend = ps + jb->nprocs; \ | ||
4069 | while (ps < psend) { \ | ||
4070 | if (ps->ps_pid != -1) { \ | ||
4071 | stmt; \ | ||
4072 | } \ | ||
4073 | ps++; \ | ||
4074 | } \ | ||
4075 | } | ||
4076 | |||
4077 | LOOP(pid_nr++); | ||
4078 | pidp = pidlist = ckmalloc(sizeof(*pidlist)*pid_nr); | ||
4079 | LOOP(*pidp++ = (HANDLE)ps->ps_pid); | ||
4080 | #undef LOOP | ||
4081 | |||
4082 | idx = WaitForMultipleObjects(pid_nr, pidlist, FALSE, INFINITE); | ||
4083 | if (idx >= pid_nr) { | ||
4084 | free(pidlist); | ||
4085 | return -1; | ||
4086 | } | ||
4087 | GetExitCodeProcess(pidlist[idx], &win_status); | ||
4088 | pid = (int)pidlist[idx]; | ||
4089 | free(pidlist); | ||
4090 | *status = (int)win_status; | ||
4091 | return pid; | ||
4092 | } | ||
4093 | #endif | ||
4094 | |||
3892 | static int | 4095 | static int |
3893 | dowait(int wait_flags, struct job *job) | 4096 | dowait(int wait_flags, struct job *job) |
3894 | { | 4097 | { |
@@ -3905,7 +4108,11 @@ dowait(int wait_flags, struct job *job) | |||
3905 | * NB: _not_ safe_waitpid, we need to detect EINTR */ | 4108 | * NB: _not_ safe_waitpid, we need to detect EINTR */ |
3906 | if (doing_jobctl) | 4109 | if (doing_jobctl) |
3907 | wait_flags |= WUNTRACED; | 4110 | wait_flags |= WUNTRACED; |
4111 | #if ENABLE_PLATFORM_MINGW32 | ||
4112 | pid = waitpid_child(&status); | ||
4113 | #else | ||
3908 | pid = waitpid(-1, &status, wait_flags); | 4114 | pid = waitpid(-1, &status, wait_flags); |
4115 | #endif | ||
3909 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", | 4116 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", |
3910 | pid, status, errno, strerror(errno))); | 4117 | pid, status, errno, strerror(errno))); |
3911 | if (pid <= 0) | 4118 | if (pid <= 0) |
@@ -3928,6 +4135,8 @@ dowait(int wait_flags, struct job *job) | |||
3928 | jobno(jp), pid, ps->ps_status, status)); | 4135 | jobno(jp), pid, ps->ps_status, status)); |
3929 | ps->ps_status = status; | 4136 | ps->ps_status = status; |
3930 | thisjob = jp; | 4137 | thisjob = jp; |
4138 | if (ENABLE_PLATFORM_MINGW32) | ||
4139 | ps->ps_pid = -1; | ||
3931 | } | 4140 | } |
3932 | if (ps->ps_status == -1) | 4141 | if (ps->ps_status == -1) |
3933 | state = JOBRUNNING; | 4142 | state = JOBRUNNING; |
@@ -4159,6 +4368,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
4159 | int retval; | 4368 | int retval; |
4160 | struct job *jp; | 4369 | struct job *jp; |
4161 | 4370 | ||
4371 | if (ENABLE_PLATFORM_MINGW32) | ||
4372 | return 0; | ||
4373 | |||
4162 | if (pending_sig) | 4374 | if (pending_sig) |
4163 | raise_exception(EXSIG); | 4375 | raise_exception(EXSIG); |
4164 | 4376 | ||
@@ -4770,7 +4982,7 @@ static void | |||
4770 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 4982 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
4771 | { | 4983 | { |
4772 | TRACE(("In parent shell: child = %d\n", pid)); | 4984 | TRACE(("In parent shell: child = %d\n", pid)); |
4773 | if (!jp) { | 4985 | if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */ |
4774 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) | 4986 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) |
4775 | continue; | 4987 | continue; |
4776 | jobless++; | 4988 | jobless++; |
@@ -4810,6 +5022,9 @@ forkshell(struct job *jp, union node *n, int mode) | |||
4810 | int pid; | 5022 | int pid; |
4811 | 5023 | ||
4812 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); | 5024 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); |
5025 | if (ENABLE_PLATFORM_MINGW32) | ||
5026 | return -1; | ||
5027 | |||
4813 | pid = fork(); | 5028 | pid = fork(); |
4814 | if (pid < 0) { | 5029 | if (pid < 0) { |
4815 | TRACE(("Fork failed, errno=%d", errno)); | 5030 | TRACE(("Fork failed, errno=%d", errno)); |
@@ -5006,11 +5221,39 @@ noclobberopen(const char *fname) | |||
5006 | */ | 5221 | */ |
5007 | /* openhere needs this forward reference */ | 5222 | /* openhere needs this forward reference */ |
5008 | static void expandhere(union node *arg, int fd); | 5223 | static void expandhere(union node *arg, int fd); |
5224 | #if ENABLE_PLATFORM_MINGW32 | ||
5225 | static void | ||
5226 | forkshell_openhere(struct forkshell *fs) | ||
5227 | { | ||
5228 | union node *redir = fs->n; | ||
5229 | int pip[2]; | ||
5230 | |||
5231 | pip[0] = fs->fd[0]; | ||
5232 | pip[1] = fs->fd[1]; | ||
5233 | |||
5234 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
5235 | |||
5236 | close(pip[0]); | ||
5237 | ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); | ||
5238 | ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); | ||
5239 | ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); | ||
5240 | ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); | ||
5241 | signal(SIGPIPE, SIG_DFL); | ||
5242 | if (redir->type == NHERE) { | ||
5243 | size_t len = strlen(redir->nhere.doc->narg.text); | ||
5244 | full_write(pip[1], redir->nhere.doc->narg.text, len); | ||
5245 | } else /* NXHERE */ | ||
5246 | expandhere(redir->nhere.doc, pip[1]); | ||
5247 | _exit(EXIT_SUCCESS); | ||
5248 | } | ||
5249 | #endif | ||
5250 | |||
5009 | static int | 5251 | static int |
5010 | openhere(union node *redir) | 5252 | openhere(union node *redir) |
5011 | { | 5253 | { |
5012 | int pip[2]; | 5254 | int pip[2]; |
5013 | size_t len = 0; | 5255 | size_t len = 0; |
5256 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5014 | 5257 | ||
5015 | if (pipe(pip) < 0) | 5258 | if (pipe(pip) < 0) |
5016 | ash_msg_and_raise_error("pipe call failed"); | 5259 | ash_msg_and_raise_error("pipe call failed"); |
@@ -5021,6 +5264,16 @@ openhere(union node *redir) | |||
5021 | goto out; | 5264 | goto out; |
5022 | } | 5265 | } |
5023 | } | 5266 | } |
5267 | #if ENABLE_PLATFORM_MINGW32 | ||
5268 | memset(&fs, 0, sizeof(fs)); | ||
5269 | fs.fp = forkshell_openhere; | ||
5270 | fs.flags = 0; | ||
5271 | fs.n = redir; | ||
5272 | fs.fd[0] = pip[0]; | ||
5273 | fs.fd[1] = pip[1]; | ||
5274 | if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0) | ||
5275 | ash_msg_and_raise_error("unable to spawn shell"); | ||
5276 | #endif | ||
5024 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | 5277 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { |
5025 | /* child */ | 5278 | /* child */ |
5026 | close(pip[0]); | 5279 | close(pip[0]); |
@@ -5046,6 +5299,31 @@ openredirect(union node *redir) | |||
5046 | char *fname; | 5299 | char *fname; |
5047 | int f; | 5300 | int f; |
5048 | 5301 | ||
5302 | #if ENABLE_PLATFORM_MINGW32 | ||
5303 | /* Support for /dev/null */ | ||
5304 | switch (redir->nfile.type) { | ||
5305 | case NFROM: | ||
5306 | if (!strcmp(redir->nfile.expfname, "/dev/null")) | ||
5307 | return open("nul",O_RDWR); | ||
5308 | if (!strncmp(redir->nfile.expfname, "/dev/", 5)) { | ||
5309 | ash_msg("Unhandled device %s\n", redir->nfile.expfname); | ||
5310 | return -1; | ||
5311 | } | ||
5312 | break; | ||
5313 | |||
5314 | case NFROMTO: | ||
5315 | case NTO: | ||
5316 | case NCLOBBER: | ||
5317 | case NAPPEND: | ||
5318 | if (!strcmp(redir->nfile.expfname, "/dev/null")) | ||
5319 | return open("nul",O_RDWR); | ||
5320 | if (!strncmp(redir->nfile.expfname, "/dev/", 5)) { | ||
5321 | ash_msg("Unhandled device %s\n", redir->nfile.expfname); | ||
5322 | return -1; | ||
5323 | } | ||
5324 | break; | ||
5325 | } | ||
5326 | #endif | ||
5049 | switch (redir->nfile.type) { | 5327 | switch (redir->nfile.type) { |
5050 | case NFROM: | 5328 | case NFROM: |
5051 | fname = redir->nfile.expfname; | 5329 | fname = redir->nfile.expfname; |
@@ -5128,6 +5406,18 @@ copyfd(int from, int to) | |||
5128 | /*if (from != to)*/ | 5406 | /*if (from != to)*/ |
5129 | newfd = dup2(from, to); | 5407 | newfd = dup2(from, to); |
5130 | } else { | 5408 | } else { |
5409 | if (ENABLE_PLATFORM_MINGW32) { | ||
5410 | char* fds = ckmalloc(to); | ||
5411 | int i,fd; | ||
5412 | memset(fds,0,to); | ||
5413 | while ((fd = dup(from)) < to && fd >= 0) | ||
5414 | fds[fd] = 1; | ||
5415 | for (i = 0;i < to;i ++) | ||
5416 | if (fds[i]) | ||
5417 | close(i); | ||
5418 | free(fds); | ||
5419 | return fd; | ||
5420 | } | ||
5131 | newfd = fcntl(from, F_DUPFD, to); | 5421 | newfd = fcntl(from, F_DUPFD, to); |
5132 | } | 5422 | } |
5133 | if (newfd < 0) { | 5423 | if (newfd < 0) { |
@@ -5286,7 +5576,7 @@ redirect(union node *redir, int flags) | |||
5286 | /* Careful to not accidentally "save" | 5576 | /* Careful to not accidentally "save" |
5287 | * to the same fd as right side fd in N>&M */ | 5577 | * to the same fd as right side fd in N>&M */ |
5288 | int minfd = right_fd < 10 ? 10 : right_fd + 1; | 5578 | int minfd = right_fd < 10 ? 10 : right_fd + 1; |
5289 | i = fcntl(fd, F_DUPFD, minfd); | 5579 | i = copyfd(fd, minfd); |
5290 | /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds | 5580 | /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds |
5291 | * are closed in popredir() in the child, preventing them from leaking | 5581 | * are closed in popredir() in the child, preventing them from leaking |
5292 | * into child. (popredir() also cleans up the mess in case of failures) | 5582 | * into child. (popredir() also cleans up the mess in case of failures) |
@@ -5751,6 +6041,8 @@ exptilde(char *startp, char *p, int flags) | |||
5751 | if (*name == '\0') { | 6041 | if (*name == '\0') { |
5752 | home = lookupvar("HOME"); | 6042 | home = lookupvar("HOME"); |
5753 | } else { | 6043 | } else { |
6044 | if (ENABLE_PLATFORM_MINGW32) | ||
6045 | goto lose; | ||
5754 | pw = getpwnam(name); | 6046 | pw = getpwnam(name); |
5755 | if (pw == NULL) | 6047 | if (pw == NULL) |
5756 | goto lose; | 6048 | goto lose; |
@@ -5778,6 +6070,7 @@ struct backcmd { /* result of evalbackcmd */ | |||
5778 | int fd; /* file descriptor to read from */ | 6070 | int fd; /* file descriptor to read from */ |
5779 | int nleft; /* number of chars in buffer */ | 6071 | int nleft; /* number of chars in buffer */ |
5780 | char *buf; /* buffer */ | 6072 | char *buf; /* buffer */ |
6073 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5781 | struct job *jp; /* job structure for command */ | 6074 | struct job *jp; /* job structure for command */ |
5782 | }; | 6075 | }; |
5783 | 6076 | ||
@@ -5786,6 +6079,25 @@ static uint8_t back_exitstatus; /* exit status of backquoted command */ | |||
5786 | #define EV_EXIT 01 /* exit after evaluating tree */ | 6079 | #define EV_EXIT 01 /* exit after evaluating tree */ |
5787 | static void evaltree(union node *, int); | 6080 | static void evaltree(union node *, int); |
5788 | 6081 | ||
6082 | #if ENABLE_PLATFORM_MINGW32 | ||
6083 | static void | ||
6084 | forkshell_evalbackcmd(struct forkshell *fs) | ||
6085 | { | ||
6086 | union node *n = fs->n; | ||
6087 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
6088 | |||
6089 | FORCE_INT_ON; | ||
6090 | close(pip[0]); | ||
6091 | if (pip[1] != 1) { | ||
6092 | /*close(1);*/ | ||
6093 | copyfd(pip[1], 1 | COPYFD_EXACT); | ||
6094 | close(pip[1]); | ||
6095 | } | ||
6096 | eflag = 0; | ||
6097 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ | ||
6098 | /* NOTREACHED */ | ||
6099 | } | ||
6100 | #endif | ||
5789 | static void FAST_FUNC | 6101 | static void FAST_FUNC |
5790 | evalbackcmd(union node *n, struct backcmd *result) | 6102 | evalbackcmd(union node *n, struct backcmd *result) |
5791 | { | 6103 | { |
@@ -5794,6 +6106,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5794 | result->fd = -1; | 6106 | result->fd = -1; |
5795 | result->buf = NULL; | 6107 | result->buf = NULL; |
5796 | result->nleft = 0; | 6108 | result->nleft = 0; |
6109 | IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs))); | ||
5797 | result->jp = NULL; | 6110 | result->jp = NULL; |
5798 | if (n == NULL) | 6111 | if (n == NULL) |
5799 | goto out; | 6112 | goto out; |
@@ -5808,6 +6121,14 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5808 | if (pipe(pip) < 0) | 6121 | if (pipe(pip) < 0) |
5809 | ash_msg_and_raise_error("pipe call failed"); | 6122 | ash_msg_and_raise_error("pipe call failed"); |
5810 | jp = makejob(/*n,*/ 1); | 6123 | jp = makejob(/*n,*/ 1); |
6124 | #if ENABLE_PLATFORM_MINGW32 | ||
6125 | result->fs.fp = forkshell_evalbackcmd; | ||
6126 | result->fs.n = n; | ||
6127 | result->fs.fd[0] = pip[0]; | ||
6128 | result->fs.fd[1] = pip[1]; | ||
6129 | if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0) | ||
6130 | ash_msg_and_raise_error("unable to spawn shell"); | ||
6131 | #endif | ||
5811 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 6132 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
5812 | FORCE_INT_ON; | 6133 | FORCE_INT_ON; |
5813 | close(pip[0]); | 6134 | close(pip[0]); |
@@ -7409,7 +7730,7 @@ shellexec(char **argv, const char *path, int idx) | |||
7409 | 7730 | ||
7410 | clearredir(/*drop:*/ 1); | 7731 | clearredir(/*drop:*/ 1); |
7411 | envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); | 7732 | envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); |
7412 | if (strchr(argv[0], '/') != NULL | 7733 | if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\'))) |
7413 | #if ENABLE_FEATURE_SH_STANDALONE | 7734 | #if ENABLE_FEATURE_SH_STANDALONE |
7414 | || (applet_no = find_applet_by_name(argv[0])) >= 0 | 7735 | || (applet_no = find_applet_by_name(argv[0])) >= 0 |
7415 | #endif | 7736 | #endif |
@@ -7912,6 +8233,10 @@ static int funcblocksize; /* size of structures in function */ | |||
7912 | static int funcstringsize; /* size of strings in node */ | 8233 | static int funcstringsize; /* size of strings in node */ |
7913 | static void *funcblock; /* block to allocate function from */ | 8234 | static void *funcblock; /* block to allocate function from */ |
7914 | static char *funcstring; /* block to allocate strings from */ | 8235 | static char *funcstring; /* block to allocate strings from */ |
8236 | #if ENABLE_PLATFORM_MINGW32 | ||
8237 | static int nodeptrsize; | ||
8238 | static int *nodeptr; | ||
8239 | #endif | ||
7915 | 8240 | ||
7916 | /* flags in argument to evaltree */ | 8241 | /* flags in argument to evaltree */ |
7917 | #define EV_EXIT 01 /* exit after evaluating tree */ | 8242 | #define EV_EXIT 01 /* exit after evaluating tree */ |
@@ -7957,6 +8282,7 @@ sizenodelist(struct nodelist *lp) | |||
7957 | { | 8282 | { |
7958 | while (lp) { | 8283 | while (lp) { |
7959 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); | 8284 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); |
8285 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
7960 | calcsize(lp->n); | 8286 | calcsize(lp->n); |
7961 | lp = lp->next; | 8287 | lp = lp->next; |
7962 | } | 8288 | } |
@@ -7973,15 +8299,18 @@ calcsize(union node *n) | |||
7973 | calcsize(n->ncmd.redirect); | 8299 | calcsize(n->ncmd.redirect); |
7974 | calcsize(n->ncmd.args); | 8300 | calcsize(n->ncmd.args); |
7975 | calcsize(n->ncmd.assign); | 8301 | calcsize(n->ncmd.assign); |
8302 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
7976 | break; | 8303 | break; |
7977 | case NPIPE: | 8304 | case NPIPE: |
7978 | sizenodelist(n->npipe.cmdlist); | 8305 | sizenodelist(n->npipe.cmdlist); |
8306 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
7979 | break; | 8307 | break; |
7980 | case NREDIR: | 8308 | case NREDIR: |
7981 | case NBACKGND: | 8309 | case NBACKGND: |
7982 | case NSUBSHELL: | 8310 | case NSUBSHELL: |
7983 | calcsize(n->nredir.redirect); | 8311 | calcsize(n->nredir.redirect); |
7984 | calcsize(n->nredir.n); | 8312 | calcsize(n->nredir.n); |
8313 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
7985 | break; | 8314 | break; |
7986 | case NAND: | 8315 | case NAND: |
7987 | case NOR: | 8316 | case NOR: |
@@ -7990,31 +8319,37 @@ calcsize(union node *n) | |||
7990 | case NUNTIL: | 8319 | case NUNTIL: |
7991 | calcsize(n->nbinary.ch2); | 8320 | calcsize(n->nbinary.ch2); |
7992 | calcsize(n->nbinary.ch1); | 8321 | calcsize(n->nbinary.ch1); |
8322 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
7993 | break; | 8323 | break; |
7994 | case NIF: | 8324 | case NIF: |
7995 | calcsize(n->nif.elsepart); | 8325 | calcsize(n->nif.elsepart); |
7996 | calcsize(n->nif.ifpart); | 8326 | calcsize(n->nif.ifpart); |
7997 | calcsize(n->nif.test); | 8327 | calcsize(n->nif.test); |
8328 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
7998 | break; | 8329 | break; |
7999 | case NFOR: | 8330 | case NFOR: |
8000 | funcstringsize += strlen(n->nfor.var) + 1; | 8331 | funcstringsize += strlen(n->nfor.var) + 1; |
8001 | calcsize(n->nfor.body); | 8332 | calcsize(n->nfor.body); |
8002 | calcsize(n->nfor.args); | 8333 | calcsize(n->nfor.args); |
8334 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8003 | break; | 8335 | break; |
8004 | case NCASE: | 8336 | case NCASE: |
8005 | calcsize(n->ncase.cases); | 8337 | calcsize(n->ncase.cases); |
8006 | calcsize(n->ncase.expr); | 8338 | calcsize(n->ncase.expr); |
8339 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8007 | break; | 8340 | break; |
8008 | case NCLIST: | 8341 | case NCLIST: |
8009 | calcsize(n->nclist.body); | 8342 | calcsize(n->nclist.body); |
8010 | calcsize(n->nclist.pattern); | 8343 | calcsize(n->nclist.pattern); |
8011 | calcsize(n->nclist.next); | 8344 | calcsize(n->nclist.next); |
8345 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8012 | break; | 8346 | break; |
8013 | case NDEFUN: | 8347 | case NDEFUN: |
8014 | case NARG: | 8348 | case NARG: |
8015 | sizenodelist(n->narg.backquote); | 8349 | sizenodelist(n->narg.backquote); |
8016 | funcstringsize += strlen(n->narg.text) + 1; | 8350 | funcstringsize += strlen(n->narg.text) + 1; |
8017 | calcsize(n->narg.next); | 8351 | calcsize(n->narg.next); |
8352 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8018 | break; | 8353 | break; |
8019 | case NTO: | 8354 | case NTO: |
8020 | #if ENABLE_ASH_BASH_COMPAT | 8355 | #if ENABLE_ASH_BASH_COMPAT |
@@ -8026,28 +8361,34 @@ calcsize(union node *n) | |||
8026 | case NAPPEND: | 8361 | case NAPPEND: |
8027 | calcsize(n->nfile.fname); | 8362 | calcsize(n->nfile.fname); |
8028 | calcsize(n->nfile.next); | 8363 | calcsize(n->nfile.next); |
8364 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8029 | break; | 8365 | break; |
8030 | case NTOFD: | 8366 | case NTOFD: |
8031 | case NFROMFD: | 8367 | case NFROMFD: |
8032 | calcsize(n->ndup.vname); | 8368 | calcsize(n->ndup.vname); |
8033 | calcsize(n->ndup.next); | 8369 | calcsize(n->ndup.next); |
8370 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8034 | break; | 8371 | break; |
8035 | case NHERE: | 8372 | case NHERE: |
8036 | case NXHERE: | 8373 | case NXHERE: |
8037 | calcsize(n->nhere.doc); | 8374 | calcsize(n->nhere.doc); |
8038 | calcsize(n->nhere.next); | 8375 | calcsize(n->nhere.next); |
8376 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8039 | break; | 8377 | break; |
8040 | case NNOT: | 8378 | case NNOT: |
8041 | calcsize(n->nnot.com); | 8379 | calcsize(n->nnot.com); |
8380 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
8042 | break; | 8381 | break; |
8043 | }; | 8382 | }; |
8044 | } | 8383 | } |
8045 | 8384 | ||
8046 | static char * | 8385 | static char * |
8047 | nodeckstrdup(char *s) | 8386 | nodeckstrdup(const char *s) |
8048 | { | 8387 | { |
8049 | char *rtn = funcstring; | 8388 | char *rtn = funcstring; |
8050 | 8389 | ||
8390 | if (!s) | ||
8391 | return NULL; | ||
8051 | strcpy(funcstring, s); | 8392 | strcpy(funcstring, s); |
8052 | funcstring += strlen(s) + 1; | 8393 | funcstring += strlen(s) + 1; |
8053 | return rtn; | 8394 | return rtn; |
@@ -8055,6 +8396,18 @@ nodeckstrdup(char *s) | |||
8055 | 8396 | ||
8056 | static union node *copynode(union node *); | 8397 | static union node *copynode(union node *); |
8057 | 8398 | ||
8399 | #if ENABLE_PLATFORM_MINGW32 | ||
8400 | # define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (int)&(dst);} | ||
8401 | # define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);}} | ||
8402 | # define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);}} | ||
8403 | # define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);*nodeptr++ = (int)&(dst4);}} | ||
8404 | #else | ||
8405 | # define SAVE_PTR(dst) | ||
8406 | # define SAVE_PTR2(dst,dst2) | ||
8407 | # define SAVE_PTR3(dst,dst2,dst3) | ||
8408 | # define SAVE_PTR4(dst,dst2,dst3,dst4) | ||
8409 | #endif | ||
8410 | |||
8058 | static struct nodelist * | 8411 | static struct nodelist * |
8059 | copynodelist(struct nodelist *lp) | 8412 | copynodelist(struct nodelist *lp) |
8060 | { | 8413 | { |
@@ -8066,6 +8419,7 @@ copynodelist(struct nodelist *lp) | |||
8066 | *lpp = funcblock; | 8419 | *lpp = funcblock; |
8067 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); | 8420 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); |
8068 | (*lpp)->n = copynode(lp->n); | 8421 | (*lpp)->n = copynode(lp->n); |
8422 | SAVE_PTR2((*lpp)->n, (*lpp)->next); | ||
8069 | lp = lp->next; | 8423 | lp = lp->next; |
8070 | lpp = &(*lpp)->next; | 8424 | lpp = &(*lpp)->next; |
8071 | } | 8425 | } |
@@ -8088,16 +8442,19 @@ copynode(union node *n) | |||
8088 | new->ncmd.redirect = copynode(n->ncmd.redirect); | 8442 | new->ncmd.redirect = copynode(n->ncmd.redirect); |
8089 | new->ncmd.args = copynode(n->ncmd.args); | 8443 | new->ncmd.args = copynode(n->ncmd.args); |
8090 | new->ncmd.assign = copynode(n->ncmd.assign); | 8444 | new->ncmd.assign = copynode(n->ncmd.assign); |
8445 | SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign); | ||
8091 | break; | 8446 | break; |
8092 | case NPIPE: | 8447 | case NPIPE: |
8093 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | 8448 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); |
8094 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; | 8449 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; |
8450 | SAVE_PTR(new->npipe.cmdlist); | ||
8095 | break; | 8451 | break; |
8096 | case NREDIR: | 8452 | case NREDIR: |
8097 | case NBACKGND: | 8453 | case NBACKGND: |
8098 | case NSUBSHELL: | 8454 | case NSUBSHELL: |
8099 | new->nredir.redirect = copynode(n->nredir.redirect); | 8455 | new->nredir.redirect = copynode(n->nredir.redirect); |
8100 | new->nredir.n = copynode(n->nredir.n); | 8456 | new->nredir.n = copynode(n->nredir.n); |
8457 | SAVE_PTR2(new->nredir.redirect,new->nredir.n); | ||
8101 | break; | 8458 | break; |
8102 | case NAND: | 8459 | case NAND: |
8103 | case NOR: | 8460 | case NOR: |
@@ -8106,31 +8463,37 @@ copynode(union node *n) | |||
8106 | case NUNTIL: | 8463 | case NUNTIL: |
8107 | new->nbinary.ch2 = copynode(n->nbinary.ch2); | 8464 | new->nbinary.ch2 = copynode(n->nbinary.ch2); |
8108 | new->nbinary.ch1 = copynode(n->nbinary.ch1); | 8465 | new->nbinary.ch1 = copynode(n->nbinary.ch1); |
8466 | SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2); | ||
8109 | break; | 8467 | break; |
8110 | case NIF: | 8468 | case NIF: |
8111 | new->nif.elsepart = copynode(n->nif.elsepart); | 8469 | new->nif.elsepart = copynode(n->nif.elsepart); |
8112 | new->nif.ifpart = copynode(n->nif.ifpart); | 8470 | new->nif.ifpart = copynode(n->nif.ifpart); |
8113 | new->nif.test = copynode(n->nif.test); | 8471 | new->nif.test = copynode(n->nif.test); |
8472 | SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test); | ||
8114 | break; | 8473 | break; |
8115 | case NFOR: | 8474 | case NFOR: |
8116 | new->nfor.var = nodeckstrdup(n->nfor.var); | 8475 | new->nfor.var = nodeckstrdup(n->nfor.var); |
8117 | new->nfor.body = copynode(n->nfor.body); | 8476 | new->nfor.body = copynode(n->nfor.body); |
8118 | new->nfor.args = copynode(n->nfor.args); | 8477 | new->nfor.args = copynode(n->nfor.args); |
8478 | SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args); | ||
8119 | break; | 8479 | break; |
8120 | case NCASE: | 8480 | case NCASE: |
8121 | new->ncase.cases = copynode(n->ncase.cases); | 8481 | new->ncase.cases = copynode(n->ncase.cases); |
8122 | new->ncase.expr = copynode(n->ncase.expr); | 8482 | new->ncase.expr = copynode(n->ncase.expr); |
8483 | SAVE_PTR2(new->ncase.cases,new->ncase.expr); | ||
8123 | break; | 8484 | break; |
8124 | case NCLIST: | 8485 | case NCLIST: |
8125 | new->nclist.body = copynode(n->nclist.body); | 8486 | new->nclist.body = copynode(n->nclist.body); |
8126 | new->nclist.pattern = copynode(n->nclist.pattern); | 8487 | new->nclist.pattern = copynode(n->nclist.pattern); |
8127 | new->nclist.next = copynode(n->nclist.next); | 8488 | new->nclist.next = copynode(n->nclist.next); |
8489 | SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next); | ||
8128 | break; | 8490 | break; |
8129 | case NDEFUN: | 8491 | case NDEFUN: |
8130 | case NARG: | 8492 | case NARG: |
8131 | new->narg.backquote = copynodelist(n->narg.backquote); | 8493 | new->narg.backquote = copynodelist(n->narg.backquote); |
8132 | new->narg.text = nodeckstrdup(n->narg.text); | 8494 | new->narg.text = nodeckstrdup(n->narg.text); |
8133 | new->narg.next = copynode(n->narg.next); | 8495 | new->narg.next = copynode(n->narg.next); |
8496 | SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next); | ||
8134 | break; | 8497 | break; |
8135 | case NTO: | 8498 | case NTO: |
8136 | #if ENABLE_ASH_BASH_COMPAT | 8499 | #if ENABLE_ASH_BASH_COMPAT |
@@ -8143,6 +8506,7 @@ copynode(union node *n) | |||
8143 | new->nfile.fname = copynode(n->nfile.fname); | 8506 | new->nfile.fname = copynode(n->nfile.fname); |
8144 | new->nfile.fd = n->nfile.fd; | 8507 | new->nfile.fd = n->nfile.fd; |
8145 | new->nfile.next = copynode(n->nfile.next); | 8508 | new->nfile.next = copynode(n->nfile.next); |
8509 | SAVE_PTR2(new->nfile.fname,new->nfile.next); | ||
8146 | break; | 8510 | break; |
8147 | case NTOFD: | 8511 | case NTOFD: |
8148 | case NFROMFD: | 8512 | case NFROMFD: |
@@ -8150,15 +8514,18 @@ copynode(union node *n) | |||
8150 | new->ndup.dupfd = n->ndup.dupfd; | 8514 | new->ndup.dupfd = n->ndup.dupfd; |
8151 | new->ndup.fd = n->ndup.fd; | 8515 | new->ndup.fd = n->ndup.fd; |
8152 | new->ndup.next = copynode(n->ndup.next); | 8516 | new->ndup.next = copynode(n->ndup.next); |
8517 | SAVE_PTR2(new->ndup.vname,new->ndup.next); | ||
8153 | break; | 8518 | break; |
8154 | case NHERE: | 8519 | case NHERE: |
8155 | case NXHERE: | 8520 | case NXHERE: |
8156 | new->nhere.doc = copynode(n->nhere.doc); | 8521 | new->nhere.doc = copynode(n->nhere.doc); |
8157 | new->nhere.fd = n->nhere.fd; | 8522 | new->nhere.fd = n->nhere.fd; |
8158 | new->nhere.next = copynode(n->nhere.next); | 8523 | new->nhere.next = copynode(n->nhere.next); |
8524 | SAVE_PTR2(new->nhere.doc,new->nhere.next); | ||
8159 | break; | 8525 | break; |
8160 | case NNOT: | 8526 | case NNOT: |
8161 | new->nnot.com = copynode(n->nnot.com); | 8527 | new->nnot.com = copynode(n->nnot.com); |
8528 | SAVE_PTR(new->nnot.com); | ||
8162 | break; | 8529 | break; |
8163 | }; | 8530 | }; |
8164 | new->type = n->type; | 8531 | new->type = n->type; |
@@ -8181,6 +8548,7 @@ copyfunc(union node *n) | |||
8181 | f = ckmalloc(blocksize + funcstringsize); | 8548 | f = ckmalloc(blocksize + funcstringsize); |
8182 | funcblock = (char *) f + offsetof(struct funcnode, n); | 8549 | funcblock = (char *) f + offsetof(struct funcnode, n); |
8183 | funcstring = (char *) f + blocksize; | 8550 | funcstring = (char *) f + blocksize; |
8551 | IF_PLATFORM_MINGW32(nodeptr = NULL); | ||
8184 | copynode(n); | 8552 | copynode(n); |
8185 | f->count = 0; | 8553 | f->count = 0; |
8186 | return f; | 8554 | return f; |
@@ -8533,9 +8901,26 @@ evalcase(union node *n, int flags) | |||
8533 | /* | 8901 | /* |
8534 | * Kick off a subshell to evaluate a tree. | 8902 | * Kick off a subshell to evaluate a tree. |
8535 | */ | 8903 | */ |
8904 | #if ENABLE_PLATFORM_MINGW32 | ||
8905 | static void | ||
8906 | forkshell_evalsubshell(struct forkshell *fs) | ||
8907 | { | ||
8908 | union node *n = fs->n; | ||
8909 | int flags = fs->flags; | ||
8910 | |||
8911 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
8912 | INT_ON; | ||
8913 | flags |= EV_EXIT; | ||
8914 | expredir(n->nredir.redirect); | ||
8915 | redirect(n->nredir.redirect, 0); | ||
8916 | evaltreenr(n->nredir.n, flags); | ||
8917 | /* never returns */ | ||
8918 | } | ||
8919 | #endif | ||
8536 | static void | 8920 | static void |
8537 | evalsubshell(union node *n, int flags) | 8921 | evalsubshell(union node *n, int flags) |
8538 | { | 8922 | { |
8923 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
8539 | struct job *jp; | 8924 | struct job *jp; |
8540 | int backgnd = (n->type == NBACKGND); | 8925 | int backgnd = (n->type == NBACKGND); |
8541 | int status; | 8926 | int status; |
@@ -8545,6 +8930,14 @@ evalsubshell(union node *n, int flags) | |||
8545 | goto nofork; | 8930 | goto nofork; |
8546 | INT_OFF; | 8931 | INT_OFF; |
8547 | jp = makejob(/*n,*/ 1); | 8932 | jp = makejob(/*n,*/ 1); |
8933 | #if ENABLE_PLATFORM_MINGW32 | ||
8934 | memset(&fs, 0, sizeof(fs)); | ||
8935 | fs.fp = forkshell_evalsubshell; | ||
8936 | fs.n = n; | ||
8937 | fs.flags = flags; | ||
8938 | if (spawn_forkshell(jp, &fs, backgnd) < 0) | ||
8939 | ash_msg_and_raise_error("unable to spawn shell"); | ||
8940 | #endif | ||
8548 | if (forkshell(jp, n, backgnd) == 0) { | 8941 | if (forkshell(jp, n, backgnd) == 0) { |
8549 | /* child */ | 8942 | /* child */ |
8550 | INT_ON; | 8943 | INT_ON; |
@@ -8621,9 +9014,35 @@ expredir(union node *n) | |||
8621 | * of the shell, which make the last process in a pipeline the parent | 9014 | * of the shell, which make the last process in a pipeline the parent |
8622 | * of all the rest.) | 9015 | * of all the rest.) |
8623 | */ | 9016 | */ |
9017 | #if ENABLE_PLATFORM_MINGW32 | ||
9018 | static void | ||
9019 | forkshell_evalpipe(struct forkshell *fs) | ||
9020 | { | ||
9021 | union node *n = fs->n; | ||
9022 | int flags = fs->flags; | ||
9023 | int prevfd = fs->fd[2]; | ||
9024 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
9025 | |||
9026 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
9027 | INT_ON; | ||
9028 | if (pip[1] >= 0) { | ||
9029 | close(pip[0]); | ||
9030 | } | ||
9031 | if (prevfd > 0) { | ||
9032 | dup2(prevfd, 0); | ||
9033 | close(prevfd); | ||
9034 | } | ||
9035 | if (pip[1] > 1) { | ||
9036 | dup2(pip[1], 1); | ||
9037 | close(pip[1]); | ||
9038 | } | ||
9039 | evaltreenr(n, flags); | ||
9040 | } | ||
9041 | #endif | ||
8624 | static void | 9042 | static void |
8625 | evalpipe(union node *n, int flags) | 9043 | evalpipe(union node *n, int flags) |
8626 | { | 9044 | { |
9045 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
8627 | struct job *jp; | 9046 | struct job *jp; |
8628 | struct nodelist *lp; | 9047 | struct nodelist *lp; |
8629 | int pipelen; | 9048 | int pipelen; |
@@ -8647,6 +9066,17 @@ evalpipe(union node *n, int flags) | |||
8647 | ash_msg_and_raise_error("pipe call failed"); | 9066 | ash_msg_and_raise_error("pipe call failed"); |
8648 | } | 9067 | } |
8649 | } | 9068 | } |
9069 | #if ENABLE_PLATFORM_MINGW32 | ||
9070 | memset(&fs, 0, sizeof(fs)); | ||
9071 | fs.fp = forkshell_evalpipe; | ||
9072 | fs.flags = flags; | ||
9073 | fs.n = lp->n; | ||
9074 | fs.fd[0] = pip[0]; | ||
9075 | fs.fd[1] = pip[1]; | ||
9076 | fs.fd[2] = prevfd; | ||
9077 | if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0) | ||
9078 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9079 | #endif | ||
8650 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { | 9080 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { |
8651 | INT_ON; | 9081 | INT_ON; |
8652 | if (pip[1] >= 0) { | 9082 | if (pip[1] >= 0) { |
@@ -9115,6 +9545,20 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
9115 | * as POSIX mandates */ | 9545 | * as POSIX mandates */ |
9116 | return back_exitstatus; | 9546 | return back_exitstatus; |
9117 | } | 9547 | } |
9548 | |||
9549 | #if ENABLE_PLATFORM_MINGW32 | ||
9550 | static void | ||
9551 | forkshell_shellexec(struct forkshell *fs) | ||
9552 | { | ||
9553 | int idx = fs->fd[0]; | ||
9554 | struct strlist *varlist = fs->strlist; | ||
9555 | char **argv = fs->argv; | ||
9556 | char *path = fs->string; | ||
9557 | |||
9558 | listsetvar(varlist, VEXPORT|VSTACK); | ||
9559 | shellexec(argv, path, idx); | ||
9560 | } | ||
9561 | #endif | ||
9118 | static void | 9562 | static void |
9119 | evalcommand(union node *cmd, int flags) | 9563 | evalcommand(union node *cmd, int flags) |
9120 | { | 9564 | { |
@@ -9292,6 +9736,27 @@ evalcommand(union node *cmd, int flags) | |||
9292 | * in a script or a subshell does not need forking, | 9736 | * in a script or a subshell does not need forking, |
9293 | * we can just exec it. | 9737 | * we can just exec it. |
9294 | */ | 9738 | */ |
9739 | #if ENABLE_PLATFORM_MINGW32 | ||
9740 | if (!(flags & EV_EXIT) || trap[0]) { | ||
9741 | /* No, forking off a child is necessary */ | ||
9742 | struct forkshell fs; | ||
9743 | |||
9744 | memset(&fs, 0, sizeof(fs)); | ||
9745 | fs.fp = forkshell_shellexec; | ||
9746 | fs.argv = argv; | ||
9747 | fs.string = (char*)path; | ||
9748 | fs.fd[0] = cmdentry.u.index; | ||
9749 | fs.strlist = varlist.list; | ||
9750 | jp = makejob(/*cmd,*/ 1); | ||
9751 | if (spawn_forkshell(jp, &fs, FORK_FG) < 0) | ||
9752 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9753 | exitstatus = waitforjob(jp); | ||
9754 | INT_ON; | ||
9755 | TRACE(("forked child exited with %d\n", exitstatus)); | ||
9756 | break; | ||
9757 | } | ||
9758 | /* goes through to shellexec() */ | ||
9759 | #endif | ||
9295 | if (!(flags & EV_EXIT) || may_have_traps) { | 9760 | if (!(flags & EV_EXIT) || may_have_traps) { |
9296 | /* No, forking off a child is necessary */ | 9761 | /* No, forking off a child is necessary */ |
9297 | INT_OFF; | 9762 | INT_OFF; |
@@ -9676,7 +10141,7 @@ preadbuffer(void) | |||
9676 | more--; | 10141 | more--; |
9677 | 10142 | ||
9678 | c = *q; | 10143 | c = *q; |
9679 | if (c == '\0') { | 10144 | if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) { |
9680 | memmove(q, q + 1, more); | 10145 | memmove(q, q + 1, more); |
9681 | } else { | 10146 | } else { |
9682 | q++; | 10147 | q++; |
@@ -12123,7 +12588,7 @@ find_dot_file(char *name) | |||
12123 | struct stat statb; | 12588 | struct stat statb; |
12124 | 12589 | ||
12125 | /* don't try this for absolute or relative paths */ | 12590 | /* don't try this for absolute or relative paths */ |
12126 | if (strchr(name, '/')) | 12591 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) |
12127 | return name; | 12592 | return name; |
12128 | 12593 | ||
12129 | /* IIRC standards do not say whether . is to be searched. | 12594 | /* IIRC standards do not say whether . is to be searched. |
@@ -12233,10 +12698,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12233 | struct stat statb; | 12698 | struct stat statb; |
12234 | int e; | 12699 | int e; |
12235 | int updatetbl; | 12700 | int updatetbl; |
12701 | IF_PLATFORM_MINGW32(int len); | ||
12236 | struct builtincmd *bcmd; | 12702 | struct builtincmd *bcmd; |
12237 | 12703 | ||
12238 | /* If name contains a slash, don't use PATH or hash table */ | 12704 | /* If name contains a slash, don't use PATH or hash table */ |
12239 | if (strchr(name, '/') != NULL) { | 12705 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) { |
12240 | entry->u.index = -1; | 12706 | entry->u.index = -1; |
12241 | if (act & DO_ABS) { | 12707 | if (act & DO_ABS) { |
12242 | while (stat(name, &statb) < 0) { | 12708 | while (stat(name, &statb) < 0) { |
@@ -12343,12 +12809,39 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12343 | } | 12809 | } |
12344 | } | 12810 | } |
12345 | /* if rehash, don't redo absolute path names */ | 12811 | /* if rehash, don't redo absolute path names */ |
12346 | if (fullname[0] == '/' && idx <= prev) { | 12812 | if (is_absolute_path(fullname) && idx <= prev) { |
12347 | if (idx < prev) | 12813 | if (idx < prev) |
12348 | continue; | 12814 | continue; |
12349 | TRACE(("searchexec \"%s\": no change\n", name)); | 12815 | TRACE(("searchexec \"%s\": no change\n", name)); |
12350 | goto success; | 12816 | goto success; |
12351 | } | 12817 | } |
12818 | #if ENABLE_PLATFORM_MINGW32 | ||
12819 | len = strlen(fullname); | ||
12820 | if (len > 4 && | ||
12821 | (!strcasecmp(fullname+len-4, ".exe") || | ||
12822 | !strcasecmp(fullname+len-4, ".com"))) { | ||
12823 | if (stat(fullname, &statb) < 0) { | ||
12824 | if (errno != ENOENT && errno != ENOTDIR) | ||
12825 | e = errno; | ||
12826 | goto loop; | ||
12827 | } | ||
12828 | } | ||
12829 | else { | ||
12830 | /* path_advance() has reserved space for .exe */ | ||
12831 | memcpy(fullname+len, ".exe", 5); | ||
12832 | if (stat(fullname, &statb) < 0) { | ||
12833 | if (errno != ENOENT && errno != ENOTDIR) | ||
12834 | e = errno; | ||
12835 | memcpy(fullname+len, ".com", 5); | ||
12836 | if (stat(fullname, &statb) < 0) { | ||
12837 | if (errno != ENOENT && errno != ENOTDIR) | ||
12838 | e = errno; | ||
12839 | goto loop; | ||
12840 | } | ||
12841 | } | ||
12842 | fullname[len] = '\0'; | ||
12843 | } | ||
12844 | #else | ||
12352 | while (stat(fullname, &statb) < 0) { | 12845 | while (stat(fullname, &statb) < 0) { |
12353 | #ifdef SYSV | 12846 | #ifdef SYSV |
12354 | if (errno == EINTR) | 12847 | if (errno == EINTR) |
@@ -12358,6 +12851,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12358 | e = errno; | 12851 | e = errno; |
12359 | goto loop; | 12852 | goto loop; |
12360 | } | 12853 | } |
12854 | #endif | ||
12361 | e = EACCES; /* if we fail, this will be the error */ | 12855 | e = EACCES; /* if we fail, this will be the error */ |
12362 | if (!S_ISREG(statb.st_mode)) | 12856 | if (!S_ISREG(statb.st_mode)) |
12363 | continue; | 12857 | continue; |
@@ -12606,6 +13100,10 @@ unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12606 | return ret & 1; | 13100 | return ret & 1; |
12607 | } | 13101 | } |
12608 | 13102 | ||
13103 | /* setmode.c */ | ||
13104 | |||
13105 | #if !ENABLE_PLATFORM_MINGW32 | ||
13106 | |||
12609 | static const unsigned char timescmd_str[] ALIGN1 = { | 13107 | static const unsigned char timescmd_str[] ALIGN1 = { |
12610 | ' ', offsetof(struct tms, tms_utime), | 13108 | ' ', offsetof(struct tms, tms_utime), |
12611 | '\n', offsetof(struct tms, tms_stime), | 13109 | '\n', offsetof(struct tms, tms_stime), |
@@ -12637,6 +13135,13 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12637 | 13135 | ||
12638 | return 0; | 13136 | return 0; |
12639 | } | 13137 | } |
13138 | #else | ||
13139 | static int FAST_FUNC | ||
13140 | timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | ||
13141 | { | ||
13142 | return 0; | ||
13143 | } | ||
13144 | #endif | ||
12640 | 13145 | ||
12641 | #if ENABLE_SH_MATH_SUPPORT | 13146 | #if ENABLE_SH_MATH_SUPPORT |
12642 | /* | 13147 | /* |
@@ -12862,13 +13367,41 @@ init(void) | |||
12862 | struct stat st1, st2; | 13367 | struct stat st1, st2; |
12863 | 13368 | ||
12864 | initvar(); | 13369 | initvar(); |
13370 | |||
13371 | #if ENABLE_PLATFORM_MINGW32 | ||
13372 | /* | ||
13373 | * case insensitive env names from Windows world | ||
13374 | * | ||
13375 | * Some standard env names such as PATH is named Path and so on | ||
13376 | * ash itself is case sensitive, so "Path" will confuse it, as | ||
13377 | * MSVC getenv() is case insensitive. | ||
13378 | * | ||
13379 | * We may end up having both Path and PATH. Then Path will be chosen | ||
13380 | * because it appears first. | ||
13381 | */ | ||
13382 | for (envp = environ; envp && *envp; envp++) | ||
13383 | if (!strncasecmp(*envp, "PATH=", 5) && | ||
13384 | strncmp(*envp, "PATH=", 5)) | ||
13385 | break; | ||
13386 | if (envp && *envp) { | ||
13387 | char *start, *end; | ||
13388 | for (envp = environ; envp && *envp; envp++) { | ||
13389 | end = strchr(*envp, '='); | ||
13390 | if (!end) | ||
13391 | continue; | ||
13392 | for (start = *envp;start < end;start++) | ||
13393 | *start = toupper(*start); | ||
13394 | } | ||
13395 | } | ||
13396 | #endif | ||
12865 | for (envp = environ; envp && *envp; envp++) { | 13397 | for (envp = environ; envp && *envp; envp++) { |
12866 | if (strchr(*envp, '=')) { | 13398 | if (strchr(*envp, '=')) { |
12867 | setvareq(*envp, VEXPORT|VTEXTFIXED); | 13399 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
12868 | } | 13400 | } |
12869 | } | 13401 | } |
12870 | 13402 | ||
12871 | setvar("PPID", utoa(getppid()), 0); | 13403 | if (!ENABLE_PLATFORM_MINGW32) |
13404 | setvar("PPID", utoa(getppid()), 0); | ||
12872 | 13405 | ||
12873 | p = lookupvar("PWD"); | 13406 | p = lookupvar("PWD"); |
12874 | if (p) | 13407 | if (p) |
@@ -12984,6 +13517,20 @@ static short profile_buf[16384]; | |||
12984 | extern int etext(); | 13517 | extern int etext(); |
12985 | #endif | 13518 | #endif |
12986 | 13519 | ||
13520 | #if ENABLE_PLATFORM_MINGW32 | ||
13521 | static const forkpoint_fn forkpoints[] = { | ||
13522 | forkshell_openhere, | ||
13523 | forkshell_evalbackcmd, | ||
13524 | forkshell_evalsubshell, | ||
13525 | forkshell_evalpipe, | ||
13526 | forkshell_shellexec, | ||
13527 | NULL | ||
13528 | }; | ||
13529 | |||
13530 | static struct forkshell* forkshell_prepare(struct forkshell *fs); | ||
13531 | static void forkshell_init(const char *idstr); | ||
13532 | #endif | ||
13533 | |||
12987 | /* | 13534 | /* |
12988 | * Main routine. We initialize things, parse the arguments, execute | 13535 | * Main routine. We initialize things, parse the arguments, execute |
12989 | * profiles if we're a login shell, and then call cmdloop to execute | 13536 | * profiles if we're a login shell, and then call cmdloop to execute |
@@ -13051,6 +13598,15 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13051 | 13598 | ||
13052 | init(); | 13599 | init(); |
13053 | setstackmark(&smark); | 13600 | setstackmark(&smark); |
13601 | |||
13602 | #if ENABLE_PLATFORM_MINGW32 | ||
13603 | if (argc == 3 && !strcmp(argv[1], "--forkshell")) { | ||
13604 | forkshell_init(argv[2]); | ||
13605 | |||
13606 | /* NOTREACHED */ | ||
13607 | bb_error_msg_and_die("subshell ended unexpectedly"); | ||
13608 | } | ||
13609 | #endif | ||
13054 | procargs(argv); | 13610 | procargs(argv); |
13055 | 13611 | ||
13056 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 13612 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY |
@@ -13126,6 +13682,524 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13126 | /* NOTREACHED */ | 13682 | /* NOTREACHED */ |
13127 | } | 13683 | } |
13128 | 13684 | ||
13685 | /* FIXME: should consider running forkparent() and forkchild() */ | ||
13686 | static int | ||
13687 | spawn_forkshell(struct job *jp, struct forkshell *fs, int mode) | ||
13688 | { | ||
13689 | const char *argv[] = { "sh", "--forkshell", NULL, NULL }; | ||
13690 | char buf[16]; | ||
13691 | |||
13692 | struct forkshell *new; | ||
13693 | new = forkshell_prepare(fs); | ||
13694 | sprintf(buf, "%x", (unsigned int)new->hMapFile); | ||
13695 | argv[2] = buf; | ||
13696 | fs->pid = mingw_spawn_applet(P_NOWAIT, "sh", argv, | ||
13697 | (const char *const *)environ); | ||
13698 | CloseHandle(new->hMapFile); | ||
13699 | UnmapViewOfFile(new); | ||
13700 | if (fs->pid == -1) { | ||
13701 | free(jp); | ||
13702 | return -1; | ||
13703 | } | ||
13704 | forkparent(jp, fs->node, mode, fs->pid); | ||
13705 | return fs->pid; | ||
13706 | } | ||
13707 | |||
13708 | /* | ||
13709 | * forkshell_prepare() and friends | ||
13710 | * | ||
13711 | * The sequence is as follows: | ||
13712 | * - funcblocksize, funcstringsize, nodeptrsize are initialized | ||
13713 | * - forkshell_size(fs) is called to calculate the exact memory needed | ||
13714 | * - a new struct is allocated | ||
13715 | * - funcblock, funcstring, nodeptr are initialized from the new block | ||
13716 | * - forkshell_copy(fs) is called to copy recursively everything over | ||
13717 | * it will record all pointers along the way, to nodeptr | ||
13718 | * | ||
13719 | * When this memory is mapped elsewhere, pointer fixup will be needed | ||
13720 | */ | ||
13721 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
13722 | static void \ | ||
13723 | name(type *p) \ | ||
13724 | { \ | ||
13725 | while (p) { \ | ||
13726 | funcblocksize += sizeof(type); | ||
13727 | /* do something here with p */ | ||
13728 | #define SLIST_SIZE_END() \ | ||
13729 | nodeptrsize++; \ | ||
13730 | p = p->next; \ | ||
13731 | } \ | ||
13732 | } | ||
13733 | |||
13734 | #define SLIST_COPY_BEGIN(name,type) \ | ||
13735 | static type * \ | ||
13736 | name(type *vp) \ | ||
13737 | { \ | ||
13738 | type *start; \ | ||
13739 | type **vpp; \ | ||
13740 | vpp = &start; \ | ||
13741 | while (vp) { \ | ||
13742 | *vpp = funcblock; \ | ||
13743 | funcblock = (char *) funcblock + sizeof(type); | ||
13744 | /* do something here with vpp and vp */ | ||
13745 | #define SLIST_COPY_END() \ | ||
13746 | SAVE_PTR((*vpp)->next); \ | ||
13747 | vp = vp->next; \ | ||
13748 | vpp = &(*vpp)->next; \ | ||
13749 | } \ | ||
13750 | *vpp = NULL; \ | ||
13751 | return start; \ | ||
13752 | } | ||
13753 | |||
13754 | /* | ||
13755 | * struct var | ||
13756 | */ | ||
13757 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
13758 | funcstringsize += strlen(p->var_text) + 1; | ||
13759 | nodeptrsize++; /* p->text */ | ||
13760 | SLIST_SIZE_END() | ||
13761 | |||
13762 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
13763 | (*vpp)->var_text = nodeckstrdup(vp->var_text); | ||
13764 | (*vpp)->flags = vp->flags; | ||
13765 | /* | ||
13766 | * The only place that can set struct var#func is varinit[], | ||
13767 | * which will be fixed by forkshell_init() | ||
13768 | */ | ||
13769 | (*vpp)->var_func = NULL; | ||
13770 | SAVE_PTR((*vpp)->var_text); | ||
13771 | SLIST_COPY_END() | ||
13772 | |||
13773 | /* | ||
13774 | * struct localvar | ||
13775 | */ | ||
13776 | SLIST_SIZE_BEGIN(localvar_size,struct localvar) | ||
13777 | var_size(p->vp); | ||
13778 | funcstringsize += strlen(p->text) + 1; | ||
13779 | nodeptrsize += 2; /* p->vp, p->text */ | ||
13780 | SLIST_SIZE_END() | ||
13781 | |||
13782 | SLIST_COPY_BEGIN(localvar_copy,struct localvar) | ||
13783 | (*vpp)->text = nodeckstrdup(vp->text); | ||
13784 | (*vpp)->flags = vp->flags; | ||
13785 | (*vpp)->vp = var_copy(vp->vp); | ||
13786 | SAVE_PTR2((*vpp)->vp, (*vpp)->text); | ||
13787 | SLIST_COPY_END() | ||
13788 | |||
13789 | /* | ||
13790 | * struct strlist | ||
13791 | */ | ||
13792 | SLIST_SIZE_BEGIN(strlist_size,struct strlist) | ||
13793 | funcstringsize += strlen(p->text) + 1; | ||
13794 | nodeptrsize++; /* p->text */ | ||
13795 | SLIST_SIZE_END() | ||
13796 | |||
13797 | SLIST_COPY_BEGIN(strlist_copy,struct strlist) | ||
13798 | (*vpp)->text = nodeckstrdup(vp->text); | ||
13799 | SAVE_PTR((*vpp)->text); | ||
13800 | SLIST_COPY_END() | ||
13801 | |||
13802 | /* | ||
13803 | * struct tblentry | ||
13804 | */ | ||
13805 | static void | ||
13806 | tblentry_size(struct tblentry *tep) | ||
13807 | { | ||
13808 | while (tep) { | ||
13809 | funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
13810 | /* CMDBUILTIN, e->param.cmd needs no pointer relocation */ | ||
13811 | if (tep->cmdtype == CMDFUNCTION) { | ||
13812 | funcblocksize += offsetof(struct funcnode, n); | ||
13813 | calcsize(&tep->param.func->n); | ||
13814 | nodeptrsize++; /* tep->param.func */ | ||
13815 | } | ||
13816 | nodeptrsize++; /* tep->next */ | ||
13817 | tep = tep->next; | ||
13818 | } | ||
13819 | } | ||
13820 | |||
13821 | static struct tblentry * | ||
13822 | tblentry_copy(struct tblentry *tep) | ||
13823 | { | ||
13824 | struct tblentry *start; | ||
13825 | struct tblentry **newp; | ||
13826 | int size; | ||
13827 | |||
13828 | newp = &start; | ||
13829 | while (tep) { | ||
13830 | *newp = funcblock; | ||
13831 | size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
13832 | |||
13833 | funcblock = (char *) funcblock + size; | ||
13834 | memcpy(*newp, tep, size); | ||
13835 | switch (tep->cmdtype) { | ||
13836 | case CMDBUILTIN: | ||
13837 | /* No pointer saving, this field must be fixed by forkshell_init() */ | ||
13838 | (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab); | ||
13839 | break; | ||
13840 | case CMDFUNCTION: | ||
13841 | (*newp)->param.func = funcblock; | ||
13842 | funcblock = (char *) funcblock + offsetof(struct funcnode, n); | ||
13843 | copynode(&tep->param.func->n); | ||
13844 | SAVE_PTR((*newp)->param.func); | ||
13845 | break; | ||
13846 | default: | ||
13847 | break; | ||
13848 | } | ||
13849 | SAVE_PTR((*newp)->next); | ||
13850 | tep = tep->next; | ||
13851 | newp = &(*newp)->next; | ||
13852 | } | ||
13853 | *newp = NULL; | ||
13854 | return start; | ||
13855 | } | ||
13856 | |||
13857 | static void | ||
13858 | cmdtable_size(struct tblentry **cmdtablep) | ||
13859 | { | ||
13860 | int i; | ||
13861 | nodeptrsize += CMDTABLESIZE; | ||
13862 | funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE; | ||
13863 | for (i = 0; i < CMDTABLESIZE; i++) | ||
13864 | tblentry_size(cmdtablep[i]); | ||
13865 | } | ||
13866 | |||
13867 | static struct tblentry ** | ||
13868 | cmdtable_copy(struct tblentry **cmdtablep) | ||
13869 | { | ||
13870 | struct tblentry **new = funcblock; | ||
13871 | int i; | ||
13872 | |||
13873 | funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE; | ||
13874 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
13875 | new[i] = tblentry_copy(cmdtablep[i]); | ||
13876 | SAVE_PTR(new[i]); | ||
13877 | } | ||
13878 | return new; | ||
13879 | } | ||
13880 | |||
13881 | /* | ||
13882 | * char ** | ||
13883 | */ | ||
13884 | static void | ||
13885 | argv_size(char **p) | ||
13886 | { | ||
13887 | while (p && *p) { | ||
13888 | funcblocksize += sizeof(char *); | ||
13889 | funcstringsize += strlen(*p)+1; | ||
13890 | nodeptrsize++; | ||
13891 | p++; | ||
13892 | } | ||
13893 | funcblocksize += sizeof(char *); | ||
13894 | } | ||
13895 | |||
13896 | static char ** | ||
13897 | argv_copy(char **p) | ||
13898 | { | ||
13899 | char **new, **start = funcblock; | ||
13900 | |||
13901 | while (p && *p) { | ||
13902 | new = funcblock; | ||
13903 | funcblock = (char *) funcblock + sizeof(char *); | ||
13904 | *new = nodeckstrdup(*p); | ||
13905 | SAVE_PTR(*new); | ||
13906 | p++; | ||
13907 | new++; | ||
13908 | } | ||
13909 | new = funcblock; | ||
13910 | funcblock = (char *) funcblock + sizeof(char *); | ||
13911 | *new = NULL; | ||
13912 | return start; | ||
13913 | } | ||
13914 | |||
13915 | /* | ||
13916 | * struct redirtab | ||
13917 | */ | ||
13918 | static void | ||
13919 | redirtab_size(struct redirtab *rdtp) | ||
13920 | { | ||
13921 | while (rdtp) { | ||
13922 | funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
13923 | rdtp = rdtp->next; | ||
13924 | nodeptrsize++; /* rdtp->next */ | ||
13925 | } | ||
13926 | } | ||
13927 | |||
13928 | static struct redirtab * | ||
13929 | redirtab_copy(struct redirtab *rdtp) | ||
13930 | { | ||
13931 | struct redirtab *start; | ||
13932 | struct redirtab **vpp; | ||
13933 | |||
13934 | vpp = &start; | ||
13935 | while (rdtp) { | ||
13936 | int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
13937 | *vpp = funcblock; | ||
13938 | funcblock = (char *) funcblock + size; | ||
13939 | memcpy(*vpp, rdtp, size); | ||
13940 | SAVE_PTR((*vpp)->next); | ||
13941 | rdtp = rdtp->next; | ||
13942 | vpp = &(*vpp)->next; | ||
13943 | } | ||
13944 | *vpp = NULL; | ||
13945 | return start; | ||
13946 | } | ||
13947 | |||
13948 | #undef shellparam | ||
13949 | #undef redirlist | ||
13950 | #undef varinit | ||
13951 | #undef vartab | ||
13952 | static void | ||
13953 | globals_var_size(struct globals_var *gvp) | ||
13954 | { | ||
13955 | int i; | ||
13956 | |||
13957 | funcblocksize += sizeof(struct globals_var); | ||
13958 | argv_size(gvp->shellparam.p); | ||
13959 | redirtab_size(gvp->redirlist); | ||
13960 | for (i = 0; i < VTABSIZE; i++) | ||
13961 | var_size(gvp->vartab[i]); | ||
13962 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
13963 | var_size(gvp->varinit+i); | ||
13964 | nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */ | ||
13965 | } | ||
13966 | |||
13967 | #undef g_nullredirs | ||
13968 | #undef preverrout_fd | ||
13969 | static struct globals_var * | ||
13970 | globals_var_copy(struct globals_var *gvp) | ||
13971 | { | ||
13972 | int i; | ||
13973 | struct globals_var *new; | ||
13974 | |||
13975 | new = funcblock; | ||
13976 | funcblock = (char *) funcblock + sizeof(struct globals_var); | ||
13977 | |||
13978 | /* shparam */ | ||
13979 | memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam)); | ||
13980 | new->shellparam.malloced = 0; | ||
13981 | new->shellparam.p = argv_copy(gvp->shellparam.p); | ||
13982 | SAVE_PTR(new->shellparam.p); | ||
13983 | |||
13984 | new->redirlist = redirtab_copy(gvp->redirlist); | ||
13985 | SAVE_PTR(new->redirlist); | ||
13986 | |||
13987 | new->g_nullredirs = gvp->g_nullredirs; | ||
13988 | new->preverrout_fd = gvp->preverrout_fd; | ||
13989 | for (i = 0; i < VTABSIZE; i++) { | ||
13990 | new->vartab[i] = var_copy(gvp->vartab[i]); | ||
13991 | SAVE_PTR(new->vartab[i]); | ||
13992 | } | ||
13993 | |||
13994 | /* Can't use var_copy because varinit is already allocated */ | ||
13995 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { | ||
13996 | new->varinit[i].next = NULL; | ||
13997 | new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text); | ||
13998 | SAVE_PTR(new->varinit[i].var_text); | ||
13999 | new->varinit[i].flags = gvp->varinit[i].flags; | ||
14000 | new->varinit[i].var_func = gvp->varinit[i].var_func; | ||
14001 | } | ||
14002 | return new; | ||
14003 | } | ||
14004 | |||
14005 | #undef minusc | ||
14006 | #undef curdir | ||
14007 | #undef physdir | ||
14008 | #undef arg0 | ||
14009 | #undef nullstr | ||
14010 | static void | ||
14011 | globals_misc_size(struct globals_misc *p) | ||
14012 | { | ||
14013 | funcblocksize += sizeof(struct globals_misc); | ||
14014 | funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1; | ||
14015 | if (p->curdir != p->nullstr) | ||
14016 | funcstringsize += strlen(p->curdir) + 1; | ||
14017 | if (p->physdir != p->nullstr) | ||
14018 | funcstringsize += strlen(p->physdir) + 1; | ||
14019 | funcstringsize += strlen(p->arg0) + 1; | ||
14020 | nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */ | ||
14021 | } | ||
14022 | |||
14023 | static struct globals_misc * | ||
14024 | globals_misc_copy(struct globals_misc *p) | ||
14025 | { | ||
14026 | struct globals_misc *new = funcblock; | ||
14027 | |||
14028 | funcblock = (char *) funcblock + sizeof(struct globals_misc); | ||
14029 | memcpy(new, p, sizeof(struct globals_misc)); | ||
14030 | |||
14031 | new->minusc = nodeckstrdup(p->minusc); | ||
14032 | new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr; | ||
14033 | new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr; | ||
14034 | new->arg0 = nodeckstrdup(p->arg0); | ||
14035 | SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0); | ||
14036 | return new; | ||
14037 | } | ||
14038 | |||
14039 | static void | ||
14040 | forkshell_size(struct forkshell *fs) | ||
14041 | { | ||
14042 | funcblocksize += sizeof(struct forkshell); | ||
14043 | globals_var_size(fs->gvp); | ||
14044 | globals_misc_size(fs->gmp); | ||
14045 | cmdtable_size(fs->cmdtable); | ||
14046 | localvar_size(fs->localvars); | ||
14047 | /* optlist_transfer(sending, fd); */ | ||
14048 | /* misc_transfer(sending, fd); */ | ||
14049 | |||
14050 | calcsize(fs->n); | ||
14051 | argv_size(fs->argv); | ||
14052 | funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1; | ||
14053 | strlist_size(fs->strlist); | ||
14054 | |||
14055 | nodeptrsize += 8; /* gvp, gmp, cmdtable, localvars, n, argv, string, strlist */ | ||
14056 | } | ||
14057 | |||
14058 | static struct forkshell * | ||
14059 | forkshell_copy(struct forkshell *fs) | ||
14060 | { | ||
14061 | struct forkshell *new; | ||
14062 | |||
14063 | new = funcblock; | ||
14064 | funcblock = (char *) funcblock + sizeof(struct forkshell); | ||
14065 | |||
14066 | memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */ | ||
14067 | new->gvp = globals_var_copy(fs->gvp); | ||
14068 | new->gmp = globals_misc_copy(fs->gmp); | ||
14069 | new->cmdtable = cmdtable_copy(fs->cmdtable); | ||
14070 | new->localvars = localvar_copy(fs->localvars); | ||
14071 | SAVE_PTR4(new->gvp, new->gmp, new->cmdtable, new->localvars); | ||
14072 | |||
14073 | /* new->fs will be reconstructed from new->fpid */ | ||
14074 | new->n = copynode(fs->n); | ||
14075 | new->argv = argv_copy(fs->argv); | ||
14076 | new->string = nodeckstrdup(fs->string); | ||
14077 | new->strlist = strlist_copy(fs->strlist); | ||
14078 | SAVE_PTR4(new->n, new->argv, new->string, new->strlist); | ||
14079 | return new; | ||
14080 | } | ||
14081 | |||
14082 | static struct forkshell * | ||
14083 | forkshell_prepare(struct forkshell *fs) | ||
14084 | { | ||
14085 | struct forkshell *new; | ||
14086 | int size, fp, nodeptr_offset; | ||
14087 | HANDLE h; | ||
14088 | SECURITY_ATTRIBUTES sa; | ||
14089 | |||
14090 | for (fp = 0; forkpoints[fp] && forkpoints[fp] != fs->fp; fp++) | ||
14091 | ; | ||
14092 | |||
14093 | if (!forkpoints[fp]) | ||
14094 | bb_error_msg_and_die("invalid forkpoint %08x", (int)fs->fp); | ||
14095 | fs->fpid = fp; | ||
14096 | |||
14097 | /* Calculate size of "new" */ | ||
14098 | fs->gvp = ash_ptr_to_globals_var; | ||
14099 | fs->gmp = ash_ptr_to_globals_misc; | ||
14100 | fs->cmdtable = cmdtable; | ||
14101 | fs->localvars = localvars; | ||
14102 | |||
14103 | nodeptrsize = 1; /* NULL terminated */ | ||
14104 | funcblocksize = 0; | ||
14105 | funcstringsize = 0; | ||
14106 | forkshell_size(fs); | ||
14107 | size = funcblocksize + funcstringsize + nodeptrsize*sizeof(int); | ||
14108 | |||
14109 | /* Allocate, initialize pointers */ | ||
14110 | memset(&sa, 0, sizeof(sa)); | ||
14111 | sa.nLength = sizeof(sa); | ||
14112 | sa.lpSecurityDescriptor = NULL; | ||
14113 | sa.bInheritHandle = TRUE; | ||
14114 | h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL); | ||
14115 | new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
14116 | /* new = ckmalloc(size); */ | ||
14117 | funcblock = new; | ||
14118 | funcstring = (char *) funcblock + funcblocksize; | ||
14119 | nodeptr = (int*)((char *) funcstring + funcstringsize); | ||
14120 | nodeptr_offset = (int) nodeptr - (int) new; | ||
14121 | |||
14122 | /* Now pack them all */ | ||
14123 | forkshell_copy(fs); | ||
14124 | |||
14125 | /* Finish it up */ | ||
14126 | *nodeptr = 0; | ||
14127 | new->size = size; | ||
14128 | new->nodeptr_offset = nodeptr_offset; | ||
14129 | new->old_base = new; | ||
14130 | new->hMapFile = h; | ||
14131 | return new; | ||
14132 | } | ||
14133 | |||
14134 | #undef exception_handler | ||
14135 | #undef trap | ||
14136 | #undef trap_ptr | ||
14137 | static void *sticky_mem_start, *sticky_mem_end; | ||
14138 | static void | ||
14139 | forkshell_init(const char *idstr) | ||
14140 | { | ||
14141 | struct forkshell *fs; | ||
14142 | int map_handle; | ||
14143 | HANDLE h; | ||
14144 | struct globals_var **gvpp; | ||
14145 | struct globals_misc **gmpp; | ||
14146 | int i; | ||
14147 | |||
14148 | if (sscanf(idstr, "%x", &map_handle) != 1) | ||
14149 | bb_error_msg_and_die("invalid forkshell ID"); | ||
14150 | |||
14151 | h = (HANDLE)map_handle; | ||
14152 | fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
14153 | if (!fs) | ||
14154 | bb_error_msg_and_die("Invalid forkshell memory"); | ||
14155 | |||
14156 | /* this memory can't be freed */ | ||
14157 | sticky_mem_start = fs; | ||
14158 | sticky_mem_end = (char *) fs + fs->size; | ||
14159 | /* pointer fixup */ | ||
14160 | nodeptr = (int*)((char*)fs + fs->nodeptr_offset); | ||
14161 | while (*nodeptr) { | ||
14162 | int *ptr = (int*)((char*)fs + (*nodeptr - (int)fs->old_base)); | ||
14163 | if (*ptr) | ||
14164 | *ptr -= ((int)fs->old_base - (int)fs); | ||
14165 | nodeptr++; | ||
14166 | } | ||
14167 | /* Now fix up stuff that can't be transferred */ | ||
14168 | fs->fp = forkpoints[fs->fpid]; | ||
14169 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
14170 | fs->gvp->varinit[i].var_func = varinit_data[i].var_func; | ||
14171 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
14172 | struct tblentry *e = fs->cmdtable[i]; | ||
14173 | while (e) { | ||
14174 | if (e->cmdtype == CMDBUILTIN) | ||
14175 | e->param.cmd = builtintab + (int)e->param.cmd; | ||
14176 | e = e->next; | ||
14177 | } | ||
14178 | } | ||
14179 | fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler; | ||
14180 | for (i = 0; i < NSIG; i++) | ||
14181 | fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i]; | ||
14182 | fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr; | ||
14183 | |||
14184 | /* Switch global variables */ | ||
14185 | gvpp = (struct globals_var **)&ash_ptr_to_globals_var; | ||
14186 | *gvpp = fs->gvp; | ||
14187 | gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc; | ||
14188 | *gmpp = fs->gmp; | ||
14189 | localvars = fs->localvars; | ||
14190 | cmdtable = fs->cmdtable; | ||
14191 | |||
14192 | fs->fp(fs); | ||
14193 | } | ||
14194 | |||
14195 | #undef free | ||
14196 | static void | ||
14197 | sticky_free(void *base) | ||
14198 | { | ||
14199 | if (base >= sticky_mem_start && base < sticky_mem_end) | ||
14200 | return; | ||
14201 | free(base); | ||
14202 | } | ||
13129 | 14203 | ||
13130 | /*- | 14204 | /*- |
13131 | * Copyright (c) 1989, 1991, 1993, 1994 | 14205 | * Copyright (c) 1989, 1991, 1993, 1994 |