aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c1407
1 files changed, 1344 insertions, 63 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 1deae7c2f..18e53a0da 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -15,6 +15,21 @@
15 * 15 *
16 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
17 */ 17 */
18
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
18//config:config ASH 33//config:config ASH
19//config: bool "ash (77 kb)" 34//config: bool "ash (77 kb)"
20//config: default y 35//config: default y
@@ -132,6 +147,18 @@
132//config: you to run the specified command or builtin, 147//config: you to run the specified command or builtin,
133//config: even when there is a function with the same name. 148//config: even when there is a function with the same name.
134//config: 149//config:
150//config:
151//config:config ASH_NOCONSOLE
152//config: bool "'noconsole' option"
153//config: default y
154//config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32
155//config: help
156//config: Enable support for the 'noconsole' option, which attempts to
157//config: hide the console normally associated with a command line
158//config: application. This may be useful when running a shell script
159//config: from a GUI application. Disable this if your platform doesn't
160//config: support the required APIs.
161//config:
135//config:endif # ash options 162//config:endif # ash options
136 163
137//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) 164//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
@@ -240,10 +267,58 @@ typedef long arith_t;
240# define PIPE_BUF 4096 /* amount of buffering in a pipe */ 267# define PIPE_BUF 4096 /* amount of buffering in a pipe */
241#endif 268#endif
242 269
270#if !ENABLE_PLATFORM_MINGW32
271# define is_absolute_path(path) ((path)[0] == '/')
272#endif
273
243#if !BB_MMU 274#if !BB_MMU
244# error "Do not even bother, ash will not run on NOMMU machine" 275# error "Do not even bother, ash will not run on NOMMU machine"
245#endif 276#endif
246 277
278#if ENABLE_PLATFORM_MINGW32
279union node;
280struct strlist;
281struct job;
282
283struct forkshell {
284 /* filled by forkshell_copy() */
285 struct globals_var *gvp;
286 struct globals_misc *gmp;
287 struct tblentry **cmdtable;
288 /* struct alias **atab; */
289 /* struct parsefile *g_parsefile; */
290 HANDLE hMapFile;
291 void *old_base;
292 int nodeptr_offset;
293 int size;
294
295 /* type of forkshell */
296 int fpid;
297
298 /* optional data, used by forkshell_child */
299 int flags;
300 int fd[10];
301 union node *n;
302 char **argv;
303 char *string;
304 struct strlist *strlist;
305};
306
307enum {
308 FS_OPENHERE,
309 FS_EVALBACKCMD,
310 FS_EVALSUBSHELL,
311 FS_EVALPIPE,
312 FS_SHELLEXEC
313};
314
315static struct forkshell* forkshell_prepare(struct forkshell *fs);
316static void forkshell_init(const char *idstr);
317static void forkshell_child(struct forkshell *fs);
318static void sticky_free(void *p);
319#define free(p) sticky_free(p)
320static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode);
321#endif
247 322
248/* ============ Hash table sizes. Configurable. */ 323/* ============ Hash table sizes. Configurable. */
249 324
@@ -276,6 +351,12 @@ static const char *const optletters_optnames[] = {
276 ,"\0" "nolog" 351 ,"\0" "nolog"
277 ,"\0" "debug" 352 ,"\0" "debug"
278#endif 353#endif
354#if ENABLE_PLATFORM_MINGW32
355 ,"X" "winxp"
356#endif
357#if ENABLE_ASH_NOCONSOLE
358 ,"\0" "noconsole"
359#endif
279}; 360};
280 361
281#define optletters(n) optletters_optnames[n][0] 362#define optletters(n) optletters_optnames[n][0]
@@ -354,6 +435,12 @@ struct globals_misc {
354# define nolog optlist[14 + BASH_PIPEFAIL] 435# define nolog optlist[14 + BASH_PIPEFAIL]
355# define debug optlist[15 + BASH_PIPEFAIL] 436# define debug optlist[15 + BASH_PIPEFAIL]
356#endif 437#endif
438#if ENABLE_PLATFORM_MINGW32
439# define winxp optlist[14 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
440#endif
441#if ENABLE_ASH_NOCONSOLE
442# define noconsole optlist[15 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
443#endif
357 444
358 /* trap handler commands */ 445 /* trap handler commands */
359 /* 446 /*
@@ -2434,10 +2521,22 @@ path_advance(const char **path, const char *name)
2434 if (*path == NULL) 2521 if (*path == NULL)
2435 return NULL; 2522 return NULL;
2436 start = *path; 2523 start = *path;
2524#if ENABLE_PLATFORM_MINGW32
2525 p = next_path_sep(start);
2526 q = strchr(start, '%');
2527 if ((p && q && q < p) || (!p && q))
2528 p = q;
2529 if (!p)
2530 for (p = start; *p; p++)
2531 continue;
2532#else
2437 for (p = start; *p && *p != ':' && *p != '%'; p++) 2533 for (p = start; *p && *p != ':' && *p != '%'; p++)
2438 continue; 2534 continue;
2535#endif
2439 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2536 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2440 while (stackblocksize() < len) 2537
2538 /* preserve space for .exe too */
2539 while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len))
2441 growstackblock(); 2540 growstackblock();
2442 q = stackblock(); 2541 q = stackblock();
2443 if (p != start) { 2542 if (p != start) {
@@ -2448,10 +2547,19 @@ path_advance(const char **path, const char *name)
2448 pathopt = NULL; 2547 pathopt = NULL;
2449 if (*p == '%') { 2548 if (*p == '%') {
2450 pathopt = ++p; 2549 pathopt = ++p;
2550#if ENABLE_PLATFORM_MINGW32
2551 p = next_path_sep(start);
2552
2553 /* *p != ':' and '*' would suffice */
2554 if (!p)
2555 p = pathopt - 1;
2556#else
2451 while (*p && *p != ':') 2557 while (*p && *p != ':')
2452 p++; 2558 p++;
2559#endif
2453 } 2560 }
2454 if (*p == ':') 2561 if (*p == ':' ||
2562 (ENABLE_PLATFORM_MINGW32 && *p == ';'))
2455 *path = p + 1; 2563 *path = p + 1;
2456 else 2564 else
2457 *path = NULL; 2565 *path = NULL;
@@ -2560,6 +2668,106 @@ cdopt(void)
2560static const char * 2668static const char *
2561updatepwd(const char *dir) 2669updatepwd(const char *dir)
2562{ 2670{
2671#if ENABLE_PLATFORM_MINGW32
2672#define is_path_sep(x) ((x) == '/' || (x) == '\\')
2673#define is_unc_path(x) (is_path_sep(x[0]) && is_path_sep(x[1]))
2674 /*
2675 * Due to Windows drive notion, getting pwd is a completely
2676 * different thing. Handle it in a separate routine
2677 */
2678
2679 char *new;
2680 char *p;
2681 char *cdcomppath;
2682 const char *lim;
2683 /*
2684 * There are five cases that make some kind of sense
2685 * absdrive + abspath: c:/path
2686 * absdrive + !abspath: c:path
2687 * !absdrive + abspath: /path
2688 * !absdrive + uncpath: //host/share
2689 * !absdrive + !abspath: path
2690 *
2691 * Damn DOS!
2692 * c:path behaviour is "undefined"
2693 * To properly handle this case, I have to keep track of cwd
2694 * of every drive, which is too painful to do.
2695 * So when c:path is given, I assume it's c:${curdir}path
2696 * with ${curdir} comes from the current drive
2697 */
2698 int absdrive = *dir && dir[1] == ':';
2699 int abspath = absdrive ? is_path_sep(dir[2]) : is_path_sep(*dir);
2700
2701 cdcomppath = sstrdup(dir);
2702 STARTSTACKSTR(new);
2703 if (!absdrive && curdir == nullstr)
2704 return 0;
2705 if (!abspath) {
2706 if (curdir == nullstr)
2707 return 0;
2708 new = stack_putstr(curdir, new);
2709 }
2710 new = makestrspace(strlen(dir) + 2, new);
2711
2712 if ( is_unc_path(dir) || (!absdrive && !abspath && is_unc_path(curdir)) ) {
2713 lim = (char *)stackblock() + 1;
2714 }
2715 else {
2716 char *drive = stackblock();
2717 if (absdrive) {
2718 *drive = *dir;
2719 cdcomppath += 2;
2720 dir += 2;
2721 } else {
2722 *drive = *curdir;
2723 }
2724 drive[1] = ':'; /* in case of absolute drive+path */
2725
2726 if (abspath)
2727 new = drive + 2;
2728 lim = drive + 3;
2729 }
2730
2731 if (!abspath) {
2732 if (!is_path_sep(new[-1]))
2733 USTPUTC('/', new);
2734 if (new > lim && is_path_sep(*lim))
2735 lim++;
2736 } else {
2737 USTPUTC('/', new);
2738 cdcomppath ++;
2739 if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) {
2740 USTPUTC('/', new);
2741 cdcomppath++;
2742 lim++;
2743 }
2744 }
2745 p = strtok(cdcomppath, "/\\");
2746 while (p) {
2747 switch (*p) {
2748 case '.':
2749 if (p[1] == '.' && p[2] == '\0') {
2750 while (new > lim) {
2751 STUNPUTC(new);
2752 if (is_path_sep(new[-1]))
2753 break;
2754 }
2755 break;
2756 }
2757 if (p[1] == '\0')
2758 break;
2759 /* fall through */
2760 default:
2761 new = stack_putstr(p, new);
2762 USTPUTC('/', new);
2763 }
2764 p = strtok(0, "/\\");
2765 }
2766 if (new > lim)
2767 STUNPUTC(new);
2768 *new = 0;
2769 return stackblock();
2770#else
2563 char *new; 2771 char *new;
2564 char *p; 2772 char *p;
2565 char *cdcomppath; 2773 char *cdcomppath;
@@ -2613,6 +2821,7 @@ updatepwd(const char *dir)
2613 STUNPUTC(new); 2821 STUNPUTC(new);
2614 *new = 0; 2822 *new = 0;
2615 return stackblock(); 2823 return stackblock();
2824#endif
2616} 2825}
2617 2826
2618/* 2827/*
@@ -2707,7 +2916,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2707 } 2916 }
2708 if (!dest) 2917 if (!dest)
2709 dest = nullstr; 2918 dest = nullstr;
2710 if (*dest == '/') 2919 if (is_absolute_path(dest))
2711 goto step6; 2920 goto step6;
2712 if (*dest == '.') { 2921 if (*dest == '.') {
2713 c = dest[1]; 2922 c = dest[1];
@@ -3409,6 +3618,9 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3409 */ 3618 */
3410struct procstat { 3619struct procstat {
3411 pid_t ps_pid; /* process id */ 3620 pid_t ps_pid; /* process id */
3621#if ENABLE_PLATFORM_MINGW32
3622 HANDLE ps_proc;
3623#endif
3412 int ps_status; /* last process status from wait() */ 3624 int ps_status; /* last process status from wait() */
3413 char *ps_cmd; /* text of command being run */ 3625 char *ps_cmd; /* text of command being run */
3414}; 3626};
@@ -3437,7 +3649,9 @@ struct job {
3437}; 3649};
3438 3650
3439static struct job *makejob(/*union node *,*/ int); 3651static struct job *makejob(/*union node *,*/ int);
3652#if !ENABLE_PLATFORM_MINGW32
3440static int forkshell(struct job *, union node *, int); 3653static int forkshell(struct job *, union node *, int);
3654#endif
3441static int waitforjob(struct job *); 3655static int waitforjob(struct job *);
3442 3656
3443#if !JOBS 3657#if !JOBS
@@ -3462,6 +3676,7 @@ ignoresig(int signo)
3462 sigmode[signo - 1] = S_HARD_IGN; 3676 sigmode[signo - 1] = S_HARD_IGN;
3463} 3677}
3464 3678
3679#if !ENABLE_PLATFORM_MINGW32
3465/* 3680/*
3466 * Only one usage site - in setsignal() 3681 * Only one usage site - in setsignal()
3467 */ 3682 */
@@ -3586,6 +3801,9 @@ setsignal(int signo)
3586 3801
3587 *t = new_act; 3802 *t = new_act;
3588} 3803}
3804#else
3805#define setsignal(s)
3806#endif
3589 3807
3590/* mode flags for set_curjob */ 3808/* mode flags for set_curjob */
3591#define CUR_DELETE 2 3809#define CUR_DELETE 2
@@ -4083,6 +4301,98 @@ sprint_status48(char *s, int status, int sigonly)
4083 return col; 4301 return col;
4084} 4302}
4085 4303
4304#if ENABLE_PLATFORM_MINGW32
4305
4306HANDLE hSIGINT; /* Ctrl-C is pressed */
4307
4308static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
4309{
4310 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
4311 SetEvent(hSIGINT);
4312 pending_int = 1;
4313 return TRUE;
4314 }
4315 return FALSE;
4316}
4317
4318/*
4319 * Windows does not know about parent-child relationship
4320 * They don't support waitpid(-1)
4321 */
4322static pid_t
4323waitpid_child(int *status, int wait_flags)
4324{
4325 pid_t *pidlist;
4326 HANDLE *proclist;
4327 int pid_nr = 0;
4328 pid_t pid;
4329 DWORD win_status, idx;
4330 struct job *jb;
4331
4332 for (jb = curjob; jb; jb = jb->prev_job) {
4333 if (jb->state != JOBDONE)
4334 pid_nr += jb->nprocs;
4335 }
4336 if ( pid_nr++ == 0 )
4337 return -1;
4338
4339 pidlist = ckmalloc(sizeof(*pidlist)*pid_nr);
4340 proclist = ckmalloc(sizeof(*proclist)*pid_nr);
4341
4342 pidlist[0] = -1;
4343 proclist[0] = hSIGINT;
4344 pid_nr = 1;
4345 for (jb = curjob; jb; jb = jb->prev_job) {
4346 struct procstat *ps, *psend;
4347 if (jb->state == JOBDONE)
4348 continue;
4349 ps = jb->ps;
4350 psend = ps + jb->nprocs;
4351 while (ps < psend) {
4352 if (ps->ps_pid != -1 && ps->ps_proc != NULL) {
4353 pidlist[pid_nr] = ps->ps_pid;
4354 proclist[pid_nr++] = ps->ps_proc;
4355 }
4356 ps++;
4357 }
4358 }
4359
4360 if (pid_nr == 1) {
4361 free(pidlist);
4362 free(proclist);
4363 return -1;
4364 }
4365
4366 idx = WaitForMultipleObjects(pid_nr, proclist, FALSE,
4367 wait_flags|WNOHANG ? 1 : INFINITE);
4368 if (idx >= pid_nr) {
4369 free(pidlist);
4370 free(proclist);
4371 return -1;
4372 }
4373 if (!idx) { /* hSIGINT */
4374 int i;
4375 ResetEvent(hSIGINT);
4376 for (i = 1; i < pid_nr; i++)
4377 TerminateProcess(proclist[i], 1);
4378 pid = pidlist[1];
4379 free(pidlist);
4380 free(proclist);
4381 *status = 260; /* terminated by a signal */
4382 return pid;
4383 }
4384 GetExitCodeProcess(proclist[idx], &win_status);
4385 pid = pidlist[idx];
4386 free(pidlist);
4387 free(proclist);
4388 *status = (int)win_status;
4389 return pid;
4390}
4391#define waitpid(p, s, f) waitpid_child(s, f)
4392#define wait_block_or_sig(s) waitpid_child(s, 0)
4393
4394#else
4395
4086static int 4396static int
4087wait_block_or_sig(int *status) 4397wait_block_or_sig(int *status)
4088{ 4398{
@@ -4115,6 +4425,7 @@ wait_block_or_sig(int *status)
4115 4425
4116 return pid; 4426 return pid;
4117} 4427}
4428#endif
4118 4429
4119#define DOWAIT_NONBLOCK 0 4430#define DOWAIT_NONBLOCK 0
4120#define DOWAIT_BLOCK 1 4431#define DOWAIT_BLOCK 1
@@ -4183,6 +4494,11 @@ dowait(int block, struct job *job)
4183 jobno(jp), pid, ps->ps_status, status)); 4494 jobno(jp), pid, ps->ps_status, status));
4184 ps->ps_status = status; 4495 ps->ps_status = status;
4185 thisjob = jp; 4496 thisjob = jp;
4497#if ENABLE_PLATFORM_MINGW32
4498 ps->ps_pid = -1;
4499 CloseHandle(ps->ps_proc);
4500 ps->ps_proc = NULL;
4501#endif
4186 } 4502 }
4187 if (ps->ps_status == -1) 4503 if (ps->ps_status == -1)
4188 jobstate = JOBRUNNING; 4504 jobstate = JOBRUNNING;
@@ -4865,6 +5181,7 @@ commandtext(union node *n)
4865 * 5181 *
4866 * Called with interrupts off. 5182 * Called with interrupts off.
4867 */ 5183 */
5184#if !ENABLE_PLATFORM_MINGW32
4868/* 5185/*
4869 * Clear traps on a fork. 5186 * Clear traps on a fork.
4870 */ 5187 */
@@ -5014,16 +5331,24 @@ forkchild(struct job *jp, union node *n, int mode)
5014 freejob(jp); 5331 freejob(jp);
5015 jobless = 0; 5332 jobless = 0;
5016} 5333}
5334#endif
5017 5335
5018/* Called after fork(), in parent */ 5336/* Called after fork(), in parent */
5019#if !JOBS 5337#if !JOBS
5020#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) 5338#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5021#endif 5339#endif
5022static void 5340static void
5341#if !ENABLE_PLATFORM_MINGW32
5023forkparent(struct job *jp, union node *n, int mode, pid_t pid) 5342forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5343#else
5344forkparent(struct job *jp, union node *n, int mode, HANDLE proc)
5345#endif
5024{ 5346{
5347#if ENABLE_PLATFORM_MINGW32
5348 pid_t pid = GetProcessId(proc);
5349#endif
5025 TRACE(("In parent shell: child = %d\n", pid)); 5350 TRACE(("In parent shell: child = %d\n", pid));
5026 if (!jp) { 5351 if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */
5027 /* jp is NULL when called by openhere() for heredoc support */ 5352 /* jp is NULL when called by openhere() for heredoc support */
5028 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) 5353 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5029 continue; 5354 continue;
@@ -5049,6 +5374,9 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5049 if (jp) { 5374 if (jp) {
5050 struct procstat *ps = &jp->ps[jp->nprocs++]; 5375 struct procstat *ps = &jp->ps[jp->nprocs++];
5051 ps->ps_pid = pid; 5376 ps->ps_pid = pid;
5377#if ENABLE_PLATFORM_MINGW32
5378 ps->ps_proc = proc;
5379#endif
5052 ps->ps_status = -1; 5380 ps->ps_status = -1;
5053 ps->ps_cmd = nullstr; 5381 ps->ps_cmd = nullstr;
5054#if JOBS 5382#if JOBS
@@ -5058,6 +5386,7 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5058 } 5386 }
5059} 5387}
5060 5388
5389#if !ENABLE_PLATFORM_MINGW32
5061/* jp and n are NULL when called by openhere() for heredoc support */ 5390/* jp and n are NULL when called by openhere() for heredoc support */
5062static int 5391static int
5063forkshell(struct job *jp, union node *n, int mode) 5392forkshell(struct job *jp, union node *n, int mode)
@@ -5080,6 +5409,7 @@ forkshell(struct job *jp, union node *n, int mode)
5080 } 5409 }
5081 return pid; 5410 return pid;
5082} 5411}
5412#endif
5083 5413
5084/* 5414/*
5085 * Wait for job to finish. 5415 * Wait for job to finish.
@@ -5211,6 +5541,7 @@ openhere(union node *redir)
5211{ 5541{
5212 int pip[2]; 5542 int pip[2];
5213 size_t len = 0; 5543 size_t len = 0;
5544 IF_PLATFORM_MINGW32(struct forkshell fs);
5214 5545
5215 if (pipe(pip) < 0) 5546 if (pipe(pip) < 0)
5216 ash_msg_and_raise_error("pipe call failed"); 5547 ash_msg_and_raise_error("pipe call failed");
@@ -5221,6 +5552,15 @@ openhere(union node *redir)
5221 goto out; 5552 goto out;
5222 } 5553 }
5223 } 5554 }
5555#if ENABLE_PLATFORM_MINGW32
5556 memset(&fs, 0, sizeof(fs));
5557 fs.fpid = FS_OPENHERE;
5558 fs.n = redir;
5559 fs.fd[0] = pip[0];
5560 fs.fd[1] = pip[1];
5561 if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0)
5562 ash_msg_and_raise_error("unable to spawn shell");
5563#else
5224 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 5564 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5225 /* child */ 5565 /* child */
5226 close(pip[0]); 5566 close(pip[0]);
@@ -5235,6 +5575,7 @@ openhere(union node *redir)
5235 expandhere(redir->nhere.doc, pip[1]); 5575 expandhere(redir->nhere.doc, pip[1]);
5236 _exit(EXIT_SUCCESS); 5576 _exit(EXIT_SUCCESS);
5237 } 5577 }
5578#endif
5238 out: 5579 out:
5239 close(pip[1]); 5580 close(pip[1]);
5240 return pip[0]; 5581 return pip[0];
@@ -5261,6 +5602,31 @@ openredirect(union node *redir)
5261 * allocated space. Do it only when we know it is safe. 5602 * allocated space. Do it only when we know it is safe.
5262 */ 5603 */
5263 fname = redir->nfile.expfname; 5604 fname = redir->nfile.expfname;
5605#if ENABLE_PLATFORM_MINGW32
5606 /* Support for /dev/null */
5607 switch (redir->nfile.type) {
5608 case NFROM:
5609 if (!strcmp(fname, "/dev/null"))
5610 return open("nul",O_RDWR);
5611 if (!strncmp(fname, "/dev/", 5)) {
5612 ash_msg("Unhandled device %s\n", fname);
5613 return -1;
5614 }
5615 break;
5616
5617 case NFROMTO:
5618 case NTO:
5619 case NCLOBBER:
5620 case NAPPEND:
5621 if (!strcmp(fname, "/dev/null"))
5622 return open("nul",O_RDWR);
5623 if (!strncmp(fname, "/dev/", 5)) {
5624 ash_msg("Unhandled device %s\n", fname);
5625 return -1;
5626 }
5627 break;
5628 }
5629#endif
5264 5630
5265 switch (redir->nfile.type) { 5631 switch (redir->nfile.type) {
5266 default: 5632 default:
@@ -5312,6 +5678,9 @@ openredirect(union node *redir)
5312 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); 5678 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5313 if (f < 0) 5679 if (f < 0)
5314 goto ecreate; 5680 goto ecreate;
5681#if ENABLE_PLATFORM_MINGW32
5682 lseek(f, 0, SEEK_END);
5683#endif
5315 break; 5684 break;
5316 } 5685 }
5317 5686
@@ -6240,6 +6609,7 @@ struct backcmd { /* result of evalbackcmd */
6240 int fd; /* file descriptor to read from */ 6609 int fd; /* file descriptor to read from */
6241 int nleft; /* number of chars in buffer */ 6610 int nleft; /* number of chars in buffer */
6242 char *buf; /* buffer */ 6611 char *buf; /* buffer */
6612 IF_PLATFORM_MINGW32(struct forkshell fs);
6243 struct job *jp; /* job structure for command */ 6613 struct job *jp; /* job structure for command */
6244}; 6614};
6245 6615
@@ -6271,6 +6641,7 @@ evalbackcmd(union node *n, struct backcmd *result)
6271 result->fd = -1; 6641 result->fd = -1;
6272 result->buf = NULL; 6642 result->buf = NULL;
6273 result->nleft = 0; 6643 result->nleft = 0;
6644 IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs)));
6274 result->jp = NULL; 6645 result->jp = NULL;
6275 if (n == NULL) { 6646 if (n == NULL) {
6276 goto out; 6647 goto out;
@@ -6279,6 +6650,14 @@ evalbackcmd(union node *n, struct backcmd *result)
6279 if (pipe(pip) < 0) 6650 if (pipe(pip) < 0)
6280 ash_msg_and_raise_error("pipe call failed"); 6651 ash_msg_and_raise_error("pipe call failed");
6281 jp = makejob(/*n,*/ 1); 6652 jp = makejob(/*n,*/ 1);
6653#if ENABLE_PLATFORM_MINGW32
6654 result->fs.fpid = FS_EVALBACKCMD;
6655 result->fs.n = n;
6656 result->fs.fd[0] = pip[0];
6657 result->fs.fd[1] = pip[1];
6658 if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0)
6659 ash_msg_and_raise_error("unable to spawn shell");
6660#else
6282 if (forkshell(jp, n, FORK_NOJOB) == 0) { 6661 if (forkshell(jp, n, FORK_NOJOB) == 0) {
6283 /* child */ 6662 /* child */
6284 FORCE_INT_ON; 6663 FORCE_INT_ON;
@@ -6301,6 +6680,7 @@ evalbackcmd(union node *n, struct backcmd *result)
6301 evaltreenr(n, EV_EXIT); 6680 evaltreenr(n, EV_EXIT);
6302 /* NOTREACHED */ 6681 /* NOTREACHED */
6303 } 6682 }
6683#endif
6304 /* parent */ 6684 /* parent */
6305 close(pip[1]); 6685 close(pip[1]);
6306 result->fd = pip[0]; 6686 result->fd = pip[0];
@@ -6357,7 +6737,8 @@ expbackq(union node *cmd, int flag)
6357 6737
6358 /* Eat all trailing newlines */ 6738 /* Eat all trailing newlines */
6359 dest = expdest; 6739 dest = expdest;
6360 for (; dest > (char *)stackblock() && dest[-1] == '\n';) 6740 for (; dest > (char *)stackblock() && (dest[-1] == '\n' ||
6741 (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));)
6361 STUNPUTC(dest); 6742 STUNPUTC(dest);
6362 expdest = dest; 6743 expdest = dest;
6363 6744
@@ -7856,7 +8237,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
7856 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ 8237 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
7857 8238
7858 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); 8239 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7859 if (strchr(prog, '/') != NULL 8240 if ((strchr(prog, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(prog, '\\')))
7860#if ENABLE_FEATURE_SH_STANDALONE 8241#if ENABLE_FEATURE_SH_STANDALONE
7861 || (applet_no = find_applet_by_name(prog)) >= 0 8242 || (applet_no = find_applet_by_name(prog)) >= 0
7862#endif 8243#endif
@@ -8440,10 +8821,14 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8440#endif 8821#endif
8441 8822
8442 8823
8443/*static int funcblocksize; // size of structures in function */ 8824static int funcblocksize; /* size of structures in function */
8444/*static int funcstringsize; // size of strings in node */ 8825static int funcstringsize; /* size of strings in node */
8445static void *funcblock; /* block to allocate function from */ 8826static void *funcblock; /* block to allocate function from */
8446static char *funcstring_end; /* end of block to allocate strings from */ 8827static char *funcstring; /* block to allocate strings from */
8828#if ENABLE_PLATFORM_MINGW32
8829static int nodeptrsize;
8830static char **nodeptr;
8831#endif
8447 8832
8448static const uint8_t nodesize[N_NUMBER] ALIGN1 = { 8833static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8449 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), 8834 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
@@ -8477,72 +8862,81 @@ static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8477 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)), 8862 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
8478}; 8863};
8479 8864
8480static int calcsize(int funcblocksize, union node *n); 8865static void calcsize(union node *n);
8481 8866
8482static int 8867static void
8483sizenodelist(int funcblocksize, struct nodelist *lp) 8868sizenodelist(struct nodelist *lp)
8484{ 8869{
8485 while (lp) { 8870 while (lp) {
8486 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 8871 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8487 funcblocksize = calcsize(funcblocksize, lp->n); 8872 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8873 calcsize(lp->n);
8488 lp = lp->next; 8874 lp = lp->next;
8489 } 8875 }
8490 return funcblocksize;
8491} 8876}
8492 8877
8493static int 8878static void
8494calcsize(int funcblocksize, union node *n) 8879calcsize(union node *n)
8495{ 8880{
8496 if (n == NULL) 8881 if (n == NULL)
8497 return funcblocksize; 8882 return;
8498 funcblocksize += nodesize[n->type]; 8883 funcblocksize += nodesize[n->type];
8499 switch (n->type) { 8884 switch (n->type) {
8500 case NCMD: 8885 case NCMD:
8501 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect); 8886 calcsize(n->ncmd.redirect);
8502 funcblocksize = calcsize(funcblocksize, n->ncmd.args); 8887 calcsize(n->ncmd.args);
8503 funcblocksize = calcsize(funcblocksize, n->ncmd.assign); 8888 calcsize(n->ncmd.assign);
8889 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8504 break; 8890 break;
8505 case NPIPE: 8891 case NPIPE:
8506 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist); 8892 sizenodelist(n->npipe.cmdlist);
8893 IF_PLATFORM_MINGW32(nodeptrsize++);
8507 break; 8894 break;
8508 case NREDIR: 8895 case NREDIR:
8509 case NBACKGND: 8896 case NBACKGND:
8510 case NSUBSHELL: 8897 case NSUBSHELL:
8511 funcblocksize = calcsize(funcblocksize, n->nredir.redirect); 8898 calcsize(n->nredir.redirect);
8512 funcblocksize = calcsize(funcblocksize, n->nredir.n); 8899 calcsize(n->nredir.n);
8900 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8513 break; 8901 break;
8514 case NAND: 8902 case NAND:
8515 case NOR: 8903 case NOR:
8516 case NSEMI: 8904 case NSEMI:
8517 case NWHILE: 8905 case NWHILE:
8518 case NUNTIL: 8906 case NUNTIL:
8519 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2); 8907 calcsize(n->nbinary.ch2);
8520 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1); 8908 calcsize(n->nbinary.ch1);
8909 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8521 break; 8910 break;
8522 case NIF: 8911 case NIF:
8523 funcblocksize = calcsize(funcblocksize, n->nif.elsepart); 8912 calcsize(n->nif.elsepart);
8524 funcblocksize = calcsize(funcblocksize, n->nif.ifpart); 8913 calcsize(n->nif.ifpart);
8525 funcblocksize = calcsize(funcblocksize, n->nif.test); 8914 calcsize(n->nif.test);
8915 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8526 break; 8916 break;
8527 case NFOR: 8917 case NFOR:
8528 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */ 8918 funcstringsize += strlen(n->nfor.var) + 1;
8529 funcblocksize = calcsize(funcblocksize, n->nfor.body); 8919 calcsize(n->nfor.body);
8530 funcblocksize = calcsize(funcblocksize, n->nfor.args); 8920 calcsize(n->nfor.args);
8921 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8531 break; 8922 break;
8532 case NCASE: 8923 case NCASE:
8533 funcblocksize = calcsize(funcblocksize, n->ncase.cases); 8924 calcsize(n->ncase.cases);
8534 funcblocksize = calcsize(funcblocksize, n->ncase.expr); 8925 calcsize(n->ncase.expr);
8926 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8535 break; 8927 break;
8536 case NCLIST: 8928 case NCLIST:
8537 funcblocksize = calcsize(funcblocksize, n->nclist.body); 8929 calcsize(n->nclist.body);
8538 funcblocksize = calcsize(funcblocksize, n->nclist.pattern); 8930 calcsize(n->nclist.pattern);
8539 funcblocksize = calcsize(funcblocksize, n->nclist.next); 8931 calcsize(n->nclist.next);
8932 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8540 break; 8933 break;
8541 case NDEFUN: 8934 case NDEFUN:
8542 case NARG: 8935 case NARG:
8543 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote); 8936 sizenodelist(n->narg.backquote);
8544 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */ 8937 funcstringsize += strlen(n->narg.text) + 1;
8545 funcblocksize = calcsize(funcblocksize, n->narg.next); 8938 calcsize(n->narg.next);
8939 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8546 break; 8940 break;
8547 case NTO: 8941 case NTO:
8548#if BASH_REDIR_OUTPUT 8942#if BASH_REDIR_OUTPUT
@@ -8552,35 +8946,55 @@ calcsize(int funcblocksize, union node *n)
8552 case NFROM: 8946 case NFROM:
8553 case NFROMTO: 8947 case NFROMTO:
8554 case NAPPEND: 8948 case NAPPEND:
8555 funcblocksize = calcsize(funcblocksize, n->nfile.fname); 8949 calcsize(n->nfile.fname);
8556 funcblocksize = calcsize(funcblocksize, n->nfile.next); 8950 calcsize(n->nfile.next);
8951 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8557 break; 8952 break;
8558 case NTOFD: 8953 case NTOFD:
8559 case NFROMFD: 8954 case NFROMFD:
8560 funcblocksize = calcsize(funcblocksize, n->ndup.vname); 8955 calcsize(n->ndup.vname);
8561 funcblocksize = calcsize(funcblocksize, n->ndup.next); 8956 calcsize(n->ndup.next);
8957 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8562 break; 8958 break;
8563 case NHERE: 8959 case NHERE:
8564 case NXHERE: 8960 case NXHERE:
8565 funcblocksize = calcsize(funcblocksize, n->nhere.doc); 8961 calcsize(n->nhere.doc);
8566 funcblocksize = calcsize(funcblocksize, n->nhere.next); 8962 calcsize(n->nhere.next);
8963 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8567 break; 8964 break;
8568 case NNOT: 8965 case NNOT:
8569 funcblocksize = calcsize(funcblocksize, n->nnot.com); 8966 calcsize(n->nnot.com);
8967 IF_PLATFORM_MINGW32(nodeptrsize++);
8570 break; 8968 break;
8571 }; 8969 };
8572 return funcblocksize;
8573} 8970}
8574 8971
8575static char * 8972static char *
8576nodeckstrdup(char *s) 8973nodeckstrdup(const char *s)
8577{ 8974{
8578 funcstring_end -= SHELL_ALIGN(strlen(s) + 1); 8975 char *rtn = funcstring;
8579 return strcpy(funcstring_end, s); 8976
8977 if (!s)
8978 return NULL;
8979 strcpy(funcstring, s);
8980 funcstring += strlen(s) + 1;
8981 return rtn;
8580} 8982}
8581 8983
8582static union node *copynode(union node *); 8984static union node *copynode(union node *);
8583 8985
8986#if ENABLE_PLATFORM_MINGW32
8987# define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (char *)&(dst);}
8988# define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);}}
8989# define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);}}
8990# define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);*nodeptr++ = (char *)&(dst4);}}
8991#else
8992# define SAVE_PTR(dst)
8993# define SAVE_PTR2(dst,dst2)
8994# define SAVE_PTR3(dst,dst2,dst3)
8995# define SAVE_PTR4(dst,dst2,dst3,dst4)
8996#endif
8997
8584static struct nodelist * 8998static struct nodelist *
8585copynodelist(struct nodelist *lp) 8999copynodelist(struct nodelist *lp)
8586{ 9000{
@@ -8592,6 +9006,7 @@ copynodelist(struct nodelist *lp)
8592 *lpp = funcblock; 9006 *lpp = funcblock;
8593 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); 9007 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8594 (*lpp)->n = copynode(lp->n); 9008 (*lpp)->n = copynode(lp->n);
9009 SAVE_PTR2((*lpp)->n, (*lpp)->next);
8595 lp = lp->next; 9010 lp = lp->next;
8596 lpp = &(*lpp)->next; 9011 lpp = &(*lpp)->next;
8597 } 9012 }
@@ -8614,16 +9029,19 @@ copynode(union node *n)
8614 new->ncmd.redirect = copynode(n->ncmd.redirect); 9029 new->ncmd.redirect = copynode(n->ncmd.redirect);
8615 new->ncmd.args = copynode(n->ncmd.args); 9030 new->ncmd.args = copynode(n->ncmd.args);
8616 new->ncmd.assign = copynode(n->ncmd.assign); 9031 new->ncmd.assign = copynode(n->ncmd.assign);
9032 SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign);
8617 break; 9033 break;
8618 case NPIPE: 9034 case NPIPE:
8619 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 9035 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8620 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; 9036 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
9037 SAVE_PTR(new->npipe.cmdlist);
8621 break; 9038 break;
8622 case NREDIR: 9039 case NREDIR:
8623 case NBACKGND: 9040 case NBACKGND:
8624 case NSUBSHELL: 9041 case NSUBSHELL:
8625 new->nredir.redirect = copynode(n->nredir.redirect); 9042 new->nredir.redirect = copynode(n->nredir.redirect);
8626 new->nredir.n = copynode(n->nredir.n); 9043 new->nredir.n = copynode(n->nredir.n);
9044 SAVE_PTR2(new->nredir.redirect,new->nredir.n);
8627 break; 9045 break;
8628 case NAND: 9046 case NAND:
8629 case NOR: 9047 case NOR:
@@ -8632,31 +9050,37 @@ copynode(union node *n)
8632 case NUNTIL: 9050 case NUNTIL:
8633 new->nbinary.ch2 = copynode(n->nbinary.ch2); 9051 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8634 new->nbinary.ch1 = copynode(n->nbinary.ch1); 9052 new->nbinary.ch1 = copynode(n->nbinary.ch1);
9053 SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2);
8635 break; 9054 break;
8636 case NIF: 9055 case NIF:
8637 new->nif.elsepart = copynode(n->nif.elsepart); 9056 new->nif.elsepart = copynode(n->nif.elsepart);
8638 new->nif.ifpart = copynode(n->nif.ifpart); 9057 new->nif.ifpart = copynode(n->nif.ifpart);
8639 new->nif.test = copynode(n->nif.test); 9058 new->nif.test = copynode(n->nif.test);
9059 SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test);
8640 break; 9060 break;
8641 case NFOR: 9061 case NFOR:
8642 new->nfor.var = nodeckstrdup(n->nfor.var); 9062 new->nfor.var = nodeckstrdup(n->nfor.var);
8643 new->nfor.body = copynode(n->nfor.body); 9063 new->nfor.body = copynode(n->nfor.body);
8644 new->nfor.args = copynode(n->nfor.args); 9064 new->nfor.args = copynode(n->nfor.args);
9065 SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args);
8645 break; 9066 break;
8646 case NCASE: 9067 case NCASE:
8647 new->ncase.cases = copynode(n->ncase.cases); 9068 new->ncase.cases = copynode(n->ncase.cases);
8648 new->ncase.expr = copynode(n->ncase.expr); 9069 new->ncase.expr = copynode(n->ncase.expr);
9070 SAVE_PTR2(new->ncase.cases,new->ncase.expr);
8649 break; 9071 break;
8650 case NCLIST: 9072 case NCLIST:
8651 new->nclist.body = copynode(n->nclist.body); 9073 new->nclist.body = copynode(n->nclist.body);
8652 new->nclist.pattern = copynode(n->nclist.pattern); 9074 new->nclist.pattern = copynode(n->nclist.pattern);
8653 new->nclist.next = copynode(n->nclist.next); 9075 new->nclist.next = copynode(n->nclist.next);
9076 SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next);
8654 break; 9077 break;
8655 case NDEFUN: 9078 case NDEFUN:
8656 case NARG: 9079 case NARG:
8657 new->narg.backquote = copynodelist(n->narg.backquote); 9080 new->narg.backquote = copynodelist(n->narg.backquote);
8658 new->narg.text = nodeckstrdup(n->narg.text); 9081 new->narg.text = nodeckstrdup(n->narg.text);
8659 new->narg.next = copynode(n->narg.next); 9082 new->narg.next = copynode(n->narg.next);
9083 SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next);
8660 break; 9084 break;
8661 case NTO: 9085 case NTO:
8662#if BASH_REDIR_OUTPUT 9086#if BASH_REDIR_OUTPUT
@@ -8669,6 +9093,7 @@ copynode(union node *n)
8669 new->nfile.fname = copynode(n->nfile.fname); 9093 new->nfile.fname = copynode(n->nfile.fname);
8670 new->nfile.fd = n->nfile.fd; 9094 new->nfile.fd = n->nfile.fd;
8671 new->nfile.next = copynode(n->nfile.next); 9095 new->nfile.next = copynode(n->nfile.next);
9096 SAVE_PTR2(new->nfile.fname,new->nfile.next);
8672 break; 9097 break;
8673 case NTOFD: 9098 case NTOFD:
8674 case NFROMFD: 9099 case NFROMFD:
@@ -8676,15 +9101,18 @@ copynode(union node *n)
8676 new->ndup.dupfd = n->ndup.dupfd; 9101 new->ndup.dupfd = n->ndup.dupfd;
8677 new->ndup.fd = n->ndup.fd; 9102 new->ndup.fd = n->ndup.fd;
8678 new->ndup.next = copynode(n->ndup.next); 9103 new->ndup.next = copynode(n->ndup.next);
9104 SAVE_PTR2(new->ndup.vname,new->ndup.next);
8679 break; 9105 break;
8680 case NHERE: 9106 case NHERE:
8681 case NXHERE: 9107 case NXHERE:
8682 new->nhere.doc = copynode(n->nhere.doc); 9108 new->nhere.doc = copynode(n->nhere.doc);
8683 new->nhere.fd = n->nhere.fd; 9109 new->nhere.fd = n->nhere.fd;
8684 new->nhere.next = copynode(n->nhere.next); 9110 new->nhere.next = copynode(n->nhere.next);
9111 SAVE_PTR2(new->nhere.doc,new->nhere.next);
8685 break; 9112 break;
8686 case NNOT: 9113 case NNOT:
8687 new->nnot.com = copynode(n->nnot.com); 9114 new->nnot.com = copynode(n->nnot.com);
9115 SAVE_PTR(new->nnot.com);
8688 break; 9116 break;
8689 }; 9117 };
8690 new->type = n->type; 9118 new->type = n->type;
@@ -8700,13 +9128,16 @@ copyfunc(union node *n)
8700 struct funcnode *f; 9128 struct funcnode *f;
8701 size_t blocksize; 9129 size_t blocksize;
8702 9130
8703 /*funcstringsize = 0;*/ 9131 funcblocksize = offsetof(struct funcnode, n);
8704 blocksize = offsetof(struct funcnode, n) + calcsize(0, n); 9132 funcstringsize = 0;
8705 f = ckzalloc(blocksize /* + funcstringsize */); 9133 calcsize(n);
9134 blocksize = funcblocksize;
9135 f = ckmalloc(blocksize + funcstringsize);
8706 funcblock = (char *) f + offsetof(struct funcnode, n); 9136 funcblock = (char *) f + offsetof(struct funcnode, n);
8707 funcstring_end = (char *) f + blocksize; 9137 funcstring = (char *) f + blocksize;
9138 IF_PLATFORM_MINGW32(nodeptr = NULL);
8708 copynode(n); 9139 copynode(n);
8709 /* f->count = 0; - ckzalloc did it */ 9140 f->count = 0;
8710 return f; 9141 return f;
8711} 9142}
8712 9143
@@ -9042,6 +9473,7 @@ evalcase(union node *n, int flags)
9042static int 9473static int
9043evalsubshell(union node *n, int flags) 9474evalsubshell(union node *n, int flags)
9044{ 9475{
9476 IF_PLATFORM_MINGW32(struct forkshell fs;)
9045 struct job *jp; 9477 struct job *jp;
9046 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ 9478 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
9047 int status; 9479 int status;
@@ -9053,12 +9485,22 @@ evalsubshell(union node *n, int flags)
9053 if (backgnd == FORK_FG) 9485 if (backgnd == FORK_FG)
9054 get_tty_state(); 9486 get_tty_state();
9055 jp = makejob(/*n,*/ 1); 9487 jp = makejob(/*n,*/ 1);
9488#if ENABLE_PLATFORM_MINGW32
9489 memset(&fs, 0, sizeof(fs));
9490 fs.fpid = FS_EVALSUBSHELL;
9491 fs.n = n;
9492 fs.flags = flags;
9493 if (spawn_forkshell(jp, &fs, backgnd) < 0)
9494 ash_msg_and_raise_error("unable to spawn shell");
9495 if ( 0 ) {
9496#else
9056 if (forkshell(jp, n, backgnd) == 0) { 9497 if (forkshell(jp, n, backgnd) == 0) {
9057 /* child */ 9498 /* child */
9058 INT_ON; 9499 INT_ON;
9059 flags |= EV_EXIT; 9500 flags |= EV_EXIT;
9060 if (backgnd) 9501 if (backgnd)
9061 flags &= ~EV_TESTED; 9502 flags &= ~EV_TESTED;
9503#endif
9062 nofork: 9504 nofork:
9063 redirect(n->nredir.redirect, 0); 9505 redirect(n->nredir.redirect, 0);
9064 evaltreenr(n->nredir.n, flags); 9506 evaltreenr(n->nredir.n, flags);
@@ -9145,6 +9587,7 @@ expredir(union node *n)
9145static int 9587static int
9146evalpipe(union node *n, int flags) 9588evalpipe(union node *n, int flags)
9147{ 9589{
9590 IF_PLATFORM_MINGW32(struct forkshell fs;)
9148 struct job *jp; 9591 struct job *jp;
9149 struct nodelist *lp; 9592 struct nodelist *lp;
9150 int pipelen; 9593 int pipelen;
@@ -9171,6 +9614,17 @@ evalpipe(union node *n, int flags)
9171 ash_msg_and_raise_error("pipe call failed"); 9614 ash_msg_and_raise_error("pipe call failed");
9172 } 9615 }
9173 } 9616 }
9617#if ENABLE_PLATFORM_MINGW32
9618 memset(&fs, 0, sizeof(fs));
9619 fs.fpid = FS_EVALPIPE;
9620 fs.flags = flags;
9621 fs.n = lp->n;
9622 fs.fd[0] = pip[0];
9623 fs.fd[1] = pip[1];
9624 fs.fd[2] = prevfd;
9625 if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0)
9626 ash_msg_and_raise_error("unable to spawn shell");
9627#else
9174 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { 9628 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
9175 /* child */ 9629 /* child */
9176 INT_ON; 9630 INT_ON;
@@ -9188,6 +9642,7 @@ evalpipe(union node *n, int flags)
9188 evaltreenr(lp->n, flags); 9642 evaltreenr(lp->n, flags);
9189 /* never returns */ 9643 /* never returns */
9190 } 9644 }
9645#endif
9191 /* parent */ 9646 /* parent */
9192 if (prevfd >= 0) 9647 if (prevfd >= 0)
9193 close(prevfd); 9648 close(prevfd);
@@ -9717,6 +10172,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9717 * as POSIX mandates */ 10172 * as POSIX mandates */
9718 return back_exitstatus; 10173 return back_exitstatus;
9719} 10174}
10175
9720static int 10176static int
9721evalcommand(union node *cmd, int flags) 10177evalcommand(union node *cmd, int flags)
9722{ 10178{
@@ -9915,7 +10371,15 @@ evalcommand(union node *cmd, int flags)
9915 */ 10371 */
9916 /* find_command() encodes applet_no as (-2 - applet_no) */ 10372 /* find_command() encodes applet_no as (-2 - applet_no) */
9917 int applet_no = (- cmdentry.u.index - 2); 10373 int applet_no = (- cmdentry.u.index - 2);
9918 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { 10374 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)
10375#if ENABLE_PLATFORM_MINGW32
10376 /*
10377 * Fork long-running nofork applets (e.g. yes) in interactive
10378 * sessions. Otherwise ctrl-c won't let the user kill them.
10379 */
10380 && !(iflag && long_running_applet(applet_no))
10381#endif
10382 ) {
9919 listsetvar(varlist.list, VEXPORT|VSTACK); 10383 listsetvar(varlist.list, VEXPORT|VSTACK);
9920 /* run <applet>_main() */ 10384 /* run <applet>_main() */
9921 status = run_nofork_applet(applet_no, argv); 10385 status = run_nofork_applet(applet_no, argv);
@@ -9926,6 +10390,28 @@ evalcommand(union node *cmd, int flags)
9926 * in a script or a subshell does not need forking, 10390 * in a script or a subshell does not need forking,
9927 * we can just exec it. 10391 * we can just exec it.
9928 */ 10392 */
10393#if ENABLE_PLATFORM_MINGW32
10394 if (!(flags & EV_EXIT) || trap[0]) {
10395 /* No, forking off a child is necessary */
10396 struct forkshell fs;
10397
10398 INT_OFF;
10399 memset(&fs, 0, sizeof(fs));
10400 fs.fpid = FS_SHELLEXEC;
10401 fs.argv = argv;
10402 fs.string = (char*)path;
10403 fs.fd[0] = cmdentry.u.index;
10404 fs.strlist = varlist.list;
10405 jp = makejob(/*cmd,*/ 1);
10406 if (spawn_forkshell(jp, &fs, FORK_FG) < 0)
10407 ash_msg_and_raise_error("unable to spawn shell");
10408 status = waitforjob(jp);
10409 INT_ON;
10410 TRACE(("forked child exited with %d\n", exitstatus));
10411 break;
10412 }
10413 /* goes through to shellexec() */
10414#else
9929 if (!(flags & EV_EXIT) || may_have_traps) { 10415 if (!(flags & EV_EXIT) || may_have_traps) {
9930 /* No, forking off a child is necessary */ 10416 /* No, forking off a child is necessary */
9931 INT_OFF; 10417 INT_OFF;
@@ -9942,6 +10428,7 @@ evalcommand(union node *cmd, int flags)
9942 FORCE_INT_ON; 10428 FORCE_INT_ON;
9943 /* fall through to exec'ing external program */ 10429 /* fall through to exec'ing external program */
9944 } 10430 }
10431#endif
9945 listsetvar(varlist.list, VEXPORT|VSTACK); 10432 listsetvar(varlist.list, VEXPORT|VSTACK);
9946 shellexec(argv[0], argv, path, cmdentry.u.index); 10433 shellexec(argv[0], argv, path, cmdentry.u.index);
9947 /* NOTREACHED */ 10434 /* NOTREACHED */
@@ -10325,7 +10812,7 @@ preadbuffer(void)
10325 more--; 10812 more--;
10326 10813
10327 c = *q; 10814 c = *q;
10328 if (c == '\0') { 10815 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) {
10329 memmove(q, q + 1, more); 10816 memmove(q, q + 1, more);
10330 } else { 10817 } else {
10331 q++; 10818 q++;
@@ -10487,6 +10974,7 @@ popallfiles(void)
10487 popfile(); 10974 popfile();
10488} 10975}
10489 10976
10977#if !ENABLE_PLATFORM_MINGW32
10490/* 10978/*
10491 * Close the file(s) that the shell is reading commands from. Called 10979 * Close the file(s) that the shell is reading commands from. Called
10492 * after a fork is done. 10980 * after a fork is done.
@@ -10500,6 +10988,7 @@ closescript(void)
10500 g_parsefile->pf_fd = 0; 10988 g_parsefile->pf_fd = 0;
10501 } 10989 }
10502} 10990}
10991#endif
10503 10992
10504/* 10993/*
10505 * Like setinputfile, but takes an open file descriptor. Call this with 10994 * Like setinputfile, but takes an open file descriptor. Call this with
@@ -12786,7 +13275,7 @@ find_dot_file(char *name)
12786 struct stat statb; 13275 struct stat statb;
12787 13276
12788 /* don't try this for absolute or relative paths */ 13277 /* don't try this for absolute or relative paths */
12789 if (strchr(name, '/')) 13278 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\')))
12790 return name; 13279 return name;
12791 13280
12792 while ((fullname = path_advance(&path, name)) != NULL) { 13281 while ((fullname = path_advance(&path, name)) != NULL) {
@@ -12897,17 +13386,22 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12897 struct tblentry *cmdp; 13386 struct tblentry *cmdp;
12898 int idx; 13387 int idx;
12899 int prev; 13388 int prev;
12900 char *fullname; 13389 char *fullname IF_PLATFORM_MINGW32(= NULL);
12901 struct stat statb; 13390 struct stat statb;
12902 int e; 13391 int e;
12903 int updatetbl; 13392 int updatetbl;
13393 IF_PLATFORM_MINGW32(int len;)
12904 struct builtincmd *bcmd; 13394 struct builtincmd *bcmd;
12905 13395
12906 /* If name contains a slash, don't use PATH or hash table */ 13396 /* If name contains a slash, don't use PATH or hash table */
12907 if (strchr(name, '/') != NULL) { 13397 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) {
12908 entry->u.index = -1; 13398 entry->u.index = -1;
12909 if (act & DO_ABS) { 13399 if (act & DO_ABS) {
12910 while (stat(name, &statb) < 0) { 13400 while (stat(name, &statb) < 0
13401#if ENABLE_PLATFORM_MINGW32
13402 && (fullname=file_is_win32_executable(name)) == NULL
13403#endif
13404 ) {
12911#ifdef SYSV 13405#ifdef SYSV
12912 if (errno == EINTR) 13406 if (errno == EINTR)
12913 continue; 13407 continue;
@@ -12915,6 +13409,9 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12915 entry->cmdtype = CMDUNKNOWN; 13409 entry->cmdtype = CMDUNKNOWN;
12916 return; 13410 return;
12917 } 13411 }
13412#if ENABLE_PLATFORM_MINGW32
13413 free(fullname);
13414#endif
12918 } 13415 }
12919 entry->cmdtype = CMDNORMAL; 13416 entry->cmdtype = CMDNORMAL;
12920 return; 13417 return;
@@ -13011,12 +13508,48 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13011 } 13508 }
13012 } 13509 }
13013 /* if rehash, don't redo absolute path names */ 13510 /* if rehash, don't redo absolute path names */
13014 if (fullname[0] == '/' && idx <= prev) { 13511 if (is_absolute_path(fullname) && idx <= prev) {
13015 if (idx < prev) 13512 if (idx < prev)
13016 continue; 13513 continue;
13017 TRACE(("searchexec \"%s\": no change\n", name)); 13514 TRACE(("searchexec \"%s\": no change\n", name));
13018 goto success; 13515 goto success;
13019 } 13516 }
13517#if ENABLE_PLATFORM_MINGW32
13518 len = strlen(fullname);
13519 if (len > 4 &&
13520 (!strcasecmp(fullname+len-4, ".exe") ||
13521 !strcasecmp(fullname+len-4, ".com"))) {
13522 if (stat(fullname, &statb) < 0) {
13523 if (errno != ENOENT && errno != ENOTDIR)
13524 e = errno;
13525 goto loop;
13526 }
13527 }
13528 else {
13529 /* path_advance() has reserved space for .exe */
13530 memcpy(fullname+len, ".exe", 5);
13531 if (stat(fullname, &statb) < 0) {
13532 if (errno != ENOENT && errno != ENOTDIR)
13533 e = errno;
13534 memcpy(fullname+len, ".com", 5);
13535 if (stat(fullname, &statb) < 0) {
13536 if (errno != ENOENT && errno != ENOTDIR)
13537 e = errno;
13538 fullname[len] = '\0';
13539 if (stat(fullname, &statb) < 0) {
13540 if (errno != ENOENT && errno != ENOTDIR)
13541 e = errno;
13542 goto loop;
13543 }
13544 if (!file_is_executable(fullname)) {
13545 e = ENOEXEC;
13546 goto loop;
13547 }
13548 }
13549 }
13550 fullname[len] = '\0';
13551 }
13552#else
13020 while (stat(fullname, &statb) < 0) { 13553 while (stat(fullname, &statb) < 0) {
13021#ifdef SYSV 13554#ifdef SYSV
13022 if (errno == EINTR) 13555 if (errno == EINTR)
@@ -13026,6 +13559,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13026 e = errno; 13559 e = errno;
13027 goto loop; 13560 goto loop;
13028 } 13561 }
13562#endif
13029 e = EACCES; /* if we fail, this will be the error */ 13563 e = EACCES; /* if we fail, this will be the error */
13030 if (!S_ISREG(statb.st_mode)) 13564 if (!S_ISREG(statb.st_mode))
13031 continue; 13565 continue;
@@ -13542,7 +14076,11 @@ exitshell(void)
13542} 14076}
13543 14077
13544static void 14078static void
14079#if ENABLE_PLATFORM_MINGW32
14080init(int xp)
14081#else
13545init(void) 14082init(void)
14083#endif
13546{ 14084{
13547 /* we will never free this */ 14085 /* we will never free this */
13548 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); 14086 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
@@ -13561,6 +14099,86 @@ init(void)
13561 struct stat st1, st2; 14099 struct stat st1, st2;
13562 14100
13563 initvar(); 14101 initvar();
14102
14103#if ENABLE_PLATFORM_MINGW32
14104 /*
14105 * case insensitive env names from Windows world
14106 *
14107 * Some standard env names such as PATH is named Path and so on
14108 * ash itself is case sensitive, so "Path" will confuse it, as
14109 * MSVC getenv() is case insensitive.
14110 *
14111 * We may end up having both Path and PATH. Then Path will be chosen
14112 * because it appears first.
14113 */
14114 for (envp = environ; envp && *envp; envp++) {
14115 if (strncasecmp(*envp, "PATH=", 5) == 0 &&
14116 strncmp(*envp, "PATH=", 5) != 0) {
14117 break;
14118 }
14119 }
14120
14121 if (envp && *envp) {
14122 /*
14123 * If we get here it's because the environment contains a path
14124 * variable called something other than PATH. This suggests we
14125 * haven't been invoked from an earlier instance of BusyBox.
14126 */
14127 char *start, *end, *s;
14128 struct passwd *pw;
14129
14130 for (envp = environ; envp && *envp; envp++) {
14131 if (!(end=strchr(*envp, '=')))
14132 continue;
14133
14134 /* make all variable names uppercase */
14135 for (start = *envp;start < end;start++)
14136 *start = toupper(*start);
14137
14138 /* skip conversion of variables known to cause problems */
14139 if ( strncmp(*envp, "SYSTEMROOT=", 11) == 0 ||
14140 strncmp(*envp, "COMSPEC=", 8) == 0 ) {
14141 continue;
14142 }
14143
14144 /* convert backslashes to forward slashes in value */
14145 if (!xp) {
14146 for ( s=end+1; *s; ++s ) {
14147 if ( *s == '\\' ) {
14148 *s = '/';
14149 }
14150 }
14151 }
14152
14153 /* check for invalid characters in name */
14154 for (start = *envp;start < end;start++) {
14155 if (!isdigit(*start) && !isalpha(*start) && *start != '_') {
14156 break;
14157 }
14158 }
14159
14160 if (start != end) {
14161 /*
14162 * Make a copy of the variable, replacing invalid
14163 * characters in the name with underscores.
14164 */
14165 char *var = xstrdup(*envp);
14166
14167 for (start = var;*start != '=';start++) {
14168 if (!isdigit(*start) && !isalpha(*start)) {
14169 *start = '_';
14170 }
14171 }
14172 setvareq(var, VEXPORT|VNOSAVE);
14173 }
14174 }
14175
14176 /* some initialisation normally performed at login */
14177 pw = xgetpwuid(getuid());
14178 setup_environment(pw->pw_shell,
14179 SETUP_ENV_CHANGEENV|SETUP_ENV_NO_CHDIR, pw);
14180 }
14181#endif
13564 for (envp = environ; envp && *envp; envp++) { 14182 for (envp = environ; envp && *envp; envp++) {
13565 p = endofname(*envp); 14183 p = endofname(*envp);
13566 if (p != *envp && *p == '=') { 14184 if (p != *envp && *p == '=') {
@@ -13772,17 +14390,44 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13772 exception_handler = &jmploc; 14390 exception_handler = &jmploc;
13773 rootpid = getpid(); 14391 rootpid = getpid();
13774 14392
13775 init(); 14393 init(IF_PLATFORM_MINGW32(argc >= 2 && strcmp(argv[1], "-X") == 0));
13776 setstackmark(&smark); 14394 setstackmark(&smark);
14395
14396#if ENABLE_PLATFORM_MINGW32
14397 hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL);
14398 SetConsoleCtrlHandler(ctrl_handler, TRUE);
14399
14400 if (argc == 3 && !strcmp(argv[1], "--forkshell")) {
14401 forkshell_init(argv[2]);
14402
14403 /* NOTREACHED */
14404 bb_error_msg_and_die("subshell ended unexpectedly");
14405 }
14406#endif
13777 login_sh = procargs(argv); 14407 login_sh = procargs(argv);
13778#if DEBUG 14408#if DEBUG
13779 TRACE(("Shell args: ")); 14409 TRACE(("Shell args: "));
13780 trace_puts_args(argv); 14410 trace_puts_args(argv);
13781#endif 14411#endif
13782 14412
14413#if ENABLE_ASH_NOCONSOLE
14414 if ( noconsole ) {
14415 DWORD dummy;
14416
14417 if ( GetConsoleProcessList(&dummy, 1) == 1 ) {
14418 ShowWindow(GetConsoleWindow(), SW_HIDE);
14419 }
14420 }
14421#endif
14422
13783 if (login_sh) { 14423 if (login_sh) {
13784 const char *hp; 14424 const char *hp;
13785 14425
14426#if ENABLE_PLATFORM_MINGW32
14427 chdir(xgetpwuid(getuid())->pw_dir);
14428 setpwd(NULL, 0);
14429#endif
14430
13786 state = 1; 14431 state = 1;
13787 read_profile("/etc/profile"); 14432 read_profile("/etc/profile");
13788 state1: 14433 state1:
@@ -13857,6 +14502,642 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13857 /* NOTREACHED */ 14502 /* NOTREACHED */
13858} 14503}
13859 14504
14505#if ENABLE_PLATFORM_MINGW32
14506static void
14507forkshell_openhere(struct forkshell *fs)
14508{
14509 union node *redir = fs->n;
14510 int pip[2];
14511
14512 pip[0] = fs->fd[0];
14513 pip[1] = fs->fd[1];
14514
14515 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14516
14517 close(pip[0]);
14518 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
14519 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
14520 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
14521 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
14522 signal(SIGPIPE, SIG_DFL);
14523 if (redir->type == NHERE) {
14524 size_t len = strlen(redir->nhere.doc->narg.text);
14525 full_write(pip[1], redir->nhere.doc->narg.text, len);
14526 } else /* NXHERE */
14527 expandhere(redir->nhere.doc, pip[1]);
14528 _exit(EXIT_SUCCESS);
14529}
14530
14531static void
14532forkshell_evalbackcmd(struct forkshell *fs)
14533{
14534 union node *n = fs->n;
14535 int pip[2] = {fs->fd[0], fs->fd[1]};
14536
14537 FORCE_INT_ON;
14538 close(pip[0]);
14539 if (pip[1] != 1) {
14540 /*close(1);*/
14541 dup2_or_raise(pip[1], 1);
14542 close(pip[1]);
14543 }
14544 eflag = 0;
14545 evaltree(n, EV_EXIT); /* actually evaltreenr... */
14546 /* NOTREACHED */
14547}
14548
14549static void
14550forkshell_evalsubshell(struct forkshell *fs)
14551{
14552 union node *n = fs->n;
14553 int flags = fs->flags;
14554
14555 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14556 INT_ON;
14557 flags |= EV_EXIT;
14558 expredir(n->nredir.redirect);
14559 redirect(n->nredir.redirect, 0);
14560 evaltreenr(n->nredir.n, flags);
14561 /* never returns */
14562}
14563
14564static void
14565forkshell_evalpipe(struct forkshell *fs)
14566{
14567 union node *n = fs->n;
14568 int flags = fs->flags;
14569 int prevfd = fs->fd[2];
14570 int pip[2] = {fs->fd[0], fs->fd[1]};
14571
14572 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14573 INT_ON;
14574 if (pip[1] >= 0) {
14575 close(pip[0]);
14576 }
14577 if (prevfd > 0) {
14578 dup2(prevfd, 0);
14579 close(prevfd);
14580 }
14581 if (pip[1] > 1) {
14582 dup2(pip[1], 1);
14583 close(pip[1]);
14584 }
14585 evaltreenr(n, flags);
14586}
14587
14588static void
14589forkshell_shellexec(struct forkshell *fs)
14590{
14591 int idx = fs->fd[0];
14592 struct strlist *varlist = fs->strlist;
14593 char **argv = fs->argv;
14594 char *path = fs->string;
14595
14596 FORCE_INT_ON;
14597 listsetvar(varlist, VEXPORT|VSTACK);
14598 shellexec(argv[0], argv, path, idx);
14599}
14600
14601static void
14602forkshell_child(struct forkshell *fs)
14603{
14604 switch ( fs->fpid ) {
14605 case FS_OPENHERE:
14606 forkshell_openhere(fs);
14607 break;
14608 case FS_EVALBACKCMD:
14609 forkshell_evalbackcmd(fs);
14610 break;
14611 case FS_EVALSUBSHELL:
14612 forkshell_evalsubshell(fs);
14613 break;
14614 case FS_EVALPIPE:
14615 forkshell_evalpipe(fs);
14616 break;
14617 case FS_SHELLEXEC:
14618 forkshell_shellexec(fs);
14619 break;
14620 }
14621}
14622
14623/*
14624 * Reset the pointers to the builtin environment variables in the hash
14625 * table to point to varinit rather than the bogus copy created during
14626 * forkshell_prepare.
14627 */
14628static void
14629reinitvar(void)
14630{
14631 struct var *vp;
14632 struct var *end;
14633 struct var **vpp;
14634 struct var **old;
14635
14636 vp = varinit;
14637 end = vp + ARRAY_SIZE(varinit);
14638 do {
14639 vpp = hashvar(vp->var_text);
14640 if ( (old=findvar(vpp, vp->var_text)) != NULL ) {
14641 vp->next = (*old)->next;
14642 *old = vp;
14643 }
14644 } while (++vp < end);
14645}
14646
14647/* FIXME: should consider running forkparent() and forkchild() */
14648static int
14649spawn_forkshell(struct job *jp, struct forkshell *fs, int mode)
14650{
14651 struct forkshell *new;
14652 char buf[16];
14653 const char *argv[] = { "sh", "--forkshell", NULL, NULL };
14654 intptr_t ret;
14655
14656 new = forkshell_prepare(fs);
14657 sprintf(buf, "%x", (unsigned int)new->hMapFile);
14658 argv[2] = buf;
14659 ret = mingw_spawn_proc(argv);
14660 CloseHandle(new->hMapFile);
14661 UnmapViewOfFile(new);
14662 if (ret == -1) {
14663 free(jp);
14664 return -1;
14665 }
14666 forkparent(jp, fs->node, mode, (HANDLE)ret);
14667 return ret == -1 ? -1 : 0;
14668}
14669
14670/*
14671 * forkshell_prepare() and friends
14672 *
14673 * The sequence is as follows:
14674 * - funcblocksize, funcstringsize, nodeptrsize are initialized
14675 * - forkshell_size(fs) is called to calculate the exact memory needed
14676 * - a new struct is allocated
14677 * - funcblock, funcstring, nodeptr are initialized from the new block
14678 * - forkshell_copy(fs) is called to copy recursively everything over
14679 * it will record all pointers along the way, to nodeptr
14680 *
14681 * When this memory is mapped elsewhere, pointer fixup will be needed
14682 */
14683#define SLIST_SIZE_BEGIN(name,type) \
14684static void \
14685name(type *p) \
14686{ \
14687 while (p) { \
14688 funcblocksize += sizeof(type);
14689 /* do something here with p */
14690#define SLIST_SIZE_END() \
14691 nodeptrsize++; \
14692 p = p->next; \
14693 } \
14694}
14695
14696#define SLIST_COPY_BEGIN(name,type) \
14697static type * \
14698name(type *vp) \
14699{ \
14700 type *start; \
14701 type **vpp; \
14702 vpp = &start; \
14703 while (vp) { \
14704 *vpp = funcblock; \
14705 funcblock = (char *) funcblock + sizeof(type);
14706 /* do something here with vpp and vp */
14707#define SLIST_COPY_END() \
14708 SAVE_PTR((*vpp)->next); \
14709 vp = vp->next; \
14710 vpp = &(*vpp)->next; \
14711 } \
14712 *vpp = NULL; \
14713 return start; \
14714}
14715
14716/*
14717 * struct var
14718 */
14719SLIST_SIZE_BEGIN(var_size,struct var)
14720funcstringsize += strlen(p->var_text) + 1;
14721nodeptrsize++; /* p->text */
14722SLIST_SIZE_END()
14723
14724SLIST_COPY_BEGIN(var_copy,struct var)
14725(*vpp)->var_text = nodeckstrdup(vp->var_text);
14726(*vpp)->flags = vp->flags;
14727/*
14728 * The only place that can set struct var#func is varinit[],
14729 * which will be fixed by forkshell_init()
14730 */
14731(*vpp)->var_func = NULL;
14732SAVE_PTR((*vpp)->var_text);
14733SLIST_COPY_END()
14734
14735/*
14736 * struct strlist
14737 */
14738SLIST_SIZE_BEGIN(strlist_size,struct strlist)
14739funcstringsize += strlen(p->text) + 1;
14740nodeptrsize++; /* p->text */
14741SLIST_SIZE_END()
14742
14743SLIST_COPY_BEGIN(strlist_copy,struct strlist)
14744(*vpp)->text = nodeckstrdup(vp->text);
14745SAVE_PTR((*vpp)->text);
14746SLIST_COPY_END()
14747
14748/*
14749 * struct tblentry
14750 */
14751static void
14752tblentry_size(struct tblentry *tep)
14753{
14754 while (tep) {
14755 funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14756 /* CMDBUILTIN, e->param.cmd needs no pointer relocation */
14757 if (tep->cmdtype == CMDFUNCTION) {
14758 funcblocksize += offsetof(struct funcnode, n);
14759 calcsize(&tep->param.func->n);
14760 nodeptrsize++; /* tep->param.func */
14761 }
14762 nodeptrsize++; /* tep->next */
14763 tep = tep->next;
14764 }
14765}
14766
14767static struct tblentry *
14768tblentry_copy(struct tblentry *tep)
14769{
14770 struct tblentry *start;
14771 struct tblentry **newp;
14772 int size;
14773
14774 newp = &start;
14775 while (tep) {
14776 *newp = funcblock;
14777 size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14778
14779 funcblock = (char *) funcblock + size;
14780 memcpy(*newp, tep, size);
14781 switch (tep->cmdtype) {
14782 case CMDBUILTIN:
14783 /* No pointer saving, this field must be fixed by forkshell_init() */
14784 (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab);
14785 break;
14786 case CMDFUNCTION:
14787 (*newp)->param.func = funcblock;
14788 funcblock = (char *) funcblock + offsetof(struct funcnode, n);
14789 copynode(&tep->param.func->n);
14790 SAVE_PTR((*newp)->param.func);
14791 break;
14792 default:
14793 break;
14794 }
14795 SAVE_PTR((*newp)->next);
14796 tep = tep->next;
14797 newp = &(*newp)->next;
14798 }
14799 *newp = NULL;
14800 return start;
14801}
14802
14803static void
14804cmdtable_size(struct tblentry **cmdtablep)
14805{
14806 int i;
14807 nodeptrsize += CMDTABLESIZE;
14808 funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE;
14809 for (i = 0; i < CMDTABLESIZE; i++)
14810 tblentry_size(cmdtablep[i]);
14811}
14812
14813static struct tblentry **
14814cmdtable_copy(struct tblentry **cmdtablep)
14815{
14816 struct tblentry **new = funcblock;
14817 int i;
14818
14819 funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE;
14820 for (i = 0; i < CMDTABLESIZE; i++) {
14821 new[i] = tblentry_copy(cmdtablep[i]);
14822 SAVE_PTR(new[i]);
14823 }
14824 return new;
14825}
14826
14827/*
14828 * char **
14829 */
14830static void
14831argv_size(char **p)
14832{
14833 while (p && *p) {
14834 funcblocksize += sizeof(char *);
14835 funcstringsize += strlen(*p)+1;
14836 nodeptrsize++;
14837 p++;
14838 }
14839 funcblocksize += sizeof(char *);
14840}
14841
14842static char **
14843argv_copy(char **p)
14844{
14845 char **new, **start = funcblock;
14846
14847 while (p && *p) {
14848 new = funcblock;
14849 funcblock = (char *) funcblock + sizeof(char *);
14850 *new = nodeckstrdup(*p);
14851 SAVE_PTR(*new);
14852 p++;
14853 new++;
14854 }
14855 new = funcblock;
14856 funcblock = (char *) funcblock + sizeof(char *);
14857 *new = NULL;
14858 return start;
14859}
14860
14861/*
14862 * struct redirtab
14863 */
14864static void
14865redirtab_size(struct redirtab *rdtp)
14866{
14867 while (rdtp) {
14868 funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14869 rdtp = rdtp->next;
14870 nodeptrsize++; /* rdtp->next */
14871 }
14872}
14873
14874static struct redirtab *
14875redirtab_copy(struct redirtab *rdtp)
14876{
14877 struct redirtab *start;
14878 struct redirtab **vpp;
14879
14880 vpp = &start;
14881 while (rdtp) {
14882 int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14883 *vpp = funcblock;
14884 funcblock = (char *) funcblock + size;
14885 memcpy(*vpp, rdtp, size);
14886 SAVE_PTR((*vpp)->next);
14887 rdtp = rdtp->next;
14888 vpp = &(*vpp)->next;
14889 }
14890 *vpp = NULL;
14891 return start;
14892}
14893
14894#undef shellparam
14895#undef redirlist
14896#undef varinit
14897#undef vartab
14898static void
14899globals_var_size(struct globals_var *gvp)
14900{
14901 int i;
14902
14903 funcblocksize += sizeof(struct globals_var);
14904 argv_size(gvp->shellparam.p);
14905 redirtab_size(gvp->redirlist);
14906 for (i = 0; i < VTABSIZE; i++)
14907 var_size(gvp->vartab[i]);
14908 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14909 var_size(gvp->varinit+i);
14910 nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */
14911}
14912
14913#undef preverrout_fd
14914static struct globals_var *
14915globals_var_copy(struct globals_var *gvp)
14916{
14917 int i;
14918 struct globals_var *new;
14919
14920 new = funcblock;
14921 funcblock = (char *) funcblock + sizeof(struct globals_var);
14922
14923 /* shparam */
14924 memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam));
14925 new->shellparam.malloced = 0;
14926 new->shellparam.p = argv_copy(gvp->shellparam.p);
14927 SAVE_PTR(new->shellparam.p);
14928
14929 new->redirlist = redirtab_copy(gvp->redirlist);
14930 SAVE_PTR(new->redirlist);
14931
14932 new->preverrout_fd = gvp->preverrout_fd;
14933 for (i = 0; i < VTABSIZE; i++) {
14934 new->vartab[i] = var_copy(gvp->vartab[i]);
14935 SAVE_PTR(new->vartab[i]);
14936 }
14937
14938 /* Can't use var_copy because varinit is already allocated */
14939 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) {
14940 new->varinit[i].next = NULL;
14941 new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text);
14942 SAVE_PTR(new->varinit[i].var_text);
14943 new->varinit[i].flags = gvp->varinit[i].flags;
14944 new->varinit[i].var_func = gvp->varinit[i].var_func;
14945 }
14946 return new;
14947}
14948
14949#undef minusc
14950#undef curdir
14951#undef physdir
14952#undef arg0
14953#undef nullstr
14954static void
14955globals_misc_size(struct globals_misc *p)
14956{
14957 funcblocksize += sizeof(struct globals_misc);
14958 funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1;
14959 if (p->curdir != p->nullstr)
14960 funcstringsize += strlen(p->curdir) + 1;
14961 if (p->physdir != p->nullstr)
14962 funcstringsize += strlen(p->physdir) + 1;
14963 funcstringsize += strlen(p->arg0) + 1;
14964 nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */
14965}
14966
14967static struct globals_misc *
14968globals_misc_copy(struct globals_misc *p)
14969{
14970 struct globals_misc *new = funcblock;
14971
14972 funcblock = (char *) funcblock + sizeof(struct globals_misc);
14973 memcpy(new, p, sizeof(struct globals_misc));
14974
14975 new->minusc = nodeckstrdup(p->minusc);
14976 new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr;
14977 new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr;
14978 new->arg0 = nodeckstrdup(p->arg0);
14979 SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0);
14980 return new;
14981}
14982
14983static void
14984forkshell_size(struct forkshell *fs)
14985{
14986 funcblocksize += sizeof(struct forkshell);
14987 globals_var_size(fs->gvp);
14988 globals_misc_size(fs->gmp);
14989 cmdtable_size(fs->cmdtable);
14990 /* optlist_transfer(sending, fd); */
14991 /* misc_transfer(sending, fd); */
14992
14993 calcsize(fs->n);
14994 argv_size(fs->argv);
14995 funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1;
14996 strlist_size(fs->strlist);
14997
14998 nodeptrsize += 7; /* gvp, gmp, cmdtable, n, argv, string, strlist */
14999}
15000
15001static struct forkshell *
15002forkshell_copy(struct forkshell *fs)
15003{
15004 struct forkshell *new;
15005
15006 new = funcblock;
15007 funcblock = (char *) funcblock + sizeof(struct forkshell);
15008
15009 memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */
15010 new->gvp = globals_var_copy(fs->gvp);
15011 new->gmp = globals_misc_copy(fs->gmp);
15012 new->cmdtable = cmdtable_copy(fs->cmdtable);
15013 SAVE_PTR3(new->gvp, new->gmp, new->cmdtable);
15014
15015 new->n = copynode(fs->n);
15016 new->argv = argv_copy(fs->argv);
15017 new->string = nodeckstrdup(fs->string);
15018 new->strlist = strlist_copy(fs->strlist);
15019 SAVE_PTR4(new->n, new->argv, new->string, new->strlist);
15020 return new;
15021}
15022
15023static struct forkshell *
15024forkshell_prepare(struct forkshell *fs)
15025{
15026 struct forkshell *new;
15027 int size, nodeptr_offset;
15028 HANDLE h;
15029 SECURITY_ATTRIBUTES sa;
15030
15031 /* Calculate size of "new" */
15032 fs->gvp = ash_ptr_to_globals_var;
15033 fs->gmp = ash_ptr_to_globals_misc;
15034 fs->cmdtable = cmdtable;
15035
15036 nodeptrsize = 1; /* NULL terminated */
15037 funcblocksize = 0;
15038 funcstringsize = 0;
15039 forkshell_size(fs);
15040 size = funcblocksize + funcstringsize + nodeptrsize*sizeof(char *);
15041
15042 /* Allocate, initialize pointers */
15043 memset(&sa, 0, sizeof(sa));
15044 sa.nLength = sizeof(sa);
15045 sa.lpSecurityDescriptor = NULL;
15046 sa.bInheritHandle = TRUE;
15047 h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL);
15048 new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
15049 /* new = ckmalloc(size); */
15050 funcblock = new;
15051 funcstring = (char *) funcblock + funcblocksize;
15052 nodeptr = (char **)((char *)funcstring + funcstringsize);
15053 nodeptr_offset = (char *)nodeptr - (char *)new;
15054
15055 /* Now pack them all */
15056 forkshell_copy(fs);
15057
15058 /* Finish it up */
15059 *nodeptr = NULL;
15060 new->size = size;
15061 new->nodeptr_offset = nodeptr_offset;
15062 new->old_base = new;
15063 new->hMapFile = h;
15064 return new;
15065}
15066
15067#undef exception_handler
15068#undef trap
15069#undef trap_ptr
15070static void *sticky_mem_start, *sticky_mem_end;
15071static void
15072forkshell_init(const char *idstr)
15073{
15074 struct forkshell *fs;
15075 int map_handle;
15076 HANDLE h;
15077 struct globals_var **gvpp;
15078 struct globals_misc **gmpp;
15079 int i;
15080 char **ptr;
15081
15082 if (sscanf(idstr, "%x", &map_handle) != 1)
15083 bb_error_msg_and_die("invalid forkshell ID");
15084
15085 h = (HANDLE)map_handle;
15086 fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
15087 if (!fs)
15088 bb_error_msg_and_die("Invalid forkshell memory");
15089
15090 /* this memory can't be freed */
15091 sticky_mem_start = fs;
15092 sticky_mem_end = (char *) fs + fs->size;
15093
15094 /* pointer fixup */
15095 nodeptr = (char **)((char *)fs + fs->nodeptr_offset);
15096 for ( i=0; nodeptr[i]; ++i ) {
15097 ptr = (char **)((char *)fs + (nodeptr[i] - (char *)fs->old_base));
15098 if (*ptr)
15099 *ptr = (char *)fs + (*ptr - (char *)fs->old_base);
15100 }
15101
15102 /* Now fix up stuff that can't be transferred */
15103 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
15104 fs->gvp->varinit[i].var_func = varinit_data[i].var_func;
15105 for (i = 0; i < CMDTABLESIZE; i++) {
15106 struct tblentry *e = fs->cmdtable[i];
15107 while (e) {
15108 if (e->cmdtype == CMDBUILTIN)
15109 e->param.cmd = builtintab + (int)e->param.cmd;
15110 e = e->next;
15111 }
15112 }
15113 fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler;
15114 for (i = 0; i < NSIG; i++)
15115 fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i];
15116 fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr;
15117
15118 /* Switch global variables */
15119 gvpp = (struct globals_var **)&ash_ptr_to_globals_var;
15120 *gvpp = fs->gvp;
15121 gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc;
15122 *gmpp = fs->gmp;
15123 cmdtable = fs->cmdtable;
15124
15125 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
15126
15127 reinitvar();
15128
15129 forkshell_child(fs);
15130}
15131
15132#undef free
15133static void
15134sticky_free(void *base)
15135{
15136 if (base >= sticky_mem_start && base < sticky_mem_end)
15137 return;
15138 free(base);
15139}
15140#endif
13860 15141
13861/*- 15142/*-
13862 * Copyright (c) 1989, 1991, 1993, 1994 15143 * Copyright (c) 1989, 1991, 1993, 1994