aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c1099
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
97struct forkshell;
98union node;
99struct strlist;
100struct job;
101
102typedef void (*forkpoint_fn)(struct forkshell *fs);
103struct 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};
127static void sticky_free(void *p);
128#define free(p) sticky_free(p)
129static 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
774opentrace(void) 823opentrace(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)
2380static const char * 2441static const char *
2381updatepwd(const char *dir) 2442updatepwd(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 */
3944static pid_t
3945waitpid_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
3783static int 3986static int
3784dowait(int wait_flags, struct job *job) 3987dowait(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
4660forkparent(struct job *jp, union node *n, int mode, pid_t pid) 4872forkparent(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 */
4898static void expandhere(union node *arg, int fd); 5113static void expandhere(union node *arg, int fd);
5114#if ENABLE_PLATFORM_MINGW32
5115static void
5116forkshell_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
4899static int 5141static int
4900openhere(union node *redir) 5142openhere(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 */
5663static void evaltree(union node *, int); 5956static void evaltree(union node *, int);
5664 5957
5958#if ENABLE_PLATFORM_MINGW32
5959static void
5960forkshell_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
5665static void FAST_FUNC 5977static void FAST_FUNC
5666evalbackcmd(union node *n, struct backcmd *result) 5978evalbackcmd(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 */
7816static int funcstringsize; /* size of strings in node */ 8137static int funcstringsize; /* size of strings in node */
7817static void *funcblock; /* block to allocate function from */ 8138static void *funcblock; /* block to allocate function from */
7818static char *funcstring; /* block to allocate strings from */ 8139static char *funcstring; /* block to allocate strings from */
8140#if ENABLE_PLATFORM_MINGW32
8141static int nodeptrsize;
8142static 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
7950static char * 8289static char *
7951nodeckstrdup(char *s) 8290nodeckstrdup(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
7960static union node *copynode(union node *); 8301static 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
7962static struct nodelist * 8315static struct nodelist *
7963copynodelist(struct nodelist *lp) 8316copynodelist(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
8809static void
8810forkshell_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
8440static void 8824static void
8441evalsubshell(union node *n, int flags) 8825evalsubshell(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
8922static void
8923forkshell_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
8528static void 8946static void
8529evalpipe(union node *n, int flags) 8947evalpipe(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
9454static void
9455forkshell_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
9022static void 9466static void
9023evalcommand(union node *cmd, int flags) 9467evalcommand(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
12496static const unsigned char timescmd_str[] ALIGN1 = { 12991static 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
13022static int FAST_FUNC
13023timescmd(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];
12882extern int etext(); 13412extern int etext();
12883#endif 13413#endif
12884 13414
13415#if ENABLE_PLATFORM_MINGW32
13416static const forkpoint_fn forkpoints[] = {
13417 forkshell_openhere,
13418 forkshell_evalbackcmd,
13419 forkshell_evalsubshell,
13420 forkshell_evalpipe,
13421 forkshell_shellexec,
13422 NULL
13423};
13424
13425static struct forkshell* forkshell_prepare(struct forkshell *fs);
13426static 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() */
13580static int
13581spawn_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) \
13616static void \
13617name(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) \
13629static type * \
13630name(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 */
13651SLIST_SIZE_BEGIN(var_size,struct var)
13652funcstringsize += strlen(p->text) + 1;
13653nodeptrsize++; /* p->text */
13654SLIST_SIZE_END()
13655
13656SLIST_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;
13664SAVE_PTR((*vpp)->text);
13665SLIST_COPY_END()
13666
13667/*
13668 * struct localvar
13669 */
13670SLIST_SIZE_BEGIN(localvar_size,struct localvar)
13671var_size(p->vp);
13672funcstringsize += strlen(p->text) + 1;
13673nodeptrsize += 2; /* p->vp, p->text */
13674SLIST_SIZE_END()
13675
13676SLIST_COPY_BEGIN(localvar_copy,struct localvar)
13677(*vpp)->text = nodeckstrdup(vp->text);
13678(*vpp)->flags = vp->flags;
13679(*vpp)->vp = var_copy(vp->vp);
13680SAVE_PTR2((*vpp)->vp, (*vpp)->text);
13681SLIST_COPY_END()
13682
13683/*
13684 * struct strlist
13685 */
13686SLIST_SIZE_BEGIN(strlist_size,struct strlist)
13687funcstringsize += strlen(p->text) + 1;
13688nodeptrsize++; /* p->text */
13689SLIST_SIZE_END()
13690
13691SLIST_COPY_BEGIN(strlist_copy,struct strlist)
13692(*vpp)->text = nodeckstrdup(vp->text);
13693SAVE_PTR((*vpp)->text);
13694SLIST_COPY_END()
13695
13696/*
13697 * struct tblentry
13698 */
13699static void
13700tblentry_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
13715static struct tblentry *
13716tblentry_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
13751static void
13752cmdtable_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
13761static struct tblentry **
13762cmdtable_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 */
13778static void
13779argv_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
13790static char **
13791argv_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 */
13812static void
13813redirtab_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
13822static struct redirtab *
13823redirtab_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
13846static void
13847globals_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
13863static struct globals_var *
13864globals_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
13904static void
13905globals_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
13917static struct globals_misc *
13918globals_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
13933static void
13934forkshell_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
13952static struct forkshell *
13953forkshell_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
13976static struct forkshell *
13977forkshell_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
14031static void *sticky_mem_start, *sticky_mem_end;
14032static void
14033forkshell_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
14090static void
14091sticky_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