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