diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 1099 |
1 files changed, 1085 insertions, 14 deletions
diff --git a/shell/ash.c b/shell/ash.c index d082333ba..16a331bb0 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. |
@@ -43,7 +55,9 @@ | |||
43 | #endif | 55 | #endif |
44 | 56 | ||
45 | #include "busybox.h" /* for applet_names */ | 57 | #include "busybox.h" /* for applet_names */ |
58 | #ifndef __MINGW32__ | ||
46 | #include <paths.h> | 59 | #include <paths.h> |
60 | #endif | ||
47 | #include <setjmp.h> | 61 | #include <setjmp.h> |
48 | #include <fnmatch.h> | 62 | #include <fnmatch.h> |
49 | 63 | ||
@@ -79,6 +93,41 @@ | |||
79 | # 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" |
80 | #endif | 94 | #endif |
81 | 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 | ||
82 | 131 | ||
83 | /* ============ Hash table sizes. Configurable. */ | 132 | /* ============ Hash table sizes. Configurable. */ |
84 | 133 | ||
@@ -774,7 +823,7 @@ static void | |||
774 | opentrace(void) | 823 | opentrace(void) |
775 | { | 824 | { |
776 | char s[100]; | 825 | char s[100]; |
777 | #ifdef O_APPEND | 826 | #if defined(O_APPEND) && !ENABLE_PLATFORM_MINGW32 |
778 | int flags; | 827 | int flags; |
779 | #endif | 828 | #endif |
780 | 829 | ||
@@ -799,7 +848,7 @@ opentrace(void) | |||
799 | return; | 848 | return; |
800 | } | 849 | } |
801 | } | 850 | } |
802 | #ifdef O_APPEND | 851 | #if defined(O_APPEND) && !ENABLE_PLATFORM_MINGW32 |
803 | flags = fcntl(fileno(tracefile), F_GETFL); | 852 | flags = fcntl(fileno(tracefile), F_GETFL); |
804 | if (flags >= 0) | 853 | if (flags >= 0) |
805 | fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); | 854 | fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); |
@@ -2261,10 +2310,22 @@ path_advance(const char **path, const char *name) | |||
2261 | if (*path == NULL) | 2310 | if (*path == NULL) |
2262 | return NULL; | 2311 | return NULL; |
2263 | start = *path; | 2312 | start = *path; |
2313 | #if ENABLE_PLATFORM_MINGW32 | ||
2314 | p = next_path_sep(start); | ||
2315 | q = strchr(start, '%'); | ||
2316 | if ((p && q && q < p) || (!p && q)) | ||
2317 | p = q; | ||
2318 | if (!p) | ||
2319 | for (p = start; *p; p++) | ||
2320 | continue; | ||
2321 | #else | ||
2264 | for (p = start; *p && *p != ':' && *p != '%'; p++) | 2322 | for (p = start; *p && *p != ':' && *p != '%'; p++) |
2265 | continue; | 2323 | continue; |
2324 | #endif | ||
2266 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ | 2325 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ |
2267 | while (stackblocksize() < len) | 2326 | |
2327 | /* preserve space for .exe too */ | ||
2328 | while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len)) | ||
2268 | growstackblock(); | 2329 | growstackblock(); |
2269 | q = stackblock(); | 2330 | q = stackblock(); |
2270 | if (p != start) { | 2331 | if (p != start) { |
@@ -2380,6 +2441,98 @@ cdopt(void) | |||
2380 | static const char * | 2441 | static const char * |
2381 | updatepwd(const char *dir) | 2442 | updatepwd(const char *dir) |
2382 | { | 2443 | { |
2444 | #if ENABLE_PLATFORM_MINGW32 | ||
2445 | /* | ||
2446 | * Due to Windows drive notion, getting pwd is a completely | ||
2447 | * different thing. Handle it in a separate routine | ||
2448 | */ | ||
2449 | |||
2450 | char *new; | ||
2451 | char *p; | ||
2452 | char *cdcomppath; | ||
2453 | const char *lim; | ||
2454 | /* | ||
2455 | * There are four cases | ||
2456 | * absdrive + abspath: c:/path | ||
2457 | * absdrive + !abspath: c:path | ||
2458 | * !absdrive + abspath: /path | ||
2459 | * !absdrive + !abspath: path | ||
2460 | * | ||
2461 | * Damn DOS! | ||
2462 | * c:path behaviour is "undefined" | ||
2463 | * To properly handle this case, I have to keep track of cwd | ||
2464 | * of every drive, which is too painful to do. | ||
2465 | * So when c:path is given, I assume it's c:${curdir}path | ||
2466 | * with ${curdir} comes from the current drive | ||
2467 | */ | ||
2468 | int absdrive = *dir && dir[1] == ':'; | ||
2469 | int abspath = absdrive ? dir[2] == '/' : *dir == '/'; | ||
2470 | char *drive; | ||
2471 | |||
2472 | cdcomppath = ststrdup(dir); | ||
2473 | STARTSTACKSTR(new); | ||
2474 | if (!absdrive && curdir == nullstr) | ||
2475 | return 0; | ||
2476 | if (!abspath) { | ||
2477 | if (curdir == nullstr) | ||
2478 | return 0; | ||
2479 | new = stack_putstr(curdir, new); | ||
2480 | } | ||
2481 | new = makestrspace(strlen(dir) + 2, new); | ||
2482 | |||
2483 | drive = stackblock(); | ||
2484 | if (absdrive) { | ||
2485 | *drive = *dir; | ||
2486 | cdcomppath += 2; | ||
2487 | dir += 2; | ||
2488 | } else { | ||
2489 | *drive = *curdir; | ||
2490 | } | ||
2491 | drive[1] = ':'; /* in case of absolute drive+path */ | ||
2492 | |||
2493 | if (abspath) | ||
2494 | new = drive + 2; | ||
2495 | lim = drive + 3; | ||
2496 | if (!abspath) { | ||
2497 | if (new[-1] != '/') | ||
2498 | USTPUTC('/', new); | ||
2499 | if (new > lim && *lim == '/') | ||
2500 | lim++; | ||
2501 | } else { | ||
2502 | USTPUTC('/', new); | ||
2503 | cdcomppath ++; | ||
2504 | if (dir[1] == '/' && dir[2] != '/') { | ||
2505 | USTPUTC('/', new); | ||
2506 | cdcomppath++; | ||
2507 | lim++; | ||
2508 | } | ||
2509 | } | ||
2510 | p = strtok(cdcomppath, "/"); | ||
2511 | while (p) { | ||
2512 | switch (*p) { | ||
2513 | case '.': | ||
2514 | if (p[1] == '.' && p[2] == '\0') { | ||
2515 | while (new > lim) { | ||
2516 | STUNPUTC(new); | ||
2517 | if (new[-1] == '/') | ||
2518 | break; | ||
2519 | } | ||
2520 | break; | ||
2521 | } | ||
2522 | if (p[1] == '\0') | ||
2523 | break; | ||
2524 | /* fall through */ | ||
2525 | default: | ||
2526 | new = stack_putstr(p, new); | ||
2527 | USTPUTC('/', new); | ||
2528 | } | ||
2529 | p = strtok(0, "/"); | ||
2530 | } | ||
2531 | if (new > lim) | ||
2532 | STUNPUTC(new); | ||
2533 | *new = 0; | ||
2534 | return stackblock(); | ||
2535 | #else | ||
2383 | char *new; | 2536 | char *new; |
2384 | char *p; | 2537 | char *p; |
2385 | char *cdcomppath; | 2538 | char *cdcomppath; |
@@ -2433,6 +2586,7 @@ updatepwd(const char *dir) | |||
2433 | STUNPUTC(new); | 2586 | STUNPUTC(new); |
2434 | *new = 0; | 2587 | *new = 0; |
2435 | return stackblock(); | 2588 | return stackblock(); |
2589 | #endif | ||
2436 | } | 2590 | } |
2437 | 2591 | ||
2438 | /* | 2592 | /* |
@@ -2527,7 +2681,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2527 | } | 2681 | } |
2528 | if (!dest) | 2682 | if (!dest) |
2529 | dest = nullstr; | 2683 | dest = nullstr; |
2530 | if (*dest == '/') | 2684 | if (is_absolute_path(dest)) |
2531 | goto step7; | 2685 | goto step7; |
2532 | if (*dest == '.') { | 2686 | if (*dest == '.') { |
2533 | c = dest[1]; | 2687 | c = dest[1]; |
@@ -3299,6 +3453,8 @@ setsignal(int signo) | |||
3299 | char cur_act, new_act; | 3453 | char cur_act, new_act; |
3300 | struct sigaction act; | 3454 | struct sigaction act; |
3301 | 3455 | ||
3456 | if (ENABLE_PLATFORM_MINGW32) | ||
3457 | return; | ||
3302 | t = trap[signo]; | 3458 | t = trap[signo]; |
3303 | new_act = S_DFL; | 3459 | new_act = S_DFL; |
3304 | if (t != NULL) { /* trap for this sig is set */ | 3460 | if (t != NULL) { /* trap for this sig is set */ |
@@ -3606,7 +3762,7 @@ setjobctl(int on) | |||
3606 | if (--fd < 0) | 3762 | if (--fd < 0) |
3607 | goto out; | 3763 | goto out; |
3608 | } | 3764 | } |
3609 | fd = fcntl(fd, F_DUPFD, 10); | 3765 | fd = copyfd(fd, 10); |
3610 | if (ofd >= 0) | 3766 | if (ofd >= 0) |
3611 | close(ofd); | 3767 | close(ofd); |
3612 | if (fd < 0) | 3768 | if (fd < 0) |
@@ -3780,6 +3936,53 @@ sprint_status(char *s, int status, int sigonly) | |||
3780 | return col; | 3936 | return col; |
3781 | } | 3937 | } |
3782 | 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 | |||
3783 | static int | 3986 | static int |
3784 | dowait(int wait_flags, struct job *job) | 3987 | dowait(int wait_flags, struct job *job) |
3785 | { | 3988 | { |
@@ -3796,7 +3999,11 @@ dowait(int wait_flags, struct job *job) | |||
3796 | * NB: _not_ safe_waitpid, we need to detect EINTR */ | 3999 | * NB: _not_ safe_waitpid, we need to detect EINTR */ |
3797 | if (doing_jobctl) | 4000 | if (doing_jobctl) |
3798 | wait_flags |= WUNTRACED; | 4001 | wait_flags |= WUNTRACED; |
4002 | #if ENABLE_PLATFORM_MINGW32 | ||
4003 | pid = waitpid_child(&status); | ||
4004 | #else | ||
3799 | pid = waitpid(-1, &status, wait_flags); | 4005 | pid = waitpid(-1, &status, wait_flags); |
4006 | #endif | ||
3800 | 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", |
3801 | pid, status, errno, strerror(errno))); | 4008 | pid, status, errno, strerror(errno))); |
3802 | if (pid <= 0) | 4009 | if (pid <= 0) |
@@ -3819,6 +4026,8 @@ dowait(int wait_flags, struct job *job) | |||
3819 | jobno(jp), pid, ps->ps_status, status)); | 4026 | jobno(jp), pid, ps->ps_status, status)); |
3820 | ps->ps_status = status; | 4027 | ps->ps_status = status; |
3821 | thisjob = jp; | 4028 | thisjob = jp; |
4029 | if (ENABLE_PLATFORM_MINGW32) | ||
4030 | ps->ps_pid = -1; | ||
3822 | } | 4031 | } |
3823 | if (ps->ps_status == -1) | 4032 | if (ps->ps_status == -1) |
3824 | state = JOBRUNNING; | 4033 | state = JOBRUNNING; |
@@ -4050,6 +4259,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
4050 | int retval; | 4259 | int retval; |
4051 | struct job *jp; | 4260 | struct job *jp; |
4052 | 4261 | ||
4262 | if (ENABLE_PLATFORM_MINGW32) | ||
4263 | return 0; | ||
4264 | |||
4053 | if (pending_sig) | 4265 | if (pending_sig) |
4054 | raise_exception(EXSIG); | 4266 | raise_exception(EXSIG); |
4055 | 4267 | ||
@@ -4660,7 +4872,7 @@ static void | |||
4660 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 4872 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
4661 | { | 4873 | { |
4662 | TRACE(("In parent shell: child = %d\n", pid)); | 4874 | TRACE(("In parent shell: child = %d\n", pid)); |
4663 | if (!jp) { | 4875 | if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */ |
4664 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) | 4876 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) |
4665 | continue; | 4877 | continue; |
4666 | jobless++; | 4878 | jobless++; |
@@ -4700,6 +4912,9 @@ forkshell(struct job *jp, union node *n, int mode) | |||
4700 | int pid; | 4912 | int pid; |
4701 | 4913 | ||
4702 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); | 4914 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); |
4915 | if (ENABLE_PLATFORM_MINGW32) | ||
4916 | return -1; | ||
4917 | |||
4703 | pid = fork(); | 4918 | pid = fork(); |
4704 | if (pid < 0) { | 4919 | if (pid < 0) { |
4705 | TRACE(("Fork failed, errno=%d", errno)); | 4920 | TRACE(("Fork failed, errno=%d", errno)); |
@@ -4896,11 +5111,39 @@ noclobberopen(const char *fname) | |||
4896 | */ | 5111 | */ |
4897 | /* openhere needs this forward reference */ | 5112 | /* openhere needs this forward reference */ |
4898 | static void expandhere(union node *arg, int fd); | 5113 | static void expandhere(union node *arg, int fd); |
5114 | #if ENABLE_PLATFORM_MINGW32 | ||
5115 | static void | ||
5116 | forkshell_openhere(struct forkshell *fs) | ||
5117 | { | ||
5118 | union node *redir = fs->n; | ||
5119 | int pip[2]; | ||
5120 | |||
5121 | pip[0] = fs->fd[0]; | ||
5122 | pip[1] = fs->fd[1]; | ||
5123 | |||
5124 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
5125 | |||
5126 | close(pip[0]); | ||
5127 | ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); | ||
5128 | ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); | ||
5129 | ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); | ||
5130 | ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); | ||
5131 | signal(SIGPIPE, SIG_DFL); | ||
5132 | if (redir->type == NHERE) { | ||
5133 | size_t len = strlen(redir->nhere.doc->narg.text); | ||
5134 | full_write(pip[1], redir->nhere.doc->narg.text, len); | ||
5135 | } else /* NXHERE */ | ||
5136 | expandhere(redir->nhere.doc, pip[1]); | ||
5137 | _exit(EXIT_SUCCESS); | ||
5138 | } | ||
5139 | #endif | ||
5140 | |||
4899 | static int | 5141 | static int |
4900 | openhere(union node *redir) | 5142 | openhere(union node *redir) |
4901 | { | 5143 | { |
4902 | int pip[2]; | 5144 | int pip[2]; |
4903 | size_t len = 0; | 5145 | size_t len = 0; |
5146 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
4904 | 5147 | ||
4905 | if (pipe(pip) < 0) | 5148 | if (pipe(pip) < 0) |
4906 | ash_msg_and_raise_error("pipe call failed"); | 5149 | ash_msg_and_raise_error("pipe call failed"); |
@@ -4911,6 +5154,16 @@ openhere(union node *redir) | |||
4911 | goto out; | 5154 | goto out; |
4912 | } | 5155 | } |
4913 | } | 5156 | } |
5157 | #if ENABLE_PLATFORM_MINGW32 | ||
5158 | memset(&fs, 0, sizeof(fs)); | ||
5159 | fs.fp = forkshell_openhere; | ||
5160 | fs.flags = 0; | ||
5161 | fs.n = redir; | ||
5162 | fs.fd[0] = pip[0]; | ||
5163 | fs.fd[1] = pip[1]; | ||
5164 | if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0) | ||
5165 | ash_msg_and_raise_error("unable to spawn shell"); | ||
5166 | #endif | ||
4914 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | 5167 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { |
4915 | /* child */ | 5168 | /* child */ |
4916 | close(pip[0]); | 5169 | close(pip[0]); |
@@ -4936,6 +5189,31 @@ openredirect(union node *redir) | |||
4936 | char *fname; | 5189 | char *fname; |
4937 | int f; | 5190 | int f; |
4938 | 5191 | ||
5192 | #if ENABLE_PLATFORM_MINGW32 | ||
5193 | /* Support for /dev/null */ | ||
5194 | switch (redir->nfile.type) { | ||
5195 | case NFROM: | ||
5196 | if (!strcmp(redir->nfile.expfname, "/dev/null")) | ||
5197 | return open("nul",O_RDWR); | ||
5198 | if (!strncmp(redir->nfile.expfname, "/dev/", 5)) { | ||
5199 | ash_msg("Unhandled device %s\n", redir->nfile.expfname); | ||
5200 | return -1; | ||
5201 | } | ||
5202 | break; | ||
5203 | |||
5204 | case NFROMTO: | ||
5205 | case NTO: | ||
5206 | case NCLOBBER: | ||
5207 | case NAPPEND: | ||
5208 | if (!strcmp(redir->nfile.expfname, "/dev/null")) | ||
5209 | return open("nul",O_RDWR); | ||
5210 | if (!strncmp(redir->nfile.expfname, "/dev/", 5)) { | ||
5211 | ash_msg("Unhandled device %s\n", redir->nfile.expfname); | ||
5212 | return -1; | ||
5213 | } | ||
5214 | break; | ||
5215 | } | ||
5216 | #endif | ||
4939 | switch (redir->nfile.type) { | 5217 | switch (redir->nfile.type) { |
4940 | case NFROM: | 5218 | case NFROM: |
4941 | fname = redir->nfile.expfname; | 5219 | fname = redir->nfile.expfname; |
@@ -5018,6 +5296,18 @@ copyfd(int from, int to) | |||
5018 | /*if (from != to)*/ | 5296 | /*if (from != to)*/ |
5019 | newfd = dup2(from, to); | 5297 | newfd = dup2(from, to); |
5020 | } else { | 5298 | } else { |
5299 | if (ENABLE_PLATFORM_MINGW32) { | ||
5300 | char* fds = ckmalloc(to); | ||
5301 | int i,fd; | ||
5302 | memset(fds,0,to); | ||
5303 | while ((fd = dup(from)) < to && fd >= 0) | ||
5304 | fds[fd] = 1; | ||
5305 | for (i = 0;i < to;i ++) | ||
5306 | if (fds[i]) | ||
5307 | close(i); | ||
5308 | free(fds); | ||
5309 | return fd; | ||
5310 | } | ||
5021 | newfd = fcntl(from, F_DUPFD, to); | 5311 | newfd = fcntl(from, F_DUPFD, to); |
5022 | } | 5312 | } |
5023 | if (newfd < 0) { | 5313 | if (newfd < 0) { |
@@ -5162,7 +5452,7 @@ redirect(union node *redir, int flags) | |||
5162 | #endif | 5452 | #endif |
5163 | if (need_to_remember(sv, fd)) { | 5453 | if (need_to_remember(sv, fd)) { |
5164 | /* Copy old descriptor */ | 5454 | /* Copy old descriptor */ |
5165 | i = fcntl(fd, F_DUPFD, 10); | 5455 | i = copyfd(fd, 10); |
5166 | /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds | 5456 | /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds |
5167 | * are closed in popredir() in the child, preventing them from leaking | 5457 | * are closed in popredir() in the child, preventing them from leaking |
5168 | * into child. (popredir() also cleans up the mess in case of failures) | 5458 | * into child. (popredir() also cleans up the mess in case of failures) |
@@ -5627,6 +5917,8 @@ exptilde(char *startp, char *p, int flags) | |||
5627 | if (*name == '\0') { | 5917 | if (*name == '\0') { |
5628 | home = lookupvar(homestr); | 5918 | home = lookupvar(homestr); |
5629 | } else { | 5919 | } else { |
5920 | if (ENABLE_PLATFORM_MINGW32) | ||
5921 | goto lose; | ||
5630 | pw = getpwnam(name); | 5922 | pw = getpwnam(name); |
5631 | if (pw == NULL) | 5923 | if (pw == NULL) |
5632 | goto lose; | 5924 | goto lose; |
@@ -5654,6 +5946,7 @@ struct backcmd { /* result of evalbackcmd */ | |||
5654 | int fd; /* file descriptor to read from */ | 5946 | int fd; /* file descriptor to read from */ |
5655 | int nleft; /* number of chars in buffer */ | 5947 | int nleft; /* number of chars in buffer */ |
5656 | char *buf; /* buffer */ | 5948 | char *buf; /* buffer */ |
5949 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5657 | struct job *jp; /* job structure for command */ | 5950 | struct job *jp; /* job structure for command */ |
5658 | }; | 5951 | }; |
5659 | 5952 | ||
@@ -5662,6 +5955,25 @@ static uint8_t back_exitstatus; /* exit status of backquoted command */ | |||
5662 | #define EV_EXIT 01 /* exit after evaluating tree */ | 5955 | #define EV_EXIT 01 /* exit after evaluating tree */ |
5663 | static void evaltree(union node *, int); | 5956 | static void evaltree(union node *, int); |
5664 | 5957 | ||
5958 | #if ENABLE_PLATFORM_MINGW32 | ||
5959 | static void | ||
5960 | forkshell_evalbackcmd(struct forkshell *fs) | ||
5961 | { | ||
5962 | union node *n = fs->n; | ||
5963 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
5964 | |||
5965 | FORCE_INT_ON; | ||
5966 | close(pip[0]); | ||
5967 | if (pip[1] != 1) { | ||
5968 | /*close(1);*/ | ||
5969 | copyfd(pip[1], 1 | COPYFD_EXACT); | ||
5970 | close(pip[1]); | ||
5971 | } | ||
5972 | eflag = 0; | ||
5973 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ | ||
5974 | /* NOTREACHED */ | ||
5975 | } | ||
5976 | #endif | ||
5665 | static void FAST_FUNC | 5977 | static void FAST_FUNC |
5666 | evalbackcmd(union node *n, struct backcmd *result) | 5978 | evalbackcmd(union node *n, struct backcmd *result) |
5667 | { | 5979 | { |
@@ -5670,6 +5982,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5670 | result->fd = -1; | 5982 | result->fd = -1; |
5671 | result->buf = NULL; | 5983 | result->buf = NULL; |
5672 | result->nleft = 0; | 5984 | result->nleft = 0; |
5985 | IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs))); | ||
5673 | result->jp = NULL; | 5986 | result->jp = NULL; |
5674 | if (n == NULL) | 5987 | if (n == NULL) |
5675 | goto out; | 5988 | goto out; |
@@ -5684,6 +5997,14 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5684 | if (pipe(pip) < 0) | 5997 | if (pipe(pip) < 0) |
5685 | ash_msg_and_raise_error("pipe call failed"); | 5998 | ash_msg_and_raise_error("pipe call failed"); |
5686 | jp = makejob(/*n,*/ 1); | 5999 | jp = makejob(/*n,*/ 1); |
6000 | #if ENABLE_PLATFORM_MINGW32 | ||
6001 | result->fs.fp = forkshell_evalbackcmd; | ||
6002 | result->fs.n = n; | ||
6003 | result->fs.fd[0] = pip[0]; | ||
6004 | result->fs.fd[1] = pip[1]; | ||
6005 | if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0) | ||
6006 | ash_msg_and_raise_error("unable to spawn shell"); | ||
6007 | #endif | ||
5687 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 6008 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
5688 | FORCE_INT_ON; | 6009 | FORCE_INT_ON; |
5689 | close(pip[0]); | 6010 | close(pip[0]); |
@@ -7299,7 +7620,7 @@ shellexec(char **argv, const char *path, int idx) | |||
7299 | 7620 | ||
7300 | clearredir(/*drop:*/ 1); | 7621 | clearredir(/*drop:*/ 1); |
7301 | envp = listvars(VEXPORT, VUNSET, 0); | 7622 | envp = listvars(VEXPORT, VUNSET, 0); |
7302 | if (strchr(argv[0], '/') != NULL | 7623 | if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\'))) |
7303 | #if ENABLE_FEATURE_SH_STANDALONE | 7624 | #if ENABLE_FEATURE_SH_STANDALONE |
7304 | || (applet_no = find_applet_by_name(argv[0])) >= 0 | 7625 | || (applet_no = find_applet_by_name(argv[0])) >= 0 |
7305 | #endif | 7626 | #endif |
@@ -7816,6 +8137,10 @@ static int funcblocksize; /* size of structures in function */ | |||
7816 | static int funcstringsize; /* size of strings in node */ | 8137 | static int funcstringsize; /* size of strings in node */ |
7817 | static void *funcblock; /* block to allocate function from */ | 8138 | static void *funcblock; /* block to allocate function from */ |
7818 | static char *funcstring; /* block to allocate strings from */ | 8139 | static char *funcstring; /* block to allocate strings from */ |
8140 | #if ENABLE_PLATFORM_MINGW32 | ||
8141 | static int nodeptrsize; | ||
8142 | static int *nodeptr; | ||
8143 | #endif | ||
7819 | 8144 | ||
7820 | /* flags in argument to evaltree */ | 8145 | /* flags in argument to evaltree */ |
7821 | #define EV_EXIT 01 /* exit after evaluating tree */ | 8146 | #define EV_EXIT 01 /* exit after evaluating tree */ |
@@ -7861,6 +8186,7 @@ sizenodelist(struct nodelist *lp) | |||
7861 | { | 8186 | { |
7862 | while (lp) { | 8187 | while (lp) { |
7863 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); | 8188 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); |
8189 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
7864 | calcsize(lp->n); | 8190 | calcsize(lp->n); |
7865 | lp = lp->next; | 8191 | lp = lp->next; |
7866 | } | 8192 | } |
@@ -7877,15 +8203,18 @@ calcsize(union node *n) | |||
7877 | calcsize(n->ncmd.redirect); | 8203 | calcsize(n->ncmd.redirect); |
7878 | calcsize(n->ncmd.args); | 8204 | calcsize(n->ncmd.args); |
7879 | calcsize(n->ncmd.assign); | 8205 | calcsize(n->ncmd.assign); |
8206 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
7880 | break; | 8207 | break; |
7881 | case NPIPE: | 8208 | case NPIPE: |
7882 | sizenodelist(n->npipe.cmdlist); | 8209 | sizenodelist(n->npipe.cmdlist); |
8210 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
7883 | break; | 8211 | break; |
7884 | case NREDIR: | 8212 | case NREDIR: |
7885 | case NBACKGND: | 8213 | case NBACKGND: |
7886 | case NSUBSHELL: | 8214 | case NSUBSHELL: |
7887 | calcsize(n->nredir.redirect); | 8215 | calcsize(n->nredir.redirect); |
7888 | calcsize(n->nredir.n); | 8216 | calcsize(n->nredir.n); |
8217 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
7889 | break; | 8218 | break; |
7890 | case NAND: | 8219 | case NAND: |
7891 | case NOR: | 8220 | case NOR: |
@@ -7894,31 +8223,37 @@ calcsize(union node *n) | |||
7894 | case NUNTIL: | 8223 | case NUNTIL: |
7895 | calcsize(n->nbinary.ch2); | 8224 | calcsize(n->nbinary.ch2); |
7896 | calcsize(n->nbinary.ch1); | 8225 | calcsize(n->nbinary.ch1); |
8226 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
7897 | break; | 8227 | break; |
7898 | case NIF: | 8228 | case NIF: |
7899 | calcsize(n->nif.elsepart); | 8229 | calcsize(n->nif.elsepart); |
7900 | calcsize(n->nif.ifpart); | 8230 | calcsize(n->nif.ifpart); |
7901 | calcsize(n->nif.test); | 8231 | calcsize(n->nif.test); |
8232 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
7902 | break; | 8233 | break; |
7903 | case NFOR: | 8234 | case NFOR: |
7904 | funcstringsize += strlen(n->nfor.var) + 1; | 8235 | funcstringsize += strlen(n->nfor.var) + 1; |
7905 | calcsize(n->nfor.body); | 8236 | calcsize(n->nfor.body); |
7906 | calcsize(n->nfor.args); | 8237 | calcsize(n->nfor.args); |
8238 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
7907 | break; | 8239 | break; |
7908 | case NCASE: | 8240 | case NCASE: |
7909 | calcsize(n->ncase.cases); | 8241 | calcsize(n->ncase.cases); |
7910 | calcsize(n->ncase.expr); | 8242 | calcsize(n->ncase.expr); |
8243 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
7911 | break; | 8244 | break; |
7912 | case NCLIST: | 8245 | case NCLIST: |
7913 | calcsize(n->nclist.body); | 8246 | calcsize(n->nclist.body); |
7914 | calcsize(n->nclist.pattern); | 8247 | calcsize(n->nclist.pattern); |
7915 | calcsize(n->nclist.next); | 8248 | calcsize(n->nclist.next); |
8249 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
7916 | break; | 8250 | break; |
7917 | case NDEFUN: | 8251 | case NDEFUN: |
7918 | case NARG: | 8252 | case NARG: |
7919 | sizenodelist(n->narg.backquote); | 8253 | sizenodelist(n->narg.backquote); |
7920 | funcstringsize += strlen(n->narg.text) + 1; | 8254 | funcstringsize += strlen(n->narg.text) + 1; |
7921 | calcsize(n->narg.next); | 8255 | calcsize(n->narg.next); |
8256 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
7922 | break; | 8257 | break; |
7923 | case NTO: | 8258 | case NTO: |
7924 | #if ENABLE_ASH_BASH_COMPAT | 8259 | #if ENABLE_ASH_BASH_COMPAT |
@@ -7930,28 +8265,34 @@ calcsize(union node *n) | |||
7930 | case NAPPEND: | 8265 | case NAPPEND: |
7931 | calcsize(n->nfile.fname); | 8266 | calcsize(n->nfile.fname); |
7932 | calcsize(n->nfile.next); | 8267 | calcsize(n->nfile.next); |
8268 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
7933 | break; | 8269 | break; |
7934 | case NTOFD: | 8270 | case NTOFD: |
7935 | case NFROMFD: | 8271 | case NFROMFD: |
7936 | calcsize(n->ndup.vname); | 8272 | calcsize(n->ndup.vname); |
7937 | calcsize(n->ndup.next); | 8273 | calcsize(n->ndup.next); |
8274 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
7938 | break; | 8275 | break; |
7939 | case NHERE: | 8276 | case NHERE: |
7940 | case NXHERE: | 8277 | case NXHERE: |
7941 | calcsize(n->nhere.doc); | 8278 | calcsize(n->nhere.doc); |
7942 | calcsize(n->nhere.next); | 8279 | calcsize(n->nhere.next); |
8280 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
7943 | break; | 8281 | break; |
7944 | case NNOT: | 8282 | case NNOT: |
7945 | calcsize(n->nnot.com); | 8283 | calcsize(n->nnot.com); |
8284 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
7946 | break; | 8285 | break; |
7947 | }; | 8286 | }; |
7948 | } | 8287 | } |
7949 | 8288 | ||
7950 | static char * | 8289 | static char * |
7951 | nodeckstrdup(char *s) | 8290 | nodeckstrdup(const char *s) |
7952 | { | 8291 | { |
7953 | char *rtn = funcstring; | 8292 | char *rtn = funcstring; |
7954 | 8293 | ||
8294 | if (!s) | ||
8295 | return NULL; | ||
7955 | strcpy(funcstring, s); | 8296 | strcpy(funcstring, s); |
7956 | funcstring += strlen(s) + 1; | 8297 | funcstring += strlen(s) + 1; |
7957 | return rtn; | 8298 | return rtn; |
@@ -7959,6 +8300,18 @@ nodeckstrdup(char *s) | |||
7959 | 8300 | ||
7960 | static union node *copynode(union node *); | 8301 | static union node *copynode(union node *); |
7961 | 8302 | ||
8303 | #if ENABLE_PLATFORM_MINGW32 | ||
8304 | # define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (int)&(dst);} | ||
8305 | # define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);}} | ||
8306 | # define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);}} | ||
8307 | # define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);*nodeptr++ = (int)&(dst4);}} | ||
8308 | #else | ||
8309 | # define SAVE_PTR(dst) | ||
8310 | # define SAVE_PTR2(dst,dst2) | ||
8311 | # define SAVE_PTR3(dst,dst2,dst3) | ||
8312 | # define SAVE_PTR4(dst,dst2,dst3,dst4) | ||
8313 | #endif | ||
8314 | |||
7962 | static struct nodelist * | 8315 | static struct nodelist * |
7963 | copynodelist(struct nodelist *lp) | 8316 | copynodelist(struct nodelist *lp) |
7964 | { | 8317 | { |
@@ -7970,6 +8323,7 @@ copynodelist(struct nodelist *lp) | |||
7970 | *lpp = funcblock; | 8323 | *lpp = funcblock; |
7971 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); | 8324 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); |
7972 | (*lpp)->n = copynode(lp->n); | 8325 | (*lpp)->n = copynode(lp->n); |
8326 | SAVE_PTR2((*lpp)->n, (*lpp)->next); | ||
7973 | lp = lp->next; | 8327 | lp = lp->next; |
7974 | lpp = &(*lpp)->next; | 8328 | lpp = &(*lpp)->next; |
7975 | } | 8329 | } |
@@ -7992,16 +8346,19 @@ copynode(union node *n) | |||
7992 | new->ncmd.redirect = copynode(n->ncmd.redirect); | 8346 | new->ncmd.redirect = copynode(n->ncmd.redirect); |
7993 | new->ncmd.args = copynode(n->ncmd.args); | 8347 | new->ncmd.args = copynode(n->ncmd.args); |
7994 | new->ncmd.assign = copynode(n->ncmd.assign); | 8348 | new->ncmd.assign = copynode(n->ncmd.assign); |
8349 | SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign); | ||
7995 | break; | 8350 | break; |
7996 | case NPIPE: | 8351 | case NPIPE: |
7997 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | 8352 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); |
7998 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; | 8353 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; |
8354 | SAVE_PTR(new->npipe.cmdlist); | ||
7999 | break; | 8355 | break; |
8000 | case NREDIR: | 8356 | case NREDIR: |
8001 | case NBACKGND: | 8357 | case NBACKGND: |
8002 | case NSUBSHELL: | 8358 | case NSUBSHELL: |
8003 | new->nredir.redirect = copynode(n->nredir.redirect); | 8359 | new->nredir.redirect = copynode(n->nredir.redirect); |
8004 | new->nredir.n = copynode(n->nredir.n); | 8360 | new->nredir.n = copynode(n->nredir.n); |
8361 | SAVE_PTR2(new->nredir.redirect,new->nredir.n); | ||
8005 | break; | 8362 | break; |
8006 | case NAND: | 8363 | case NAND: |
8007 | case NOR: | 8364 | case NOR: |
@@ -8010,31 +8367,37 @@ copynode(union node *n) | |||
8010 | case NUNTIL: | 8367 | case NUNTIL: |
8011 | new->nbinary.ch2 = copynode(n->nbinary.ch2); | 8368 | new->nbinary.ch2 = copynode(n->nbinary.ch2); |
8012 | new->nbinary.ch1 = copynode(n->nbinary.ch1); | 8369 | new->nbinary.ch1 = copynode(n->nbinary.ch1); |
8370 | SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2); | ||
8013 | break; | 8371 | break; |
8014 | case NIF: | 8372 | case NIF: |
8015 | new->nif.elsepart = copynode(n->nif.elsepart); | 8373 | new->nif.elsepart = copynode(n->nif.elsepart); |
8016 | new->nif.ifpart = copynode(n->nif.ifpart); | 8374 | new->nif.ifpart = copynode(n->nif.ifpart); |
8017 | new->nif.test = copynode(n->nif.test); | 8375 | new->nif.test = copynode(n->nif.test); |
8376 | SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test); | ||
8018 | break; | 8377 | break; |
8019 | case NFOR: | 8378 | case NFOR: |
8020 | new->nfor.var = nodeckstrdup(n->nfor.var); | 8379 | new->nfor.var = nodeckstrdup(n->nfor.var); |
8021 | new->nfor.body = copynode(n->nfor.body); | 8380 | new->nfor.body = copynode(n->nfor.body); |
8022 | new->nfor.args = copynode(n->nfor.args); | 8381 | new->nfor.args = copynode(n->nfor.args); |
8382 | SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args); | ||
8023 | break; | 8383 | break; |
8024 | case NCASE: | 8384 | case NCASE: |
8025 | new->ncase.cases = copynode(n->ncase.cases); | 8385 | new->ncase.cases = copynode(n->ncase.cases); |
8026 | new->ncase.expr = copynode(n->ncase.expr); | 8386 | new->ncase.expr = copynode(n->ncase.expr); |
8387 | SAVE_PTR2(new->ncase.cases,new->ncase.expr); | ||
8027 | break; | 8388 | break; |
8028 | case NCLIST: | 8389 | case NCLIST: |
8029 | new->nclist.body = copynode(n->nclist.body); | 8390 | new->nclist.body = copynode(n->nclist.body); |
8030 | new->nclist.pattern = copynode(n->nclist.pattern); | 8391 | new->nclist.pattern = copynode(n->nclist.pattern); |
8031 | new->nclist.next = copynode(n->nclist.next); | 8392 | new->nclist.next = copynode(n->nclist.next); |
8393 | SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next); | ||
8032 | break; | 8394 | break; |
8033 | case NDEFUN: | 8395 | case NDEFUN: |
8034 | case NARG: | 8396 | case NARG: |
8035 | new->narg.backquote = copynodelist(n->narg.backquote); | 8397 | new->narg.backquote = copynodelist(n->narg.backquote); |
8036 | new->narg.text = nodeckstrdup(n->narg.text); | 8398 | new->narg.text = nodeckstrdup(n->narg.text); |
8037 | new->narg.next = copynode(n->narg.next); | 8399 | new->narg.next = copynode(n->narg.next); |
8400 | SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next); | ||
8038 | break; | 8401 | break; |
8039 | case NTO: | 8402 | case NTO: |
8040 | #if ENABLE_ASH_BASH_COMPAT | 8403 | #if ENABLE_ASH_BASH_COMPAT |
@@ -8047,6 +8410,7 @@ copynode(union node *n) | |||
8047 | new->nfile.fname = copynode(n->nfile.fname); | 8410 | new->nfile.fname = copynode(n->nfile.fname); |
8048 | new->nfile.fd = n->nfile.fd; | 8411 | new->nfile.fd = n->nfile.fd; |
8049 | new->nfile.next = copynode(n->nfile.next); | 8412 | new->nfile.next = copynode(n->nfile.next); |
8413 | SAVE_PTR2(new->nfile.fname,new->nfile.next); | ||
8050 | break; | 8414 | break; |
8051 | case NTOFD: | 8415 | case NTOFD: |
8052 | case NFROMFD: | 8416 | case NFROMFD: |
@@ -8054,15 +8418,18 @@ copynode(union node *n) | |||
8054 | new->ndup.dupfd = n->ndup.dupfd; | 8418 | new->ndup.dupfd = n->ndup.dupfd; |
8055 | new->ndup.fd = n->ndup.fd; | 8419 | new->ndup.fd = n->ndup.fd; |
8056 | new->ndup.next = copynode(n->ndup.next); | 8420 | new->ndup.next = copynode(n->ndup.next); |
8421 | SAVE_PTR2(new->ndup.vname,new->ndup.next); | ||
8057 | break; | 8422 | break; |
8058 | case NHERE: | 8423 | case NHERE: |
8059 | case NXHERE: | 8424 | case NXHERE: |
8060 | new->nhere.doc = copynode(n->nhere.doc); | 8425 | new->nhere.doc = copynode(n->nhere.doc); |
8061 | new->nhere.fd = n->nhere.fd; | 8426 | new->nhere.fd = n->nhere.fd; |
8062 | new->nhere.next = copynode(n->nhere.next); | 8427 | new->nhere.next = copynode(n->nhere.next); |
8428 | SAVE_PTR2(new->nhere.doc,new->nhere.next); | ||
8063 | break; | 8429 | break; |
8064 | case NNOT: | 8430 | case NNOT: |
8065 | new->nnot.com = copynode(n->nnot.com); | 8431 | new->nnot.com = copynode(n->nnot.com); |
8432 | SAVE_PTR(new->nnot.com); | ||
8066 | break; | 8433 | break; |
8067 | }; | 8434 | }; |
8068 | new->type = n->type; | 8435 | new->type = n->type; |
@@ -8085,6 +8452,7 @@ copyfunc(union node *n) | |||
8085 | f = ckmalloc(blocksize + funcstringsize); | 8452 | f = ckmalloc(blocksize + funcstringsize); |
8086 | funcblock = (char *) f + offsetof(struct funcnode, n); | 8453 | funcblock = (char *) f + offsetof(struct funcnode, n); |
8087 | funcstring = (char *) f + blocksize; | 8454 | funcstring = (char *) f + blocksize; |
8455 | IF_PLATFORM_MINGW32(nodeptr = NULL); | ||
8088 | copynode(n); | 8456 | copynode(n); |
8089 | f->count = 0; | 8457 | f->count = 0; |
8090 | return f; | 8458 | return f; |
@@ -8437,9 +8805,26 @@ evalcase(union node *n, int flags) | |||
8437 | /* | 8805 | /* |
8438 | * Kick off a subshell to evaluate a tree. | 8806 | * Kick off a subshell to evaluate a tree. |
8439 | */ | 8807 | */ |
8808 | #if ENABLE_PLATFORM_MINGW32 | ||
8809 | static void | ||
8810 | forkshell_evalsubshell(struct forkshell *fs) | ||
8811 | { | ||
8812 | union node *n = fs->n; | ||
8813 | int flags = fs->flags; | ||
8814 | |||
8815 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
8816 | INT_ON; | ||
8817 | flags |= EV_EXIT; | ||
8818 | expredir(n->nredir.redirect); | ||
8819 | redirect(n->nredir.redirect, 0); | ||
8820 | evaltreenr(n->nredir.n, flags); | ||
8821 | /* never returns */ | ||
8822 | } | ||
8823 | #endif | ||
8440 | static void | 8824 | static void |
8441 | evalsubshell(union node *n, int flags) | 8825 | evalsubshell(union node *n, int flags) |
8442 | { | 8826 | { |
8827 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
8443 | struct job *jp; | 8828 | struct job *jp; |
8444 | int backgnd = (n->type == NBACKGND); | 8829 | int backgnd = (n->type == NBACKGND); |
8445 | int status; | 8830 | int status; |
@@ -8449,6 +8834,14 @@ evalsubshell(union node *n, int flags) | |||
8449 | goto nofork; | 8834 | goto nofork; |
8450 | INT_OFF; | 8835 | INT_OFF; |
8451 | jp = makejob(/*n,*/ 1); | 8836 | jp = makejob(/*n,*/ 1); |
8837 | #if ENABLE_PLATFORM_MINGW32 | ||
8838 | memset(&fs, 0, sizeof(fs)); | ||
8839 | fs.fp = forkshell_evalsubshell; | ||
8840 | fs.n = n; | ||
8841 | fs.flags = flags; | ||
8842 | if (spawn_forkshell(jp, &fs, backgnd) < 0) | ||
8843 | ash_msg_and_raise_error("unable to spawn shell"); | ||
8844 | #endif | ||
8452 | if (forkshell(jp, n, backgnd) == 0) { | 8845 | if (forkshell(jp, n, backgnd) == 0) { |
8453 | /* child */ | 8846 | /* child */ |
8454 | INT_ON; | 8847 | INT_ON; |
@@ -8525,9 +8918,35 @@ expredir(union node *n) | |||
8525 | * of the shell, which make the last process in a pipeline the parent | 8918 | * of the shell, which make the last process in a pipeline the parent |
8526 | * of all the rest.) | 8919 | * of all the rest.) |
8527 | */ | 8920 | */ |
8921 | #if ENABLE_PLATFORM_MINGW32 | ||
8922 | static void | ||
8923 | forkshell_evalpipe(struct forkshell *fs) | ||
8924 | { | ||
8925 | union node *n = fs->n; | ||
8926 | int flags = fs->flags; | ||
8927 | int prevfd = fs->fd[2]; | ||
8928 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
8929 | |||
8930 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
8931 | INT_ON; | ||
8932 | if (pip[1] >= 0) { | ||
8933 | close(pip[0]); | ||
8934 | } | ||
8935 | if (prevfd > 0) { | ||
8936 | dup2(prevfd, 0); | ||
8937 | close(prevfd); | ||
8938 | } | ||
8939 | if (pip[1] > 1) { | ||
8940 | dup2(pip[1], 1); | ||
8941 | close(pip[1]); | ||
8942 | } | ||
8943 | evaltreenr(n, flags); | ||
8944 | } | ||
8945 | #endif | ||
8528 | static void | 8946 | static void |
8529 | evalpipe(union node *n, int flags) | 8947 | evalpipe(union node *n, int flags) |
8530 | { | 8948 | { |
8949 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
8531 | struct job *jp; | 8950 | struct job *jp; |
8532 | struct nodelist *lp; | 8951 | struct nodelist *lp; |
8533 | int pipelen; | 8952 | int pipelen; |
@@ -8551,6 +8970,17 @@ evalpipe(union node *n, int flags) | |||
8551 | ash_msg_and_raise_error("pipe call failed"); | 8970 | ash_msg_and_raise_error("pipe call failed"); |
8552 | } | 8971 | } |
8553 | } | 8972 | } |
8973 | #if ENABLE_PLATFORM_MINGW32 | ||
8974 | memset(&fs, 0, sizeof(fs)); | ||
8975 | fs.fp = forkshell_evalpipe; | ||
8976 | fs.flags = flags; | ||
8977 | fs.n = lp->n; | ||
8978 | fs.fd[0] = pip[0]; | ||
8979 | fs.fd[1] = pip[1]; | ||
8980 | fs.fd[2] = prevfd; | ||
8981 | if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0) | ||
8982 | ash_msg_and_raise_error("unable to spawn shell"); | ||
8983 | #endif | ||
8554 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { | 8984 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { |
8555 | INT_ON; | 8985 | INT_ON; |
8556 | if (pip[1] >= 0) { | 8986 | if (pip[1] >= 0) { |
@@ -9019,6 +9449,20 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
9019 | * as POSIX mandates */ | 9449 | * as POSIX mandates */ |
9020 | return back_exitstatus; | 9450 | return back_exitstatus; |
9021 | } | 9451 | } |
9452 | |||
9453 | #if ENABLE_PLATFORM_MINGW32 | ||
9454 | static void | ||
9455 | forkshell_shellexec(struct forkshell *fs) | ||
9456 | { | ||
9457 | int idx = fs->fd[0]; | ||
9458 | struct strlist *varlist = fs->strlist; | ||
9459 | char **argv = fs->argv; | ||
9460 | char *path = fs->string; | ||
9461 | |||
9462 | listsetvar(varlist, VEXPORT|VSTACK); | ||
9463 | shellexec(argv, path, idx); | ||
9464 | } | ||
9465 | #endif | ||
9022 | static void | 9466 | static void |
9023 | evalcommand(union node *cmd, int flags) | 9467 | evalcommand(union node *cmd, int flags) |
9024 | { | 9468 | { |
@@ -9195,6 +9639,26 @@ evalcommand(union node *cmd, int flags) | |||
9195 | } | 9639 | } |
9196 | } | 9640 | } |
9197 | #endif | 9641 | #endif |
9642 | #if ENABLE_PLATFORM_MINGW32 | ||
9643 | if (!(flags & EV_EXIT) || trap[0]) { | ||
9644 | struct forkshell fs; | ||
9645 | |||
9646 | memset(&fs, 0, sizeof(fs)); | ||
9647 | fs.fp = forkshell_shellexec; | ||
9648 | fs.argv = argv; | ||
9649 | fs.string = (char*)path; | ||
9650 | fs.fd[0] = cmdentry.u.index; | ||
9651 | fs.strlist = varlist.list; | ||
9652 | jp = makejob(/*cmd,*/ 1); | ||
9653 | if (spawn_forkshell(jp, &fs, FORK_FG) < 0) | ||
9654 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9655 | exitstatus = waitforjob(jp); | ||
9656 | INT_ON; | ||
9657 | TRACE(("forked child exited with %d\n", exitstatus)); | ||
9658 | break; | ||
9659 | } | ||
9660 | /* goes through to shellexec() */ | ||
9661 | #endif | ||
9198 | /* Fork off a child process if necessary. */ | 9662 | /* Fork off a child process if necessary. */ |
9199 | if (!(flags & EV_EXIT) || may_have_traps) { | 9663 | if (!(flags & EV_EXIT) || may_have_traps) { |
9200 | INT_OFF; | 9664 | INT_OFF; |
@@ -9578,7 +10042,7 @@ preadbuffer(void) | |||
9578 | more--; | 10042 | more--; |
9579 | 10043 | ||
9580 | c = *q; | 10044 | c = *q; |
9581 | if (c == '\0') { | 10045 | if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) { |
9582 | memmove(q, q + 1, more); | 10046 | memmove(q, q + 1, more); |
9583 | } else { | 10047 | } else { |
9584 | q++; | 10048 | q++; |
@@ -12005,7 +12469,7 @@ find_dot_file(char *name) | |||
12005 | struct stat statb; | 12469 | struct stat statb; |
12006 | 12470 | ||
12007 | /* don't try this for absolute or relative paths */ | 12471 | /* don't try this for absolute or relative paths */ |
12008 | if (strchr(name, '/')) | 12472 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) |
12009 | return name; | 12473 | return name; |
12010 | 12474 | ||
12011 | /* IIRC standards do not say whether . is to be searched. | 12475 | /* IIRC standards do not say whether . is to be searched. |
@@ -12115,10 +12579,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12115 | struct stat statb; | 12579 | struct stat statb; |
12116 | int e; | 12580 | int e; |
12117 | int updatetbl; | 12581 | int updatetbl; |
12582 | IF_PLATFORM_MINGW32(int len); | ||
12118 | struct builtincmd *bcmd; | 12583 | struct builtincmd *bcmd; |
12119 | 12584 | ||
12120 | /* If name contains a slash, don't use PATH or hash table */ | 12585 | /* If name contains a slash, don't use PATH or hash table */ |
12121 | if (strchr(name, '/') != NULL) { | 12586 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) { |
12122 | entry->u.index = -1; | 12587 | entry->u.index = -1; |
12123 | if (act & DO_ABS) { | 12588 | if (act & DO_ABS) { |
12124 | while (stat(name, &statb) < 0) { | 12589 | while (stat(name, &statb) < 0) { |
@@ -12225,12 +12690,39 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12225 | } | 12690 | } |
12226 | } | 12691 | } |
12227 | /* if rehash, don't redo absolute path names */ | 12692 | /* if rehash, don't redo absolute path names */ |
12228 | if (fullname[0] == '/' && idx <= prev) { | 12693 | if (is_absolute_path(fullname) && idx <= prev) { |
12229 | if (idx < prev) | 12694 | if (idx < prev) |
12230 | continue; | 12695 | continue; |
12231 | TRACE(("searchexec \"%s\": no change\n", name)); | 12696 | TRACE(("searchexec \"%s\": no change\n", name)); |
12232 | goto success; | 12697 | goto success; |
12233 | } | 12698 | } |
12699 | #if ENABLE_PLATFORM_MINGW32 | ||
12700 | len = strlen(fullname); | ||
12701 | if (len > 4 && | ||
12702 | (!strcasecmp(fullname+len-4, ".exe") || | ||
12703 | !strcasecmp(fullname+len-4, ".com"))) { | ||
12704 | if (stat(fullname, &statb) < 0) { | ||
12705 | if (errno != ENOENT && errno != ENOTDIR) | ||
12706 | e = errno; | ||
12707 | goto loop; | ||
12708 | } | ||
12709 | } | ||
12710 | else { | ||
12711 | /* path_advance() has reserved space for .exe */ | ||
12712 | memcpy(fullname+len, ".exe", 5); | ||
12713 | if (stat(fullname, &statb) < 0) { | ||
12714 | if (errno != ENOENT && errno != ENOTDIR) | ||
12715 | e = errno; | ||
12716 | memcpy(fullname+len, ".com", 5); | ||
12717 | if (stat(fullname, &statb) < 0) { | ||
12718 | if (errno != ENOENT && errno != ENOTDIR) | ||
12719 | e = errno; | ||
12720 | goto loop; | ||
12721 | } | ||
12722 | } | ||
12723 | fullname[len] = '\0'; | ||
12724 | } | ||
12725 | #else | ||
12234 | while (stat(fullname, &statb) < 0) { | 12726 | while (stat(fullname, &statb) < 0) { |
12235 | #ifdef SYSV | 12727 | #ifdef SYSV |
12236 | if (errno == EINTR) | 12728 | if (errno == EINTR) |
@@ -12240,6 +12732,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12240 | e = errno; | 12732 | e = errno; |
12241 | goto loop; | 12733 | goto loop; |
12242 | } | 12734 | } |
12735 | #endif | ||
12243 | e = EACCES; /* if we fail, this will be the error */ | 12736 | e = EACCES; /* if we fail, this will be the error */ |
12244 | if (!S_ISREG(statb.st_mode)) | 12737 | if (!S_ISREG(statb.st_mode)) |
12245 | continue; | 12738 | continue; |
@@ -12491,6 +12984,8 @@ unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12491 | 12984 | ||
12492 | /* setmode.c */ | 12985 | /* setmode.c */ |
12493 | 12986 | ||
12987 | #if !ENABLE_PLATFORM_MINGW32 | ||
12988 | |||
12494 | #include <sys/times.h> | 12989 | #include <sys/times.h> |
12495 | 12990 | ||
12496 | static const unsigned char timescmd_str[] ALIGN1 = { | 12991 | static const unsigned char timescmd_str[] ALIGN1 = { |
@@ -12523,6 +13018,13 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12523 | 13018 | ||
12524 | return 0; | 13019 | return 0; |
12525 | } | 13020 | } |
13021 | #else | ||
13022 | static int FAST_FUNC | ||
13023 | timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | ||
13024 | { | ||
13025 | return 0; | ||
13026 | } | ||
13027 | #endif | ||
12526 | 13028 | ||
12527 | #if ENABLE_SH_MATH_SUPPORT | 13029 | #if ENABLE_SH_MATH_SUPPORT |
12528 | /* | 13030 | /* |
@@ -12760,13 +13262,41 @@ init(void) | |||
12760 | struct stat st1, st2; | 13262 | struct stat st1, st2; |
12761 | 13263 | ||
12762 | initvar(); | 13264 | initvar(); |
13265 | |||
13266 | #if ENABLE_PLATFORM_MINGW32 | ||
13267 | /* | ||
13268 | * case insensitive env names from Windows world | ||
13269 | * | ||
13270 | * Some standard env names such as PATH is named Path and so on | ||
13271 | * ash itself is case sensitive, so "Path" will confuse it, as | ||
13272 | * MSVC getenv() is case insensitive. | ||
13273 | * | ||
13274 | * We may end up having both Path and PATH. Then Path will be chosen | ||
13275 | * because it appears first. | ||
13276 | */ | ||
13277 | for (envp = environ; envp && *envp; envp++) | ||
13278 | if (!strncasecmp(*envp, "PATH=", 5) && | ||
13279 | strncmp(*envp, "PATH=", 5)) | ||
13280 | break; | ||
13281 | if (envp && *envp) { | ||
13282 | char *start, *end; | ||
13283 | for (envp = environ; envp && *envp; envp++) { | ||
13284 | end = strchr(*envp, '='); | ||
13285 | if (!end) | ||
13286 | continue; | ||
13287 | for (start = *envp;start < end;start++) | ||
13288 | *start = toupper(*start); | ||
13289 | } | ||
13290 | } | ||
13291 | #endif | ||
12763 | for (envp = environ; envp && *envp; envp++) { | 13292 | for (envp = environ; envp && *envp; envp++) { |
12764 | if (strchr(*envp, '=')) { | 13293 | if (strchr(*envp, '=')) { |
12765 | setvareq(*envp, VEXPORT|VTEXTFIXED); | 13294 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
12766 | } | 13295 | } |
12767 | } | 13296 | } |
12768 | 13297 | ||
12769 | setvar("PPID", utoa(getppid()), 0); | 13298 | if (!ENABLE_PLATFORM_MINGW32) |
13299 | setvar("PPID", utoa(getppid()), 0); | ||
12770 | 13300 | ||
12771 | p = lookupvar("PWD"); | 13301 | p = lookupvar("PWD"); |
12772 | if (p) | 13302 | if (p) |
@@ -12882,6 +13412,20 @@ static short profile_buf[16384]; | |||
12882 | extern int etext(); | 13412 | extern int etext(); |
12883 | #endif | 13413 | #endif |
12884 | 13414 | ||
13415 | #if ENABLE_PLATFORM_MINGW32 | ||
13416 | static const forkpoint_fn forkpoints[] = { | ||
13417 | forkshell_openhere, | ||
13418 | forkshell_evalbackcmd, | ||
13419 | forkshell_evalsubshell, | ||
13420 | forkshell_evalpipe, | ||
13421 | forkshell_shellexec, | ||
13422 | NULL | ||
13423 | }; | ||
13424 | |||
13425 | static struct forkshell* forkshell_prepare(struct forkshell *fs); | ||
13426 | static void forkshell_init(const char *idstr); | ||
13427 | #endif | ||
13428 | |||
12885 | /* | 13429 | /* |
12886 | * Main routine. We initialize things, parse the arguments, execute | 13430 | * Main routine. We initialize things, parse the arguments, execute |
12887 | * profiles if we're a login shell, and then call cmdloop to execute | 13431 | * profiles if we're a login shell, and then call cmdloop to execute |
@@ -12949,6 +13493,15 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
12949 | 13493 | ||
12950 | init(); | 13494 | init(); |
12951 | setstackmark(&smark); | 13495 | setstackmark(&smark); |
13496 | |||
13497 | #if ENABLE_PLATFORM_MINGW32 | ||
13498 | if (argc == 3 && !strcmp(argv[1], "--forkshell")) { | ||
13499 | forkshell_init(argv[2]); | ||
13500 | |||
13501 | /* NOTREACHED */ | ||
13502 | bb_error_msg_and_die("subshell ended unexpectedly"); | ||
13503 | } | ||
13504 | #endif | ||
12952 | procargs(argv); | 13505 | procargs(argv); |
12953 | 13506 | ||
12954 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 13507 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY |
@@ -13023,6 +13576,524 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13023 | /* NOTREACHED */ | 13576 | /* NOTREACHED */ |
13024 | } | 13577 | } |
13025 | 13578 | ||
13579 | /* FIXME: should consider running forkparent() and forkchild() */ | ||
13580 | static int | ||
13581 | spawn_forkshell(struct job *jp, struct forkshell *fs, int mode) | ||
13582 | { | ||
13583 | const char *argv[] = { "sh", "--forkshell", NULL, NULL }; | ||
13584 | char buf[16]; | ||
13585 | |||
13586 | struct forkshell *new; | ||
13587 | new = forkshell_prepare(fs); | ||
13588 | sprintf(buf, "%x", (unsigned int)new->hMapFile); | ||
13589 | argv[2] = buf; | ||
13590 | fs->pid = mingw_spawn_applet(P_NOWAIT, "sh", argv, | ||
13591 | (const char *const *)environ); | ||
13592 | CloseHandle(new->hMapFile); | ||
13593 | UnmapViewOfFile(new); | ||
13594 | if (fs->pid == -1) { | ||
13595 | free(jp); | ||
13596 | return -1; | ||
13597 | } | ||
13598 | forkparent(jp, fs->node, mode, fs->pid); | ||
13599 | return fs->pid; | ||
13600 | } | ||
13601 | |||
13602 | /* | ||
13603 | * forkshell_prepare() and friends | ||
13604 | * | ||
13605 | * The sequence is as follows: | ||
13606 | * - funcblocksize, funcstringsize, nodeptrsize are initialized | ||
13607 | * - forkshell_size(fs) is called to calculate the exact memory needed | ||
13608 | * - a new struct is allocated | ||
13609 | * - funcblock, funcstring, nodeptr are initialized from the new block | ||
13610 | * - forkshell_copy(fs) is called to copy recursively everything over | ||
13611 | * it will record all pointers along the way, to nodeptr | ||
13612 | * | ||
13613 | * When this memory is mapped elsewhere, pointer fixup will be needed | ||
13614 | */ | ||
13615 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
13616 | static void \ | ||
13617 | name(type *p) \ | ||
13618 | { \ | ||
13619 | while (p) { \ | ||
13620 | funcblocksize += sizeof(type); | ||
13621 | /* do something here with p */ | ||
13622 | #define SLIST_SIZE_END() \ | ||
13623 | nodeptrsize++; \ | ||
13624 | p = p->next; \ | ||
13625 | } \ | ||
13626 | } | ||
13627 | |||
13628 | #define SLIST_COPY_BEGIN(name,type) \ | ||
13629 | static type * \ | ||
13630 | name(type *vp) \ | ||
13631 | { \ | ||
13632 | type *start; \ | ||
13633 | type **vpp; \ | ||
13634 | vpp = &start; \ | ||
13635 | while (vp) { \ | ||
13636 | *vpp = funcblock; \ | ||
13637 | funcblock = (char *) funcblock + sizeof(type); | ||
13638 | /* do something here with vpp and vp */ | ||
13639 | #define SLIST_COPY_END() \ | ||
13640 | SAVE_PTR((*vpp)->next); \ | ||
13641 | vp = vp->next; \ | ||
13642 | vpp = &(*vpp)->next; \ | ||
13643 | } \ | ||
13644 | *vpp = NULL; \ | ||
13645 | return start; \ | ||
13646 | } | ||
13647 | |||
13648 | /* | ||
13649 | * struct var | ||
13650 | */ | ||
13651 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
13652 | funcstringsize += strlen(p->text) + 1; | ||
13653 | nodeptrsize++; /* p->text */ | ||
13654 | SLIST_SIZE_END() | ||
13655 | |||
13656 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
13657 | (*vpp)->text = nodeckstrdup(vp->text); | ||
13658 | (*vpp)->flags = vp->flags; | ||
13659 | /* | ||
13660 | * The only place that can set struct var#func is varinit[], | ||
13661 | * which will be fixed by forkshell_init() | ||
13662 | */ | ||
13663 | (*vpp)->func = NULL; | ||
13664 | SAVE_PTR((*vpp)->text); | ||
13665 | SLIST_COPY_END() | ||
13666 | |||
13667 | /* | ||
13668 | * struct localvar | ||
13669 | */ | ||
13670 | SLIST_SIZE_BEGIN(localvar_size,struct localvar) | ||
13671 | var_size(p->vp); | ||
13672 | funcstringsize += strlen(p->text) + 1; | ||
13673 | nodeptrsize += 2; /* p->vp, p->text */ | ||
13674 | SLIST_SIZE_END() | ||
13675 | |||
13676 | SLIST_COPY_BEGIN(localvar_copy,struct localvar) | ||
13677 | (*vpp)->text = nodeckstrdup(vp->text); | ||
13678 | (*vpp)->flags = vp->flags; | ||
13679 | (*vpp)->vp = var_copy(vp->vp); | ||
13680 | SAVE_PTR2((*vpp)->vp, (*vpp)->text); | ||
13681 | SLIST_COPY_END() | ||
13682 | |||
13683 | /* | ||
13684 | * struct strlist | ||
13685 | */ | ||
13686 | SLIST_SIZE_BEGIN(strlist_size,struct strlist) | ||
13687 | funcstringsize += strlen(p->text) + 1; | ||
13688 | nodeptrsize++; /* p->text */ | ||
13689 | SLIST_SIZE_END() | ||
13690 | |||
13691 | SLIST_COPY_BEGIN(strlist_copy,struct strlist) | ||
13692 | (*vpp)->text = nodeckstrdup(vp->text); | ||
13693 | SAVE_PTR((*vpp)->text); | ||
13694 | SLIST_COPY_END() | ||
13695 | |||
13696 | /* | ||
13697 | * struct tblentry | ||
13698 | */ | ||
13699 | static void | ||
13700 | tblentry_size(struct tblentry *tep) | ||
13701 | { | ||
13702 | while (tep) { | ||
13703 | funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
13704 | /* CMDBUILTIN, e->param.cmd needs no pointer relocation */ | ||
13705 | if (tep->cmdtype == CMDFUNCTION) { | ||
13706 | funcblocksize += offsetof(struct funcnode, n); | ||
13707 | calcsize(&tep->param.func->n); | ||
13708 | nodeptrsize++; /* tep->param.func */ | ||
13709 | } | ||
13710 | nodeptrsize++; /* tep->next */ | ||
13711 | tep = tep->next; | ||
13712 | } | ||
13713 | } | ||
13714 | |||
13715 | static struct tblentry * | ||
13716 | tblentry_copy(struct tblentry *tep) | ||
13717 | { | ||
13718 | struct tblentry *start; | ||
13719 | struct tblentry **newp; | ||
13720 | int size; | ||
13721 | |||
13722 | newp = &start; | ||
13723 | while (tep) { | ||
13724 | *newp = funcblock; | ||
13725 | size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
13726 | |||
13727 | funcblock = (char *) funcblock + size; | ||
13728 | memcpy(*newp, tep, size); | ||
13729 | switch (tep->cmdtype) { | ||
13730 | case CMDBUILTIN: | ||
13731 | /* No pointer saving, this field must be fixed by forkshell_init() */ | ||
13732 | (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab); | ||
13733 | break; | ||
13734 | case CMDFUNCTION: | ||
13735 | (*newp)->param.func = funcblock; | ||
13736 | funcblock = (char *) funcblock + offsetof(struct funcnode, n); | ||
13737 | copynode(&tep->param.func->n); | ||
13738 | SAVE_PTR((*newp)->param.func); | ||
13739 | break; | ||
13740 | default: | ||
13741 | break; | ||
13742 | } | ||
13743 | SAVE_PTR((*newp)->next); | ||
13744 | tep = tep->next; | ||
13745 | newp = &(*newp)->next; | ||
13746 | } | ||
13747 | *newp = NULL; | ||
13748 | return start; | ||
13749 | } | ||
13750 | |||
13751 | static void | ||
13752 | cmdtable_size(struct tblentry **cmdtablep) | ||
13753 | { | ||
13754 | int i; | ||
13755 | nodeptrsize += CMDTABLESIZE; | ||
13756 | funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE; | ||
13757 | for (i = 0; i < CMDTABLESIZE; i++) | ||
13758 | tblentry_size(cmdtablep[i]); | ||
13759 | } | ||
13760 | |||
13761 | static struct tblentry ** | ||
13762 | cmdtable_copy(struct tblentry **cmdtablep) | ||
13763 | { | ||
13764 | struct tblentry **new = funcblock; | ||
13765 | int i; | ||
13766 | |||
13767 | funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE; | ||
13768 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
13769 | new[i] = tblentry_copy(cmdtablep[i]); | ||
13770 | SAVE_PTR(new[i]); | ||
13771 | } | ||
13772 | return new; | ||
13773 | } | ||
13774 | |||
13775 | /* | ||
13776 | * char ** | ||
13777 | */ | ||
13778 | static void | ||
13779 | argv_size(char **p) | ||
13780 | { | ||
13781 | while (p && *p) { | ||
13782 | funcblocksize += sizeof(char *); | ||
13783 | funcstringsize += strlen(*p)+1; | ||
13784 | nodeptrsize++; | ||
13785 | p++; | ||
13786 | } | ||
13787 | funcblocksize += sizeof(char *); | ||
13788 | } | ||
13789 | |||
13790 | static char ** | ||
13791 | argv_copy(char **p) | ||
13792 | { | ||
13793 | char **new, **start = funcblock; | ||
13794 | |||
13795 | while (p && *p) { | ||
13796 | new = funcblock; | ||
13797 | funcblock = (char *) funcblock + sizeof(char *); | ||
13798 | *new = nodeckstrdup(*p); | ||
13799 | SAVE_PTR(*new); | ||
13800 | p++; | ||
13801 | new++; | ||
13802 | } | ||
13803 | new = funcblock; | ||
13804 | funcblock = (char *) funcblock + sizeof(char *); | ||
13805 | *new = NULL; | ||
13806 | return start; | ||
13807 | } | ||
13808 | |||
13809 | /* | ||
13810 | * struct redirtab | ||
13811 | */ | ||
13812 | static void | ||
13813 | redirtab_size(struct redirtab *rdtp) | ||
13814 | { | ||
13815 | while (rdtp) { | ||
13816 | funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
13817 | rdtp = rdtp->next; | ||
13818 | nodeptrsize++; /* rdtp->next */ | ||
13819 | } | ||
13820 | } | ||
13821 | |||
13822 | static struct redirtab * | ||
13823 | redirtab_copy(struct redirtab *rdtp) | ||
13824 | { | ||
13825 | struct redirtab *start; | ||
13826 | struct redirtab **vpp; | ||
13827 | |||
13828 | vpp = &start; | ||
13829 | while (rdtp) { | ||
13830 | int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
13831 | *vpp = funcblock; | ||
13832 | funcblock = (char *) funcblock + size; | ||
13833 | memcpy(*vpp, rdtp, size); | ||
13834 | SAVE_PTR((*vpp)->next); | ||
13835 | rdtp = rdtp->next; | ||
13836 | vpp = &(*vpp)->next; | ||
13837 | } | ||
13838 | *vpp = NULL; | ||
13839 | return start; | ||
13840 | } | ||
13841 | |||
13842 | #undef shellparam | ||
13843 | #undef redirlist | ||
13844 | #undef varinit | ||
13845 | #undef vartab | ||
13846 | static void | ||
13847 | globals_var_size(struct globals_var *gvp) | ||
13848 | { | ||
13849 | int i; | ||
13850 | |||
13851 | funcblocksize += sizeof(struct globals_var); | ||
13852 | argv_size(gvp->shellparam.p); | ||
13853 | redirtab_size(gvp->redirlist); | ||
13854 | for (i = 0; i < VTABSIZE; i++) | ||
13855 | var_size(gvp->vartab[i]); | ||
13856 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
13857 | var_size(gvp->varinit+i); | ||
13858 | nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */ | ||
13859 | } | ||
13860 | |||
13861 | #undef g_nullredirs | ||
13862 | #undef preverrout_fd | ||
13863 | static struct globals_var * | ||
13864 | globals_var_copy(struct globals_var *gvp) | ||
13865 | { | ||
13866 | int i; | ||
13867 | struct globals_var *new; | ||
13868 | |||
13869 | new = funcblock; | ||
13870 | funcblock = (char *) funcblock + sizeof(struct globals_var); | ||
13871 | |||
13872 | /* shparam */ | ||
13873 | memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam)); | ||
13874 | new->shellparam.malloced = 0; | ||
13875 | new->shellparam.p = argv_copy(gvp->shellparam.p); | ||
13876 | SAVE_PTR(new->shellparam.p); | ||
13877 | |||
13878 | new->redirlist = redirtab_copy(gvp->redirlist); | ||
13879 | SAVE_PTR(new->redirlist); | ||
13880 | |||
13881 | new->g_nullredirs = gvp->g_nullredirs; | ||
13882 | new->preverrout_fd = gvp->preverrout_fd; | ||
13883 | for (i = 0; i < VTABSIZE; i++) { | ||
13884 | new->vartab[i] = var_copy(gvp->vartab[i]); | ||
13885 | SAVE_PTR(new->vartab[i]); | ||
13886 | } | ||
13887 | |||
13888 | /* Can't use var_copy because varinit is already allocated */ | ||
13889 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { | ||
13890 | new->varinit[i].next = NULL; | ||
13891 | new->varinit[i].text = nodeckstrdup(gvp->varinit[i].text); | ||
13892 | SAVE_PTR(new->varinit[i].text); | ||
13893 | new->varinit[i].flags = gvp->varinit[i].flags; | ||
13894 | new->varinit[i].func = gvp->varinit[i].func; | ||
13895 | } | ||
13896 | return new; | ||
13897 | } | ||
13898 | |||
13899 | #undef minusc | ||
13900 | #undef curdir | ||
13901 | #undef physdir | ||
13902 | #undef arg0 | ||
13903 | #undef nullstr | ||
13904 | static void | ||
13905 | globals_misc_size(struct globals_misc *p) | ||
13906 | { | ||
13907 | funcblocksize += sizeof(struct globals_misc); | ||
13908 | funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1; | ||
13909 | if (p->curdir != p->nullstr) | ||
13910 | funcstringsize += strlen(p->curdir) + 1; | ||
13911 | if (p->physdir != p->nullstr) | ||
13912 | funcstringsize += strlen(p->physdir) + 1; | ||
13913 | funcstringsize += strlen(p->arg0) + 1; | ||
13914 | nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */ | ||
13915 | } | ||
13916 | |||
13917 | static struct globals_misc * | ||
13918 | globals_misc_copy(struct globals_misc *p) | ||
13919 | { | ||
13920 | struct globals_misc *new = funcblock; | ||
13921 | |||
13922 | funcblock = (char *) funcblock + sizeof(struct globals_misc); | ||
13923 | memcpy(new, p, sizeof(struct globals_misc)); | ||
13924 | |||
13925 | new->minusc = nodeckstrdup(p->minusc); | ||
13926 | new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr; | ||
13927 | new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr; | ||
13928 | new->arg0 = nodeckstrdup(p->arg0); | ||
13929 | SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0); | ||
13930 | return new; | ||
13931 | } | ||
13932 | |||
13933 | static void | ||
13934 | forkshell_size(struct forkshell *fs) | ||
13935 | { | ||
13936 | funcblocksize += sizeof(struct forkshell); | ||
13937 | globals_var_size(fs->gvp); | ||
13938 | globals_misc_size(fs->gmp); | ||
13939 | cmdtable_size(fs->cmdtable); | ||
13940 | localvar_size(fs->localvars); | ||
13941 | /* optlist_transfer(sending, fd); */ | ||
13942 | /* misc_transfer(sending, fd); */ | ||
13943 | |||
13944 | calcsize(fs->n); | ||
13945 | argv_size(fs->argv); | ||
13946 | funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1; | ||
13947 | strlist_size(fs->strlist); | ||
13948 | |||
13949 | nodeptrsize += 8; /* gvp, gmp, cmdtable, localvars, n, argv, string, strlist */ | ||
13950 | } | ||
13951 | |||
13952 | static struct forkshell * | ||
13953 | forkshell_copy(struct forkshell *fs) | ||
13954 | { | ||
13955 | struct forkshell *new; | ||
13956 | |||
13957 | new = funcblock; | ||
13958 | funcblock = (char *) funcblock + sizeof(struct forkshell); | ||
13959 | |||
13960 | memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */ | ||
13961 | new->gvp = globals_var_copy(fs->gvp); | ||
13962 | new->gmp = globals_misc_copy(fs->gmp); | ||
13963 | new->cmdtable = cmdtable_copy(fs->cmdtable); | ||
13964 | new->localvars = localvar_copy(fs->localvars); | ||
13965 | SAVE_PTR4(new->gvp, new->gmp, new->cmdtable, new->localvars); | ||
13966 | |||
13967 | /* new->fs will be reconstructed from new->fpid */ | ||
13968 | new->n = copynode(fs->n); | ||
13969 | new->argv = argv_copy(fs->argv); | ||
13970 | new->string = nodeckstrdup(fs->string); | ||
13971 | new->strlist = strlist_copy(fs->strlist); | ||
13972 | SAVE_PTR4(new->n, new->argv, new->string, new->strlist); | ||
13973 | return new; | ||
13974 | } | ||
13975 | |||
13976 | static struct forkshell * | ||
13977 | forkshell_prepare(struct forkshell *fs) | ||
13978 | { | ||
13979 | struct forkshell *new; | ||
13980 | int size, fp, nodeptr_offset; | ||
13981 | HANDLE h; | ||
13982 | SECURITY_ATTRIBUTES sa; | ||
13983 | |||
13984 | for (fp = 0; forkpoints[fp] && forkpoints[fp] != fs->fp; fp++) | ||
13985 | ; | ||
13986 | |||
13987 | if (!forkpoints[fp]) | ||
13988 | bb_error_msg_and_die("invalid forkpoint %08x", (int)fs->fp); | ||
13989 | fs->fpid = fp; | ||
13990 | |||
13991 | /* Calculate size of "new" */ | ||
13992 | fs->gvp = ash_ptr_to_globals_var; | ||
13993 | fs->gmp = ash_ptr_to_globals_misc; | ||
13994 | fs->cmdtable = cmdtable; | ||
13995 | fs->localvars = localvars; | ||
13996 | |||
13997 | nodeptrsize = 1; /* NULL terminated */ | ||
13998 | funcblocksize = 0; | ||
13999 | funcstringsize = 0; | ||
14000 | forkshell_size(fs); | ||
14001 | size = funcblocksize + funcstringsize + nodeptrsize*sizeof(int); | ||
14002 | |||
14003 | /* Allocate, initialize pointers */ | ||
14004 | memset(&sa, 0, sizeof(sa)); | ||
14005 | sa.nLength = sizeof(sa); | ||
14006 | sa.lpSecurityDescriptor = NULL; | ||
14007 | sa.bInheritHandle = TRUE; | ||
14008 | h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL); | ||
14009 | new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
14010 | /* new = ckmalloc(size); */ | ||
14011 | funcblock = new; | ||
14012 | funcstring = (char *) funcblock + funcblocksize; | ||
14013 | nodeptr = (int*)((char *) funcstring + funcstringsize); | ||
14014 | nodeptr_offset = (int) nodeptr - (int) new; | ||
14015 | |||
14016 | /* Now pack them all */ | ||
14017 | forkshell_copy(fs); | ||
14018 | |||
14019 | /* Finish it up */ | ||
14020 | *nodeptr = 0; | ||
14021 | new->size = size; | ||
14022 | new->nodeptr_offset = nodeptr_offset; | ||
14023 | new->old_base = new; | ||
14024 | new->hMapFile = h; | ||
14025 | return new; | ||
14026 | } | ||
14027 | |||
14028 | #undef exception_handler | ||
14029 | #undef trap | ||
14030 | #undef trap_ptr | ||
14031 | static void *sticky_mem_start, *sticky_mem_end; | ||
14032 | static void | ||
14033 | forkshell_init(const char *idstr) | ||
14034 | { | ||
14035 | struct forkshell *fs; | ||
14036 | int map_handle; | ||
14037 | HANDLE h; | ||
14038 | struct globals_var **gvpp; | ||
14039 | struct globals_misc **gmpp; | ||
14040 | int i; | ||
14041 | |||
14042 | if (sscanf(idstr, "%x", &map_handle) != 1) | ||
14043 | bb_error_msg_and_die("invalid forkshell ID"); | ||
14044 | |||
14045 | h = (HANDLE)map_handle; | ||
14046 | fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
14047 | if (!fs) | ||
14048 | bb_error_msg_and_die("Invalid forkshell memory"); | ||
14049 | |||
14050 | /* this memory can't be freed */ | ||
14051 | sticky_mem_start = fs; | ||
14052 | sticky_mem_end = (char *) fs + fs->size; | ||
14053 | /* pointer fixup */ | ||
14054 | nodeptr = (int*)((char*)fs + fs->nodeptr_offset); | ||
14055 | while (*nodeptr) { | ||
14056 | int *ptr = (int*)((char*)fs + (*nodeptr - (int)fs->old_base)); | ||
14057 | if (*ptr) | ||
14058 | *ptr -= ((int)fs->old_base - (int)fs); | ||
14059 | nodeptr++; | ||
14060 | } | ||
14061 | /* Now fix up stuff that can't be transferred */ | ||
14062 | fs->fp = forkpoints[fs->fpid]; | ||
14063 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
14064 | fs->gvp->varinit[i].func = varinit_data[i].func; | ||
14065 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
14066 | struct tblentry *e = fs->cmdtable[i]; | ||
14067 | while (e) { | ||
14068 | if (e->cmdtype == CMDBUILTIN) | ||
14069 | e->param.cmd = builtintab + (int)e->param.cmd; | ||
14070 | e = e->next; | ||
14071 | } | ||
14072 | } | ||
14073 | fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler; | ||
14074 | for (i = 0; i < NSIG; i++) | ||
14075 | fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i]; | ||
14076 | fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr; | ||
14077 | |||
14078 | /* Switch global variables */ | ||
14079 | gvpp = (struct globals_var **)&ash_ptr_to_globals_var; | ||
14080 | *gvpp = fs->gvp; | ||
14081 | gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc; | ||
14082 | *gmpp = fs->gmp; | ||
14083 | localvars = fs->localvars; | ||
14084 | cmdtable = fs->cmdtable; | ||
14085 | |||
14086 | fs->fp(fs); | ||
14087 | } | ||
14088 | |||
14089 | #undef free | ||
14090 | static void | ||
14091 | sticky_free(void *base) | ||
14092 | { | ||
14093 | if (base >= sticky_mem_start && base < sticky_mem_end) | ||
14094 | return; | ||
14095 | free(base); | ||
14096 | } | ||
13026 | 14097 | ||
13027 | /*- | 14098 | /*- |
13028 | * Copyright (c) 1989, 1991, 1993, 1994 | 14099 | * Copyright (c) 1989, 1991, 1993, 1994 |