aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c1165
-rw-r--r--shell/shell_common.c12
2 files changed, 1164 insertions, 13 deletions
diff --git a/shell/ash.c b/shell/ash.c
index edcb7c028..369bb5bb9 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -17,6 +17,20 @@
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" extension is still understood as executable
25 * - shell scripts on the path are detected by the presence of '#!';
26 * the path to the interpreter is ignored, PATH is searched to find it
27 * - both / and \ are supported in PATH. Usually you must use /
28 * - trap/job does not work
29 * - /dev/null is supported for redirection
30 * - no $PPID
31 */
32
33/*
20 * The following should be set to reflect the type of system you have: 34 * The following should be set to reflect the type of system you have:
21 * JOBS -> 1 if you have Berkeley job control, 0 otherwise. 35 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
22 * define SYSV if you are running under System V. 36 * define SYSV if you are running under System V.
@@ -37,7 +51,10 @@
37 51
38#define JOBS ENABLE_ASH_JOB_CONTROL 52#define JOBS ENABLE_ASH_JOB_CONTROL
39 53
54#include "busybox.h" /* for applet_names */
55#if !ENABLE_PLATFORM_MINGW32
40#include <paths.h> 56#include <paths.h>
57#endif
41#include <setjmp.h> 58#include <setjmp.h>
42#include <fnmatch.h> 59#include <fnmatch.h>
43#include <sys/times.h> 60#include <sys/times.h>
@@ -71,6 +88,10 @@
71# define PIPE_BUF 4096 /* amount of buffering in a pipe */ 88# define PIPE_BUF 4096 /* amount of buffering in a pipe */
72#endif 89#endif
73 90
91#if !ENABLE_PLATFORM_MINGW32
92# define is_absolute_path(path) ((path)[0] == '/')
93#endif
94
74#if !BB_MMU 95#if !BB_MMU
75# error "Do not even bother, ash will not run on NOMMU machine" 96# error "Do not even bother, ash will not run on NOMMU machine"
76#endif 97#endif
@@ -193,6 +214,41 @@
193//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o 214//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
194//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o 215//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
195 216
217#if ENABLE_PLATFORM_MINGW32
218struct forkshell;
219union node;
220struct strlist;
221struct job;
222
223typedef void (*forkpoint_fn)(struct forkshell *fs);
224struct forkshell {
225 /* filled by forkshell_copy() */
226 struct globals_var *gvp;
227 struct globals_misc *gmp;
228 struct tblentry **cmdtable;
229 struct localvar *localvars;
230 /* struct alias **atab; */
231 /* struct parsefile *g_parsefile; */
232 int fpid;
233 HANDLE hMapFile;
234 void *old_base;
235 int nodeptr_offset;
236 int size;
237
238 forkpoint_fn fp;
239 /* optional data, used by forkpoint_fn */
240 int flags;
241 int fd[10];
242 union node *n;
243 char **argv;
244 char *string;
245 struct strlist *strlist;
246 pid_t pid;
247};
248static void sticky_free(void *p);
249#define free(p) sticky_free(p)
250static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode);
251#endif
196 252
197/* ============ Hash table sizes. Configurable. */ 253/* ============ Hash table sizes. Configurable. */
198 254
@@ -2369,10 +2425,22 @@ path_advance(const char **path, const char *name)
2369 if (*path == NULL) 2425 if (*path == NULL)
2370 return NULL; 2426 return NULL;
2371 start = *path; 2427 start = *path;
2428#if ENABLE_PLATFORM_MINGW32
2429 p = next_path_sep(start);
2430 q = strchr(start, '%');
2431 if ((p && q && q < p) || (!p && q))
2432 p = q;
2433 if (!p)
2434 for (p = start; *p; p++)
2435 continue;
2436#else
2372 for (p = start; *p && *p != ':' && *p != '%'; p++) 2437 for (p = start; *p && *p != ':' && *p != '%'; p++)
2373 continue; 2438 continue;
2439#endif
2374 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2440 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2375 while (stackblocksize() < len) 2441
2442 /* preserve space for .exe too */
2443 while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len))
2376 growstackblock(); 2444 growstackblock();
2377 q = stackblock(); 2445 q = stackblock();
2378 if (p != start) { 2446 if (p != start) {
@@ -2384,10 +2452,19 @@ path_advance(const char **path, const char *name)
2384 pathopt = NULL; 2452 pathopt = NULL;
2385 if (*p == '%') { 2453 if (*p == '%') {
2386 pathopt = ++p; 2454 pathopt = ++p;
2455#if ENABLE_PLATFORM_MINGW32
2456 p = next_path_sep(start);
2457
2458 /* *p != ':' and '*' would suffice */
2459 if (!p)
2460 p = pathopt - 1;
2461#else
2387 while (*p && *p != ':') 2462 while (*p && *p != ':')
2388 p++; 2463 p++;
2464#endif
2389 } 2465 }
2390 if (*p == ':') 2466 if (*p == ':' ||
2467 (ENABLE_PLATFORM_MINGW32 && *p == ';'))
2391 *path = p + 1; 2468 *path = p + 1;
2392 else 2469 else
2393 *path = NULL; 2470 *path = NULL;
@@ -2489,6 +2566,99 @@ cdopt(void)
2489static const char * 2566static const char *
2490updatepwd(const char *dir) 2567updatepwd(const char *dir)
2491{ 2568{
2569#if ENABLE_PLATFORM_MINGW32
2570#define is_path_sep(x) ((x) == '/' || (x) == '\\')
2571 /*
2572 * Due to Windows drive notion, getting pwd is a completely
2573 * different thing. Handle it in a separate routine
2574 */
2575
2576 char *new;
2577 char *p;
2578 char *cdcomppath;
2579 const char *lim;
2580 /*
2581 * There are four cases
2582 * absdrive + abspath: c:/path
2583 * absdrive + !abspath: c:path
2584 * !absdrive + abspath: /path
2585 * !absdrive + !abspath: path
2586 *
2587 * Damn DOS!
2588 * c:path behaviour is "undefined"
2589 * To properly handle this case, I have to keep track of cwd
2590 * of every drive, which is too painful to do.
2591 * So when c:path is given, I assume it's c:${curdir}path
2592 * with ${curdir} comes from the current drive
2593 */
2594 int absdrive = *dir && dir[1] == ':';
2595 int abspath = absdrive ? is_path_sep(dir[2]) : is_path_sep(*dir);
2596 char *drive;
2597
2598 cdcomppath = ststrdup(dir);
2599 STARTSTACKSTR(new);
2600 if (!absdrive && curdir == nullstr)
2601 return 0;
2602 if (!abspath) {
2603 if (curdir == nullstr)
2604 return 0;
2605 new = stack_putstr(curdir, new);
2606 }
2607 new = makestrspace(strlen(dir) + 2, new);
2608
2609 drive = stackblock();
2610 if (absdrive) {
2611 *drive = *dir;
2612 cdcomppath += 2;
2613 dir += 2;
2614 } else {
2615 *drive = *curdir;
2616 }
2617 drive[1] = ':'; /* in case of absolute drive+path */
2618
2619 if (abspath)
2620 new = drive + 2;
2621 lim = drive + 3;
2622 if (!abspath) {
2623 if (!is_path_sep(new[-1]))
2624 USTPUTC('/', new);
2625 if (new > lim && is_path_sep(*lim))
2626 lim++;
2627 } else {
2628 USTPUTC('/', new);
2629 cdcomppath ++;
2630 if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) {
2631 USTPUTC('/', new);
2632 cdcomppath++;
2633 lim++;
2634 }
2635 }
2636 p = strtok(cdcomppath, "/\\");
2637 while (p) {
2638 switch (*p) {
2639 case '.':
2640 if (p[1] == '.' && p[2] == '\0') {
2641 while (new > lim) {
2642 STUNPUTC(new);
2643 if (is_path_sep(new[-1]))
2644 break;
2645 }
2646 break;
2647 }
2648 if (p[1] == '\0')
2649 break;
2650 /* fall through */
2651 default:
2652 new = stack_putstr(p, new);
2653 USTPUTC('/', new);
2654 }
2655 p = strtok(0, "/\\");
2656 }
2657 if (new > lim)
2658 STUNPUTC(new);
2659 *new = 0;
2660 return stackblock();
2661#else
2492 char *new; 2662 char *new;
2493 char *p; 2663 char *p;
2494 char *cdcomppath; 2664 char *cdcomppath;
@@ -2542,6 +2712,7 @@ updatepwd(const char *dir)
2542 STUNPUTC(new); 2712 STUNPUTC(new);
2543 *new = 0; 2713 *new = 0;
2544 return stackblock(); 2714 return stackblock();
2715#endif
2545} 2716}
2546 2717
2547/* 2718/*
@@ -2636,7 +2807,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2636 } 2807 }
2637 if (!dest) 2808 if (!dest)
2638 dest = nullstr; 2809 dest = nullstr;
2639 if (*dest == '/') 2810 if (is_absolute_path(dest))
2640 goto step7; 2811 goto step7;
2641 if (*dest == '.') { 2812 if (*dest == '.') {
2642 c = dest[1]; 2813 c = dest[1];
@@ -3408,6 +3579,8 @@ setsignal(int signo)
3408 char cur_act, new_act; 3579 char cur_act, new_act;
3409 struct sigaction act; 3580 struct sigaction act;
3410 3581
3582 if (ENABLE_PLATFORM_MINGW32)
3583 return;
3411 t = trap[signo]; 3584 t = trap[signo];
3412 new_act = S_DFL; 3585 new_act = S_DFL;
3413 if (t != NULL) { /* trap for this sig is set */ 3586 if (t != NULL) { /* trap for this sig is set */
@@ -3929,6 +4102,79 @@ sprint_status(char *s, int status, int sigonly)
3929 return col; 4102 return col;
3930} 4103}
3931 4104
4105#if ENABLE_PLATFORM_MINGW32
4106
4107HANDLE hSIGINT; /* Ctrl-C is pressed */
4108
4109static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
4110{
4111 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
4112 SetEvent(hSIGINT);
4113 return TRUE;
4114 }
4115 return FALSE;
4116}
4117
4118/*
4119 * Windows does not know about parent-child relationship
4120 * They don't support waitpid(-1)
4121 */
4122static pid_t
4123waitpid_child(int *status, int wait_flags)
4124{
4125 HANDLE *pidlist, *pidp;
4126 int pid_nr = 0;
4127 pid_t pid;
4128 DWORD win_status, idx;
4129 struct job *jb;
4130
4131 #define LOOP(stmt) \
4132 for (jb = curjob; jb; jb = jb->prev_job) { \
4133 struct procstat *ps, *psend; \
4134 if (jb->state == JOBDONE) \
4135 continue; \
4136 ps = jb->ps; \
4137 psend = ps + jb->nprocs; \
4138 while (ps < psend) { \
4139 if (ps->ps_pid != -1) { \
4140 stmt; \
4141 } \
4142 ps++; \
4143 } \
4144 }
4145
4146 LOOP(pid_nr++);
4147 if (!pid_nr)
4148 return -1;
4149 pid_nr++;
4150 pidp = pidlist = ckmalloc(sizeof(*pidlist)*pid_nr);
4151 *pidp++ = hSIGINT;
4152 LOOP(*pidp++ = (HANDLE)ps->ps_pid);
4153 #undef LOOP
4154
4155 idx = WaitForMultipleObjects(pid_nr, pidlist, FALSE,
4156 wait_flags|WNOHANG ? 0 : INFINITE);
4157 if (idx >= pid_nr) {
4158 free(pidlist);
4159 return -1;
4160 }
4161 if (!idx) { /* hSIGINT */
4162 int i;
4163 ResetEvent(hSIGINT);
4164 for (i = 1; i < pid_nr; i++)
4165 TerminateProcess(pidlist[i], 1);
4166 free(pidlist);
4167 *status = 260; /* terminated by a signal */
4168 return pidlist[1];
4169 }
4170 GetExitCodeProcess(pidlist[idx], &win_status);
4171 pid = (int)pidlist[idx];
4172 free(pidlist);
4173 *status = (int)win_status;
4174 return pid;
4175}
4176#endif
4177
3932static int 4178static int
3933dowait(int wait_flags, struct job *job) 4179dowait(int wait_flags, struct job *job)
3934{ 4180{
@@ -3945,7 +4191,11 @@ dowait(int wait_flags, struct job *job)
3945 * NB: _not_ safe_waitpid, we need to detect EINTR */ 4191 * NB: _not_ safe_waitpid, we need to detect EINTR */
3946 if (doing_jobctl) 4192 if (doing_jobctl)
3947 wait_flags |= WUNTRACED; 4193 wait_flags |= WUNTRACED;
4194#if ENABLE_PLATFORM_MINGW32
4195 pid = waitpid_child(&status, wait_flags);
4196#else
3948 pid = waitpid(-1, &status, wait_flags); 4197 pid = waitpid(-1, &status, wait_flags);
4198#endif
3949 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", 4199 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3950 pid, status, errno, strerror(errno))); 4200 pid, status, errno, strerror(errno)));
3951 if (pid <= 0) 4201 if (pid <= 0)
@@ -3968,6 +4218,8 @@ dowait(int wait_flags, struct job *job)
3968 jobno(jp), pid, ps->ps_status, status)); 4218 jobno(jp), pid, ps->ps_status, status));
3969 ps->ps_status = status; 4219 ps->ps_status = status;
3970 thisjob = jp; 4220 thisjob = jp;
4221 if (ENABLE_PLATFORM_MINGW32)
4222 ps->ps_pid = -1;
3971 } 4223 }
3972 if (ps->ps_status == -1) 4224 if (ps->ps_status == -1)
3973 state = JOBRUNNING; 4225 state = JOBRUNNING;
@@ -4199,6 +4451,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
4199 int retval; 4451 int retval;
4200 struct job *jp; 4452 struct job *jp;
4201 4453
4454 if (ENABLE_PLATFORM_MINGW32)
4455 return 0;
4456
4202 if (pending_sig) 4457 if (pending_sig)
4203 raise_exception(EXSIG); 4458 raise_exception(EXSIG);
4204 4459
@@ -4811,7 +5066,7 @@ static void
4811forkparent(struct job *jp, union node *n, int mode, pid_t pid) 5066forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4812{ 5067{
4813 TRACE(("In parent shell: child = %d\n", pid)); 5068 TRACE(("In parent shell: child = %d\n", pid));
4814 if (!jp) { 5069 if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */
4815 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) 5070 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4816 continue; 5071 continue;
4817 jobless++; 5072 jobless++;
@@ -4851,6 +5106,9 @@ forkshell(struct job *jp, union node *n, int mode)
4851 int pid; 5106 int pid;
4852 5107
4853 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); 5108 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5109 if (ENABLE_PLATFORM_MINGW32)
5110 return -1;
5111
4854 pid = fork(); 5112 pid = fork();
4855 if (pid < 0) { 5113 if (pid < 0) {
4856 TRACE(("Fork failed, errno=%d", errno)); 5114 TRACE(("Fork failed, errno=%d", errno));
@@ -5053,11 +5311,39 @@ noclobberopen(const char *fname)
5053 */ 5311 */
5054/* openhere needs this forward reference */ 5312/* openhere needs this forward reference */
5055static void expandhere(union node *arg, int fd); 5313static void expandhere(union node *arg, int fd);
5314#if ENABLE_PLATFORM_MINGW32
5315static void
5316forkshell_openhere(struct forkshell *fs)
5317{
5318 union node *redir = fs->n;
5319 int pip[2];
5320
5321 pip[0] = fs->fd[0];
5322 pip[1] = fs->fd[1];
5323
5324 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
5325
5326 close(pip[0]);
5327 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5328 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5329 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5330 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5331 signal(SIGPIPE, SIG_DFL);
5332 if (redir->type == NHERE) {
5333 size_t len = strlen(redir->nhere.doc->narg.text);
5334 full_write(pip[1], redir->nhere.doc->narg.text, len);
5335 } else /* NXHERE */
5336 expandhere(redir->nhere.doc, pip[1]);
5337 _exit(EXIT_SUCCESS);
5338}
5339#endif
5340
5056static int 5341static int
5057openhere(union node *redir) 5342openhere(union node *redir)
5058{ 5343{
5059 int pip[2]; 5344 int pip[2];
5060 size_t len = 0; 5345 size_t len = 0;
5346 IF_PLATFORM_MINGW32(struct forkshell fs);
5061 5347
5062 if (pipe(pip) < 0) 5348 if (pipe(pip) < 0)
5063 ash_msg_and_raise_error("pipe call failed"); 5349 ash_msg_and_raise_error("pipe call failed");
@@ -5068,6 +5354,16 @@ openhere(union node *redir)
5068 goto out; 5354 goto out;
5069 } 5355 }
5070 } 5356 }
5357#if ENABLE_PLATFORM_MINGW32
5358 memset(&fs, 0, sizeof(fs));
5359 fs.fp = forkshell_openhere;
5360 fs.flags = 0;
5361 fs.n = redir;
5362 fs.fd[0] = pip[0];
5363 fs.fd[1] = pip[1];
5364 if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0)
5365 ash_msg_and_raise_error("unable to spawn shell");
5366#endif
5071 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 5367 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5072 /* child */ 5368 /* child */
5073 close(pip[0]); 5369 close(pip[0]);
@@ -5094,6 +5390,31 @@ openredirect(union node *redir)
5094 int f; 5390 int f;
5095 5391
5096 fname = redir->nfile.expfname; 5392 fname = redir->nfile.expfname;
5393#if ENABLE_PLATFORM_MINGW32
5394 /* Support for /dev/null */
5395 switch (redir->nfile.type) {
5396 case NFROM:
5397 if (!strcmp(fname, "/dev/null"))
5398 return open("nul",O_RDWR);
5399 if (!strncmp(fname, "/dev/", 5)) {
5400 ash_msg("Unhandled device %s\n", fname);
5401 return -1;
5402 }
5403 break;
5404
5405 case NFROMTO:
5406 case NTO:
5407 case NCLOBBER:
5408 case NAPPEND:
5409 if (!strcmp(fname, "/dev/null"))
5410 return open("nul",O_RDWR);
5411 if (!strncmp(fname, "/dev/", 5)) {
5412 ash_msg("Unhandled device %s\n", fname);
5413 return -1;
5414 }
5415 break;
5416 }
5417#endif
5097 switch (redir->nfile.type) { 5418 switch (redir->nfile.type) {
5098 case NFROM: 5419 case NFROM:
5099 f = open(fname, O_RDONLY); 5420 f = open(fname, O_RDONLY);
@@ -5791,6 +6112,8 @@ exptilde(char *startp, char *p, int flags)
5791 if (*name == '\0') { 6112 if (*name == '\0') {
5792 home = lookupvar("HOME"); 6113 home = lookupvar("HOME");
5793 } else { 6114 } else {
6115 if (ENABLE_PLATFORM_MINGW32)
6116 goto lose;
5794 pw = getpwnam(name); 6117 pw = getpwnam(name);
5795 if (pw == NULL) 6118 if (pw == NULL)
5796 goto lose; 6119 goto lose;
@@ -5818,6 +6141,7 @@ struct backcmd { /* result of evalbackcmd */
5818 int fd; /* file descriptor to read from */ 6141 int fd; /* file descriptor to read from */
5819 int nleft; /* number of chars in buffer */ 6142 int nleft; /* number of chars in buffer */
5820 char *buf; /* buffer */ 6143 char *buf; /* buffer */
6144 IF_PLATFORM_MINGW32(struct forkshell fs);
5821 struct job *jp; /* job structure for command */ 6145 struct job *jp; /* job structure for command */
5822}; 6146};
5823 6147
@@ -5826,6 +6150,25 @@ static uint8_t back_exitstatus; /* exit status of backquoted command */
5826#define EV_EXIT 01 /* exit after evaluating tree */ 6150#define EV_EXIT 01 /* exit after evaluating tree */
5827static void evaltree(union node *, int); 6151static void evaltree(union node *, int);
5828 6152
6153#if ENABLE_PLATFORM_MINGW32
6154static void
6155forkshell_evalbackcmd(struct forkshell *fs)
6156{
6157 union node *n = fs->n;
6158 int pip[2] = {fs->fd[0], fs->fd[1]};
6159
6160 FORCE_INT_ON;
6161 close(pip[0]);
6162 if (pip[1] != 1) {
6163 /*close(1);*/
6164 copyfd(pip[1], 1 | COPYFD_EXACT);
6165 close(pip[1]);
6166 }
6167 eflag = 0;
6168 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6169 /* NOTREACHED */
6170}
6171#endif
5829static void FAST_FUNC 6172static void FAST_FUNC
5830evalbackcmd(union node *n, struct backcmd *result) 6173evalbackcmd(union node *n, struct backcmd *result)
5831{ 6174{
@@ -5834,6 +6177,7 @@ evalbackcmd(union node *n, struct backcmd *result)
5834 result->fd = -1; 6177 result->fd = -1;
5835 result->buf = NULL; 6178 result->buf = NULL;
5836 result->nleft = 0; 6179 result->nleft = 0;
6180 IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs)));
5837 result->jp = NULL; 6181 result->jp = NULL;
5838 if (n == NULL) 6182 if (n == NULL)
5839 goto out; 6183 goto out;
@@ -5848,6 +6192,14 @@ evalbackcmd(union node *n, struct backcmd *result)
5848 if (pipe(pip) < 0) 6192 if (pipe(pip) < 0)
5849 ash_msg_and_raise_error("pipe call failed"); 6193 ash_msg_and_raise_error("pipe call failed");
5850 jp = makejob(/*n,*/ 1); 6194 jp = makejob(/*n,*/ 1);
6195#if ENABLE_PLATFORM_MINGW32
6196 result->fs.fp = forkshell_evalbackcmd;
6197 result->fs.n = n;
6198 result->fs.fd[0] = pip[0];
6199 result->fs.fd[1] = pip[1];
6200 if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0)
6201 ash_msg_and_raise_error("unable to spawn shell");
6202#endif
5851 if (forkshell(jp, n, FORK_NOJOB) == 0) { 6203 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5852 FORCE_INT_ON; 6204 FORCE_INT_ON;
5853 close(pip[0]); 6205 close(pip[0]);
@@ -5918,7 +6270,8 @@ expbackq(union node *cmd, int quoted, int quotes)
5918 6270
5919 /* Eat all trailing newlines */ 6271 /* Eat all trailing newlines */
5920 dest = expdest; 6272 dest = expdest;
5921 for (; dest > (char *)stackblock() && dest[-1] == '\n';) 6273 for (; dest > (char *)stackblock() && (dest[-1] == '\n' ||
6274 (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));)
5922 STUNPUTC(dest); 6275 STUNPUTC(dest);
5923 expdest = dest; 6276 expdest = dest;
5924 6277
@@ -7465,7 +7818,7 @@ shellexec(char **argv, const char *path, int idx)
7465 7818
7466 clearredir(/*drop:*/ 1); 7819 clearredir(/*drop:*/ 1);
7467 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); 7820 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7468 if (strchr(argv[0], '/') != NULL 7821 if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\')))
7469#if ENABLE_FEATURE_SH_STANDALONE 7822#if ENABLE_FEATURE_SH_STANDALONE
7470 || (applet_no = find_applet_by_name(argv[0])) >= 0 7823 || (applet_no = find_applet_by_name(argv[0])) >= 0
7471#endif 7824#endif
@@ -7976,6 +8329,10 @@ static int funcblocksize; /* size of structures in function */
7976static int funcstringsize; /* size of strings in node */ 8329static int funcstringsize; /* size of strings in node */
7977static void *funcblock; /* block to allocate function from */ 8330static void *funcblock; /* block to allocate function from */
7978static char *funcstring; /* block to allocate strings from */ 8331static char *funcstring; /* block to allocate strings from */
8332#if ENABLE_PLATFORM_MINGW32
8333static int nodeptrsize;
8334static int *nodeptr;
8335#endif
7979 8336
7980/* flags in argument to evaltree */ 8337/* flags in argument to evaltree */
7981#define EV_EXIT 01 /* exit after evaluating tree */ 8338#define EV_EXIT 01 /* exit after evaluating tree */
@@ -8021,6 +8378,7 @@ sizenodelist(struct nodelist *lp)
8021{ 8378{
8022 while (lp) { 8379 while (lp) {
8023 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 8380 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8381 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8024 calcsize(lp->n); 8382 calcsize(lp->n);
8025 lp = lp->next; 8383 lp = lp->next;
8026 } 8384 }
@@ -8037,15 +8395,18 @@ calcsize(union node *n)
8037 calcsize(n->ncmd.redirect); 8395 calcsize(n->ncmd.redirect);
8038 calcsize(n->ncmd.args); 8396 calcsize(n->ncmd.args);
8039 calcsize(n->ncmd.assign); 8397 calcsize(n->ncmd.assign);
8398 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8040 break; 8399 break;
8041 case NPIPE: 8400 case NPIPE:
8042 sizenodelist(n->npipe.cmdlist); 8401 sizenodelist(n->npipe.cmdlist);
8402 IF_PLATFORM_MINGW32(nodeptrsize++);
8043 break; 8403 break;
8044 case NREDIR: 8404 case NREDIR:
8045 case NBACKGND: 8405 case NBACKGND:
8046 case NSUBSHELL: 8406 case NSUBSHELL:
8047 calcsize(n->nredir.redirect); 8407 calcsize(n->nredir.redirect);
8048 calcsize(n->nredir.n); 8408 calcsize(n->nredir.n);
8409 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8049 break; 8410 break;
8050 case NAND: 8411 case NAND:
8051 case NOR: 8412 case NOR:
@@ -8054,31 +8415,37 @@ calcsize(union node *n)
8054 case NUNTIL: 8415 case NUNTIL:
8055 calcsize(n->nbinary.ch2); 8416 calcsize(n->nbinary.ch2);
8056 calcsize(n->nbinary.ch1); 8417 calcsize(n->nbinary.ch1);
8418 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8057 break; 8419 break;
8058 case NIF: 8420 case NIF:
8059 calcsize(n->nif.elsepart); 8421 calcsize(n->nif.elsepart);
8060 calcsize(n->nif.ifpart); 8422 calcsize(n->nif.ifpart);
8061 calcsize(n->nif.test); 8423 calcsize(n->nif.test);
8424 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8062 break; 8425 break;
8063 case NFOR: 8426 case NFOR:
8064 funcstringsize += strlen(n->nfor.var) + 1; 8427 funcstringsize += strlen(n->nfor.var) + 1;
8065 calcsize(n->nfor.body); 8428 calcsize(n->nfor.body);
8066 calcsize(n->nfor.args); 8429 calcsize(n->nfor.args);
8430 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8067 break; 8431 break;
8068 case NCASE: 8432 case NCASE:
8069 calcsize(n->ncase.cases); 8433 calcsize(n->ncase.cases);
8070 calcsize(n->ncase.expr); 8434 calcsize(n->ncase.expr);
8435 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8071 break; 8436 break;
8072 case NCLIST: 8437 case NCLIST:
8073 calcsize(n->nclist.body); 8438 calcsize(n->nclist.body);
8074 calcsize(n->nclist.pattern); 8439 calcsize(n->nclist.pattern);
8075 calcsize(n->nclist.next); 8440 calcsize(n->nclist.next);
8441 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8076 break; 8442 break;
8077 case NDEFUN: 8443 case NDEFUN:
8078 case NARG: 8444 case NARG:
8079 sizenodelist(n->narg.backquote); 8445 sizenodelist(n->narg.backquote);
8080 funcstringsize += strlen(n->narg.text) + 1; 8446 funcstringsize += strlen(n->narg.text) + 1;
8081 calcsize(n->narg.next); 8447 calcsize(n->narg.next);
8448 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8082 break; 8449 break;
8083 case NTO: 8450 case NTO:
8084#if ENABLE_ASH_BASH_COMPAT 8451#if ENABLE_ASH_BASH_COMPAT
@@ -8090,28 +8457,34 @@ calcsize(union node *n)
8090 case NAPPEND: 8457 case NAPPEND:
8091 calcsize(n->nfile.fname); 8458 calcsize(n->nfile.fname);
8092 calcsize(n->nfile.next); 8459 calcsize(n->nfile.next);
8460 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8093 break; 8461 break;
8094 case NTOFD: 8462 case NTOFD:
8095 case NFROMFD: 8463 case NFROMFD:
8096 calcsize(n->ndup.vname); 8464 calcsize(n->ndup.vname);
8097 calcsize(n->ndup.next); 8465 calcsize(n->ndup.next);
8466 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8098 break; 8467 break;
8099 case NHERE: 8468 case NHERE:
8100 case NXHERE: 8469 case NXHERE:
8101 calcsize(n->nhere.doc); 8470 calcsize(n->nhere.doc);
8102 calcsize(n->nhere.next); 8471 calcsize(n->nhere.next);
8472 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8103 break; 8473 break;
8104 case NNOT: 8474 case NNOT:
8105 calcsize(n->nnot.com); 8475 calcsize(n->nnot.com);
8476 IF_PLATFORM_MINGW32(nodeptrsize++);
8106 break; 8477 break;
8107 }; 8478 };
8108} 8479}
8109 8480
8110static char * 8481static char *
8111nodeckstrdup(char *s) 8482nodeckstrdup(const char *s)
8112{ 8483{
8113 char *rtn = funcstring; 8484 char *rtn = funcstring;
8114 8485
8486 if (!s)
8487 return NULL;
8115 strcpy(funcstring, s); 8488 strcpy(funcstring, s);
8116 funcstring += strlen(s) + 1; 8489 funcstring += strlen(s) + 1;
8117 return rtn; 8490 return rtn;
@@ -8119,6 +8492,18 @@ nodeckstrdup(char *s)
8119 8492
8120static union node *copynode(union node *); 8493static union node *copynode(union node *);
8121 8494
8495#if ENABLE_PLATFORM_MINGW32
8496# define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (int)&(dst);}
8497# define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);}}
8498# define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);}}
8499# define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);*nodeptr++ = (int)&(dst4);}}
8500#else
8501# define SAVE_PTR(dst)
8502# define SAVE_PTR2(dst,dst2)
8503# define SAVE_PTR3(dst,dst2,dst3)
8504# define SAVE_PTR4(dst,dst2,dst3,dst4)
8505#endif
8506
8122static struct nodelist * 8507static struct nodelist *
8123copynodelist(struct nodelist *lp) 8508copynodelist(struct nodelist *lp)
8124{ 8509{
@@ -8130,6 +8515,7 @@ copynodelist(struct nodelist *lp)
8130 *lpp = funcblock; 8515 *lpp = funcblock;
8131 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); 8516 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8132 (*lpp)->n = copynode(lp->n); 8517 (*lpp)->n = copynode(lp->n);
8518 SAVE_PTR2((*lpp)->n, (*lpp)->next);
8133 lp = lp->next; 8519 lp = lp->next;
8134 lpp = &(*lpp)->next; 8520 lpp = &(*lpp)->next;
8135 } 8521 }
@@ -8152,16 +8538,19 @@ copynode(union node *n)
8152 new->ncmd.redirect = copynode(n->ncmd.redirect); 8538 new->ncmd.redirect = copynode(n->ncmd.redirect);
8153 new->ncmd.args = copynode(n->ncmd.args); 8539 new->ncmd.args = copynode(n->ncmd.args);
8154 new->ncmd.assign = copynode(n->ncmd.assign); 8540 new->ncmd.assign = copynode(n->ncmd.assign);
8541 SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign);
8155 break; 8542 break;
8156 case NPIPE: 8543 case NPIPE:
8157 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 8544 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8158 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; 8545 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8546 SAVE_PTR(new->npipe.cmdlist);
8159 break; 8547 break;
8160 case NREDIR: 8548 case NREDIR:
8161 case NBACKGND: 8549 case NBACKGND:
8162 case NSUBSHELL: 8550 case NSUBSHELL:
8163 new->nredir.redirect = copynode(n->nredir.redirect); 8551 new->nredir.redirect = copynode(n->nredir.redirect);
8164 new->nredir.n = copynode(n->nredir.n); 8552 new->nredir.n = copynode(n->nredir.n);
8553 SAVE_PTR2(new->nredir.redirect,new->nredir.n);
8165 break; 8554 break;
8166 case NAND: 8555 case NAND:
8167 case NOR: 8556 case NOR:
@@ -8170,31 +8559,37 @@ copynode(union node *n)
8170 case NUNTIL: 8559 case NUNTIL:
8171 new->nbinary.ch2 = copynode(n->nbinary.ch2); 8560 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8172 new->nbinary.ch1 = copynode(n->nbinary.ch1); 8561 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8562 SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2);
8173 break; 8563 break;
8174 case NIF: 8564 case NIF:
8175 new->nif.elsepart = copynode(n->nif.elsepart); 8565 new->nif.elsepart = copynode(n->nif.elsepart);
8176 new->nif.ifpart = copynode(n->nif.ifpart); 8566 new->nif.ifpart = copynode(n->nif.ifpart);
8177 new->nif.test = copynode(n->nif.test); 8567 new->nif.test = copynode(n->nif.test);
8568 SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test);
8178 break; 8569 break;
8179 case NFOR: 8570 case NFOR:
8180 new->nfor.var = nodeckstrdup(n->nfor.var); 8571 new->nfor.var = nodeckstrdup(n->nfor.var);
8181 new->nfor.body = copynode(n->nfor.body); 8572 new->nfor.body = copynode(n->nfor.body);
8182 new->nfor.args = copynode(n->nfor.args); 8573 new->nfor.args = copynode(n->nfor.args);
8574 SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args);
8183 break; 8575 break;
8184 case NCASE: 8576 case NCASE:
8185 new->ncase.cases = copynode(n->ncase.cases); 8577 new->ncase.cases = copynode(n->ncase.cases);
8186 new->ncase.expr = copynode(n->ncase.expr); 8578 new->ncase.expr = copynode(n->ncase.expr);
8579 SAVE_PTR2(new->ncase.cases,new->ncase.expr);
8187 break; 8580 break;
8188 case NCLIST: 8581 case NCLIST:
8189 new->nclist.body = copynode(n->nclist.body); 8582 new->nclist.body = copynode(n->nclist.body);
8190 new->nclist.pattern = copynode(n->nclist.pattern); 8583 new->nclist.pattern = copynode(n->nclist.pattern);
8191 new->nclist.next = copynode(n->nclist.next); 8584 new->nclist.next = copynode(n->nclist.next);
8585 SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next);
8192 break; 8586 break;
8193 case NDEFUN: 8587 case NDEFUN:
8194 case NARG: 8588 case NARG:
8195 new->narg.backquote = copynodelist(n->narg.backquote); 8589 new->narg.backquote = copynodelist(n->narg.backquote);
8196 new->narg.text = nodeckstrdup(n->narg.text); 8590 new->narg.text = nodeckstrdup(n->narg.text);
8197 new->narg.next = copynode(n->narg.next); 8591 new->narg.next = copynode(n->narg.next);
8592 SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next);
8198 break; 8593 break;
8199 case NTO: 8594 case NTO:
8200#if ENABLE_ASH_BASH_COMPAT 8595#if ENABLE_ASH_BASH_COMPAT
@@ -8207,6 +8602,7 @@ copynode(union node *n)
8207 new->nfile.fname = copynode(n->nfile.fname); 8602 new->nfile.fname = copynode(n->nfile.fname);
8208 new->nfile.fd = n->nfile.fd; 8603 new->nfile.fd = n->nfile.fd;
8209 new->nfile.next = copynode(n->nfile.next); 8604 new->nfile.next = copynode(n->nfile.next);
8605 SAVE_PTR2(new->nfile.fname,new->nfile.next);
8210 break; 8606 break;
8211 case NTOFD: 8607 case NTOFD:
8212 case NFROMFD: 8608 case NFROMFD:
@@ -8214,15 +8610,18 @@ copynode(union node *n)
8214 new->ndup.dupfd = n->ndup.dupfd; 8610 new->ndup.dupfd = n->ndup.dupfd;
8215 new->ndup.fd = n->ndup.fd; 8611 new->ndup.fd = n->ndup.fd;
8216 new->ndup.next = copynode(n->ndup.next); 8612 new->ndup.next = copynode(n->ndup.next);
8613 SAVE_PTR2(new->ndup.vname,new->ndup.next);
8217 break; 8614 break;
8218 case NHERE: 8615 case NHERE:
8219 case NXHERE: 8616 case NXHERE:
8220 new->nhere.doc = copynode(n->nhere.doc); 8617 new->nhere.doc = copynode(n->nhere.doc);
8221 new->nhere.fd = n->nhere.fd; 8618 new->nhere.fd = n->nhere.fd;
8222 new->nhere.next = copynode(n->nhere.next); 8619 new->nhere.next = copynode(n->nhere.next);
8620 SAVE_PTR2(new->nhere.doc,new->nhere.next);
8223 break; 8621 break;
8224 case NNOT: 8622 case NNOT:
8225 new->nnot.com = copynode(n->nnot.com); 8623 new->nnot.com = copynode(n->nnot.com);
8624 SAVE_PTR(new->nnot.com);
8226 break; 8625 break;
8227 }; 8626 };
8228 new->type = n->type; 8627 new->type = n->type;
@@ -8245,6 +8644,7 @@ copyfunc(union node *n)
8245 f = ckmalloc(blocksize + funcstringsize); 8644 f = ckmalloc(blocksize + funcstringsize);
8246 funcblock = (char *) f + offsetof(struct funcnode, n); 8645 funcblock = (char *) f + offsetof(struct funcnode, n);
8247 funcstring = (char *) f + blocksize; 8646 funcstring = (char *) f + blocksize;
8647 IF_PLATFORM_MINGW32(nodeptr = NULL);
8248 copynode(n); 8648 copynode(n);
8249 f->count = 0; 8649 f->count = 0;
8250 return f; 8650 return f;
@@ -8601,9 +9001,26 @@ evalcase(union node *n, int flags)
8601/* 9001/*
8602 * Kick off a subshell to evaluate a tree. 9002 * Kick off a subshell to evaluate a tree.
8603 */ 9003 */
9004#if ENABLE_PLATFORM_MINGW32
9005static void
9006forkshell_evalsubshell(struct forkshell *fs)
9007{
9008 union node *n = fs->n;
9009 int flags = fs->flags;
9010
9011 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
9012 INT_ON;
9013 flags |= EV_EXIT;
9014 expredir(n->nredir.redirect);
9015 redirect(n->nredir.redirect, 0);
9016 evaltreenr(n->nredir.n, flags);
9017 /* never returns */
9018}
9019#endif
8604static void 9020static void
8605evalsubshell(union node *n, int flags) 9021evalsubshell(union node *n, int flags)
8606{ 9022{
9023 IF_PLATFORM_MINGW32(struct forkshell fs;)
8607 struct job *jp; 9024 struct job *jp;
8608 int backgnd = (n->type == NBACKGND); 9025 int backgnd = (n->type == NBACKGND);
8609 int status; 9026 int status;
@@ -8613,6 +9030,14 @@ evalsubshell(union node *n, int flags)
8613 goto nofork; 9030 goto nofork;
8614 INT_OFF; 9031 INT_OFF;
8615 jp = makejob(/*n,*/ 1); 9032 jp = makejob(/*n,*/ 1);
9033#if ENABLE_PLATFORM_MINGW32
9034 memset(&fs, 0, sizeof(fs));
9035 fs.fp = forkshell_evalsubshell;
9036 fs.n = n;
9037 fs.flags = flags;
9038 if (spawn_forkshell(jp, &fs, backgnd) < 0)
9039 ash_msg_and_raise_error("unable to spawn shell");
9040#endif
8616 if (forkshell(jp, n, backgnd) == 0) { 9041 if (forkshell(jp, n, backgnd) == 0) {
8617 /* child */ 9042 /* child */
8618 INT_ON; 9043 INT_ON;
@@ -8701,9 +9126,35 @@ expredir(union node *n)
8701 * of the shell, which make the last process in a pipeline the parent 9126 * of the shell, which make the last process in a pipeline the parent
8702 * of all the rest.) 9127 * of all the rest.)
8703 */ 9128 */
9129#if ENABLE_PLATFORM_MINGW32
9130static void
9131forkshell_evalpipe(struct forkshell *fs)
9132{
9133 union node *n = fs->n;
9134 int flags = fs->flags;
9135 int prevfd = fs->fd[2];
9136 int pip[2] = {fs->fd[0], fs->fd[1]};
9137
9138 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
9139 INT_ON;
9140 if (pip[1] >= 0) {
9141 close(pip[0]);
9142 }
9143 if (prevfd > 0) {
9144 dup2(prevfd, 0);
9145 close(prevfd);
9146 }
9147 if (pip[1] > 1) {
9148 dup2(pip[1], 1);
9149 close(pip[1]);
9150 }
9151 evaltreenr(n, flags);
9152}
9153#endif
8704static void 9154static void
8705evalpipe(union node *n, int flags) 9155evalpipe(union node *n, int flags)
8706{ 9156{
9157 IF_PLATFORM_MINGW32(struct forkshell fs;)
8707 struct job *jp; 9158 struct job *jp;
8708 struct nodelist *lp; 9159 struct nodelist *lp;
8709 int pipelen; 9160 int pipelen;
@@ -8727,6 +9178,17 @@ evalpipe(union node *n, int flags)
8727 ash_msg_and_raise_error("pipe call failed"); 9178 ash_msg_and_raise_error("pipe call failed");
8728 } 9179 }
8729 } 9180 }
9181#if ENABLE_PLATFORM_MINGW32
9182 memset(&fs, 0, sizeof(fs));
9183 fs.fp = forkshell_evalpipe;
9184 fs.flags = flags;
9185 fs.n = lp->n;
9186 fs.fd[0] = pip[0];
9187 fs.fd[1] = pip[1];
9188 fs.fd[2] = prevfd;
9189 if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0)
9190 ash_msg_and_raise_error("unable to spawn shell");
9191#endif
8730 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { 9192 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8731 INT_ON; 9193 INT_ON;
8732 if (pip[1] >= 0) { 9194 if (pip[1] >= 0) {
@@ -9195,6 +9657,20 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9195 * as POSIX mandates */ 9657 * as POSIX mandates */
9196 return back_exitstatus; 9658 return back_exitstatus;
9197} 9659}
9660
9661#if ENABLE_PLATFORM_MINGW32
9662static void
9663forkshell_shellexec(struct forkshell *fs)
9664{
9665 int idx = fs->fd[0];
9666 struct strlist *varlist = fs->strlist;
9667 char **argv = fs->argv;
9668 char *path = fs->string;
9669
9670 listsetvar(varlist, VEXPORT|VSTACK);
9671 shellexec(argv, path, idx);
9672}
9673#endif
9198static void 9674static void
9199evalcommand(union node *cmd, int flags) 9675evalcommand(union node *cmd, int flags)
9200{ 9676{
@@ -9372,6 +9848,27 @@ evalcommand(union node *cmd, int flags)
9372 * in a script or a subshell does not need forking, 9848 * in a script or a subshell does not need forking,
9373 * we can just exec it. 9849 * we can just exec it.
9374 */ 9850 */
9851#if ENABLE_PLATFORM_MINGW32
9852 if (!(flags & EV_EXIT) || trap[0]) {
9853 /* No, forking off a child is necessary */
9854 struct forkshell fs;
9855
9856 memset(&fs, 0, sizeof(fs));
9857 fs.fp = forkshell_shellexec;
9858 fs.argv = argv;
9859 fs.string = (char*)path;
9860 fs.fd[0] = cmdentry.u.index;
9861 fs.strlist = varlist.list;
9862 jp = makejob(/*cmd,*/ 1);
9863 if (spawn_forkshell(jp, &fs, FORK_FG) < 0)
9864 ash_msg_and_raise_error("unable to spawn shell");
9865 exitstatus = waitforjob(jp);
9866 INT_ON;
9867 TRACE(("forked child exited with %d\n", exitstatus));
9868 break;
9869 }
9870 /* goes through to shellexec() */
9871#else
9375 if (!(flags & EV_EXIT) || may_have_traps) { 9872 if (!(flags & EV_EXIT) || may_have_traps) {
9376 /* No, forking off a child is necessary */ 9873 /* No, forking off a child is necessary */
9377 INT_OFF; 9874 INT_OFF;
@@ -9387,6 +9884,7 @@ evalcommand(union node *cmd, int flags)
9387 FORCE_INT_ON; 9884 FORCE_INT_ON;
9388 /* fall through to exec'ing external program */ 9885 /* fall through to exec'ing external program */
9389 } 9886 }
9887#endif
9390 listsetvar(varlist.list, VEXPORT|VSTACK); 9888 listsetvar(varlist.list, VEXPORT|VSTACK);
9391 shellexec(argv, path, cmdentry.u.index); 9889 shellexec(argv, path, cmdentry.u.index);
9392 /* NOTREACHED */ 9890 /* NOTREACHED */
@@ -9779,7 +10277,7 @@ preadbuffer(void)
9779 more--; 10277 more--;
9780 10278
9781 c = *q; 10279 c = *q;
9782 if (c == '\0') { 10280 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) {
9783 memmove(q, q + 1, more); 10281 memmove(q, q + 1, more);
9784 } else { 10282 } else {
9785 q++; 10283 q++;
@@ -12211,7 +12709,7 @@ find_dot_file(char *name)
12211 struct stat statb; 12709 struct stat statb;
12212 12710
12213 /* don't try this for absolute or relative paths */ 12711 /* don't try this for absolute or relative paths */
12214 if (strchr(name, '/')) 12712 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\')))
12215 return name; 12713 return name;
12216 12714
12217 /* IIRC standards do not say whether . is to be searched. 12715 /* IIRC standards do not say whether . is to be searched.
@@ -12327,10 +12825,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12327 struct stat statb; 12825 struct stat statb;
12328 int e; 12826 int e;
12329 int updatetbl; 12827 int updatetbl;
12828 IF_PLATFORM_MINGW32(int len;)
12330 struct builtincmd *bcmd; 12829 struct builtincmd *bcmd;
12331 12830
12332 /* If name contains a slash, don't use PATH or hash table */ 12831 /* If name contains a slash, don't use PATH or hash table */
12333 if (strchr(name, '/') != NULL) { 12832 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) {
12334 entry->u.index = -1; 12833 entry->u.index = -1;
12335 if (act & DO_ABS) { 12834 if (act & DO_ABS) {
12336 while (stat(name, &statb) < 0) { 12835 while (stat(name, &statb) < 0) {
@@ -12437,12 +12936,48 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12437 } 12936 }
12438 } 12937 }
12439 /* if rehash, don't redo absolute path names */ 12938 /* if rehash, don't redo absolute path names */
12440 if (fullname[0] == '/' && idx <= prev) { 12939 if (is_absolute_path(fullname) && idx <= prev) {
12441 if (idx < prev) 12940 if (idx < prev)
12442 continue; 12941 continue;
12443 TRACE(("searchexec \"%s\": no change\n", name)); 12942 TRACE(("searchexec \"%s\": no change\n", name));
12444 goto success; 12943 goto success;
12445 } 12944 }
12945#if ENABLE_PLATFORM_MINGW32
12946 len = strlen(fullname);
12947 if (len > 4 &&
12948 (!strcasecmp(fullname+len-4, ".exe") ||
12949 !strcasecmp(fullname+len-4, ".com"))) {
12950 if (stat(fullname, &statb) < 0) {
12951 if (errno != ENOENT && errno != ENOTDIR)
12952 e = errno;
12953 goto loop;
12954 }
12955 }
12956 else {
12957 /* path_advance() has reserved space for .exe */
12958 memcpy(fullname+len, ".exe", 5);
12959 if (stat(fullname, &statb) < 0) {
12960 if (errno != ENOENT && errno != ENOTDIR)
12961 e = errno;
12962 memcpy(fullname+len, ".com", 5);
12963 if (stat(fullname, &statb) < 0) {
12964 if (errno != ENOENT && errno != ENOTDIR)
12965 e = errno;
12966 fullname[len] = '\0';
12967 if (stat(fullname, &statb) < 0) {
12968 if (errno != ENOENT && errno != ENOTDIR)
12969 e = errno;
12970 goto loop;
12971 }
12972 if (!execable_file(fullname)) {
12973 e = ENOEXEC;
12974 goto loop;
12975 }
12976 }
12977 }
12978 fullname[len] = '\0';
12979 }
12980#else
12446 while (stat(fullname, &statb) < 0) { 12981 while (stat(fullname, &statb) < 0) {
12447#ifdef SYSV 12982#ifdef SYSV
12448 if (errno == EINTR) 12983 if (errno == EINTR)
@@ -12452,6 +12987,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12452 e = errno; 12987 e = errno;
12453 goto loop; 12988 goto loop;
12454 } 12989 }
12990#endif
12455 e = EACCES; /* if we fail, this will be the error */ 12991 e = EACCES; /* if we fail, this will be the error */
12456 if (!S_ISREG(statb.st_mode)) 12992 if (!S_ISREG(statb.st_mode))
12457 continue; 12993 continue;
@@ -12722,6 +13258,8 @@ unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12722 return ret & 1; 13258 return ret & 1;
12723} 13259}
12724 13260
13261#if !ENABLE_PLATFORM_MINGW32
13262
12725static const unsigned char timescmd_str[] ALIGN1 = { 13263static const unsigned char timescmd_str[] ALIGN1 = {
12726 ' ', offsetof(struct tms, tms_utime), 13264 ' ', offsetof(struct tms, tms_utime),
12727 '\n', offsetof(struct tms, tms_stime), 13265 '\n', offsetof(struct tms, tms_stime),
@@ -12753,6 +13291,13 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12753 13291
12754 return 0; 13292 return 0;
12755} 13293}
13294#else
13295static int FAST_FUNC
13296timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13297{
13298 return 0;
13299}
13300#endif
12756 13301
12757#if ENABLE_SH_MATH_SUPPORT 13302#if ENABLE_SH_MATH_SUPPORT
12758/* 13303/*
@@ -12986,13 +13531,64 @@ init(void)
12986 struct stat st1, st2; 13531 struct stat st1, st2;
12987 13532
12988 initvar(); 13533 initvar();
13534
13535#if ENABLE_PLATFORM_MINGW32
13536 /*
13537 * case insensitive env names from Windows world
13538 *
13539 * Some standard env names such as PATH is named Path and so on
13540 * ash itself is case sensitive, so "Path" will confuse it, as
13541 * MSVC getenv() is case insensitive.
13542 *
13543 * We may end up having both Path and PATH. Then Path will be chosen
13544 * because it appears first.
13545 */
13546 for (envp = environ; envp && *envp; envp++) {
13547 if (strncasecmp(*envp, "PATH=", 5) == 0 &&
13548 strncmp(*envp, "PATH=", 5) != 0) {
13549 break;
13550 }
13551 }
13552
13553 if (envp && *envp) {
13554 /*
13555 * If we get here it's because the environment contains a path
13556 * variable called something other than PATH. This suggests we
13557 * haven't been invoked from an earlier instance of BusyBox.
13558 */
13559 char *start, *end;
13560 struct passwd *pw;
13561
13562 for (envp = environ; envp && *envp; envp++) {
13563 end = strchr(*envp, '=');
13564 if (!end)
13565 continue;
13566
13567 /* make all variable names uppercase */
13568 for (start = *envp;start < end;start++)
13569 *start = toupper(*start);
13570
13571 /* convert backslashes to forward slashes */
13572 for ( ++end; *end; ++end ) {
13573 if ( *end == '\\' ) {
13574 *end = '/';
13575 }
13576 }
13577 }
13578
13579 /* some initialisation normally performed at login */
13580 pw = xgetpwuid(getuid());
13581 setup_environment(pw->pw_shell, SETUP_ENV_CHANGEENV, pw);
13582 }
13583#endif
12989 for (envp = environ; envp && *envp; envp++) { 13584 for (envp = environ; envp && *envp; envp++) {
12990 if (strchr(*envp, '=')) { 13585 if (strchr(*envp, '=')) {
12991 setvareq(*envp, VEXPORT|VTEXTFIXED); 13586 setvareq(*envp, VEXPORT|VTEXTFIXED);
12992 } 13587 }
12993 } 13588 }
12994 13589
12995 setvar("PPID", utoa(getppid()), 0); 13590 if (!ENABLE_PLATFORM_MINGW32)
13591 setvar("PPID", utoa(getppid()), 0);
12996 13592
12997 p = lookupvar("PWD"); 13593 p = lookupvar("PWD");
12998 if (p) { 13594 if (p) {
@@ -13126,6 +13722,20 @@ static short profile_buf[16384];
13126extern int etext(); 13722extern int etext();
13127#endif 13723#endif
13128 13724
13725#if ENABLE_PLATFORM_MINGW32
13726static const forkpoint_fn forkpoints[] = {
13727 forkshell_openhere,
13728 forkshell_evalbackcmd,
13729 forkshell_evalsubshell,
13730 forkshell_evalpipe,
13731 forkshell_shellexec,
13732 NULL
13733};
13734
13735static struct forkshell* forkshell_prepare(struct forkshell *fs);
13736static void forkshell_init(const char *idstr);
13737#endif
13738
13129/* 13739/*
13130 * Main routine. We initialize things, parse the arguments, execute 13740 * Main routine. We initialize things, parse the arguments, execute
13131 * profiles if we're a login shell, and then call cmdloop to execute 13741 * profiles if we're a login shell, and then call cmdloop to execute
@@ -13195,6 +13805,17 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13195 13805
13196 init(); 13806 init();
13197 setstackmark(&smark); 13807 setstackmark(&smark);
13808
13809#if ENABLE_PLATFORM_MINGW32
13810 hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL);
13811 SetConsoleCtrlHandler(ctrl_handler, TRUE);
13812 if (argc == 3 && !strcmp(argv[1], "--forkshell")) {
13813 forkshell_init(argv[2]);
13814
13815 /* NOTREACHED */
13816 bb_error_msg_and_die("subshell ended unexpectedly");
13817 }
13818#endif
13198 procargs(argv); 13819 procargs(argv);
13199 13820
13200 if (argv[0] && argv[0][0] == '-') 13821 if (argv[0] && argv[0][0] == '-')
@@ -13277,6 +13898,526 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13277 /* NOTREACHED */ 13898 /* NOTREACHED */
13278} 13899}
13279 13900
13901#if ENABLE_PLATFORM_MINGW32
13902/* FIXME: should consider running forkparent() and forkchild() */
13903static int
13904spawn_forkshell(struct job *jp, struct forkshell *fs, int mode)
13905{
13906 const char *argv[] = { "sh", "--forkshell", NULL, NULL };
13907 char buf[16];
13908
13909 struct forkshell *new;
13910 new = forkshell_prepare(fs);
13911 sprintf(buf, "%x", (unsigned int)new->hMapFile);
13912 argv[2] = buf;
13913 fs->pid = mingw_spawn_applet(P_NOWAIT, "sh", argv,
13914 (const char *const *)environ);
13915 CloseHandle(new->hMapFile);
13916 UnmapViewOfFile(new);
13917 if (fs->pid == -1) {
13918 free(jp);
13919 return -1;
13920 }
13921 forkparent(jp, fs->node, mode, fs->pid);
13922 return fs->pid;
13923}
13924
13925/*
13926 * forkshell_prepare() and friends
13927 *
13928 * The sequence is as follows:
13929 * - funcblocksize, funcstringsize, nodeptrsize are initialized
13930 * - forkshell_size(fs) is called to calculate the exact memory needed
13931 * - a new struct is allocated
13932 * - funcblock, funcstring, nodeptr are initialized from the new block
13933 * - forkshell_copy(fs) is called to copy recursively everything over
13934 * it will record all pointers along the way, to nodeptr
13935 *
13936 * When this memory is mapped elsewhere, pointer fixup will be needed
13937 */
13938#define SLIST_SIZE_BEGIN(name,type) \
13939static void \
13940name(type *p) \
13941{ \
13942 while (p) { \
13943 funcblocksize += sizeof(type);
13944 /* do something here with p */
13945#define SLIST_SIZE_END() \
13946 nodeptrsize++; \
13947 p = p->next; \
13948 } \
13949}
13950
13951#define SLIST_COPY_BEGIN(name,type) \
13952static type * \
13953name(type *vp) \
13954{ \
13955 type *start; \
13956 type **vpp; \
13957 vpp = &start; \
13958 while (vp) { \
13959 *vpp = funcblock; \
13960 funcblock = (char *) funcblock + sizeof(type);
13961 /* do something here with vpp and vp */
13962#define SLIST_COPY_END() \
13963 SAVE_PTR((*vpp)->next); \
13964 vp = vp->next; \
13965 vpp = &(*vpp)->next; \
13966 } \
13967 *vpp = NULL; \
13968 return start; \
13969}
13970
13971/*
13972 * struct var
13973 */
13974SLIST_SIZE_BEGIN(var_size,struct var)
13975funcstringsize += strlen(p->var_text) + 1;
13976nodeptrsize++; /* p->text */
13977SLIST_SIZE_END()
13978
13979SLIST_COPY_BEGIN(var_copy,struct var)
13980(*vpp)->var_text = nodeckstrdup(vp->var_text);
13981(*vpp)->flags = vp->flags;
13982/*
13983 * The only place that can set struct var#func is varinit[],
13984 * which will be fixed by forkshell_init()
13985 */
13986(*vpp)->var_func = NULL;
13987SAVE_PTR((*vpp)->var_text);
13988SLIST_COPY_END()
13989
13990/*
13991 * struct localvar
13992 */
13993SLIST_SIZE_BEGIN(localvar_size,struct localvar)
13994var_size(p->vp);
13995funcstringsize += strlen(p->text) + 1;
13996nodeptrsize += 2; /* p->vp, p->text */
13997SLIST_SIZE_END()
13998
13999SLIST_COPY_BEGIN(localvar_copy,struct localvar)
14000(*vpp)->text = nodeckstrdup(vp->text);
14001(*vpp)->flags = vp->flags;
14002(*vpp)->vp = var_copy(vp->vp);
14003SAVE_PTR2((*vpp)->vp, (*vpp)->text);
14004SLIST_COPY_END()
14005
14006/*
14007 * struct strlist
14008 */
14009SLIST_SIZE_BEGIN(strlist_size,struct strlist)
14010funcstringsize += strlen(p->text) + 1;
14011nodeptrsize++; /* p->text */
14012SLIST_SIZE_END()
14013
14014SLIST_COPY_BEGIN(strlist_copy,struct strlist)
14015(*vpp)->text = nodeckstrdup(vp->text);
14016SAVE_PTR((*vpp)->text);
14017SLIST_COPY_END()
14018
14019/*
14020 * struct tblentry
14021 */
14022static void
14023tblentry_size(struct tblentry *tep)
14024{
14025 while (tep) {
14026 funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14027 /* CMDBUILTIN, e->param.cmd needs no pointer relocation */
14028 if (tep->cmdtype == CMDFUNCTION) {
14029 funcblocksize += offsetof(struct funcnode, n);
14030 calcsize(&tep->param.func->n);
14031 nodeptrsize++; /* tep->param.func */
14032 }
14033 nodeptrsize++; /* tep->next */
14034 tep = tep->next;
14035 }
14036}
14037
14038static struct tblentry *
14039tblentry_copy(struct tblentry *tep)
14040{
14041 struct tblentry *start;
14042 struct tblentry **newp;
14043 int size;
14044
14045 newp = &start;
14046 while (tep) {
14047 *newp = funcblock;
14048 size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14049
14050 funcblock = (char *) funcblock + size;
14051 memcpy(*newp, tep, size);
14052 switch (tep->cmdtype) {
14053 case CMDBUILTIN:
14054 /* No pointer saving, this field must be fixed by forkshell_init() */
14055 (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab);
14056 break;
14057 case CMDFUNCTION:
14058 (*newp)->param.func = funcblock;
14059 funcblock = (char *) funcblock + offsetof(struct funcnode, n);
14060 copynode(&tep->param.func->n);
14061 SAVE_PTR((*newp)->param.func);
14062 break;
14063 default:
14064 break;
14065 }
14066 SAVE_PTR((*newp)->next);
14067 tep = tep->next;
14068 newp = &(*newp)->next;
14069 }
14070 *newp = NULL;
14071 return start;
14072}
14073
14074static void
14075cmdtable_size(struct tblentry **cmdtablep)
14076{
14077 int i;
14078 nodeptrsize += CMDTABLESIZE;
14079 funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE;
14080 for (i = 0; i < CMDTABLESIZE; i++)
14081 tblentry_size(cmdtablep[i]);
14082}
14083
14084static struct tblentry **
14085cmdtable_copy(struct tblentry **cmdtablep)
14086{
14087 struct tblentry **new = funcblock;
14088 int i;
14089
14090 funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE;
14091 for (i = 0; i < CMDTABLESIZE; i++) {
14092 new[i] = tblentry_copy(cmdtablep[i]);
14093 SAVE_PTR(new[i]);
14094 }
14095 return new;
14096}
14097
14098/*
14099 * char **
14100 */
14101static void
14102argv_size(char **p)
14103{
14104 while (p && *p) {
14105 funcblocksize += sizeof(char *);
14106 funcstringsize += strlen(*p)+1;
14107 nodeptrsize++;
14108 p++;
14109 }
14110 funcblocksize += sizeof(char *);
14111}
14112
14113static char **
14114argv_copy(char **p)
14115{
14116 char **new, **start = funcblock;
14117
14118 while (p && *p) {
14119 new = funcblock;
14120 funcblock = (char *) funcblock + sizeof(char *);
14121 *new = nodeckstrdup(*p);
14122 SAVE_PTR(*new);
14123 p++;
14124 new++;
14125 }
14126 new = funcblock;
14127 funcblock = (char *) funcblock + sizeof(char *);
14128 *new = NULL;
14129 return start;
14130}
14131
14132/*
14133 * struct redirtab
14134 */
14135static void
14136redirtab_size(struct redirtab *rdtp)
14137{
14138 while (rdtp) {
14139 funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14140 rdtp = rdtp->next;
14141 nodeptrsize++; /* rdtp->next */
14142 }
14143}
14144
14145static struct redirtab *
14146redirtab_copy(struct redirtab *rdtp)
14147{
14148 struct redirtab *start;
14149 struct redirtab **vpp;
14150
14151 vpp = &start;
14152 while (rdtp) {
14153 int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14154 *vpp = funcblock;
14155 funcblock = (char *) funcblock + size;
14156 memcpy(*vpp, rdtp, size);
14157 SAVE_PTR((*vpp)->next);
14158 rdtp = rdtp->next;
14159 vpp = &(*vpp)->next;
14160 }
14161 *vpp = NULL;
14162 return start;
14163}
14164
14165#undef shellparam
14166#undef redirlist
14167#undef varinit
14168#undef vartab
14169static void
14170globals_var_size(struct globals_var *gvp)
14171{
14172 int i;
14173
14174 funcblocksize += sizeof(struct globals_var);
14175 argv_size(gvp->shellparam.p);
14176 redirtab_size(gvp->redirlist);
14177 for (i = 0; i < VTABSIZE; i++)
14178 var_size(gvp->vartab[i]);
14179 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14180 var_size(gvp->varinit+i);
14181 nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */
14182}
14183
14184#undef g_nullredirs
14185#undef preverrout_fd
14186static struct globals_var *
14187globals_var_copy(struct globals_var *gvp)
14188{
14189 int i;
14190 struct globals_var *new;
14191
14192 new = funcblock;
14193 funcblock = (char *) funcblock + sizeof(struct globals_var);
14194
14195 /* shparam */
14196 memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam));
14197 new->shellparam.malloced = 0;
14198 new->shellparam.p = argv_copy(gvp->shellparam.p);
14199 SAVE_PTR(new->shellparam.p);
14200
14201 new->redirlist = redirtab_copy(gvp->redirlist);
14202 SAVE_PTR(new->redirlist);
14203
14204 new->g_nullredirs = gvp->g_nullredirs;
14205 new->preverrout_fd = gvp->preverrout_fd;
14206 for (i = 0; i < VTABSIZE; i++) {
14207 new->vartab[i] = var_copy(gvp->vartab[i]);
14208 SAVE_PTR(new->vartab[i]);
14209 }
14210
14211 /* Can't use var_copy because varinit is already allocated */
14212 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) {
14213 new->varinit[i].next = NULL;
14214 new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text);
14215 SAVE_PTR(new->varinit[i].var_text);
14216 new->varinit[i].flags = gvp->varinit[i].flags;
14217 new->varinit[i].var_func = gvp->varinit[i].var_func;
14218 }
14219 return new;
14220}
14221
14222#undef minusc
14223#undef curdir
14224#undef physdir
14225#undef arg0
14226#undef nullstr
14227static void
14228globals_misc_size(struct globals_misc *p)
14229{
14230 funcblocksize += sizeof(struct globals_misc);
14231 funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1;
14232 if (p->curdir != p->nullstr)
14233 funcstringsize += strlen(p->curdir) + 1;
14234 if (p->physdir != p->nullstr)
14235 funcstringsize += strlen(p->physdir) + 1;
14236 funcstringsize += strlen(p->arg0) + 1;
14237 nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */
14238}
14239
14240static struct globals_misc *
14241globals_misc_copy(struct globals_misc *p)
14242{
14243 struct globals_misc *new = funcblock;
14244
14245 funcblock = (char *) funcblock + sizeof(struct globals_misc);
14246 memcpy(new, p, sizeof(struct globals_misc));
14247
14248 new->minusc = nodeckstrdup(p->minusc);
14249 new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr;
14250 new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr;
14251 new->arg0 = nodeckstrdup(p->arg0);
14252 SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0);
14253 return new;
14254}
14255
14256static void
14257forkshell_size(struct forkshell *fs)
14258{
14259 funcblocksize += sizeof(struct forkshell);
14260 globals_var_size(fs->gvp);
14261 globals_misc_size(fs->gmp);
14262 cmdtable_size(fs->cmdtable);
14263 localvar_size(fs->localvars);
14264 /* optlist_transfer(sending, fd); */
14265 /* misc_transfer(sending, fd); */
14266
14267 calcsize(fs->n);
14268 argv_size(fs->argv);
14269 funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1;
14270 strlist_size(fs->strlist);
14271
14272 nodeptrsize += 8; /* gvp, gmp, cmdtable, localvars, n, argv, string, strlist */
14273}
14274
14275static struct forkshell *
14276forkshell_copy(struct forkshell *fs)
14277{
14278 struct forkshell *new;
14279
14280 new = funcblock;
14281 funcblock = (char *) funcblock + sizeof(struct forkshell);
14282
14283 memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */
14284 new->gvp = globals_var_copy(fs->gvp);
14285 new->gmp = globals_misc_copy(fs->gmp);
14286 new->cmdtable = cmdtable_copy(fs->cmdtable);
14287 new->localvars = localvar_copy(fs->localvars);
14288 SAVE_PTR4(new->gvp, new->gmp, new->cmdtable, new->localvars);
14289
14290 /* new->fs will be reconstructed from new->fpid */
14291 new->n = copynode(fs->n);
14292 new->argv = argv_copy(fs->argv);
14293 new->string = nodeckstrdup(fs->string);
14294 new->strlist = strlist_copy(fs->strlist);
14295 SAVE_PTR4(new->n, new->argv, new->string, new->strlist);
14296 return new;
14297}
14298
14299static struct forkshell *
14300forkshell_prepare(struct forkshell *fs)
14301{
14302 struct forkshell *new;
14303 int size, fp, nodeptr_offset;
14304 HANDLE h;
14305 SECURITY_ATTRIBUTES sa;
14306
14307 for (fp = 0; forkpoints[fp] && forkpoints[fp] != fs->fp; fp++)
14308 ;
14309
14310 if (!forkpoints[fp])
14311 bb_error_msg_and_die("invalid forkpoint %08x", (int)fs->fp);
14312 fs->fpid = fp;
14313
14314 /* Calculate size of "new" */
14315 fs->gvp = ash_ptr_to_globals_var;
14316 fs->gmp = ash_ptr_to_globals_misc;
14317 fs->cmdtable = cmdtable;
14318 fs->localvars = localvars;
14319
14320 nodeptrsize = 1; /* NULL terminated */
14321 funcblocksize = 0;
14322 funcstringsize = 0;
14323 forkshell_size(fs);
14324 size = funcblocksize + funcstringsize + nodeptrsize*sizeof(int);
14325
14326 /* Allocate, initialize pointers */
14327 memset(&sa, 0, sizeof(sa));
14328 sa.nLength = sizeof(sa);
14329 sa.lpSecurityDescriptor = NULL;
14330 sa.bInheritHandle = TRUE;
14331 h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL);
14332 new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14333 /* new = ckmalloc(size); */
14334 funcblock = new;
14335 funcstring = (char *) funcblock + funcblocksize;
14336 nodeptr = (int*)((char *) funcstring + funcstringsize);
14337 nodeptr_offset = (int) nodeptr - (int) new;
14338
14339 /* Now pack them all */
14340 forkshell_copy(fs);
14341
14342 /* Finish it up */
14343 *nodeptr = 0;
14344 new->size = size;
14345 new->nodeptr_offset = nodeptr_offset;
14346 new->old_base = new;
14347 new->hMapFile = h;
14348 return new;
14349}
14350
14351#undef exception_handler
14352#undef trap
14353#undef trap_ptr
14354static void *sticky_mem_start, *sticky_mem_end;
14355static void
14356forkshell_init(const char *idstr)
14357{
14358 struct forkshell *fs;
14359 int map_handle;
14360 HANDLE h;
14361 struct globals_var **gvpp;
14362 struct globals_misc **gmpp;
14363 int i;
14364
14365 if (sscanf(idstr, "%x", &map_handle) != 1)
14366 bb_error_msg_and_die("invalid forkshell ID");
14367
14368 h = (HANDLE)map_handle;
14369 fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14370 if (!fs)
14371 bb_error_msg_and_die("Invalid forkshell memory");
14372
14373 /* this memory can't be freed */
14374 sticky_mem_start = fs;
14375 sticky_mem_end = (char *) fs + fs->size;
14376 /* pointer fixup */
14377 nodeptr = (int*)((char*)fs + fs->nodeptr_offset);
14378 while (*nodeptr) {
14379 int *ptr = (int*)((char*)fs + (*nodeptr - (int)fs->old_base));
14380 if (*ptr)
14381 *ptr -= ((int)fs->old_base - (int)fs);
14382 nodeptr++;
14383 }
14384 /* Now fix up stuff that can't be transferred */
14385 fs->fp = forkpoints[fs->fpid];
14386 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14387 fs->gvp->varinit[i].var_func = varinit_data[i].var_func;
14388 for (i = 0; i < CMDTABLESIZE; i++) {
14389 struct tblentry *e = fs->cmdtable[i];
14390 while (e) {
14391 if (e->cmdtype == CMDBUILTIN)
14392 e->param.cmd = builtintab + (int)e->param.cmd;
14393 e = e->next;
14394 }
14395 }
14396 fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler;
14397 for (i = 0; i < NSIG; i++)
14398 fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i];
14399 fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr;
14400
14401 /* Switch global variables */
14402 gvpp = (struct globals_var **)&ash_ptr_to_globals_var;
14403 *gvpp = fs->gvp;
14404 gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc;
14405 *gmpp = fs->gmp;
14406 localvars = fs->localvars;
14407 cmdtable = fs->cmdtable;
14408
14409 fs->fp(fs);
14410}
14411
14412#undef free
14413static void
14414sticky_free(void *base)
14415{
14416 if (base >= sticky_mem_start && base < sticky_mem_end)
14417 return;
14418 free(base);
14419}
14420#endif
13280 14421
13281/*- 14422/*-
13282 * Copyright (c) 1989, 1991, 1993, 1994 14423 * Copyright (c) 1989, 1991, 1993, 1994
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 0051f21d9..f7503cac5 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -18,7 +18,9 @@
18 */ 18 */
19#include "libbb.h" 19#include "libbb.h"
20#include "shell_common.h" 20#include "shell_common.h"
21#if !ENABLE_PLATFORM_MINGW32
21#include <sys/resource.h> /* getrlimit */ 22#include <sys/resource.h> /* getrlimit */
23#endif
22 24
23const char defifsvar[] ALIGN1 = "IFS= \t\n"; 25const char defifsvar[] ALIGN1 = "IFS= \t\n";
24 26
@@ -201,7 +203,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
201 } 203 }
202 204
203 c = buffer[bufpos]; 205 c = buffer[bufpos];
204 if (c == '\0') 206 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r'))
205 continue; 207 continue;
206 if (backslash) { 208 if (backslash) {
207 backslash = 0; 209 backslash = 0;
@@ -370,6 +372,13 @@ static const char ulimit_opt_string[] = "-HSa"
370#endif 372#endif
371 ; 373 ;
372 374
375#if ENABLE_PLATFORM_MINGW32
376int FAST_FUNC
377shell_builtin_ulimit(char **argv)
378{
379 return 1;
380}
381#else
373static void printlim(unsigned opts, const struct rlimit *limit, 382static void printlim(unsigned opts, const struct rlimit *limit,
374 const struct limits *l) 383 const struct limits *l)
375{ 384{
@@ -498,3 +507,4 @@ shell_builtin_ulimit(char **argv)
498 507
499 return 0; 508 return 0;
500} 509}
510#endif