aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c1260
1 files changed, 1248 insertions, 12 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 84502636a..08b6aa430 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 * - fake $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.
@@ -72,6 +86,10 @@
72# define PIPE_BUF 4096 /* amount of buffering in a pipe */ 86# define PIPE_BUF 4096 /* amount of buffering in a pipe */
73#endif 87#endif
74 88
89#if !ENABLE_PLATFORM_MINGW32
90# define is_absolute_path(path) ((path)[0] == '/')
91#endif
92
75#if !BB_MMU 93#if !BB_MMU
76# error "Do not even bother, ash will not run on NOMMU machine" 94# error "Do not even bother, ash will not run on NOMMU machine"
77#endif 95#endif
@@ -201,6 +219,50 @@
201//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o 219//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
202//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o 220//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
203 221
222#if ENABLE_PLATFORM_MINGW32
223union node;
224struct strlist;
225struct job;
226
227struct forkshell {
228 /* filled by forkshell_copy() */
229 struct globals_var *gvp;
230 struct globals_misc *gmp;
231 struct tblentry **cmdtable;
232 /* struct alias **atab; */
233 /* struct parsefile *g_parsefile; */
234 HANDLE hMapFile;
235 void *old_base;
236 int nodeptr_offset;
237 int size;
238
239 /* type of forkshell */
240 int fpid;
241
242 /* optional data, used by forkshell_child */
243 int flags;
244 int fd[10];
245 union node *n;
246 char **argv;
247 char *string;
248 struct strlist *strlist;
249};
250
251enum {
252 FS_OPENHERE,
253 FS_EVALBACKCMD,
254 FS_EVALSUBSHELL,
255 FS_EVALPIPE,
256 FS_SHELLEXEC
257};
258
259static struct forkshell* forkshell_prepare(struct forkshell *fs);
260static void forkshell_init(const char *idstr);
261static void forkshell_child(struct forkshell *fs);
262static void sticky_free(void *p);
263#define free(p) sticky_free(p)
264static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode);
265#endif
204 266
205/* ============ Hash table sizes. Configurable. */ 267/* ============ Hash table sizes. Configurable. */
206 268
@@ -233,6 +295,10 @@ static const char *const optletters_optnames[] = {
233 ,"\0" "nolog" 295 ,"\0" "nolog"
234 ,"\0" "debug" 296 ,"\0" "debug"
235#endif 297#endif
298#if ENABLE_PLATFORM_MINGW32
299 ,"\0" "noconsole"
300 ,"X" "winxp"
301#endif
236}; 302};
237 303
238#define optletters(n) optletters_optnames[n][0] 304#define optletters(n) optletters_optnames[n][0]
@@ -313,6 +379,10 @@ struct globals_misc {
313# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] 379# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
314# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] 380# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
315#endif 381#endif
382#if ENABLE_PLATFORM_MINGW32
383# define noconsole optlist[14 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
384# define winxp optlist[15 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
385#endif
316 386
317 /* trap handler commands */ 387 /* trap handler commands */
318 /* 388 /*
@@ -2389,10 +2459,22 @@ path_advance(const char **path, const char *name)
2389 if (*path == NULL) 2459 if (*path == NULL)
2390 return NULL; 2460 return NULL;
2391 start = *path; 2461 start = *path;
2462#if ENABLE_PLATFORM_MINGW32
2463 p = next_path_sep(start);
2464 q = strchr(start, '%');
2465 if ((p && q && q < p) || (!p && q))
2466 p = q;
2467 if (!p)
2468 for (p = start; *p; p++)
2469 continue;
2470#else
2392 for (p = start; *p && *p != ':' && *p != '%'; p++) 2471 for (p = start; *p && *p != ':' && *p != '%'; p++)
2393 continue; 2472 continue;
2473#endif
2394 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2474 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2395 while (stackblocksize() < len) 2475
2476 /* preserve space for .exe too */
2477 while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len))
2396 growstackblock(); 2478 growstackblock();
2397 q = stackblock(); 2479 q = stackblock();
2398 if (p != start) { 2480 if (p != start) {
@@ -2404,10 +2486,19 @@ path_advance(const char **path, const char *name)
2404 pathopt = NULL; 2486 pathopt = NULL;
2405 if (*p == '%') { 2487 if (*p == '%') {
2406 pathopt = ++p; 2488 pathopt = ++p;
2489#if ENABLE_PLATFORM_MINGW32
2490 p = next_path_sep(start);
2491
2492 /* *p != ':' and '*' would suffice */
2493 if (!p)
2494 p = pathopt - 1;
2495#else
2407 while (*p && *p != ':') 2496 while (*p && *p != ':')
2408 p++; 2497 p++;
2498#endif
2409 } 2499 }
2410 if (*p == ':') 2500 if (*p == ':' ||
2501 (ENABLE_PLATFORM_MINGW32 && *p == ';'))
2411 *path = p + 1; 2502 *path = p + 1;
2412 else 2503 else
2413 *path = NULL; 2504 *path = NULL;
@@ -2509,6 +2600,106 @@ cdopt(void)
2509static const char * 2600static const char *
2510updatepwd(const char *dir) 2601updatepwd(const char *dir)
2511{ 2602{
2603#if ENABLE_PLATFORM_MINGW32
2604#define is_path_sep(x) ((x) == '/' || (x) == '\\')
2605#define is_unc_path(x) (is_path_sep(x[0]) && is_path_sep(x[1]))
2606 /*
2607 * Due to Windows drive notion, getting pwd is a completely
2608 * different thing. Handle it in a separate routine
2609 */
2610
2611 char *new;
2612 char *p;
2613 char *cdcomppath;
2614 const char *lim;
2615 /*
2616 * There are five cases that make some kind of sense
2617 * absdrive + abspath: c:/path
2618 * absdrive + !abspath: c:path
2619 * !absdrive + abspath: /path
2620 * !absdrive + uncpath: //host/share
2621 * !absdrive + !abspath: path
2622 *
2623 * Damn DOS!
2624 * c:path behaviour is "undefined"
2625 * To properly handle this case, I have to keep track of cwd
2626 * of every drive, which is too painful to do.
2627 * So when c:path is given, I assume it's c:${curdir}path
2628 * with ${curdir} comes from the current drive
2629 */
2630 int absdrive = *dir && dir[1] == ':';
2631 int abspath = absdrive ? is_path_sep(dir[2]) : is_path_sep(*dir);
2632
2633 cdcomppath = ststrdup(dir);
2634 STARTSTACKSTR(new);
2635 if (!absdrive && curdir == nullstr)
2636 return 0;
2637 if (!abspath) {
2638 if (curdir == nullstr)
2639 return 0;
2640 new = stack_putstr(curdir, new);
2641 }
2642 new = makestrspace(strlen(dir) + 2, new);
2643
2644 if ( is_unc_path(dir) || (!absdrive && !abspath && is_unc_path(curdir)) ) {
2645 lim = (char *)stackblock() + 1;
2646 }
2647 else {
2648 char *drive = stackblock();
2649 if (absdrive) {
2650 *drive = *dir;
2651 cdcomppath += 2;
2652 dir += 2;
2653 } else {
2654 *drive = *curdir;
2655 }
2656 drive[1] = ':'; /* in case of absolute drive+path */
2657
2658 if (abspath)
2659 new = drive + 2;
2660 lim = drive + 3;
2661 }
2662
2663 if (!abspath) {
2664 if (!is_path_sep(new[-1]))
2665 USTPUTC('/', new);
2666 if (new > lim && is_path_sep(*lim))
2667 lim++;
2668 } else {
2669 USTPUTC('/', new);
2670 cdcomppath ++;
2671 if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) {
2672 USTPUTC('/', new);
2673 cdcomppath++;
2674 lim++;
2675 }
2676 }
2677 p = strtok(cdcomppath, "/\\");
2678 while (p) {
2679 switch (*p) {
2680 case '.':
2681 if (p[1] == '.' && p[2] == '\0') {
2682 while (new > lim) {
2683 STUNPUTC(new);
2684 if (is_path_sep(new[-1]))
2685 break;
2686 }
2687 break;
2688 }
2689 if (p[1] == '\0')
2690 break;
2691 /* fall through */
2692 default:
2693 new = stack_putstr(p, new);
2694 USTPUTC('/', new);
2695 }
2696 p = strtok(0, "/\\");
2697 }
2698 if (new > lim)
2699 STUNPUTC(new);
2700 *new = 0;
2701 return stackblock();
2702#else
2512 char *new; 2703 char *new;
2513 char *p; 2704 char *p;
2514 char *cdcomppath; 2705 char *cdcomppath;
@@ -2562,6 +2753,7 @@ updatepwd(const char *dir)
2562 STUNPUTC(new); 2753 STUNPUTC(new);
2563 *new = 0; 2754 *new = 0;
2564 return stackblock(); 2755 return stackblock();
2756#endif
2565} 2757}
2566 2758
2567/* 2759/*
@@ -2656,7 +2848,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2656 } 2848 }
2657 if (!dest) 2849 if (!dest)
2658 dest = nullstr; 2850 dest = nullstr;
2659 if (*dest == '/') 2851 if (is_absolute_path(dest))
2660 goto step7; 2852 goto step7;
2661 if (*dest == '.') { 2853 if (*dest == '.') {
2662 c = dest[1]; 2854 c = dest[1];
@@ -3374,7 +3566,9 @@ struct job {
3374}; 3566};
3375 3567
3376static struct job *makejob(/*union node *,*/ int); 3568static struct job *makejob(/*union node *,*/ int);
3569#if !ENABLE_PLATFORM_MINGW32
3377static int forkshell(struct job *, union node *, int); 3570static int forkshell(struct job *, union node *, int);
3571#endif
3378static int waitforjob(struct job *); 3572static int waitforjob(struct job *);
3379 3573
3380#if !JOBS 3574#if !JOBS
@@ -3429,6 +3623,8 @@ setsignal(int signo)
3429 char cur_act, new_act; 3623 char cur_act, new_act;
3430 struct sigaction act; 3624 struct sigaction act;
3431 3625
3626 if (ENABLE_PLATFORM_MINGW32)
3627 return;
3432 t = trap[signo]; 3628 t = trap[signo];
3433 new_act = S_DFL; 3629 new_act = S_DFL;
3434 if (t != NULL) { /* trap for this sig is set */ 3630 if (t != NULL) { /* trap for this sig is set */
@@ -3944,6 +4140,79 @@ sprint_status48(char *s, int status, int sigonly)
3944 return col; 4140 return col;
3945} 4141}
3946 4142
4143#if ENABLE_PLATFORM_MINGW32
4144
4145HANDLE hSIGINT; /* Ctrl-C is pressed */
4146
4147static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
4148{
4149 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
4150 SetEvent(hSIGINT);
4151 return TRUE;
4152 }
4153 return FALSE;
4154}
4155
4156/*
4157 * Windows does not know about parent-child relationship
4158 * They don't support waitpid(-1)
4159 */
4160static pid_t
4161waitpid_child(int *status, int wait_flags)
4162{
4163 HANDLE *pidlist, *pidp;
4164 int pid_nr = 0;
4165 pid_t pid;
4166 DWORD win_status, idx;
4167 struct job *jb;
4168
4169 #define LOOP(stmt) \
4170 for (jb = curjob; jb; jb = jb->prev_job) { \
4171 struct procstat *ps, *psend; \
4172 if (jb->state == JOBDONE) \
4173 continue; \
4174 ps = jb->ps; \
4175 psend = ps + jb->nprocs; \
4176 while (ps < psend) { \
4177 if (ps->ps_pid != -1) { \
4178 stmt; \
4179 } \
4180 ps++; \
4181 } \
4182 }
4183
4184 LOOP(pid_nr++);
4185 if (!pid_nr)
4186 return -1;
4187 pid_nr++;
4188 pidp = pidlist = ckmalloc(sizeof(*pidlist)*pid_nr);
4189 *pidp++ = hSIGINT;
4190 LOOP(*pidp++ = (HANDLE)ps->ps_pid);
4191 #undef LOOP
4192
4193 idx = WaitForMultipleObjects(pid_nr, pidlist, FALSE,
4194 wait_flags|WNOHANG ? 1 : INFINITE);
4195 if (idx >= pid_nr) {
4196 free(pidlist);
4197 return -1;
4198 }
4199 if (!idx) { /* hSIGINT */
4200 int i;
4201 ResetEvent(hSIGINT);
4202 for (i = 1; i < pid_nr; i++)
4203 TerminateProcess(pidlist[i], 1);
4204 free(pidlist);
4205 *status = 260; /* terminated by a signal */
4206 return pidlist[1];
4207 }
4208 GetExitCodeProcess(pidlist[idx], &win_status);
4209 pid = (int)pidlist[idx];
4210 free(pidlist);
4211 *status = (int)win_status;
4212 return pid;
4213}
4214#endif
4215
3947static int 4216static int
3948dowait(int wait_flags, struct job *job) 4217dowait(int wait_flags, struct job *job)
3949{ 4218{
@@ -3959,7 +4228,11 @@ dowait(int wait_flags, struct job *job)
3959 * NB: _not_ safe_waitpid, we need to detect EINTR */ 4228 * NB: _not_ safe_waitpid, we need to detect EINTR */
3960 if (doing_jobctl) 4229 if (doing_jobctl)
3961 wait_flags |= WUNTRACED; 4230 wait_flags |= WUNTRACED;
4231#if ENABLE_PLATFORM_MINGW32
4232 pid = waitpid_child(&status, wait_flags);
4233#else
3962 pid = waitpid(-1, &status, wait_flags); 4234 pid = waitpid(-1, &status, wait_flags);
4235#endif
3963 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", 4236 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3964 pid, status, errno, strerror(errno))); 4237 pid, status, errno, strerror(errno)));
3965 if (pid <= 0) 4238 if (pid <= 0)
@@ -3983,6 +4256,8 @@ dowait(int wait_flags, struct job *job)
3983 jobno(jp), pid, ps->ps_status, status)); 4256 jobno(jp), pid, ps->ps_status, status));
3984 ps->ps_status = status; 4257 ps->ps_status = status;
3985 thisjob = jp; 4258 thisjob = jp;
4259 if (ENABLE_PLATFORM_MINGW32)
4260 ps->ps_pid = -1;
3986 } 4261 }
3987 if (ps->ps_status == -1) 4262 if (ps->ps_status == -1)
3988 jobstate = JOBRUNNING; 4263 jobstate = JOBRUNNING;
@@ -4215,6 +4490,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
4215 int retval; 4490 int retval;
4216 struct job *jp; 4491 struct job *jp;
4217 4492
4493 if (ENABLE_PLATFORM_MINGW32)
4494 return 0;
4495
4218 if (pending_sig) 4496 if (pending_sig)
4219 raise_exception(EXSIG); 4497 raise_exception(EXSIG);
4220 4498
@@ -4663,6 +4941,7 @@ commandtext(union node *n)
4663 * 4941 *
4664 * Called with interrupts off. 4942 * Called with interrupts off.
4665 */ 4943 */
4944#if !ENABLE_PLATFORM_MINGW32
4666/* 4945/*
4667 * Clear traps on a fork. 4946 * Clear traps on a fork.
4668 */ 4947 */
@@ -4811,6 +5090,7 @@ forkchild(struct job *jp, union node *n, int mode)
4811 freejob(jp); 5090 freejob(jp);
4812 jobless = 0; 5091 jobless = 0;
4813} 5092}
5093#endif
4814 5094
4815/* Called after fork(), in parent */ 5095/* Called after fork(), in parent */
4816#if !JOBS 5096#if !JOBS
@@ -4820,7 +5100,7 @@ static void
4820forkparent(struct job *jp, union node *n, int mode, pid_t pid) 5100forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4821{ 5101{
4822 TRACE(("In parent shell: child = %d\n", pid)); 5102 TRACE(("In parent shell: child = %d\n", pid));
4823 if (!jp) { 5103 if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */
4824 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) 5104 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4825 continue; 5105 continue;
4826 jobless++; 5106 jobless++;
@@ -4854,12 +5134,14 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4854 } 5134 }
4855} 5135}
4856 5136
5137#if !ENABLE_PLATFORM_MINGW32
4857static int 5138static int
4858forkshell(struct job *jp, union node *n, int mode) 5139forkshell(struct job *jp, union node *n, int mode)
4859{ 5140{
4860 int pid; 5141 int pid;
4861 5142
4862 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); 5143 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5144
4863 pid = fork(); 5145 pid = fork();
4864 if (pid < 0) { 5146 if (pid < 0) {
4865 TRACE(("Fork failed, errno=%d", errno)); 5147 TRACE(("Fork failed, errno=%d", errno));
@@ -4875,6 +5157,7 @@ forkshell(struct job *jp, union node *n, int mode)
4875 } 5157 }
4876 return pid; 5158 return pid;
4877} 5159}
5160#endif
4878 5161
4879/* 5162/*
4880 * Wait for job to finish. 5163 * Wait for job to finish.
@@ -5067,6 +5350,7 @@ openhere(union node *redir)
5067{ 5350{
5068 int pip[2]; 5351 int pip[2];
5069 size_t len = 0; 5352 size_t len = 0;
5353 IF_PLATFORM_MINGW32(struct forkshell fs);
5070 5354
5071 if (pipe(pip) < 0) 5355 if (pipe(pip) < 0)
5072 ash_msg_and_raise_error("pipe call failed"); 5356 ash_msg_and_raise_error("pipe call failed");
@@ -5077,6 +5361,15 @@ openhere(union node *redir)
5077 goto out; 5361 goto out;
5078 } 5362 }
5079 } 5363 }
5364#if ENABLE_PLATFORM_MINGW32
5365 memset(&fs, 0, sizeof(fs));
5366 fs.fpid = FS_OPENHERE;
5367 fs.n = redir;
5368 fs.fd[0] = pip[0];
5369 fs.fd[1] = pip[1];
5370 if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0)
5371 ash_msg_and_raise_error("unable to spawn shell");
5372#else
5080 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 5373 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5081 /* child */ 5374 /* child */
5082 close(pip[0]); 5375 close(pip[0]);
@@ -5091,6 +5384,7 @@ openhere(union node *redir)
5091 expandhere(redir->nhere.doc, pip[1]); 5384 expandhere(redir->nhere.doc, pip[1]);
5092 _exit(EXIT_SUCCESS); 5385 _exit(EXIT_SUCCESS);
5093 } 5386 }
5387#endif
5094 out: 5388 out:
5095 close(pip[1]); 5389 close(pip[1]);
5096 return pip[0]; 5390 return pip[0];
@@ -5103,6 +5397,31 @@ openredirect(union node *redir)
5103 int f; 5397 int f;
5104 5398
5105 fname = redir->nfile.expfname; 5399 fname = redir->nfile.expfname;
5400#if ENABLE_PLATFORM_MINGW32
5401 /* Support for /dev/null */
5402 switch (redir->nfile.type) {
5403 case NFROM:
5404 if (!strcmp(fname, "/dev/null"))
5405 return open("nul",O_RDWR);
5406 if (!strncmp(fname, "/dev/", 5)) {
5407 ash_msg("Unhandled device %s\n", fname);
5408 return -1;
5409 }
5410 break;
5411
5412 case NFROMTO:
5413 case NTO:
5414 case NCLOBBER:
5415 case NAPPEND:
5416 if (!strcmp(fname, "/dev/null"))
5417 return open("nul",O_RDWR);
5418 if (!strncmp(fname, "/dev/", 5)) {
5419 ash_msg("Unhandled device %s\n", fname);
5420 return -1;
5421 }
5422 break;
5423 }
5424#endif
5106 switch (redir->nfile.type) { 5425 switch (redir->nfile.type) {
5107 case NFROM: 5426 case NFROM:
5108 f = open(fname, O_RDONLY); 5427 f = open(fname, O_RDONLY);
@@ -5135,6 +5454,9 @@ openredirect(union node *redir)
5135 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); 5454 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5136 if (f < 0) 5455 if (f < 0)
5137 goto ecreate; 5456 goto ecreate;
5457#if ENABLE_PLATFORM_MINGW32
5458 lseek(f, 0, SEEK_END);
5459#endif
5138 break; 5460 break;
5139 default: 5461 default:
5140#if DEBUG 5462#if DEBUG
@@ -5838,6 +6160,7 @@ struct backcmd { /* result of evalbackcmd */
5838 int fd; /* file descriptor to read from */ 6160 int fd; /* file descriptor to read from */
5839 int nleft; /* number of chars in buffer */ 6161 int nleft; /* number of chars in buffer */
5840 char *buf; /* buffer */ 6162 char *buf; /* buffer */
6163 IF_PLATFORM_MINGW32(struct forkshell fs);
5841 struct job *jp; /* job structure for command */ 6164 struct job *jp; /* job structure for command */
5842}; 6165};
5843 6166
@@ -5854,6 +6177,7 @@ evalbackcmd(union node *n, struct backcmd *result)
5854 result->fd = -1; 6177 result->fd = -1;
5855 result->buf = NULL; 6178 result->buf = NULL;
5856 result->nleft = 0; 6179 result->nleft = 0;
6180 IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs)));
5857 result->jp = NULL; 6181 result->jp = NULL;
5858 if (n == NULL) 6182 if (n == NULL)
5859 goto out; 6183 goto out;
@@ -5868,6 +6192,14 @@ evalbackcmd(union node *n, struct backcmd *result)
5868 if (pipe(pip) < 0) 6192 if (pipe(pip) < 0)
5869 ash_msg_and_raise_error("pipe call failed"); 6193 ash_msg_and_raise_error("pipe call failed");
5870 jp = makejob(/*n,*/ 1); 6194 jp = makejob(/*n,*/ 1);
6195#if ENABLE_PLATFORM_MINGW32
6196 result->fs.fpid = FS_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#else
5871 if (forkshell(jp, n, FORK_NOJOB) == 0) { 6203 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5872 FORCE_INT_ON; 6204 FORCE_INT_ON;
5873 close(pip[0]); 6205 close(pip[0]);
@@ -5880,6 +6212,7 @@ evalbackcmd(union node *n, struct backcmd *result)
5880 evaltree(n, EV_EXIT); /* actually evaltreenr... */ 6212 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5881 /* NOTREACHED */ 6213 /* NOTREACHED */
5882 } 6214 }
6215#endif
5883 close(pip[1]); 6216 close(pip[1]);
5884 result->fd = pip[0]; 6217 result->fd = pip[0];
5885 result->jp = jp; 6218 result->jp = jp;
@@ -5938,7 +6271,8 @@ expbackq(union node *cmd, int flag)
5938 6271
5939 /* Eat all trailing newlines */ 6272 /* Eat all trailing newlines */
5940 dest = expdest; 6273 dest = expdest;
5941 for (; dest > (char *)stackblock() && dest[-1] == '\n';) 6274 for (; dest > (char *)stackblock() && (dest[-1] == '\n' ||
6275 (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));)
5942 STUNPUTC(dest); 6276 STUNPUTC(dest);
5943 expdest = dest; 6277 expdest = dest;
5944 6278
@@ -7432,6 +7766,15 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **
7432 } 7766 }
7433} 7767}
7434 7768
7769#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE
7770/* check if command and executable are both busybox */
7771static int busybox_cmd_and_exe(const char *name)
7772{
7773 return strcmp(name, "busybox") == 0 &&
7774 strcmp(bb_basename(bb_busybox_exec_path), "busybox.exe") == 0;
7775}
7776#endif
7777
7435/* 7778/*
7436 * Exec a program. Never returns. If you change this routine, you may 7779 * Exec a program. Never returns. If you change this routine, you may
7437 * have to change the find_command routine as well. 7780 * have to change the find_command routine as well.
@@ -7448,7 +7791,7 @@ shellexec(char **argv, const char *path, int idx)
7448 7791
7449 clearredir(/*drop:*/ 1); 7792 clearredir(/*drop:*/ 1);
7450 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); 7793 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7451 if (strchr(argv[0], '/') != NULL 7794 if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\')))
7452#if ENABLE_FEATURE_SH_STANDALONE 7795#if ENABLE_FEATURE_SH_STANDALONE
7453 || (applet_no = find_applet_by_name(argv[0])) >= 0 7796 || (applet_no = find_applet_by_name(argv[0])) >= 0
7454#endif 7797#endif
@@ -7462,6 +7805,10 @@ shellexec(char **argv, const char *path, int idx)
7462 goto try_PATH; 7805 goto try_PATH;
7463 } 7806 }
7464 e = errno; 7807 e = errno;
7808#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE
7809 } else if (busybox_cmd_and_exe(argv[0])) {
7810 tryexec(-1, bb_busybox_exec_path, argv, envp);
7811#endif
7465 } else { 7812 } else {
7466 try_PATH: 7813 try_PATH:
7467 e = ENOENT; 7814 e = ENOENT;
@@ -7963,6 +8310,10 @@ static int funcblocksize; /* size of structures in function */
7963static int funcstringsize; /* size of strings in node */ 8310static int funcstringsize; /* size of strings in node */
7964static void *funcblock; /* block to allocate function from */ 8311static void *funcblock; /* block to allocate function from */
7965static char *funcstring; /* block to allocate strings from */ 8312static char *funcstring; /* block to allocate strings from */
8313#if ENABLE_PLATFORM_MINGW32
8314static int nodeptrsize;
8315static char **nodeptr;
8316#endif
7966 8317
7967/* flags in argument to evaltree */ 8318/* flags in argument to evaltree */
7968#define EV_EXIT 01 /* exit after evaluating tree */ 8319#define EV_EXIT 01 /* exit after evaluating tree */
@@ -8008,6 +8359,7 @@ sizenodelist(struct nodelist *lp)
8008{ 8359{
8009 while (lp) { 8360 while (lp) {
8010 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 8361 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8362 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8011 calcsize(lp->n); 8363 calcsize(lp->n);
8012 lp = lp->next; 8364 lp = lp->next;
8013 } 8365 }
@@ -8024,15 +8376,18 @@ calcsize(union node *n)
8024 calcsize(n->ncmd.redirect); 8376 calcsize(n->ncmd.redirect);
8025 calcsize(n->ncmd.args); 8377 calcsize(n->ncmd.args);
8026 calcsize(n->ncmd.assign); 8378 calcsize(n->ncmd.assign);
8379 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8027 break; 8380 break;
8028 case NPIPE: 8381 case NPIPE:
8029 sizenodelist(n->npipe.cmdlist); 8382 sizenodelist(n->npipe.cmdlist);
8383 IF_PLATFORM_MINGW32(nodeptrsize++);
8030 break; 8384 break;
8031 case NREDIR: 8385 case NREDIR:
8032 case NBACKGND: 8386 case NBACKGND:
8033 case NSUBSHELL: 8387 case NSUBSHELL:
8034 calcsize(n->nredir.redirect); 8388 calcsize(n->nredir.redirect);
8035 calcsize(n->nredir.n); 8389 calcsize(n->nredir.n);
8390 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8036 break; 8391 break;
8037 case NAND: 8392 case NAND:
8038 case NOR: 8393 case NOR:
@@ -8041,31 +8396,37 @@ calcsize(union node *n)
8041 case NUNTIL: 8396 case NUNTIL:
8042 calcsize(n->nbinary.ch2); 8397 calcsize(n->nbinary.ch2);
8043 calcsize(n->nbinary.ch1); 8398 calcsize(n->nbinary.ch1);
8399 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8044 break; 8400 break;
8045 case NIF: 8401 case NIF:
8046 calcsize(n->nif.elsepart); 8402 calcsize(n->nif.elsepart);
8047 calcsize(n->nif.ifpart); 8403 calcsize(n->nif.ifpart);
8048 calcsize(n->nif.test); 8404 calcsize(n->nif.test);
8405 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8049 break; 8406 break;
8050 case NFOR: 8407 case NFOR:
8051 funcstringsize += strlen(n->nfor.var) + 1; 8408 funcstringsize += strlen(n->nfor.var) + 1;
8052 calcsize(n->nfor.body); 8409 calcsize(n->nfor.body);
8053 calcsize(n->nfor.args); 8410 calcsize(n->nfor.args);
8411 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8054 break; 8412 break;
8055 case NCASE: 8413 case NCASE:
8056 calcsize(n->ncase.cases); 8414 calcsize(n->ncase.cases);
8057 calcsize(n->ncase.expr); 8415 calcsize(n->ncase.expr);
8416 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8058 break; 8417 break;
8059 case NCLIST: 8418 case NCLIST:
8060 calcsize(n->nclist.body); 8419 calcsize(n->nclist.body);
8061 calcsize(n->nclist.pattern); 8420 calcsize(n->nclist.pattern);
8062 calcsize(n->nclist.next); 8421 calcsize(n->nclist.next);
8422 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8063 break; 8423 break;
8064 case NDEFUN: 8424 case NDEFUN:
8065 case NARG: 8425 case NARG:
8066 sizenodelist(n->narg.backquote); 8426 sizenodelist(n->narg.backquote);
8067 funcstringsize += strlen(n->narg.text) + 1; 8427 funcstringsize += strlen(n->narg.text) + 1;
8068 calcsize(n->narg.next); 8428 calcsize(n->narg.next);
8429 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8069 break; 8430 break;
8070 case NTO: 8431 case NTO:
8071#if ENABLE_ASH_BASH_COMPAT 8432#if ENABLE_ASH_BASH_COMPAT
@@ -8077,28 +8438,34 @@ calcsize(union node *n)
8077 case NAPPEND: 8438 case NAPPEND:
8078 calcsize(n->nfile.fname); 8439 calcsize(n->nfile.fname);
8079 calcsize(n->nfile.next); 8440 calcsize(n->nfile.next);
8441 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8080 break; 8442 break;
8081 case NTOFD: 8443 case NTOFD:
8082 case NFROMFD: 8444 case NFROMFD:
8083 calcsize(n->ndup.vname); 8445 calcsize(n->ndup.vname);
8084 calcsize(n->ndup.next); 8446 calcsize(n->ndup.next);
8447 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8085 break; 8448 break;
8086 case NHERE: 8449 case NHERE:
8087 case NXHERE: 8450 case NXHERE:
8088 calcsize(n->nhere.doc); 8451 calcsize(n->nhere.doc);
8089 calcsize(n->nhere.next); 8452 calcsize(n->nhere.next);
8453 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8090 break; 8454 break;
8091 case NNOT: 8455 case NNOT:
8092 calcsize(n->nnot.com); 8456 calcsize(n->nnot.com);
8457 IF_PLATFORM_MINGW32(nodeptrsize++);
8093 break; 8458 break;
8094 }; 8459 };
8095} 8460}
8096 8461
8097static char * 8462static char *
8098nodeckstrdup(char *s) 8463nodeckstrdup(const char *s)
8099{ 8464{
8100 char *rtn = funcstring; 8465 char *rtn = funcstring;
8101 8466
8467 if (!s)
8468 return NULL;
8102 strcpy(funcstring, s); 8469 strcpy(funcstring, s);
8103 funcstring += strlen(s) + 1; 8470 funcstring += strlen(s) + 1;
8104 return rtn; 8471 return rtn;
@@ -8106,6 +8473,18 @@ nodeckstrdup(char *s)
8106 8473
8107static union node *copynode(union node *); 8474static union node *copynode(union node *);
8108 8475
8476#if ENABLE_PLATFORM_MINGW32
8477# define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (char *)&(dst);}
8478# define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);}}
8479# define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);}}
8480# define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);*nodeptr++ = (char *)&(dst4);}}
8481#else
8482# define SAVE_PTR(dst)
8483# define SAVE_PTR2(dst,dst2)
8484# define SAVE_PTR3(dst,dst2,dst3)
8485# define SAVE_PTR4(dst,dst2,dst3,dst4)
8486#endif
8487
8109static struct nodelist * 8488static struct nodelist *
8110copynodelist(struct nodelist *lp) 8489copynodelist(struct nodelist *lp)
8111{ 8490{
@@ -8117,6 +8496,7 @@ copynodelist(struct nodelist *lp)
8117 *lpp = funcblock; 8496 *lpp = funcblock;
8118 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); 8497 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8119 (*lpp)->n = copynode(lp->n); 8498 (*lpp)->n = copynode(lp->n);
8499 SAVE_PTR2((*lpp)->n, (*lpp)->next);
8120 lp = lp->next; 8500 lp = lp->next;
8121 lpp = &(*lpp)->next; 8501 lpp = &(*lpp)->next;
8122 } 8502 }
@@ -8139,16 +8519,19 @@ copynode(union node *n)
8139 new->ncmd.redirect = copynode(n->ncmd.redirect); 8519 new->ncmd.redirect = copynode(n->ncmd.redirect);
8140 new->ncmd.args = copynode(n->ncmd.args); 8520 new->ncmd.args = copynode(n->ncmd.args);
8141 new->ncmd.assign = copynode(n->ncmd.assign); 8521 new->ncmd.assign = copynode(n->ncmd.assign);
8522 SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign);
8142 break; 8523 break;
8143 case NPIPE: 8524 case NPIPE:
8144 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 8525 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8145 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; 8526 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8527 SAVE_PTR(new->npipe.cmdlist);
8146 break; 8528 break;
8147 case NREDIR: 8529 case NREDIR:
8148 case NBACKGND: 8530 case NBACKGND:
8149 case NSUBSHELL: 8531 case NSUBSHELL:
8150 new->nredir.redirect = copynode(n->nredir.redirect); 8532 new->nredir.redirect = copynode(n->nredir.redirect);
8151 new->nredir.n = copynode(n->nredir.n); 8533 new->nredir.n = copynode(n->nredir.n);
8534 SAVE_PTR2(new->nredir.redirect,new->nredir.n);
8152 break; 8535 break;
8153 case NAND: 8536 case NAND:
8154 case NOR: 8537 case NOR:
@@ -8157,31 +8540,37 @@ copynode(union node *n)
8157 case NUNTIL: 8540 case NUNTIL:
8158 new->nbinary.ch2 = copynode(n->nbinary.ch2); 8541 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8159 new->nbinary.ch1 = copynode(n->nbinary.ch1); 8542 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8543 SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2);
8160 break; 8544 break;
8161 case NIF: 8545 case NIF:
8162 new->nif.elsepart = copynode(n->nif.elsepart); 8546 new->nif.elsepart = copynode(n->nif.elsepart);
8163 new->nif.ifpart = copynode(n->nif.ifpart); 8547 new->nif.ifpart = copynode(n->nif.ifpart);
8164 new->nif.test = copynode(n->nif.test); 8548 new->nif.test = copynode(n->nif.test);
8549 SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test);
8165 break; 8550 break;
8166 case NFOR: 8551 case NFOR:
8167 new->nfor.var = nodeckstrdup(n->nfor.var); 8552 new->nfor.var = nodeckstrdup(n->nfor.var);
8168 new->nfor.body = copynode(n->nfor.body); 8553 new->nfor.body = copynode(n->nfor.body);
8169 new->nfor.args = copynode(n->nfor.args); 8554 new->nfor.args = copynode(n->nfor.args);
8555 SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args);
8170 break; 8556 break;
8171 case NCASE: 8557 case NCASE:
8172 new->ncase.cases = copynode(n->ncase.cases); 8558 new->ncase.cases = copynode(n->ncase.cases);
8173 new->ncase.expr = copynode(n->ncase.expr); 8559 new->ncase.expr = copynode(n->ncase.expr);
8560 SAVE_PTR2(new->ncase.cases,new->ncase.expr);
8174 break; 8561 break;
8175 case NCLIST: 8562 case NCLIST:
8176 new->nclist.body = copynode(n->nclist.body); 8563 new->nclist.body = copynode(n->nclist.body);
8177 new->nclist.pattern = copynode(n->nclist.pattern); 8564 new->nclist.pattern = copynode(n->nclist.pattern);
8178 new->nclist.next = copynode(n->nclist.next); 8565 new->nclist.next = copynode(n->nclist.next);
8566 SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next);
8179 break; 8567 break;
8180 case NDEFUN: 8568 case NDEFUN:
8181 case NARG: 8569 case NARG:
8182 new->narg.backquote = copynodelist(n->narg.backquote); 8570 new->narg.backquote = copynodelist(n->narg.backquote);
8183 new->narg.text = nodeckstrdup(n->narg.text); 8571 new->narg.text = nodeckstrdup(n->narg.text);
8184 new->narg.next = copynode(n->narg.next); 8572 new->narg.next = copynode(n->narg.next);
8573 SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next);
8185 break; 8574 break;
8186 case NTO: 8575 case NTO:
8187#if ENABLE_ASH_BASH_COMPAT 8576#if ENABLE_ASH_BASH_COMPAT
@@ -8194,6 +8583,7 @@ copynode(union node *n)
8194 new->nfile.fname = copynode(n->nfile.fname); 8583 new->nfile.fname = copynode(n->nfile.fname);
8195 new->nfile.fd = n->nfile.fd; 8584 new->nfile.fd = n->nfile.fd;
8196 new->nfile.next = copynode(n->nfile.next); 8585 new->nfile.next = copynode(n->nfile.next);
8586 SAVE_PTR2(new->nfile.fname,new->nfile.next);
8197 break; 8587 break;
8198 case NTOFD: 8588 case NTOFD:
8199 case NFROMFD: 8589 case NFROMFD:
@@ -8201,15 +8591,18 @@ copynode(union node *n)
8201 new->ndup.dupfd = n->ndup.dupfd; 8591 new->ndup.dupfd = n->ndup.dupfd;
8202 new->ndup.fd = n->ndup.fd; 8592 new->ndup.fd = n->ndup.fd;
8203 new->ndup.next = copynode(n->ndup.next); 8593 new->ndup.next = copynode(n->ndup.next);
8594 SAVE_PTR2(new->ndup.vname,new->ndup.next);
8204 break; 8595 break;
8205 case NHERE: 8596 case NHERE:
8206 case NXHERE: 8597 case NXHERE:
8207 new->nhere.doc = copynode(n->nhere.doc); 8598 new->nhere.doc = copynode(n->nhere.doc);
8208 new->nhere.fd = n->nhere.fd; 8599 new->nhere.fd = n->nhere.fd;
8209 new->nhere.next = copynode(n->nhere.next); 8600 new->nhere.next = copynode(n->nhere.next);
8601 SAVE_PTR2(new->nhere.doc,new->nhere.next);
8210 break; 8602 break;
8211 case NNOT: 8603 case NNOT:
8212 new->nnot.com = copynode(n->nnot.com); 8604 new->nnot.com = copynode(n->nnot.com);
8605 SAVE_PTR(new->nnot.com);
8213 break; 8606 break;
8214 }; 8607 };
8215 new->type = n->type; 8608 new->type = n->type;
@@ -8232,6 +8625,7 @@ copyfunc(union node *n)
8232 f = ckmalloc(blocksize + funcstringsize); 8625 f = ckmalloc(blocksize + funcstringsize);
8233 funcblock = (char *) f + offsetof(struct funcnode, n); 8626 funcblock = (char *) f + offsetof(struct funcnode, n);
8234 funcstring = (char *) f + blocksize; 8627 funcstring = (char *) f + blocksize;
8628 IF_PLATFORM_MINGW32(nodeptr = NULL);
8235 copynode(n); 8629 copynode(n);
8236 f->count = 0; 8630 f->count = 0;
8237 return f; 8631 return f;
@@ -8591,6 +8985,7 @@ evalcase(union node *n, int flags)
8591static void 8985static void
8592evalsubshell(union node *n, int flags) 8986evalsubshell(union node *n, int flags)
8593{ 8987{
8988 IF_PLATFORM_MINGW32(struct forkshell fs;)
8594 struct job *jp; 8989 struct job *jp;
8595 int backgnd = (n->type == NBACKGND); 8990 int backgnd = (n->type == NBACKGND);
8596 int status; 8991 int status;
@@ -8600,12 +8995,22 @@ evalsubshell(union node *n, int flags)
8600 goto nofork; 8995 goto nofork;
8601 INT_OFF; 8996 INT_OFF;
8602 jp = makejob(/*n,*/ 1); 8997 jp = makejob(/*n,*/ 1);
8998#if ENABLE_PLATFORM_MINGW32
8999 memset(&fs, 0, sizeof(fs));
9000 fs.fpid = FS_EVALSUBSHELL;
9001 fs.n = n;
9002 fs.flags = flags;
9003 if (spawn_forkshell(jp, &fs, backgnd) < 0)
9004 ash_msg_and_raise_error("unable to spawn shell");
9005 if ( 0 ) {
9006#else
8603 if (forkshell(jp, n, backgnd) == 0) { 9007 if (forkshell(jp, n, backgnd) == 0) {
8604 /* child */ 9008 /* child */
8605 INT_ON; 9009 INT_ON;
8606 flags |= EV_EXIT; 9010 flags |= EV_EXIT;
8607 if (backgnd) 9011 if (backgnd)
8608 flags &= ~EV_TESTED; 9012 flags &= ~EV_TESTED;
9013#endif
8609 nofork: 9014 nofork:
8610 redirect(n->nredir.redirect, 0); 9015 redirect(n->nredir.redirect, 0);
8611 evaltreenr(n->nredir.n, flags); 9016 evaltreenr(n->nredir.n, flags);
@@ -8691,6 +9096,7 @@ expredir(union node *n)
8691static void 9096static void
8692evalpipe(union node *n, int flags) 9097evalpipe(union node *n, int flags)
8693{ 9098{
9099 IF_PLATFORM_MINGW32(struct forkshell fs;)
8694 struct job *jp; 9100 struct job *jp;
8695 struct nodelist *lp; 9101 struct nodelist *lp;
8696 int pipelen; 9102 int pipelen;
@@ -8714,6 +9120,17 @@ evalpipe(union node *n, int flags)
8714 ash_msg_and_raise_error("pipe call failed"); 9120 ash_msg_and_raise_error("pipe call failed");
8715 } 9121 }
8716 } 9122 }
9123#if ENABLE_PLATFORM_MINGW32
9124 memset(&fs, 0, sizeof(fs));
9125 fs.fpid = FS_EVALPIPE;
9126 fs.flags = flags;
9127 fs.n = lp->n;
9128 fs.fd[0] = pip[0];
9129 fs.fd[1] = pip[1];
9130 fs.fd[2] = prevfd;
9131 if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0)
9132 ash_msg_and_raise_error("unable to spawn shell");
9133#else
8717 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { 9134 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8718 INT_ON; 9135 INT_ON;
8719 if (pip[1] >= 0) { 9136 if (pip[1] >= 0) {
@@ -8730,6 +9147,7 @@ evalpipe(union node *n, int flags)
8730 evaltreenr(lp->n, flags); 9147 evaltreenr(lp->n, flags);
8731 /* never returns */ 9148 /* never returns */
8732 } 9149 }
9150#endif
8733 if (prevfd >= 0) 9151 if (prevfd >= 0)
8734 close(prevfd); 9152 close(prevfd);
8735 prevfd = pip[0]; 9153 prevfd = pip[0];
@@ -9215,6 +9633,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9215 * as POSIX mandates */ 9633 * as POSIX mandates */
9216 return back_exitstatus; 9634 return back_exitstatus;
9217} 9635}
9636
9218static void 9637static void
9219evalcommand(union node *cmd, int flags) 9638evalcommand(union node *cmd, int flags)
9220{ 9639{
@@ -9392,6 +9811,27 @@ evalcommand(union node *cmd, int flags)
9392 * in a script or a subshell does not need forking, 9811 * in a script or a subshell does not need forking,
9393 * we can just exec it. 9812 * we can just exec it.
9394 */ 9813 */
9814#if ENABLE_PLATFORM_MINGW32
9815 if (!(flags & EV_EXIT) || trap[0]) {
9816 /* No, forking off a child is necessary */
9817 struct forkshell fs;
9818
9819 memset(&fs, 0, sizeof(fs));
9820 fs.fpid = FS_SHELLEXEC;
9821 fs.argv = argv;
9822 fs.string = (char*)path;
9823 fs.fd[0] = cmdentry.u.index;
9824 fs.strlist = varlist.list;
9825 jp = makejob(/*cmd,*/ 1);
9826 if (spawn_forkshell(jp, &fs, FORK_FG) < 0)
9827 ash_msg_and_raise_error("unable to spawn shell");
9828 exitstatus = waitforjob(jp);
9829 INT_ON;
9830 TRACE(("forked child exited with %d\n", exitstatus));
9831 break;
9832 }
9833 /* goes through to shellexec() */
9834#else
9395 if (!(flags & EV_EXIT) || may_have_traps) { 9835 if (!(flags & EV_EXIT) || may_have_traps) {
9396 /* No, forking off a child is necessary */ 9836 /* No, forking off a child is necessary */
9397 INT_OFF; 9837 INT_OFF;
@@ -9407,6 +9847,7 @@ evalcommand(union node *cmd, int flags)
9407 FORCE_INT_ON; 9847 FORCE_INT_ON;
9408 /* fall through to exec'ing external program */ 9848 /* fall through to exec'ing external program */
9409 } 9849 }
9850#endif
9410 listsetvar(varlist.list, VEXPORT|VSTACK); 9851 listsetvar(varlist.list, VEXPORT|VSTACK);
9411 shellexec(argv, path, cmdentry.u.index); 9852 shellexec(argv, path, cmdentry.u.index);
9412 /* NOTREACHED */ 9853 /* NOTREACHED */
@@ -9794,7 +10235,7 @@ preadbuffer(void)
9794 more--; 10235 more--;
9795 10236
9796 c = *q; 10237 c = *q;
9797 if (c == '\0') { 10238 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) {
9798 memmove(q, q + 1, more); 10239 memmove(q, q + 1, more);
9799 } else { 10240 } else {
9800 q++; 10241 q++;
@@ -9950,6 +10391,7 @@ popallfiles(void)
9950 popfile(); 10391 popfile();
9951} 10392}
9952 10393
10394#if !ENABLE_PLATFORM_MINGW32
9953/* 10395/*
9954 * Close the file(s) that the shell is reading commands from. Called 10396 * Close the file(s) that the shell is reading commands from. Called
9955 * after a fork is done. 10397 * after a fork is done.
@@ -9963,6 +10405,7 @@ closescript(void)
9963 g_parsefile->pf_fd = 0; 10405 g_parsefile->pf_fd = 0;
9964 } 10406 }
9965} 10407}
10408#endif
9966 10409
9967/* 10410/*
9968 * Like setinputfile, but takes an open file descriptor. Call this with 10411 * Like setinputfile, but takes an open file descriptor. Call this with
@@ -12160,7 +12603,7 @@ find_dot_file(char *name)
12160 struct stat statb; 12603 struct stat statb;
12161 12604
12162 /* don't try this for absolute or relative paths */ 12605 /* don't try this for absolute or relative paths */
12163 if (strchr(name, '/')) 12606 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\')))
12164 return name; 12607 return name;
12165 12608
12166 /* IIRC standards do not say whether . is to be searched. 12609 /* IIRC standards do not say whether . is to be searched.
@@ -12275,10 +12718,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12275 struct stat statb; 12718 struct stat statb;
12276 int e; 12719 int e;
12277 int updatetbl; 12720 int updatetbl;
12721 IF_PLATFORM_MINGW32(int len;)
12278 struct builtincmd *bcmd; 12722 struct builtincmd *bcmd;
12279 12723
12280 /* If name contains a slash, don't use PATH or hash table */ 12724 /* If name contains a slash, don't use PATH or hash table */
12281 if (strchr(name, '/') != NULL) { 12725 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) {
12282 entry->u.index = -1; 12726 entry->u.index = -1;
12283 if (act & DO_ABS) { 12727 if (act & DO_ABS) {
12284 while (stat(name, &statb) < 0) { 12728 while (stat(name, &statb) < 0) {
@@ -12294,6 +12738,14 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12294 return; 12738 return;
12295 } 12739 }
12296 12740
12741#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE
12742 if (busybox_cmd_and_exe(name)) {
12743 entry->u.index = -1;
12744 entry->cmdtype = CMDNORMAL;
12745 return;
12746 }
12747#endif
12748
12297/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ 12749/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
12298 12750
12299 updatetbl = (path == pathval()); 12751 updatetbl = (path == pathval());
@@ -12385,12 +12837,48 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12385 } 12837 }
12386 } 12838 }
12387 /* if rehash, don't redo absolute path names */ 12839 /* if rehash, don't redo absolute path names */
12388 if (fullname[0] == '/' && idx <= prev) { 12840 if (is_absolute_path(fullname) && idx <= prev) {
12389 if (idx < prev) 12841 if (idx < prev)
12390 continue; 12842 continue;
12391 TRACE(("searchexec \"%s\": no change\n", name)); 12843 TRACE(("searchexec \"%s\": no change\n", name));
12392 goto success; 12844 goto success;
12393 } 12845 }
12846#if ENABLE_PLATFORM_MINGW32
12847 len = strlen(fullname);
12848 if (len > 4 &&
12849 (!strcasecmp(fullname+len-4, ".exe") ||
12850 !strcasecmp(fullname+len-4, ".com"))) {
12851 if (stat(fullname, &statb) < 0) {
12852 if (errno != ENOENT && errno != ENOTDIR)
12853 e = errno;
12854 goto loop;
12855 }
12856 }
12857 else {
12858 /* path_advance() has reserved space for .exe */
12859 memcpy(fullname+len, ".exe", 5);
12860 if (stat(fullname, &statb) < 0) {
12861 if (errno != ENOENT && errno != ENOTDIR)
12862 e = errno;
12863 memcpy(fullname+len, ".com", 5);
12864 if (stat(fullname, &statb) < 0) {
12865 if (errno != ENOENT && errno != ENOTDIR)
12866 e = errno;
12867 fullname[len] = '\0';
12868 if (stat(fullname, &statb) < 0) {
12869 if (errno != ENOENT && errno != ENOTDIR)
12870 e = errno;
12871 goto loop;
12872 }
12873 if (!file_is_executable(fullname)) {
12874 e = ENOEXEC;
12875 goto loop;
12876 }
12877 }
12878 }
12879 fullname[len] = '\0';
12880 }
12881#else
12394 while (stat(fullname, &statb) < 0) { 12882 while (stat(fullname, &statb) < 0) {
12395#ifdef SYSV 12883#ifdef SYSV
12396 if (errno == EINTR) 12884 if (errno == EINTR)
@@ -12400,6 +12888,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12400 e = errno; 12888 e = errno;
12401 goto loop; 12889 goto loop;
12402 } 12890 }
12891#endif
12403 e = EACCES; /* if we fail, this will be the error */ 12892 e = EACCES; /* if we fail, this will be the error */
12404 if (!S_ISREG(statb.st_mode)) 12893 if (!S_ISREG(statb.st_mode))
12405 continue; 12894 continue;
@@ -12908,7 +13397,11 @@ exitshell(void)
12908} 13397}
12909 13398
12910static void 13399static void
13400#if ENABLE_PLATFORM_MINGW32
13401init(int xp)
13402#else
12911init(void) 13403init(void)
13404#endif
12912{ 13405{
12913 /* from input.c: */ 13406 /* from input.c: */
12914 /* we will never free this */ 13407 /* we will never free this */
@@ -12928,6 +13421,86 @@ init(void)
12928 struct stat st1, st2; 13421 struct stat st1, st2;
12929 13422
12930 initvar(); 13423 initvar();
13424
13425#if ENABLE_PLATFORM_MINGW32
13426 /*
13427 * case insensitive env names from Windows world
13428 *
13429 * Some standard env names such as PATH is named Path and so on
13430 * ash itself is case sensitive, so "Path" will confuse it, as
13431 * MSVC getenv() is case insensitive.
13432 *
13433 * We may end up having both Path and PATH. Then Path will be chosen
13434 * because it appears first.
13435 */
13436 for (envp = environ; envp && *envp; envp++) {
13437 if (strncasecmp(*envp, "PATH=", 5) == 0 &&
13438 strncmp(*envp, "PATH=", 5) != 0) {
13439 break;
13440 }
13441 }
13442
13443 if (envp && *envp) {
13444 /*
13445 * If we get here it's because the environment contains a path
13446 * variable called something other than PATH. This suggests we
13447 * haven't been invoked from an earlier instance of BusyBox.
13448 */
13449 char *start, *end;
13450 struct passwd *pw;
13451
13452 for (envp = environ; envp && *envp; envp++) {
13453 if (!(end=strchr(*envp, '=')))
13454 continue;
13455
13456 /* make all variable names uppercase */
13457 for (start = *envp;start < end;start++)
13458 *start = toupper(*start);
13459
13460 /* skip conversion of variables known to cause problems */
13461 if ( strncmp(*envp, "SYSTEMROOT=", 11) == 0 ||
13462 strncmp(*envp, "COMSPEC=", 8) == 0 ) {
13463 continue;
13464 }
13465
13466 /* convert backslashes to forward slashes */
13467 if (!xp) {
13468 for ( ++end; *end; ++end ) {
13469 if ( *end == '\\' ) {
13470 *end = '/';
13471 }
13472 }
13473 }
13474
13475 /* check for invalid characters */
13476 for (start = *envp;start < end;start++) {
13477 if (!isdigit(*start) && !isalpha(*start) && *start != '_') {
13478 break;
13479 }
13480 }
13481
13482 if (start != end) {
13483 /*
13484 * Make a copy of the variable, replacing invalid
13485 * characters in the name with underscores.
13486 */
13487 char *var = xstrdup(*envp);
13488
13489 for (start = var;*start != '=';start++) {
13490 if (!isdigit(*start) && !isalpha(*start)) {
13491 *start = '_';
13492 }
13493 }
13494 setvareq(var, VEXPORT|VNOSAVE);
13495 }
13496 }
13497
13498 /* some initialisation normally performed at login */
13499 pw = xgetpwuid(getuid());
13500 setup_environment(pw->pw_shell,
13501 SETUP_ENV_CHANGEENV|SETUP_ENV_NO_CHDIR, pw);
13502 }
13503#endif
12931 for (envp = environ; envp && *envp; envp++) { 13504 for (envp = environ; envp && *envp; envp++) {
12932 if (strchr(*envp, '=')) { 13505 if (strchr(*envp, '=')) {
12933 setvareq(*envp, VEXPORT|VTEXTFIXED); 13506 setvareq(*envp, VEXPORT|VTEXTFIXED);
@@ -13143,15 +13716,40 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13143#endif 13716#endif
13144 rootpid = getpid(); 13717 rootpid = getpid();
13145 13718
13146 init(); 13719 init(IF_PLATFORM_MINGW32(argc >= 2 && strcmp(argv[1], "-X") == 0));
13147 setstackmark(&smark); 13720 setstackmark(&smark);
13721
13722#if ENABLE_PLATFORM_MINGW32
13723 hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL);
13724 SetConsoleCtrlHandler(ctrl_handler, TRUE);
13725 if (argc == 3 && !strcmp(argv[1], "--forkshell")) {
13726 forkshell_init(argv[2]);
13727
13728 /* NOTREACHED */
13729 bb_error_msg_and_die("subshell ended unexpectedly");
13730 }
13731#endif
13148 procargs(argv); 13732 procargs(argv);
13733#if ENABLE_PLATFORM_MINGW32
13734 if ( noconsole ) {
13735 DWORD dummy;
13736
13737 if ( GetConsoleProcessList(&dummy, 1) == 1 ) {
13738 ShowWindow(GetConsoleWindow(), SW_HIDE);
13739 }
13740 }
13741#endif
13149 13742
13150 if (argv[0] && argv[0][0] == '-') 13743 if (argv[0] && argv[0][0] == '-')
13151 isloginsh = 1; 13744 isloginsh = 1;
13152 if (isloginsh) { 13745 if (isloginsh) {
13153 const char *hp; 13746 const char *hp;
13154 13747
13748#if ENABLE_PLATFORM_MINGW32
13749 chdir(xgetpwuid(getuid())->pw_dir);
13750 setpwd(NULL, 0);
13751#endif
13752
13155 state = 1; 13753 state = 1;
13156 read_profile("/etc/profile"); 13754 read_profile("/etc/profile");
13157 state1: 13755 state1:
@@ -13227,6 +13825,644 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13227 /* NOTREACHED */ 13825 /* NOTREACHED */
13228} 13826}
13229 13827
13828#if ENABLE_PLATFORM_MINGW32
13829static void
13830forkshell_openhere(struct forkshell *fs)
13831{
13832 union node *redir = fs->n;
13833 int pip[2];
13834
13835 pip[0] = fs->fd[0];
13836 pip[1] = fs->fd[1];
13837
13838 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
13839
13840 close(pip[0]);
13841 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
13842 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
13843 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
13844 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
13845 signal(SIGPIPE, SIG_DFL);
13846 if (redir->type == NHERE) {
13847 size_t len = strlen(redir->nhere.doc->narg.text);
13848 full_write(pip[1], redir->nhere.doc->narg.text, len);
13849 } else /* NXHERE */
13850 expandhere(redir->nhere.doc, pip[1]);
13851 _exit(EXIT_SUCCESS);
13852}
13853
13854static void
13855forkshell_evalbackcmd(struct forkshell *fs)
13856{
13857 union node *n = fs->n;
13858 int pip[2] = {fs->fd[0], fs->fd[1]};
13859
13860 FORCE_INT_ON;
13861 close(pip[0]);
13862 if (pip[1] != 1) {
13863 /*close(1);*/
13864 copyfd(pip[1], 1 | COPYFD_EXACT);
13865 close(pip[1]);
13866 }
13867 eflag = 0;
13868 evaltree(n, EV_EXIT); /* actually evaltreenr... */
13869 /* NOTREACHED */
13870}
13871
13872static void
13873forkshell_evalsubshell(struct forkshell *fs)
13874{
13875 union node *n = fs->n;
13876 int flags = fs->flags;
13877
13878 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
13879 INT_ON;
13880 flags |= EV_EXIT;
13881 expredir(n->nredir.redirect);
13882 redirect(n->nredir.redirect, 0);
13883 evaltreenr(n->nredir.n, flags);
13884 /* never returns */
13885}
13886
13887static void
13888forkshell_evalpipe(struct forkshell *fs)
13889{
13890 union node *n = fs->n;
13891 int flags = fs->flags;
13892 int prevfd = fs->fd[2];
13893 int pip[2] = {fs->fd[0], fs->fd[1]};
13894
13895 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
13896 INT_ON;
13897 if (pip[1] >= 0) {
13898 close(pip[0]);
13899 }
13900 if (prevfd > 0) {
13901 dup2(prevfd, 0);
13902 close(prevfd);
13903 }
13904 if (pip[1] > 1) {
13905 dup2(pip[1], 1);
13906 close(pip[1]);
13907 }
13908 evaltreenr(n, flags);
13909}
13910
13911static void
13912forkshell_shellexec(struct forkshell *fs)
13913{
13914 int idx = fs->fd[0];
13915 struct strlist *varlist = fs->strlist;
13916 char **argv = fs->argv;
13917 char *path = fs->string;
13918
13919 listsetvar(varlist, VEXPORT|VSTACK);
13920 shellexec(argv, path, idx);
13921}
13922
13923static void
13924forkshell_child(struct forkshell *fs)
13925{
13926 switch ( fs->fpid ) {
13927 case FS_OPENHERE:
13928 forkshell_openhere(fs);
13929 break;
13930 case FS_EVALBACKCMD:
13931 forkshell_evalbackcmd(fs);
13932 break;
13933 case FS_EVALSUBSHELL:
13934 forkshell_evalsubshell(fs);
13935 break;
13936 case FS_EVALPIPE:
13937 forkshell_evalpipe(fs);
13938 break;
13939 case FS_SHELLEXEC:
13940 forkshell_shellexec(fs);
13941 break;
13942 }
13943}
13944
13945/*
13946 * Reset the pointers to the builtin environment variables in the hash
13947 * table to point to varinit rather than the bogus copy created during
13948 * forkshell_prepare.
13949 */
13950static void
13951reinitvar(void)
13952{
13953 struct var *vp;
13954 struct var *end;
13955 struct var **vpp;
13956 struct var **old;
13957
13958 vp = varinit;
13959 end = vp + ARRAY_SIZE(varinit);
13960 do {
13961 vpp = hashvar(vp->var_text);
13962 if ( (old=findvar(vpp, vp->var_text)) != NULL ) {
13963 vp->next = (*old)->next;
13964 *old = vp;
13965 }
13966 } while (++vp < end);
13967}
13968
13969/* FIXME: should consider running forkparent() and forkchild() */
13970static int
13971spawn_forkshell(struct job *jp, struct forkshell *fs, int mode)
13972{
13973 struct forkshell *new;
13974 char buf[16];
13975 const char *argv[] = { "sh", "--forkshell", NULL, NULL };
13976 pid_t pid;
13977
13978 new = forkshell_prepare(fs);
13979 sprintf(buf, "%x", (unsigned int)new->hMapFile);
13980 argv[2] = buf;
13981 pid = mingw_spawn_applet(P_NOWAIT, "sh", argv,
13982 (const char *const *)environ);
13983 CloseHandle(new->hMapFile);
13984 UnmapViewOfFile(new);
13985 if (pid == -1) {
13986 free(jp);
13987 return -1;
13988 }
13989 forkparent(jp, fs->node, mode, pid);
13990 return pid;
13991}
13992
13993/*
13994 * forkshell_prepare() and friends
13995 *
13996 * The sequence is as follows:
13997 * - funcblocksize, funcstringsize, nodeptrsize are initialized
13998 * - forkshell_size(fs) is called to calculate the exact memory needed
13999 * - a new struct is allocated
14000 * - funcblock, funcstring, nodeptr are initialized from the new block
14001 * - forkshell_copy(fs) is called to copy recursively everything over
14002 * it will record all pointers along the way, to nodeptr
14003 *
14004 * When this memory is mapped elsewhere, pointer fixup will be needed
14005 */
14006#define SLIST_SIZE_BEGIN(name,type) \
14007static void \
14008name(type *p) \
14009{ \
14010 while (p) { \
14011 funcblocksize += sizeof(type);
14012 /* do something here with p */
14013#define SLIST_SIZE_END() \
14014 nodeptrsize++; \
14015 p = p->next; \
14016 } \
14017}
14018
14019#define SLIST_COPY_BEGIN(name,type) \
14020static type * \
14021name(type *vp) \
14022{ \
14023 type *start; \
14024 type **vpp; \
14025 vpp = &start; \
14026 while (vp) { \
14027 *vpp = funcblock; \
14028 funcblock = (char *) funcblock + sizeof(type);
14029 /* do something here with vpp and vp */
14030#define SLIST_COPY_END() \
14031 SAVE_PTR((*vpp)->next); \
14032 vp = vp->next; \
14033 vpp = &(*vpp)->next; \
14034 } \
14035 *vpp = NULL; \
14036 return start; \
14037}
14038
14039/*
14040 * struct var
14041 */
14042SLIST_SIZE_BEGIN(var_size,struct var)
14043funcstringsize += strlen(p->var_text) + 1;
14044nodeptrsize++; /* p->text */
14045SLIST_SIZE_END()
14046
14047SLIST_COPY_BEGIN(var_copy,struct var)
14048(*vpp)->var_text = nodeckstrdup(vp->var_text);
14049(*vpp)->flags = vp->flags;
14050/*
14051 * The only place that can set struct var#func is varinit[],
14052 * which will be fixed by forkshell_init()
14053 */
14054(*vpp)->var_func = NULL;
14055SAVE_PTR((*vpp)->var_text);
14056SLIST_COPY_END()
14057
14058/*
14059 * struct strlist
14060 */
14061SLIST_SIZE_BEGIN(strlist_size,struct strlist)
14062funcstringsize += strlen(p->text) + 1;
14063nodeptrsize++; /* p->text */
14064SLIST_SIZE_END()
14065
14066SLIST_COPY_BEGIN(strlist_copy,struct strlist)
14067(*vpp)->text = nodeckstrdup(vp->text);
14068SAVE_PTR((*vpp)->text);
14069SLIST_COPY_END()
14070
14071/*
14072 * struct tblentry
14073 */
14074static void
14075tblentry_size(struct tblentry *tep)
14076{
14077 while (tep) {
14078 funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14079 /* CMDBUILTIN, e->param.cmd needs no pointer relocation */
14080 if (tep->cmdtype == CMDFUNCTION) {
14081 funcblocksize += offsetof(struct funcnode, n);
14082 calcsize(&tep->param.func->n);
14083 nodeptrsize++; /* tep->param.func */
14084 }
14085 nodeptrsize++; /* tep->next */
14086 tep = tep->next;
14087 }
14088}
14089
14090static struct tblentry *
14091tblentry_copy(struct tblentry *tep)
14092{
14093 struct tblentry *start;
14094 struct tblentry **newp;
14095 int size;
14096
14097 newp = &start;
14098 while (tep) {
14099 *newp = funcblock;
14100 size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14101
14102 funcblock = (char *) funcblock + size;
14103 memcpy(*newp, tep, size);
14104 switch (tep->cmdtype) {
14105 case CMDBUILTIN:
14106 /* No pointer saving, this field must be fixed by forkshell_init() */
14107 (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab);
14108 break;
14109 case CMDFUNCTION:
14110 (*newp)->param.func = funcblock;
14111 funcblock = (char *) funcblock + offsetof(struct funcnode, n);
14112 copynode(&tep->param.func->n);
14113 SAVE_PTR((*newp)->param.func);
14114 break;
14115 default:
14116 break;
14117 }
14118 SAVE_PTR((*newp)->next);
14119 tep = tep->next;
14120 newp = &(*newp)->next;
14121 }
14122 *newp = NULL;
14123 return start;
14124}
14125
14126static void
14127cmdtable_size(struct tblentry **cmdtablep)
14128{
14129 int i;
14130 nodeptrsize += CMDTABLESIZE;
14131 funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE;
14132 for (i = 0; i < CMDTABLESIZE; i++)
14133 tblentry_size(cmdtablep[i]);
14134}
14135
14136static struct tblentry **
14137cmdtable_copy(struct tblentry **cmdtablep)
14138{
14139 struct tblentry **new = funcblock;
14140 int i;
14141
14142 funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE;
14143 for (i = 0; i < CMDTABLESIZE; i++) {
14144 new[i] = tblentry_copy(cmdtablep[i]);
14145 SAVE_PTR(new[i]);
14146 }
14147 return new;
14148}
14149
14150/*
14151 * char **
14152 */
14153static void
14154argv_size(char **p)
14155{
14156 while (p && *p) {
14157 funcblocksize += sizeof(char *);
14158 funcstringsize += strlen(*p)+1;
14159 nodeptrsize++;
14160 p++;
14161 }
14162 funcblocksize += sizeof(char *);
14163}
14164
14165static char **
14166argv_copy(char **p)
14167{
14168 char **new, **start = funcblock;
14169
14170 while (p && *p) {
14171 new = funcblock;
14172 funcblock = (char *) funcblock + sizeof(char *);
14173 *new = nodeckstrdup(*p);
14174 SAVE_PTR(*new);
14175 p++;
14176 new++;
14177 }
14178 new = funcblock;
14179 funcblock = (char *) funcblock + sizeof(char *);
14180 *new = NULL;
14181 return start;
14182}
14183
14184/*
14185 * struct redirtab
14186 */
14187static void
14188redirtab_size(struct redirtab *rdtp)
14189{
14190 while (rdtp) {
14191 funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14192 rdtp = rdtp->next;
14193 nodeptrsize++; /* rdtp->next */
14194 }
14195}
14196
14197static struct redirtab *
14198redirtab_copy(struct redirtab *rdtp)
14199{
14200 struct redirtab *start;
14201 struct redirtab **vpp;
14202
14203 vpp = &start;
14204 while (rdtp) {
14205 int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14206 *vpp = funcblock;
14207 funcblock = (char *) funcblock + size;
14208 memcpy(*vpp, rdtp, size);
14209 SAVE_PTR((*vpp)->next);
14210 rdtp = rdtp->next;
14211 vpp = &(*vpp)->next;
14212 }
14213 *vpp = NULL;
14214 return start;
14215}
14216
14217#undef shellparam
14218#undef redirlist
14219#undef varinit
14220#undef vartab
14221static void
14222globals_var_size(struct globals_var *gvp)
14223{
14224 int i;
14225
14226 funcblocksize += sizeof(struct globals_var);
14227 argv_size(gvp->shellparam.p);
14228 redirtab_size(gvp->redirlist);
14229 for (i = 0; i < VTABSIZE; i++)
14230 var_size(gvp->vartab[i]);
14231 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14232 var_size(gvp->varinit+i);
14233 nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */
14234}
14235
14236#undef g_nullredirs
14237#undef preverrout_fd
14238static struct globals_var *
14239globals_var_copy(struct globals_var *gvp)
14240{
14241 int i;
14242 struct globals_var *new;
14243
14244 new = funcblock;
14245 funcblock = (char *) funcblock + sizeof(struct globals_var);
14246
14247 /* shparam */
14248 memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam));
14249 new->shellparam.malloced = 0;
14250 new->shellparam.p = argv_copy(gvp->shellparam.p);
14251 SAVE_PTR(new->shellparam.p);
14252
14253 new->redirlist = redirtab_copy(gvp->redirlist);
14254 SAVE_PTR(new->redirlist);
14255
14256 new->g_nullredirs = gvp->g_nullredirs;
14257 new->preverrout_fd = gvp->preverrout_fd;
14258 for (i = 0; i < VTABSIZE; i++) {
14259 new->vartab[i] = var_copy(gvp->vartab[i]);
14260 SAVE_PTR(new->vartab[i]);
14261 }
14262
14263 /* Can't use var_copy because varinit is already allocated */
14264 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) {
14265 new->varinit[i].next = NULL;
14266 new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text);
14267 SAVE_PTR(new->varinit[i].var_text);
14268 new->varinit[i].flags = gvp->varinit[i].flags;
14269 new->varinit[i].var_func = gvp->varinit[i].var_func;
14270 }
14271 return new;
14272}
14273
14274#undef minusc
14275#undef curdir
14276#undef physdir
14277#undef arg0
14278#undef nullstr
14279static void
14280globals_misc_size(struct globals_misc *p)
14281{
14282 funcblocksize += sizeof(struct globals_misc);
14283 funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1;
14284 if (p->curdir != p->nullstr)
14285 funcstringsize += strlen(p->curdir) + 1;
14286 if (p->physdir != p->nullstr)
14287 funcstringsize += strlen(p->physdir) + 1;
14288 funcstringsize += strlen(p->arg0) + 1;
14289 nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */
14290}
14291
14292static struct globals_misc *
14293globals_misc_copy(struct globals_misc *p)
14294{
14295 struct globals_misc *new = funcblock;
14296
14297 funcblock = (char *) funcblock + sizeof(struct globals_misc);
14298 memcpy(new, p, sizeof(struct globals_misc));
14299
14300 new->minusc = nodeckstrdup(p->minusc);
14301 new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr;
14302 new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr;
14303 new->arg0 = nodeckstrdup(p->arg0);
14304 SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0);
14305 return new;
14306}
14307
14308static void
14309forkshell_size(struct forkshell *fs)
14310{
14311 funcblocksize += sizeof(struct forkshell);
14312 globals_var_size(fs->gvp);
14313 globals_misc_size(fs->gmp);
14314 cmdtable_size(fs->cmdtable);
14315 /* optlist_transfer(sending, fd); */
14316 /* misc_transfer(sending, fd); */
14317
14318 calcsize(fs->n);
14319 argv_size(fs->argv);
14320 funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1;
14321 strlist_size(fs->strlist);
14322
14323 nodeptrsize += 7; /* gvp, gmp, cmdtable, n, argv, string, strlist */
14324}
14325
14326static struct forkshell *
14327forkshell_copy(struct forkshell *fs)
14328{
14329 struct forkshell *new;
14330
14331 new = funcblock;
14332 funcblock = (char *) funcblock + sizeof(struct forkshell);
14333
14334 memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */
14335 new->gvp = globals_var_copy(fs->gvp);
14336 new->gmp = globals_misc_copy(fs->gmp);
14337 new->cmdtable = cmdtable_copy(fs->cmdtable);
14338 SAVE_PTR3(new->gvp, new->gmp, new->cmdtable);
14339
14340 new->n = copynode(fs->n);
14341 new->argv = argv_copy(fs->argv);
14342 new->string = nodeckstrdup(fs->string);
14343 new->strlist = strlist_copy(fs->strlist);
14344 SAVE_PTR4(new->n, new->argv, new->string, new->strlist);
14345 return new;
14346}
14347
14348static struct forkshell *
14349forkshell_prepare(struct forkshell *fs)
14350{
14351 struct forkshell *new;
14352 int size, nodeptr_offset;
14353 HANDLE h;
14354 SECURITY_ATTRIBUTES sa;
14355
14356 /* Calculate size of "new" */
14357 fs->gvp = ash_ptr_to_globals_var;
14358 fs->gmp = ash_ptr_to_globals_misc;
14359 fs->cmdtable = cmdtable;
14360
14361 nodeptrsize = 1; /* NULL terminated */
14362 funcblocksize = 0;
14363 funcstringsize = 0;
14364 forkshell_size(fs);
14365 size = funcblocksize + funcstringsize + nodeptrsize*sizeof(char *);
14366
14367 /* Allocate, initialize pointers */
14368 memset(&sa, 0, sizeof(sa));
14369 sa.nLength = sizeof(sa);
14370 sa.lpSecurityDescriptor = NULL;
14371 sa.bInheritHandle = TRUE;
14372 h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL);
14373 new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14374 /* new = ckmalloc(size); */
14375 funcblock = new;
14376 funcstring = (char *) funcblock + funcblocksize;
14377 nodeptr = (char **)((char *)funcstring + funcstringsize);
14378 nodeptr_offset = (char *)nodeptr - (char *)new;
14379
14380 /* Now pack them all */
14381 forkshell_copy(fs);
14382
14383 /* Finish it up */
14384 *nodeptr = NULL;
14385 new->size = size;
14386 new->nodeptr_offset = nodeptr_offset;
14387 new->old_base = new;
14388 new->hMapFile = h;
14389 return new;
14390}
14391
14392#undef exception_handler
14393#undef trap
14394#undef trap_ptr
14395static void *sticky_mem_start, *sticky_mem_end;
14396static void
14397forkshell_init(const char *idstr)
14398{
14399 struct forkshell *fs;
14400 int map_handle;
14401 HANDLE h;
14402 struct globals_var **gvpp;
14403 struct globals_misc **gmpp;
14404 int i;
14405 char **ptr;
14406
14407 if (sscanf(idstr, "%x", &map_handle) != 1)
14408 bb_error_msg_and_die("invalid forkshell ID");
14409
14410 h = (HANDLE)map_handle;
14411 fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14412 if (!fs)
14413 bb_error_msg_and_die("Invalid forkshell memory");
14414
14415 /* this memory can't be freed */
14416 sticky_mem_start = fs;
14417 sticky_mem_end = (char *) fs + fs->size;
14418
14419 /* pointer fixup */
14420 nodeptr = (char **)((char *)fs + fs->nodeptr_offset);
14421 for ( i=0; nodeptr[i]; ++i ) {
14422 ptr = (char **)((char *)fs + (nodeptr[i] - (char *)fs->old_base));
14423 if (*ptr)
14424 *ptr = (char *)fs + (*ptr - (char *)fs->old_base);
14425 }
14426
14427 /* Now fix up stuff that can't be transferred */
14428 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14429 fs->gvp->varinit[i].var_func = varinit_data[i].var_func;
14430 for (i = 0; i < CMDTABLESIZE; i++) {
14431 struct tblentry *e = fs->cmdtable[i];
14432 while (e) {
14433 if (e->cmdtype == CMDBUILTIN)
14434 e->param.cmd = builtintab + (int)e->param.cmd;
14435 e = e->next;
14436 }
14437 }
14438 fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler;
14439 for (i = 0; i < NSIG; i++)
14440 fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i];
14441 fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr;
14442
14443 /* Switch global variables */
14444 gvpp = (struct globals_var **)&ash_ptr_to_globals_var;
14445 *gvpp = fs->gvp;
14446 gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc;
14447 *gmpp = fs->gmp;
14448 cmdtable = fs->cmdtable;
14449
14450 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
14451
14452 reinitvar();
14453
14454 forkshell_child(fs);
14455}
14456
14457#undef free
14458static void
14459sticky_free(void *base)
14460{
14461 if (base >= sticky_mem_start && base < sticky_mem_end)
14462 return;
14463 free(base);
14464}
14465#endif
13230 14466
13231/*- 14467/*-
13232 * Copyright (c) 1989, 1991, 1993, 1994 14468 * Copyright (c) 1989, 1991, 1993, 1994