summaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c1197
1 files changed, 1186 insertions, 11 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 90fb00fbd..b95356034 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,9 @@ 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#endif
236}; 301};
237 302
238#define optletters(n) optletters_optnames[n][0] 303#define optletters(n) optletters_optnames[n][0]
@@ -313,6 +378,9 @@ struct globals_misc {
313# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] 378# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
314# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] 379# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
315#endif 380#endif
381#if ENABLE_PLATFORM_MINGW32
382# define noconsole optlist[14 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
383#endif
316 384
317 /* trap handler commands */ 385 /* trap handler commands */
318 /* 386 /*
@@ -2393,10 +2461,22 @@ path_advance(const char **path, const char *name)
2393 if (*path == NULL) 2461 if (*path == NULL)
2394 return NULL; 2462 return NULL;
2395 start = *path; 2463 start = *path;
2464#if ENABLE_PLATFORM_MINGW32
2465 p = next_path_sep(start);
2466 q = strchr(start, '%');
2467 if ((p && q && q < p) || (!p && q))
2468 p = q;
2469 if (!p)
2470 for (p = start; *p; p++)
2471 continue;
2472#else
2396 for (p = start; *p && *p != ':' && *p != '%'; p++) 2473 for (p = start; *p && *p != ':' && *p != '%'; p++)
2397 continue; 2474 continue;
2475#endif
2398 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2476 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2399 while (stackblocksize() < len) 2477
2478 /* preserve space for .exe too */
2479 while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len))
2400 growstackblock(); 2480 growstackblock();
2401 q = stackblock(); 2481 q = stackblock();
2402 if (p != start) { 2482 if (p != start) {
@@ -2408,10 +2488,19 @@ path_advance(const char **path, const char *name)
2408 pathopt = NULL; 2488 pathopt = NULL;
2409 if (*p == '%') { 2489 if (*p == '%') {
2410 pathopt = ++p; 2490 pathopt = ++p;
2491#if ENABLE_PLATFORM_MINGW32
2492 p = next_path_sep(start);
2493
2494 /* *p != ':' and '*' would suffice */
2495 if (!p)
2496 p = pathopt - 1;
2497#else
2411 while (*p && *p != ':') 2498 while (*p && *p != ':')
2412 p++; 2499 p++;
2500#endif
2413 } 2501 }
2414 if (*p == ':') 2502 if (*p == ':' ||
2503 (ENABLE_PLATFORM_MINGW32 && *p == ';'))
2415 *path = p + 1; 2504 *path = p + 1;
2416 else 2505 else
2417 *path = NULL; 2506 *path = NULL;
@@ -2513,6 +2602,106 @@ cdopt(void)
2513static const char * 2602static const char *
2514updatepwd(const char *dir) 2603updatepwd(const char *dir)
2515{ 2604{
2605#if ENABLE_PLATFORM_MINGW32
2606#define is_path_sep(x) ((x) == '/' || (x) == '\\')
2607#define is_unc_path(x) (is_path_sep(x[0]) && is_path_sep(x[1]))
2608 /*
2609 * Due to Windows drive notion, getting pwd is a completely
2610 * different thing. Handle it in a separate routine
2611 */
2612
2613 char *new;
2614 char *p;
2615 char *cdcomppath;
2616 const char *lim;
2617 /*
2618 * There are five cases that make some kind of sense
2619 * absdrive + abspath: c:/path
2620 * absdrive + !abspath: c:path
2621 * !absdrive + abspath: /path
2622 * !absdrive + uncpath: //host/share
2623 * !absdrive + !abspath: path
2624 *
2625 * Damn DOS!
2626 * c:path behaviour is "undefined"
2627 * To properly handle this case, I have to keep track of cwd
2628 * of every drive, which is too painful to do.
2629 * So when c:path is given, I assume it's c:${curdir}path
2630 * with ${curdir} comes from the current drive
2631 */
2632 int absdrive = *dir && dir[1] == ':';
2633 int abspath = absdrive ? is_path_sep(dir[2]) : is_path_sep(*dir);
2634
2635 cdcomppath = ststrdup(dir);
2636 STARTSTACKSTR(new);
2637 if (!absdrive && curdir == nullstr)
2638 return 0;
2639 if (!abspath) {
2640 if (curdir == nullstr)
2641 return 0;
2642 new = stack_putstr(curdir, new);
2643 }
2644 new = makestrspace(strlen(dir) + 2, new);
2645
2646 if ( is_unc_path(dir) || (!absdrive && !abspath && is_unc_path(curdir)) ) {
2647 lim = (char *)stackblock() + 1;
2648 }
2649 else {
2650 char *drive = stackblock();
2651 if (absdrive) {
2652 *drive = *dir;
2653 cdcomppath += 2;
2654 dir += 2;
2655 } else {
2656 *drive = *curdir;
2657 }
2658 drive[1] = ':'; /* in case of absolute drive+path */
2659
2660 if (abspath)
2661 new = drive + 2;
2662 lim = drive + 3;
2663 }
2664
2665 if (!abspath) {
2666 if (!is_path_sep(new[-1]))
2667 USTPUTC('/', new);
2668 if (new > lim && is_path_sep(*lim))
2669 lim++;
2670 } else {
2671 USTPUTC('/', new);
2672 cdcomppath ++;
2673 if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) {
2674 USTPUTC('/', new);
2675 cdcomppath++;
2676 lim++;
2677 }
2678 }
2679 p = strtok(cdcomppath, "/\\");
2680 while (p) {
2681 switch (*p) {
2682 case '.':
2683 if (p[1] == '.' && p[2] == '\0') {
2684 while (new > lim) {
2685 STUNPUTC(new);
2686 if (is_path_sep(new[-1]))
2687 break;
2688 }
2689 break;
2690 }
2691 if (p[1] == '\0')
2692 break;
2693 /* fall through */
2694 default:
2695 new = stack_putstr(p, new);
2696 USTPUTC('/', new);
2697 }
2698 p = strtok(0, "/\\");
2699 }
2700 if (new > lim)
2701 STUNPUTC(new);
2702 *new = 0;
2703 return stackblock();
2704#else
2516 char *new; 2705 char *new;
2517 char *p; 2706 char *p;
2518 char *cdcomppath; 2707 char *cdcomppath;
@@ -2566,6 +2755,7 @@ updatepwd(const char *dir)
2566 STUNPUTC(new); 2755 STUNPUTC(new);
2567 *new = 0; 2756 *new = 0;
2568 return stackblock(); 2757 return stackblock();
2758#endif
2569} 2759}
2570 2760
2571/* 2761/*
@@ -2660,7 +2850,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2660 } 2850 }
2661 if (!dest) 2851 if (!dest)
2662 dest = nullstr; 2852 dest = nullstr;
2663 if (*dest == '/') 2853 if (is_absolute_path(dest))
2664 goto step7; 2854 goto step7;
2665 if (*dest == '.') { 2855 if (*dest == '.') {
2666 c = dest[1]; 2856 c = dest[1];
@@ -3377,7 +3567,9 @@ struct job {
3377}; 3567};
3378 3568
3379static struct job *makejob(/*union node *,*/ int); 3569static struct job *makejob(/*union node *,*/ int);
3570#if !ENABLE_PLATFORM_MINGW32
3380static int forkshell(struct job *, union node *, int); 3571static int forkshell(struct job *, union node *, int);
3572#endif
3381static int waitforjob(struct job *); 3573static int waitforjob(struct job *);
3382 3574
3383#if !JOBS 3575#if !JOBS
@@ -3432,6 +3624,8 @@ setsignal(int signo)
3432 char cur_act, new_act; 3624 char cur_act, new_act;
3433 struct sigaction act; 3625 struct sigaction act;
3434 3626
3627 if (ENABLE_PLATFORM_MINGW32)
3628 return;
3435 t = trap[signo]; 3629 t = trap[signo];
3436 new_act = S_DFL; 3630 new_act = S_DFL;
3437 if (t != NULL) { /* trap for this sig is set */ 3631 if (t != NULL) { /* trap for this sig is set */
@@ -3953,6 +4147,79 @@ sprint_status(char *s, int status, int sigonly)
3953 return col; 4147 return col;
3954} 4148}
3955 4149
4150#if ENABLE_PLATFORM_MINGW32
4151
4152HANDLE hSIGINT; /* Ctrl-C is pressed */
4153
4154static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
4155{
4156 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
4157 SetEvent(hSIGINT);
4158 return TRUE;
4159 }
4160 return FALSE;
4161}
4162
4163/*
4164 * Windows does not know about parent-child relationship
4165 * They don't support waitpid(-1)
4166 */
4167static pid_t
4168waitpid_child(int *status, int wait_flags)
4169{
4170 HANDLE *pidlist, *pidp;
4171 int pid_nr = 0;
4172 pid_t pid;
4173 DWORD win_status, idx;
4174 struct job *jb;
4175
4176 #define LOOP(stmt) \
4177 for (jb = curjob; jb; jb = jb->prev_job) { \
4178 struct procstat *ps, *psend; \
4179 if (jb->state == JOBDONE) \
4180 continue; \
4181 ps = jb->ps; \
4182 psend = ps + jb->nprocs; \
4183 while (ps < psend) { \
4184 if (ps->ps_pid != -1) { \
4185 stmt; \
4186 } \
4187 ps++; \
4188 } \
4189 }
4190
4191 LOOP(pid_nr++);
4192 if (!pid_nr)
4193 return -1;
4194 pid_nr++;
4195 pidp = pidlist = ckmalloc(sizeof(*pidlist)*pid_nr);
4196 *pidp++ = hSIGINT;
4197 LOOP(*pidp++ = (HANDLE)ps->ps_pid);
4198 #undef LOOP
4199
4200 idx = WaitForMultipleObjects(pid_nr, pidlist, FALSE,
4201 wait_flags|WNOHANG ? 1 : INFINITE);
4202 if (idx >= pid_nr) {
4203 free(pidlist);
4204 return -1;
4205 }
4206 if (!idx) { /* hSIGINT */
4207 int i;
4208 ResetEvent(hSIGINT);
4209 for (i = 1; i < pid_nr; i++)
4210 TerminateProcess(pidlist[i], 1);
4211 free(pidlist);
4212 *status = 260; /* terminated by a signal */
4213 return pidlist[1];
4214 }
4215 GetExitCodeProcess(pidlist[idx], &win_status);
4216 pid = (int)pidlist[idx];
4217 free(pidlist);
4218 *status = (int)win_status;
4219 return pid;
4220}
4221#endif
4222
3956static int 4223static int
3957dowait(int wait_flags, struct job *job) 4224dowait(int wait_flags, struct job *job)
3958{ 4225{
@@ -3969,7 +4236,11 @@ dowait(int wait_flags, struct job *job)
3969 * NB: _not_ safe_waitpid, we need to detect EINTR */ 4236 * NB: _not_ safe_waitpid, we need to detect EINTR */
3970 if (doing_jobctl) 4237 if (doing_jobctl)
3971 wait_flags |= WUNTRACED; 4238 wait_flags |= WUNTRACED;
4239#if ENABLE_PLATFORM_MINGW32
4240 pid = waitpid_child(&status, wait_flags);
4241#else
3972 pid = waitpid(-1, &status, wait_flags); 4242 pid = waitpid(-1, &status, wait_flags);
4243#endif
3973 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", 4244 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3974 pid, status, errno, strerror(errno))); 4245 pid, status, errno, strerror(errno)));
3975 if (pid <= 0) 4246 if (pid <= 0)
@@ -3992,6 +4263,8 @@ dowait(int wait_flags, struct job *job)
3992 jobno(jp), pid, ps->ps_status, status)); 4263 jobno(jp), pid, ps->ps_status, status));
3993 ps->ps_status = status; 4264 ps->ps_status = status;
3994 thisjob = jp; 4265 thisjob = jp;
4266 if (ENABLE_PLATFORM_MINGW32)
4267 ps->ps_pid = -1;
3995 } 4268 }
3996 if (ps->ps_status == -1) 4269 if (ps->ps_status == -1)
3997 state = JOBRUNNING; 4270 state = JOBRUNNING;
@@ -4223,6 +4496,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
4223 int retval; 4496 int retval;
4224 struct job *jp; 4497 struct job *jp;
4225 4498
4499 if (ENABLE_PLATFORM_MINGW32)
4500 return 0;
4501
4226 if (pending_sig) 4502 if (pending_sig)
4227 raise_exception(EXSIG); 4503 raise_exception(EXSIG);
4228 4504
@@ -4678,6 +4954,7 @@ commandtext(union node *n)
4678 * 4954 *
4679 * Called with interrupts off. 4955 * Called with interrupts off.
4680 */ 4956 */
4957#if !ENABLE_PLATFORM_MINGW32
4681/* 4958/*
4682 * Clear traps on a fork. 4959 * Clear traps on a fork.
4683 */ 4960 */
@@ -4826,6 +5103,7 @@ forkchild(struct job *jp, union node *n, int mode)
4826 freejob(jp); 5103 freejob(jp);
4827 jobless = 0; 5104 jobless = 0;
4828} 5105}
5106#endif
4829 5107
4830/* Called after fork(), in parent */ 5108/* Called after fork(), in parent */
4831#if !JOBS 5109#if !JOBS
@@ -4835,7 +5113,7 @@ static void
4835forkparent(struct job *jp, union node *n, int mode, pid_t pid) 5113forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4836{ 5114{
4837 TRACE(("In parent shell: child = %d\n", pid)); 5115 TRACE(("In parent shell: child = %d\n", pid));
4838 if (!jp) { 5116 if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */
4839 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) 5117 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4840 continue; 5118 continue;
4841 jobless++; 5119 jobless++;
@@ -4869,12 +5147,14 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4869 } 5147 }
4870} 5148}
4871 5149
5150#if !ENABLE_PLATFORM_MINGW32
4872static int 5151static int
4873forkshell(struct job *jp, union node *n, int mode) 5152forkshell(struct job *jp, union node *n, int mode)
4874{ 5153{
4875 int pid; 5154 int pid;
4876 5155
4877 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); 5156 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5157
4878 pid = fork(); 5158 pid = fork();
4879 if (pid < 0) { 5159 if (pid < 0) {
4880 TRACE(("Fork failed, errno=%d", errno)); 5160 TRACE(("Fork failed, errno=%d", errno));
@@ -4890,6 +5170,7 @@ forkshell(struct job *jp, union node *n, int mode)
4890 } 5170 }
4891 return pid; 5171 return pid;
4892} 5172}
5173#endif
4893 5174
4894/* 5175/*
4895 * Wait for job to finish. 5176 * Wait for job to finish.
@@ -5082,6 +5363,7 @@ openhere(union node *redir)
5082{ 5363{
5083 int pip[2]; 5364 int pip[2];
5084 size_t len = 0; 5365 size_t len = 0;
5366 IF_PLATFORM_MINGW32(struct forkshell fs);
5085 5367
5086 if (pipe(pip) < 0) 5368 if (pipe(pip) < 0)
5087 ash_msg_and_raise_error("pipe call failed"); 5369 ash_msg_and_raise_error("pipe call failed");
@@ -5092,6 +5374,15 @@ openhere(union node *redir)
5092 goto out; 5374 goto out;
5093 } 5375 }
5094 } 5376 }
5377#if ENABLE_PLATFORM_MINGW32
5378 memset(&fs, 0, sizeof(fs));
5379 fs.fpid = FS_OPENHERE;
5380 fs.n = redir;
5381 fs.fd[0] = pip[0];
5382 fs.fd[1] = pip[1];
5383 if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0)
5384 ash_msg_and_raise_error("unable to spawn shell");
5385#else
5095 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 5386 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5096 /* child */ 5387 /* child */
5097 close(pip[0]); 5388 close(pip[0]);
@@ -5106,6 +5397,7 @@ openhere(union node *redir)
5106 expandhere(redir->nhere.doc, pip[1]); 5397 expandhere(redir->nhere.doc, pip[1]);
5107 _exit(EXIT_SUCCESS); 5398 _exit(EXIT_SUCCESS);
5108 } 5399 }
5400#endif
5109 out: 5401 out:
5110 close(pip[1]); 5402 close(pip[1]);
5111 return pip[0]; 5403 return pip[0];
@@ -5118,6 +5410,31 @@ openredirect(union node *redir)
5118 int f; 5410 int f;
5119 5411
5120 fname = redir->nfile.expfname; 5412 fname = redir->nfile.expfname;
5413#if ENABLE_PLATFORM_MINGW32
5414 /* Support for /dev/null */
5415 switch (redir->nfile.type) {
5416 case NFROM:
5417 if (!strcmp(fname, "/dev/null"))
5418 return open("nul",O_RDWR);
5419 if (!strncmp(fname, "/dev/", 5)) {
5420 ash_msg("Unhandled device %s\n", fname);
5421 return -1;
5422 }
5423 break;
5424
5425 case NFROMTO:
5426 case NTO:
5427 case NCLOBBER:
5428 case NAPPEND:
5429 if (!strcmp(fname, "/dev/null"))
5430 return open("nul",O_RDWR);
5431 if (!strncmp(fname, "/dev/", 5)) {
5432 ash_msg("Unhandled device %s\n", fname);
5433 return -1;
5434 }
5435 break;
5436 }
5437#endif
5121 switch (redir->nfile.type) { 5438 switch (redir->nfile.type) {
5122 case NFROM: 5439 case NFROM:
5123 f = open(fname, O_RDONLY); 5440 f = open(fname, O_RDONLY);
@@ -5842,6 +6159,7 @@ struct backcmd { /* result of evalbackcmd */
5842 int fd; /* file descriptor to read from */ 6159 int fd; /* file descriptor to read from */
5843 int nleft; /* number of chars in buffer */ 6160 int nleft; /* number of chars in buffer */
5844 char *buf; /* buffer */ 6161 char *buf; /* buffer */
6162 IF_PLATFORM_MINGW32(struct forkshell fs);
5845 struct job *jp; /* job structure for command */ 6163 struct job *jp; /* job structure for command */
5846}; 6164};
5847 6165
@@ -5858,6 +6176,7 @@ evalbackcmd(union node *n, struct backcmd *result)
5858 result->fd = -1; 6176 result->fd = -1;
5859 result->buf = NULL; 6177 result->buf = NULL;
5860 result->nleft = 0; 6178 result->nleft = 0;
6179 IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs)));
5861 result->jp = NULL; 6180 result->jp = NULL;
5862 if (n == NULL) 6181 if (n == NULL)
5863 goto out; 6182 goto out;
@@ -5872,6 +6191,14 @@ evalbackcmd(union node *n, struct backcmd *result)
5872 if (pipe(pip) < 0) 6191 if (pipe(pip) < 0)
5873 ash_msg_and_raise_error("pipe call failed"); 6192 ash_msg_and_raise_error("pipe call failed");
5874 jp = makejob(/*n,*/ 1); 6193 jp = makejob(/*n,*/ 1);
6194#if ENABLE_PLATFORM_MINGW32
6195 result->fs.fpid = FS_EVALBACKCMD;
6196 result->fs.n = n;
6197 result->fs.fd[0] = pip[0];
6198 result->fs.fd[1] = pip[1];
6199 if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0)
6200 ash_msg_and_raise_error("unable to spawn shell");
6201#else
5875 if (forkshell(jp, n, FORK_NOJOB) == 0) { 6202 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5876 FORCE_INT_ON; 6203 FORCE_INT_ON;
5877 close(pip[0]); 6204 close(pip[0]);
@@ -5884,6 +6211,7 @@ evalbackcmd(union node *n, struct backcmd *result)
5884 evaltree(n, EV_EXIT); /* actually evaltreenr... */ 6211 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5885 /* NOTREACHED */ 6212 /* NOTREACHED */
5886 } 6213 }
6214#endif
5887 close(pip[1]); 6215 close(pip[1]);
5888 result->fd = pip[0]; 6216 result->fd = pip[0];
5889 result->jp = jp; 6217 result->jp = jp;
@@ -5942,7 +6270,8 @@ expbackq(union node *cmd, int quoted, int quotes)
5942 6270
5943 /* Eat all trailing newlines */ 6271 /* Eat all trailing newlines */
5944 dest = expdest; 6272 dest = expdest;
5945 for (; dest > (char *)stackblock() && dest[-1] == '\n';) 6273 for (; dest > (char *)stackblock() && (dest[-1] == '\n' ||
6274 (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));)
5946 STUNPUTC(dest); 6275 STUNPUTC(dest);
5947 expdest = dest; 6276 expdest = dest;
5948 6277
@@ -7505,7 +7834,7 @@ shellexec(char **argv, const char *path, int idx)
7505 7834
7506 clearredir(/*drop:*/ 1); 7835 clearredir(/*drop:*/ 1);
7507 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); 7836 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7508 if (strchr(argv[0], '/') != NULL 7837 if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\')))
7509#if ENABLE_FEATURE_SH_STANDALONE 7838#if ENABLE_FEATURE_SH_STANDALONE
7510 || (applet_no = find_applet_by_name(argv[0])) >= 0 7839 || (applet_no = find_applet_by_name(argv[0])) >= 0
7511#endif 7840#endif
@@ -8016,6 +8345,10 @@ static int funcblocksize; /* size of structures in function */
8016static int funcstringsize; /* size of strings in node */ 8345static int funcstringsize; /* size of strings in node */
8017static void *funcblock; /* block to allocate function from */ 8346static void *funcblock; /* block to allocate function from */
8018static char *funcstring; /* block to allocate strings from */ 8347static char *funcstring; /* block to allocate strings from */
8348#if ENABLE_PLATFORM_MINGW32
8349static int nodeptrsize;
8350static int *nodeptr;
8351#endif
8019 8352
8020/* flags in argument to evaltree */ 8353/* flags in argument to evaltree */
8021#define EV_EXIT 01 /* exit after evaluating tree */ 8354#define EV_EXIT 01 /* exit after evaluating tree */
@@ -8061,6 +8394,7 @@ sizenodelist(struct nodelist *lp)
8061{ 8394{
8062 while (lp) { 8395 while (lp) {
8063 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 8396 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8397 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8064 calcsize(lp->n); 8398 calcsize(lp->n);
8065 lp = lp->next; 8399 lp = lp->next;
8066 } 8400 }
@@ -8077,15 +8411,18 @@ calcsize(union node *n)
8077 calcsize(n->ncmd.redirect); 8411 calcsize(n->ncmd.redirect);
8078 calcsize(n->ncmd.args); 8412 calcsize(n->ncmd.args);
8079 calcsize(n->ncmd.assign); 8413 calcsize(n->ncmd.assign);
8414 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8080 break; 8415 break;
8081 case NPIPE: 8416 case NPIPE:
8082 sizenodelist(n->npipe.cmdlist); 8417 sizenodelist(n->npipe.cmdlist);
8418 IF_PLATFORM_MINGW32(nodeptrsize++);
8083 break; 8419 break;
8084 case NREDIR: 8420 case NREDIR:
8085 case NBACKGND: 8421 case NBACKGND:
8086 case NSUBSHELL: 8422 case NSUBSHELL:
8087 calcsize(n->nredir.redirect); 8423 calcsize(n->nredir.redirect);
8088 calcsize(n->nredir.n); 8424 calcsize(n->nredir.n);
8425 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8089 break; 8426 break;
8090 case NAND: 8427 case NAND:
8091 case NOR: 8428 case NOR:
@@ -8094,31 +8431,37 @@ calcsize(union node *n)
8094 case NUNTIL: 8431 case NUNTIL:
8095 calcsize(n->nbinary.ch2); 8432 calcsize(n->nbinary.ch2);
8096 calcsize(n->nbinary.ch1); 8433 calcsize(n->nbinary.ch1);
8434 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8097 break; 8435 break;
8098 case NIF: 8436 case NIF:
8099 calcsize(n->nif.elsepart); 8437 calcsize(n->nif.elsepart);
8100 calcsize(n->nif.ifpart); 8438 calcsize(n->nif.ifpart);
8101 calcsize(n->nif.test); 8439 calcsize(n->nif.test);
8440 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8102 break; 8441 break;
8103 case NFOR: 8442 case NFOR:
8104 funcstringsize += strlen(n->nfor.var) + 1; 8443 funcstringsize += strlen(n->nfor.var) + 1;
8105 calcsize(n->nfor.body); 8444 calcsize(n->nfor.body);
8106 calcsize(n->nfor.args); 8445 calcsize(n->nfor.args);
8446 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8107 break; 8447 break;
8108 case NCASE: 8448 case NCASE:
8109 calcsize(n->ncase.cases); 8449 calcsize(n->ncase.cases);
8110 calcsize(n->ncase.expr); 8450 calcsize(n->ncase.expr);
8451 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8111 break; 8452 break;
8112 case NCLIST: 8453 case NCLIST:
8113 calcsize(n->nclist.body); 8454 calcsize(n->nclist.body);
8114 calcsize(n->nclist.pattern); 8455 calcsize(n->nclist.pattern);
8115 calcsize(n->nclist.next); 8456 calcsize(n->nclist.next);
8457 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8116 break; 8458 break;
8117 case NDEFUN: 8459 case NDEFUN:
8118 case NARG: 8460 case NARG:
8119 sizenodelist(n->narg.backquote); 8461 sizenodelist(n->narg.backquote);
8120 funcstringsize += strlen(n->narg.text) + 1; 8462 funcstringsize += strlen(n->narg.text) + 1;
8121 calcsize(n->narg.next); 8463 calcsize(n->narg.next);
8464 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8122 break; 8465 break;
8123 case NTO: 8466 case NTO:
8124#if ENABLE_ASH_BASH_COMPAT 8467#if ENABLE_ASH_BASH_COMPAT
@@ -8130,28 +8473,34 @@ calcsize(union node *n)
8130 case NAPPEND: 8473 case NAPPEND:
8131 calcsize(n->nfile.fname); 8474 calcsize(n->nfile.fname);
8132 calcsize(n->nfile.next); 8475 calcsize(n->nfile.next);
8476 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8133 break; 8477 break;
8134 case NTOFD: 8478 case NTOFD:
8135 case NFROMFD: 8479 case NFROMFD:
8136 calcsize(n->ndup.vname); 8480 calcsize(n->ndup.vname);
8137 calcsize(n->ndup.next); 8481 calcsize(n->ndup.next);
8482 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8138 break; 8483 break;
8139 case NHERE: 8484 case NHERE:
8140 case NXHERE: 8485 case NXHERE:
8141 calcsize(n->nhere.doc); 8486 calcsize(n->nhere.doc);
8142 calcsize(n->nhere.next); 8487 calcsize(n->nhere.next);
8488 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8143 break; 8489 break;
8144 case NNOT: 8490 case NNOT:
8145 calcsize(n->nnot.com); 8491 calcsize(n->nnot.com);
8492 IF_PLATFORM_MINGW32(nodeptrsize++);
8146 break; 8493 break;
8147 }; 8494 };
8148} 8495}
8149 8496
8150static char * 8497static char *
8151nodeckstrdup(char *s) 8498nodeckstrdup(const char *s)
8152{ 8499{
8153 char *rtn = funcstring; 8500 char *rtn = funcstring;
8154 8501
8502 if (!s)
8503 return NULL;
8155 strcpy(funcstring, s); 8504 strcpy(funcstring, s);
8156 funcstring += strlen(s) + 1; 8505 funcstring += strlen(s) + 1;
8157 return rtn; 8506 return rtn;
@@ -8159,6 +8508,18 @@ nodeckstrdup(char *s)
8159 8508
8160static union node *copynode(union node *); 8509static union node *copynode(union node *);
8161 8510
8511#if ENABLE_PLATFORM_MINGW32
8512# define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (int)&(dst);}
8513# define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);}}
8514# define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);}}
8515# define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);*nodeptr++ = (int)&(dst4);}}
8516#else
8517# define SAVE_PTR(dst)
8518# define SAVE_PTR2(dst,dst2)
8519# define SAVE_PTR3(dst,dst2,dst3)
8520# define SAVE_PTR4(dst,dst2,dst3,dst4)
8521#endif
8522
8162static struct nodelist * 8523static struct nodelist *
8163copynodelist(struct nodelist *lp) 8524copynodelist(struct nodelist *lp)
8164{ 8525{
@@ -8170,6 +8531,7 @@ copynodelist(struct nodelist *lp)
8170 *lpp = funcblock; 8531 *lpp = funcblock;
8171 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); 8532 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8172 (*lpp)->n = copynode(lp->n); 8533 (*lpp)->n = copynode(lp->n);
8534 SAVE_PTR2((*lpp)->n, (*lpp)->next);
8173 lp = lp->next; 8535 lp = lp->next;
8174 lpp = &(*lpp)->next; 8536 lpp = &(*lpp)->next;
8175 } 8537 }
@@ -8192,16 +8554,19 @@ copynode(union node *n)
8192 new->ncmd.redirect = copynode(n->ncmd.redirect); 8554 new->ncmd.redirect = copynode(n->ncmd.redirect);
8193 new->ncmd.args = copynode(n->ncmd.args); 8555 new->ncmd.args = copynode(n->ncmd.args);
8194 new->ncmd.assign = copynode(n->ncmd.assign); 8556 new->ncmd.assign = copynode(n->ncmd.assign);
8557 SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign);
8195 break; 8558 break;
8196 case NPIPE: 8559 case NPIPE:
8197 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 8560 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8198 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; 8561 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8562 SAVE_PTR(new->npipe.cmdlist);
8199 break; 8563 break;
8200 case NREDIR: 8564 case NREDIR:
8201 case NBACKGND: 8565 case NBACKGND:
8202 case NSUBSHELL: 8566 case NSUBSHELL:
8203 new->nredir.redirect = copynode(n->nredir.redirect); 8567 new->nredir.redirect = copynode(n->nredir.redirect);
8204 new->nredir.n = copynode(n->nredir.n); 8568 new->nredir.n = copynode(n->nredir.n);
8569 SAVE_PTR2(new->nredir.redirect,new->nredir.n);
8205 break; 8570 break;
8206 case NAND: 8571 case NAND:
8207 case NOR: 8572 case NOR:
@@ -8210,31 +8575,37 @@ copynode(union node *n)
8210 case NUNTIL: 8575 case NUNTIL:
8211 new->nbinary.ch2 = copynode(n->nbinary.ch2); 8576 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8212 new->nbinary.ch1 = copynode(n->nbinary.ch1); 8577 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8578 SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2);
8213 break; 8579 break;
8214 case NIF: 8580 case NIF:
8215 new->nif.elsepart = copynode(n->nif.elsepart); 8581 new->nif.elsepart = copynode(n->nif.elsepart);
8216 new->nif.ifpart = copynode(n->nif.ifpart); 8582 new->nif.ifpart = copynode(n->nif.ifpart);
8217 new->nif.test = copynode(n->nif.test); 8583 new->nif.test = copynode(n->nif.test);
8584 SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test);
8218 break; 8585 break;
8219 case NFOR: 8586 case NFOR:
8220 new->nfor.var = nodeckstrdup(n->nfor.var); 8587 new->nfor.var = nodeckstrdup(n->nfor.var);
8221 new->nfor.body = copynode(n->nfor.body); 8588 new->nfor.body = copynode(n->nfor.body);
8222 new->nfor.args = copynode(n->nfor.args); 8589 new->nfor.args = copynode(n->nfor.args);
8590 SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args);
8223 break; 8591 break;
8224 case NCASE: 8592 case NCASE:
8225 new->ncase.cases = copynode(n->ncase.cases); 8593 new->ncase.cases = copynode(n->ncase.cases);
8226 new->ncase.expr = copynode(n->ncase.expr); 8594 new->ncase.expr = copynode(n->ncase.expr);
8595 SAVE_PTR2(new->ncase.cases,new->ncase.expr);
8227 break; 8596 break;
8228 case NCLIST: 8597 case NCLIST:
8229 new->nclist.body = copynode(n->nclist.body); 8598 new->nclist.body = copynode(n->nclist.body);
8230 new->nclist.pattern = copynode(n->nclist.pattern); 8599 new->nclist.pattern = copynode(n->nclist.pattern);
8231 new->nclist.next = copynode(n->nclist.next); 8600 new->nclist.next = copynode(n->nclist.next);
8601 SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next);
8232 break; 8602 break;
8233 case NDEFUN: 8603 case NDEFUN:
8234 case NARG: 8604 case NARG:
8235 new->narg.backquote = copynodelist(n->narg.backquote); 8605 new->narg.backquote = copynodelist(n->narg.backquote);
8236 new->narg.text = nodeckstrdup(n->narg.text); 8606 new->narg.text = nodeckstrdup(n->narg.text);
8237 new->narg.next = copynode(n->narg.next); 8607 new->narg.next = copynode(n->narg.next);
8608 SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next);
8238 break; 8609 break;
8239 case NTO: 8610 case NTO:
8240#if ENABLE_ASH_BASH_COMPAT 8611#if ENABLE_ASH_BASH_COMPAT
@@ -8247,6 +8618,7 @@ copynode(union node *n)
8247 new->nfile.fname = copynode(n->nfile.fname); 8618 new->nfile.fname = copynode(n->nfile.fname);
8248 new->nfile.fd = n->nfile.fd; 8619 new->nfile.fd = n->nfile.fd;
8249 new->nfile.next = copynode(n->nfile.next); 8620 new->nfile.next = copynode(n->nfile.next);
8621 SAVE_PTR2(new->nfile.fname,new->nfile.next);
8250 break; 8622 break;
8251 case NTOFD: 8623 case NTOFD:
8252 case NFROMFD: 8624 case NFROMFD:
@@ -8254,15 +8626,18 @@ copynode(union node *n)
8254 new->ndup.dupfd = n->ndup.dupfd; 8626 new->ndup.dupfd = n->ndup.dupfd;
8255 new->ndup.fd = n->ndup.fd; 8627 new->ndup.fd = n->ndup.fd;
8256 new->ndup.next = copynode(n->ndup.next); 8628 new->ndup.next = copynode(n->ndup.next);
8629 SAVE_PTR2(new->ndup.vname,new->ndup.next);
8257 break; 8630 break;
8258 case NHERE: 8631 case NHERE:
8259 case NXHERE: 8632 case NXHERE:
8260 new->nhere.doc = copynode(n->nhere.doc); 8633 new->nhere.doc = copynode(n->nhere.doc);
8261 new->nhere.fd = n->nhere.fd; 8634 new->nhere.fd = n->nhere.fd;
8262 new->nhere.next = copynode(n->nhere.next); 8635 new->nhere.next = copynode(n->nhere.next);
8636 SAVE_PTR2(new->nhere.doc,new->nhere.next);
8263 break; 8637 break;
8264 case NNOT: 8638 case NNOT:
8265 new->nnot.com = copynode(n->nnot.com); 8639 new->nnot.com = copynode(n->nnot.com);
8640 SAVE_PTR(new->nnot.com);
8266 break; 8641 break;
8267 }; 8642 };
8268 new->type = n->type; 8643 new->type = n->type;
@@ -8285,6 +8660,7 @@ copyfunc(union node *n)
8285 f = ckmalloc(blocksize + funcstringsize); 8660 f = ckmalloc(blocksize + funcstringsize);
8286 funcblock = (char *) f + offsetof(struct funcnode, n); 8661 funcblock = (char *) f + offsetof(struct funcnode, n);
8287 funcstring = (char *) f + blocksize; 8662 funcstring = (char *) f + blocksize;
8663 IF_PLATFORM_MINGW32(nodeptr = NULL);
8288 copynode(n); 8664 copynode(n);
8289 f->count = 0; 8665 f->count = 0;
8290 return f; 8666 return f;
@@ -8644,6 +9020,7 @@ evalcase(union node *n, int flags)
8644static void 9020static void
8645evalsubshell(union node *n, int flags) 9021evalsubshell(union node *n, int flags)
8646{ 9022{
9023 IF_PLATFORM_MINGW32(struct forkshell fs;)
8647 struct job *jp; 9024 struct job *jp;
8648 int backgnd = (n->type == NBACKGND); 9025 int backgnd = (n->type == NBACKGND);
8649 int status; 9026 int status;
@@ -8653,12 +9030,22 @@ evalsubshell(union node *n, int flags)
8653 goto nofork; 9030 goto nofork;
8654 INT_OFF; 9031 INT_OFF;
8655 jp = makejob(/*n,*/ 1); 9032 jp = makejob(/*n,*/ 1);
9033#if ENABLE_PLATFORM_MINGW32
9034 memset(&fs, 0, sizeof(fs));
9035 fs.fpid = FS_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 if ( 0 ) {
9041#else
8656 if (forkshell(jp, n, backgnd) == 0) { 9042 if (forkshell(jp, n, backgnd) == 0) {
8657 /* child */ 9043 /* child */
8658 INT_ON; 9044 INT_ON;
8659 flags |= EV_EXIT; 9045 flags |= EV_EXIT;
8660 if (backgnd) 9046 if (backgnd)
8661 flags &= ~EV_TESTED; 9047 flags &= ~EV_TESTED;
9048#endif
8662 nofork: 9049 nofork:
8663 redirect(n->nredir.redirect, 0); 9050 redirect(n->nredir.redirect, 0);
8664 evaltreenr(n->nredir.n, flags); 9051 evaltreenr(n->nredir.n, flags);
@@ -8744,6 +9131,7 @@ expredir(union node *n)
8744static void 9131static void
8745evalpipe(union node *n, int flags) 9132evalpipe(union node *n, int flags)
8746{ 9133{
9134 IF_PLATFORM_MINGW32(struct forkshell fs;)
8747 struct job *jp; 9135 struct job *jp;
8748 struct nodelist *lp; 9136 struct nodelist *lp;
8749 int pipelen; 9137 int pipelen;
@@ -8767,6 +9155,17 @@ evalpipe(union node *n, int flags)
8767 ash_msg_and_raise_error("pipe call failed"); 9155 ash_msg_and_raise_error("pipe call failed");
8768 } 9156 }
8769 } 9157 }
9158#if ENABLE_PLATFORM_MINGW32
9159 memset(&fs, 0, sizeof(fs));
9160 fs.fpid = FS_EVALPIPE;
9161 fs.flags = flags;
9162 fs.n = lp->n;
9163 fs.fd[0] = pip[0];
9164 fs.fd[1] = pip[1];
9165 fs.fd[2] = prevfd;
9166 if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0)
9167 ash_msg_and_raise_error("unable to spawn shell");
9168#else
8770 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { 9169 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8771 INT_ON; 9170 INT_ON;
8772 if (pip[1] >= 0) { 9171 if (pip[1] >= 0) {
@@ -8783,6 +9182,7 @@ evalpipe(union node *n, int flags)
8783 evaltreenr(lp->n, flags); 9182 evaltreenr(lp->n, flags);
8784 /* never returns */ 9183 /* never returns */
8785 } 9184 }
9185#endif
8786 if (prevfd >= 0) 9186 if (prevfd >= 0)
8787 close(prevfd); 9187 close(prevfd);
8788 prevfd = pip[0]; 9188 prevfd = pip[0];
@@ -9244,6 +9644,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9244 * as POSIX mandates */ 9644 * as POSIX mandates */
9245 return back_exitstatus; 9645 return back_exitstatus;
9246} 9646}
9647
9247static void 9648static void
9248evalcommand(union node *cmd, int flags) 9649evalcommand(union node *cmd, int flags)
9249{ 9650{
@@ -9421,6 +9822,27 @@ evalcommand(union node *cmd, int flags)
9421 * in a script or a subshell does not need forking, 9822 * in a script or a subshell does not need forking,
9422 * we can just exec it. 9823 * we can just exec it.
9423 */ 9824 */
9825#if ENABLE_PLATFORM_MINGW32
9826 if (!(flags & EV_EXIT) || trap[0]) {
9827 /* No, forking off a child is necessary */
9828 struct forkshell fs;
9829
9830 memset(&fs, 0, sizeof(fs));
9831 fs.fpid = FS_SHELLEXEC;
9832 fs.argv = argv;
9833 fs.string = (char*)path;
9834 fs.fd[0] = cmdentry.u.index;
9835 fs.strlist = varlist.list;
9836 jp = makejob(/*cmd,*/ 1);
9837 if (spawn_forkshell(jp, &fs, FORK_FG) < 0)
9838 ash_msg_and_raise_error("unable to spawn shell");
9839 exitstatus = waitforjob(jp);
9840 INT_ON;
9841 TRACE(("forked child exited with %d\n", exitstatus));
9842 break;
9843 }
9844 /* goes through to shellexec() */
9845#else
9424 if (!(flags & EV_EXIT) || may_have_traps) { 9846 if (!(flags & EV_EXIT) || may_have_traps) {
9425 /* No, forking off a child is necessary */ 9847 /* No, forking off a child is necessary */
9426 INT_OFF; 9848 INT_OFF;
@@ -9436,6 +9858,7 @@ evalcommand(union node *cmd, int flags)
9436 FORCE_INT_ON; 9858 FORCE_INT_ON;
9437 /* fall through to exec'ing external program */ 9859 /* fall through to exec'ing external program */
9438 } 9860 }
9861#endif
9439 listsetvar(varlist.list, VEXPORT|VSTACK); 9862 listsetvar(varlist.list, VEXPORT|VSTACK);
9440 shellexec(argv, path, cmdentry.u.index); 9863 shellexec(argv, path, cmdentry.u.index);
9441 /* NOTREACHED */ 9864 /* NOTREACHED */
@@ -9824,7 +10247,7 @@ preadbuffer(void)
9824 more--; 10247 more--;
9825 10248
9826 c = *q; 10249 c = *q;
9827 if (c == '\0') { 10250 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) {
9828 memmove(q, q + 1, more); 10251 memmove(q, q + 1, more);
9829 } else { 10252 } else {
9830 q++; 10253 q++;
@@ -9980,6 +10403,7 @@ popallfiles(void)
9980 popfile(); 10403 popfile();
9981} 10404}
9982 10405
10406#if !ENABLE_PLATFORM_MINGW32
9983/* 10407/*
9984 * Close the file(s) that the shell is reading commands from. Called 10408 * Close the file(s) that the shell is reading commands from. Called
9985 * after a fork is done. 10409 * after a fork is done.
@@ -9993,6 +10417,7 @@ closescript(void)
9993 g_parsefile->pf_fd = 0; 10417 g_parsefile->pf_fd = 0;
9994 } 10418 }
9995} 10419}
10420#endif
9996 10421
9997/* 10422/*
9998 * Like setinputfile, but takes an open file descriptor. Call this with 10423 * Like setinputfile, but takes an open file descriptor. Call this with
@@ -12256,7 +12681,7 @@ find_dot_file(char *name)
12256 struct stat statb; 12681 struct stat statb;
12257 12682
12258 /* don't try this for absolute or relative paths */ 12683 /* don't try this for absolute or relative paths */
12259 if (strchr(name, '/')) 12684 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\')))
12260 return name; 12685 return name;
12261 12686
12262 /* IIRC standards do not say whether . is to be searched. 12687 /* IIRC standards do not say whether . is to be searched.
@@ -12371,10 +12796,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12371 struct stat statb; 12796 struct stat statb;
12372 int e; 12797 int e;
12373 int updatetbl; 12798 int updatetbl;
12799 IF_PLATFORM_MINGW32(int len;)
12374 struct builtincmd *bcmd; 12800 struct builtincmd *bcmd;
12375 12801
12376 /* If name contains a slash, don't use PATH or hash table */ 12802 /* If name contains a slash, don't use PATH or hash table */
12377 if (strchr(name, '/') != NULL) { 12803 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) {
12378 entry->u.index = -1; 12804 entry->u.index = -1;
12379 if (act & DO_ABS) { 12805 if (act & DO_ABS) {
12380 while (stat(name, &statb) < 0) { 12806 while (stat(name, &statb) < 0) {
@@ -12481,12 +12907,48 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12481 } 12907 }
12482 } 12908 }
12483 /* if rehash, don't redo absolute path names */ 12909 /* if rehash, don't redo absolute path names */
12484 if (fullname[0] == '/' && idx <= prev) { 12910 if (is_absolute_path(fullname) && idx <= prev) {
12485 if (idx < prev) 12911 if (idx < prev)
12486 continue; 12912 continue;
12487 TRACE(("searchexec \"%s\": no change\n", name)); 12913 TRACE(("searchexec \"%s\": no change\n", name));
12488 goto success; 12914 goto success;
12489 } 12915 }
12916#if ENABLE_PLATFORM_MINGW32
12917 len = strlen(fullname);
12918 if (len > 4 &&
12919 (!strcasecmp(fullname+len-4, ".exe") ||
12920 !strcasecmp(fullname+len-4, ".com"))) {
12921 if (stat(fullname, &statb) < 0) {
12922 if (errno != ENOENT && errno != ENOTDIR)
12923 e = errno;
12924 goto loop;
12925 }
12926 }
12927 else {
12928 /* path_advance() has reserved space for .exe */
12929 memcpy(fullname+len, ".exe", 5);
12930 if (stat(fullname, &statb) < 0) {
12931 if (errno != ENOENT && errno != ENOTDIR)
12932 e = errno;
12933 memcpy(fullname+len, ".com", 5);
12934 if (stat(fullname, &statb) < 0) {
12935 if (errno != ENOENT && errno != ENOTDIR)
12936 e = errno;
12937 fullname[len] = '\0';
12938 if (stat(fullname, &statb) < 0) {
12939 if (errno != ENOENT && errno != ENOTDIR)
12940 e = errno;
12941 goto loop;
12942 }
12943 if (!file_is_executable(fullname)) {
12944 e = ENOEXEC;
12945 goto loop;
12946 }
12947 }
12948 }
12949 fullname[len] = '\0';
12950 }
12951#else
12490 while (stat(fullname, &statb) < 0) { 12952 while (stat(fullname, &statb) < 0) {
12491#ifdef SYSV 12953#ifdef SYSV
12492 if (errno == EINTR) 12954 if (errno == EINTR)
@@ -12496,6 +12958,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12496 e = errno; 12958 e = errno;
12497 goto loop; 12959 goto loop;
12498 } 12960 }
12961#endif
12499 e = EACCES; /* if we fail, this will be the error */ 12962 e = EACCES; /* if we fail, this will be the error */
12500 if (!S_ISREG(statb.st_mode)) 12963 if (!S_ISREG(statb.st_mode))
12501 continue; 12964 continue;
@@ -13036,6 +13499,57 @@ init(void)
13036 struct stat st1, st2; 13499 struct stat st1, st2;
13037 13500
13038 initvar(); 13501 initvar();
13502
13503#if ENABLE_PLATFORM_MINGW32
13504 /*
13505 * case insensitive env names from Windows world
13506 *
13507 * Some standard env names such as PATH is named Path and so on
13508 * ash itself is case sensitive, so "Path" will confuse it, as
13509 * MSVC getenv() is case insensitive.
13510 *
13511 * We may end up having both Path and PATH. Then Path will be chosen
13512 * because it appears first.
13513 */
13514 for (envp = environ; envp && *envp; envp++) {
13515 if (strncasecmp(*envp, "PATH=", 5) == 0 &&
13516 strncmp(*envp, "PATH=", 5) != 0) {
13517 break;
13518 }
13519 }
13520
13521 if (envp && *envp) {
13522 /*
13523 * If we get here it's because the environment contains a path
13524 * variable called something other than PATH. This suggests we
13525 * haven't been invoked from an earlier instance of BusyBox.
13526 */
13527 char *start, *end;
13528 struct passwd *pw;
13529
13530 for (envp = environ; envp && *envp; envp++) {
13531 end = strchr(*envp, '=');
13532 if (!end)
13533 continue;
13534
13535 /* make all variable names uppercase */
13536 for (start = *envp;start < end;start++)
13537 *start = toupper(*start);
13538
13539 /* convert backslashes to forward slashes */
13540 for ( ++end; *end; ++end ) {
13541 if ( *end == '\\' ) {
13542 *end = '/';
13543 }
13544 }
13545 }
13546
13547 /* some initialisation normally performed at login */
13548 pw = xgetpwuid(getuid());
13549 setup_environment(pw->pw_shell,
13550 SETUP_ENV_CHANGEENV|SETUP_ENV_NO_CHDIR, pw);
13551 }
13552#endif
13039 for (envp = environ; envp && *envp; envp++) { 13553 for (envp = environ; envp && *envp; envp++) {
13040 if (strchr(*envp, '=')) { 13554 if (strchr(*envp, '=')) {
13041 setvareq(*envp, VEXPORT|VTEXTFIXED); 13555 setvareq(*envp, VEXPORT|VTEXTFIXED);
@@ -13253,13 +13767,38 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13253 13767
13254 init(); 13768 init();
13255 setstackmark(&smark); 13769 setstackmark(&smark);
13770
13771#if ENABLE_PLATFORM_MINGW32
13772 hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL);
13773 SetConsoleCtrlHandler(ctrl_handler, TRUE);
13774 if (argc == 3 && !strcmp(argv[1], "--forkshell")) {
13775 forkshell_init(argv[2]);
13776
13777 /* NOTREACHED */
13778 bb_error_msg_and_die("subshell ended unexpectedly");
13779 }
13780#endif
13256 procargs(argv); 13781 procargs(argv);
13782#if ENABLE_PLATFORM_MINGW32
13783 if ( noconsole ) {
13784 DWORD dummy;
13785
13786 if ( GetConsoleProcessList(&dummy, 1) == 1 ) {
13787 ShowWindow(GetConsoleWindow(), SW_HIDE);
13788 }
13789 }
13790#endif
13257 13791
13258 if (argv[0] && argv[0][0] == '-') 13792 if (argv[0] && argv[0][0] == '-')
13259 isloginsh = 1; 13793 isloginsh = 1;
13260 if (isloginsh) { 13794 if (isloginsh) {
13261 const char *hp; 13795 const char *hp;
13262 13796
13797#if ENABLE_PLATFORM_MINGW32
13798 chdir(xgetpwuid(getuid())->pw_dir);
13799 setpwd(NULL, 0);
13800#endif
13801
13263 state = 1; 13802 state = 1;
13264 read_profile("/etc/profile"); 13803 read_profile("/etc/profile");
13265 state1: 13804 state1:
@@ -13335,6 +13874,642 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13335 /* NOTREACHED */ 13874 /* NOTREACHED */
13336} 13875}
13337 13876
13877#if ENABLE_PLATFORM_MINGW32
13878static void
13879forkshell_openhere(struct forkshell *fs)
13880{
13881 union node *redir = fs->n;
13882 int pip[2];
13883
13884 pip[0] = fs->fd[0];
13885 pip[1] = fs->fd[1];
13886
13887 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
13888
13889 close(pip[0]);
13890 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
13891 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
13892 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
13893 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
13894 signal(SIGPIPE, SIG_DFL);
13895 if (redir->type == NHERE) {
13896 size_t len = strlen(redir->nhere.doc->narg.text);
13897 full_write(pip[1], redir->nhere.doc->narg.text, len);
13898 } else /* NXHERE */
13899 expandhere(redir->nhere.doc, pip[1]);
13900 _exit(EXIT_SUCCESS);
13901}
13902
13903static void
13904forkshell_evalbackcmd(struct forkshell *fs)
13905{
13906 union node *n = fs->n;
13907 int pip[2] = {fs->fd[0], fs->fd[1]};
13908
13909 FORCE_INT_ON;
13910 close(pip[0]);
13911 if (pip[1] != 1) {
13912 /*close(1);*/
13913 copyfd(pip[1], 1 | COPYFD_EXACT);
13914 close(pip[1]);
13915 }
13916 eflag = 0;
13917 evaltree(n, EV_EXIT); /* actually evaltreenr... */
13918 /* NOTREACHED */
13919}
13920
13921static void
13922forkshell_evalsubshell(struct forkshell *fs)
13923{
13924 union node *n = fs->n;
13925 int flags = fs->flags;
13926
13927 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
13928 INT_ON;
13929 flags |= EV_EXIT;
13930 expredir(n->nredir.redirect);
13931 redirect(n->nredir.redirect, 0);
13932 evaltreenr(n->nredir.n, flags);
13933 /* never returns */
13934}
13935
13936static void
13937forkshell_evalpipe(struct forkshell *fs)
13938{
13939 union node *n = fs->n;
13940 int flags = fs->flags;
13941 int prevfd = fs->fd[2];
13942 int pip[2] = {fs->fd[0], fs->fd[1]};
13943
13944 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
13945 INT_ON;
13946 if (pip[1] >= 0) {
13947 close(pip[0]);
13948 }
13949 if (prevfd > 0) {
13950 dup2(prevfd, 0);
13951 close(prevfd);
13952 }
13953 if (pip[1] > 1) {
13954 dup2(pip[1], 1);
13955 close(pip[1]);
13956 }
13957 evaltreenr(n, flags);
13958}
13959
13960static void
13961forkshell_shellexec(struct forkshell *fs)
13962{
13963 int idx = fs->fd[0];
13964 struct strlist *varlist = fs->strlist;
13965 char **argv = fs->argv;
13966 char *path = fs->string;
13967
13968 listsetvar(varlist, VEXPORT|VSTACK);
13969 shellexec(argv, path, idx);
13970}
13971
13972static void
13973forkshell_child(struct forkshell *fs)
13974{
13975 switch ( fs->fpid ) {
13976 case FS_OPENHERE:
13977 forkshell_openhere(fs);
13978 break;
13979 case FS_EVALBACKCMD:
13980 forkshell_evalbackcmd(fs);
13981 break;
13982 case FS_EVALSUBSHELL:
13983 forkshell_evalsubshell(fs);
13984 break;
13985 case FS_EVALPIPE:
13986 forkshell_evalpipe(fs);
13987 break;
13988 case FS_SHELLEXEC:
13989 forkshell_shellexec(fs);
13990 break;
13991 }
13992}
13993
13994/*
13995 * Reset the pointers to the builtin environment variables in the hash
13996 * table to point to varinit rather than the bogus copy created during
13997 * forkshell_prepare.
13998 */
13999static void
14000reinitvar(void)
14001{
14002 struct var *vp;
14003 struct var *end;
14004 struct var **vpp;
14005 struct var **old;
14006
14007 vp = varinit;
14008 end = vp + ARRAY_SIZE(varinit);
14009 do {
14010 vpp = hashvar(vp->var_text);
14011 if ( (old=findvar(vpp, vp->var_text)) != NULL ) {
14012 vp->next = (*old)->next;
14013 *old = vp;
14014 }
14015 } while (++vp < end);
14016}
14017
14018/* FIXME: should consider running forkparent() and forkchild() */
14019static int
14020spawn_forkshell(struct job *jp, struct forkshell *fs, int mode)
14021{
14022 struct forkshell *new;
14023 char buf[16];
14024 const char *argv[] = { "sh", "--forkshell", NULL, NULL };
14025 pid_t pid;
14026
14027 new = forkshell_prepare(fs);
14028 sprintf(buf, "%x", (unsigned int)new->hMapFile);
14029 argv[2] = buf;
14030 pid = mingw_spawn_applet(P_NOWAIT, "sh", argv,
14031 (const char *const *)environ);
14032 CloseHandle(new->hMapFile);
14033 UnmapViewOfFile(new);
14034 if (pid == -1) {
14035 free(jp);
14036 return -1;
14037 }
14038 forkparent(jp, fs->node, mode, pid);
14039 return pid;
14040}
14041
14042/*
14043 * forkshell_prepare() and friends
14044 *
14045 * The sequence is as follows:
14046 * - funcblocksize, funcstringsize, nodeptrsize are initialized
14047 * - forkshell_size(fs) is called to calculate the exact memory needed
14048 * - a new struct is allocated
14049 * - funcblock, funcstring, nodeptr are initialized from the new block
14050 * - forkshell_copy(fs) is called to copy recursively everything over
14051 * it will record all pointers along the way, to nodeptr
14052 *
14053 * When this memory is mapped elsewhere, pointer fixup will be needed
14054 */
14055#define SLIST_SIZE_BEGIN(name,type) \
14056static void \
14057name(type *p) \
14058{ \
14059 while (p) { \
14060 funcblocksize += sizeof(type);
14061 /* do something here with p */
14062#define SLIST_SIZE_END() \
14063 nodeptrsize++; \
14064 p = p->next; \
14065 } \
14066}
14067
14068#define SLIST_COPY_BEGIN(name,type) \
14069static type * \
14070name(type *vp) \
14071{ \
14072 type *start; \
14073 type **vpp; \
14074 vpp = &start; \
14075 while (vp) { \
14076 *vpp = funcblock; \
14077 funcblock = (char *) funcblock + sizeof(type);
14078 /* do something here with vpp and vp */
14079#define SLIST_COPY_END() \
14080 SAVE_PTR((*vpp)->next); \
14081 vp = vp->next; \
14082 vpp = &(*vpp)->next; \
14083 } \
14084 *vpp = NULL; \
14085 return start; \
14086}
14087
14088/*
14089 * struct var
14090 */
14091SLIST_SIZE_BEGIN(var_size,struct var)
14092funcstringsize += strlen(p->var_text) + 1;
14093nodeptrsize++; /* p->text */
14094SLIST_SIZE_END()
14095
14096SLIST_COPY_BEGIN(var_copy,struct var)
14097(*vpp)->var_text = nodeckstrdup(vp->var_text);
14098(*vpp)->flags = vp->flags;
14099/*
14100 * The only place that can set struct var#func is varinit[],
14101 * which will be fixed by forkshell_init()
14102 */
14103(*vpp)->var_func = NULL;
14104SAVE_PTR((*vpp)->var_text);
14105SLIST_COPY_END()
14106
14107/*
14108 * struct strlist
14109 */
14110SLIST_SIZE_BEGIN(strlist_size,struct strlist)
14111funcstringsize += strlen(p->text) + 1;
14112nodeptrsize++; /* p->text */
14113SLIST_SIZE_END()
14114
14115SLIST_COPY_BEGIN(strlist_copy,struct strlist)
14116(*vpp)->text = nodeckstrdup(vp->text);
14117SAVE_PTR((*vpp)->text);
14118SLIST_COPY_END()
14119
14120/*
14121 * struct tblentry
14122 */
14123static void
14124tblentry_size(struct tblentry *tep)
14125{
14126 while (tep) {
14127 funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14128 /* CMDBUILTIN, e->param.cmd needs no pointer relocation */
14129 if (tep->cmdtype == CMDFUNCTION) {
14130 funcblocksize += offsetof(struct funcnode, n);
14131 calcsize(&tep->param.func->n);
14132 nodeptrsize++; /* tep->param.func */
14133 }
14134 nodeptrsize++; /* tep->next */
14135 tep = tep->next;
14136 }
14137}
14138
14139static struct tblentry *
14140tblentry_copy(struct tblentry *tep)
14141{
14142 struct tblentry *start;
14143 struct tblentry **newp;
14144 int size;
14145
14146 newp = &start;
14147 while (tep) {
14148 *newp = funcblock;
14149 size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14150
14151 funcblock = (char *) funcblock + size;
14152 memcpy(*newp, tep, size);
14153 switch (tep->cmdtype) {
14154 case CMDBUILTIN:
14155 /* No pointer saving, this field must be fixed by forkshell_init() */
14156 (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab);
14157 break;
14158 case CMDFUNCTION:
14159 (*newp)->param.func = funcblock;
14160 funcblock = (char *) funcblock + offsetof(struct funcnode, n);
14161 copynode(&tep->param.func->n);
14162 SAVE_PTR((*newp)->param.func);
14163 break;
14164 default:
14165 break;
14166 }
14167 SAVE_PTR((*newp)->next);
14168 tep = tep->next;
14169 newp = &(*newp)->next;
14170 }
14171 *newp = NULL;
14172 return start;
14173}
14174
14175static void
14176cmdtable_size(struct tblentry **cmdtablep)
14177{
14178 int i;
14179 nodeptrsize += CMDTABLESIZE;
14180 funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE;
14181 for (i = 0; i < CMDTABLESIZE; i++)
14182 tblentry_size(cmdtablep[i]);
14183}
14184
14185static struct tblentry **
14186cmdtable_copy(struct tblentry **cmdtablep)
14187{
14188 struct tblentry **new = funcblock;
14189 int i;
14190
14191 funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE;
14192 for (i = 0; i < CMDTABLESIZE; i++) {
14193 new[i] = tblentry_copy(cmdtablep[i]);
14194 SAVE_PTR(new[i]);
14195 }
14196 return new;
14197}
14198
14199/*
14200 * char **
14201 */
14202static void
14203argv_size(char **p)
14204{
14205 while (p && *p) {
14206 funcblocksize += sizeof(char *);
14207 funcstringsize += strlen(*p)+1;
14208 nodeptrsize++;
14209 p++;
14210 }
14211 funcblocksize += sizeof(char *);
14212}
14213
14214static char **
14215argv_copy(char **p)
14216{
14217 char **new, **start = funcblock;
14218
14219 while (p && *p) {
14220 new = funcblock;
14221 funcblock = (char *) funcblock + sizeof(char *);
14222 *new = nodeckstrdup(*p);
14223 SAVE_PTR(*new);
14224 p++;
14225 new++;
14226 }
14227 new = funcblock;
14228 funcblock = (char *) funcblock + sizeof(char *);
14229 *new = NULL;
14230 return start;
14231}
14232
14233/*
14234 * struct redirtab
14235 */
14236static void
14237redirtab_size(struct redirtab *rdtp)
14238{
14239 while (rdtp) {
14240 funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14241 rdtp = rdtp->next;
14242 nodeptrsize++; /* rdtp->next */
14243 }
14244}
14245
14246static struct redirtab *
14247redirtab_copy(struct redirtab *rdtp)
14248{
14249 struct redirtab *start;
14250 struct redirtab **vpp;
14251
14252 vpp = &start;
14253 while (rdtp) {
14254 int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14255 *vpp = funcblock;
14256 funcblock = (char *) funcblock + size;
14257 memcpy(*vpp, rdtp, size);
14258 SAVE_PTR((*vpp)->next);
14259 rdtp = rdtp->next;
14260 vpp = &(*vpp)->next;
14261 }
14262 *vpp = NULL;
14263 return start;
14264}
14265
14266#undef shellparam
14267#undef redirlist
14268#undef varinit
14269#undef vartab
14270static void
14271globals_var_size(struct globals_var *gvp)
14272{
14273 int i;
14274
14275 funcblocksize += sizeof(struct globals_var);
14276 argv_size(gvp->shellparam.p);
14277 redirtab_size(gvp->redirlist);
14278 for (i = 0; i < VTABSIZE; i++)
14279 var_size(gvp->vartab[i]);
14280 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14281 var_size(gvp->varinit+i);
14282 nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */
14283}
14284
14285#undef g_nullredirs
14286#undef preverrout_fd
14287static struct globals_var *
14288globals_var_copy(struct globals_var *gvp)
14289{
14290 int i;
14291 struct globals_var *new;
14292
14293 new = funcblock;
14294 funcblock = (char *) funcblock + sizeof(struct globals_var);
14295
14296 /* shparam */
14297 memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam));
14298 new->shellparam.malloced = 0;
14299 new->shellparam.p = argv_copy(gvp->shellparam.p);
14300 SAVE_PTR(new->shellparam.p);
14301
14302 new->redirlist = redirtab_copy(gvp->redirlist);
14303 SAVE_PTR(new->redirlist);
14304
14305 new->g_nullredirs = gvp->g_nullredirs;
14306 new->preverrout_fd = gvp->preverrout_fd;
14307 for (i = 0; i < VTABSIZE; i++) {
14308 new->vartab[i] = var_copy(gvp->vartab[i]);
14309 SAVE_PTR(new->vartab[i]);
14310 }
14311
14312 /* Can't use var_copy because varinit is already allocated */
14313 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) {
14314 new->varinit[i].next = NULL;
14315 new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text);
14316 SAVE_PTR(new->varinit[i].var_text);
14317 new->varinit[i].flags = gvp->varinit[i].flags;
14318 new->varinit[i].var_func = gvp->varinit[i].var_func;
14319 }
14320 return new;
14321}
14322
14323#undef minusc
14324#undef curdir
14325#undef physdir
14326#undef arg0
14327#undef nullstr
14328static void
14329globals_misc_size(struct globals_misc *p)
14330{
14331 funcblocksize += sizeof(struct globals_misc);
14332 funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1;
14333 if (p->curdir != p->nullstr)
14334 funcstringsize += strlen(p->curdir) + 1;
14335 if (p->physdir != p->nullstr)
14336 funcstringsize += strlen(p->physdir) + 1;
14337 funcstringsize += strlen(p->arg0) + 1;
14338 nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */
14339}
14340
14341static struct globals_misc *
14342globals_misc_copy(struct globals_misc *p)
14343{
14344 struct globals_misc *new = funcblock;
14345
14346 funcblock = (char *) funcblock + sizeof(struct globals_misc);
14347 memcpy(new, p, sizeof(struct globals_misc));
14348
14349 new->minusc = nodeckstrdup(p->minusc);
14350 new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr;
14351 new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr;
14352 new->arg0 = nodeckstrdup(p->arg0);
14353 SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0);
14354 return new;
14355}
14356
14357static void
14358forkshell_size(struct forkshell *fs)
14359{
14360 funcblocksize += sizeof(struct forkshell);
14361 globals_var_size(fs->gvp);
14362 globals_misc_size(fs->gmp);
14363 cmdtable_size(fs->cmdtable);
14364 /* optlist_transfer(sending, fd); */
14365 /* misc_transfer(sending, fd); */
14366
14367 calcsize(fs->n);
14368 argv_size(fs->argv);
14369 funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1;
14370 strlist_size(fs->strlist);
14371
14372 nodeptrsize += 7; /* gvp, gmp, cmdtable, n, argv, string, strlist */
14373}
14374
14375static struct forkshell *
14376forkshell_copy(struct forkshell *fs)
14377{
14378 struct forkshell *new;
14379
14380 new = funcblock;
14381 funcblock = (char *) funcblock + sizeof(struct forkshell);
14382
14383 memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */
14384 new->gvp = globals_var_copy(fs->gvp);
14385 new->gmp = globals_misc_copy(fs->gmp);
14386 new->cmdtable = cmdtable_copy(fs->cmdtable);
14387 SAVE_PTR3(new->gvp, new->gmp, new->cmdtable);
14388
14389 new->n = copynode(fs->n);
14390 new->argv = argv_copy(fs->argv);
14391 new->string = nodeckstrdup(fs->string);
14392 new->strlist = strlist_copy(fs->strlist);
14393 SAVE_PTR4(new->n, new->argv, new->string, new->strlist);
14394 return new;
14395}
14396
14397static struct forkshell *
14398forkshell_prepare(struct forkshell *fs)
14399{
14400 struct forkshell *new;
14401 int size, nodeptr_offset;
14402 HANDLE h;
14403 SECURITY_ATTRIBUTES sa;
14404
14405 /* Calculate size of "new" */
14406 fs->gvp = ash_ptr_to_globals_var;
14407 fs->gmp = ash_ptr_to_globals_misc;
14408 fs->cmdtable = cmdtable;
14409
14410 nodeptrsize = 1; /* NULL terminated */
14411 funcblocksize = 0;
14412 funcstringsize = 0;
14413 forkshell_size(fs);
14414 size = funcblocksize + funcstringsize + nodeptrsize*sizeof(int);
14415
14416 /* Allocate, initialize pointers */
14417 memset(&sa, 0, sizeof(sa));
14418 sa.nLength = sizeof(sa);
14419 sa.lpSecurityDescriptor = NULL;
14420 sa.bInheritHandle = TRUE;
14421 h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL);
14422 new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14423 /* new = ckmalloc(size); */
14424 funcblock = new;
14425 funcstring = (char *) funcblock + funcblocksize;
14426 nodeptr = (int*)((char *) funcstring + funcstringsize);
14427 nodeptr_offset = (int) nodeptr - (int) new;
14428
14429 /* Now pack them all */
14430 forkshell_copy(fs);
14431
14432 /* Finish it up */
14433 *nodeptr = 0;
14434 new->size = size;
14435 new->nodeptr_offset = nodeptr_offset;
14436 new->old_base = new;
14437 new->hMapFile = h;
14438 return new;
14439}
14440
14441#undef exception_handler
14442#undef trap
14443#undef trap_ptr
14444static void *sticky_mem_start, *sticky_mem_end;
14445static void
14446forkshell_init(const char *idstr)
14447{
14448 struct forkshell *fs;
14449 int map_handle;
14450 HANDLE h;
14451 struct globals_var **gvpp;
14452 struct globals_misc **gmpp;
14453 int i;
14454
14455 if (sscanf(idstr, "%x", &map_handle) != 1)
14456 bb_error_msg_and_die("invalid forkshell ID");
14457
14458 h = (HANDLE)map_handle;
14459 fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14460 if (!fs)
14461 bb_error_msg_and_die("Invalid forkshell memory");
14462
14463 /* this memory can't be freed */
14464 sticky_mem_start = fs;
14465 sticky_mem_end = (char *) fs + fs->size;
14466 /* pointer fixup */
14467 nodeptr = (int*)((char*)fs + fs->nodeptr_offset);
14468 while (*nodeptr) {
14469 int *ptr = (int*)((char*)fs + (*nodeptr - (int)fs->old_base));
14470 if (*ptr)
14471 *ptr -= ((int)fs->old_base - (int)fs);
14472 nodeptr++;
14473 }
14474 /* Now fix up stuff that can't be transferred */
14475 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14476 fs->gvp->varinit[i].var_func = varinit_data[i].var_func;
14477 for (i = 0; i < CMDTABLESIZE; i++) {
14478 struct tblentry *e = fs->cmdtable[i];
14479 while (e) {
14480 if (e->cmdtype == CMDBUILTIN)
14481 e->param.cmd = builtintab + (int)e->param.cmd;
14482 e = e->next;
14483 }
14484 }
14485 fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler;
14486 for (i = 0; i < NSIG; i++)
14487 fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i];
14488 fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr;
14489
14490 /* Switch global variables */
14491 gvpp = (struct globals_var **)&ash_ptr_to_globals_var;
14492 *gvpp = fs->gvp;
14493 gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc;
14494 *gmpp = fs->gmp;
14495 cmdtable = fs->cmdtable;
14496
14497 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
14498
14499 reinitvar();
14500
14501 forkshell_child(fs);
14502}
14503
14504#undef free
14505static void
14506sticky_free(void *base)
14507{
14508 if (base >= sticky_mem_start && base < sticky_mem_end)
14509 return;
14510 free(base);
14511}
14512#endif
13338 14513
13339/*- 14514/*-
13340 * Copyright (c) 1989, 1991, 1993, 1994 14515 * Copyright (c) 1989, 1991, 1993, 1994