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