aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c1370
-rw-r--r--shell/shell_common.c15
2 files changed, 1323 insertions, 62 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 4ab2f2077..02e76c0ae 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.
@@ -81,6 +95,10 @@
81# define PIPE_BUF 4096 /* amount of buffering in a pipe */ 95# define PIPE_BUF 4096 /* amount of buffering in a pipe */
82#endif 96#endif
83 97
98#if !ENABLE_PLATFORM_MINGW32
99# define is_absolute_path(path) ((path)[0] == '/')
100#endif
101
84#if !BB_MMU 102#if !BB_MMU
85# error "Do not even bother, ash will not run on NOMMU machine" 103# error "Do not even bother, ash will not run on NOMMU machine"
86#endif 104#endif
@@ -219,6 +237,50 @@
219//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o 237//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
220//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o 238//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
221 239
240#if ENABLE_PLATFORM_MINGW32
241union node;
242struct strlist;
243struct job;
244
245struct forkshell {
246 /* filled by forkshell_copy() */
247 struct globals_var *gvp;
248 struct globals_misc *gmp;
249 struct tblentry **cmdtable;
250 /* struct alias **atab; */
251 /* struct parsefile *g_parsefile; */
252 HANDLE hMapFile;
253 void *old_base;
254 int nodeptr_offset;
255 int size;
256
257 /* type of forkshell */
258 int fpid;
259
260 /* optional data, used by forkshell_child */
261 int flags;
262 int fd[10];
263 union node *n;
264 char **argv;
265 char *string;
266 struct strlist *strlist;
267};
268
269enum {
270 FS_OPENHERE,
271 FS_EVALBACKCMD,
272 FS_EVALSUBSHELL,
273 FS_EVALPIPE,
274 FS_SHELLEXEC
275};
276
277static struct forkshell* forkshell_prepare(struct forkshell *fs);
278static void forkshell_init(const char *idstr);
279static void forkshell_child(struct forkshell *fs);
280static void sticky_free(void *p);
281#define free(p) sticky_free(p)
282static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode);
283#endif
222 284
223/* ============ Hash table sizes. Configurable. */ 285/* ============ Hash table sizes. Configurable. */
224 286
@@ -251,6 +313,10 @@ static const char *const optletters_optnames[] = {
251 ,"\0" "nolog" 313 ,"\0" "nolog"
252 ,"\0" "debug" 314 ,"\0" "debug"
253#endif 315#endif
316#if ENABLE_PLATFORM_MINGW32
317 ,"\0" "noconsole"
318 ,"X" "winxp"
319#endif
254}; 320};
255 321
256#define optletters(n) optletters_optnames[n][0] 322#define optletters(n) optletters_optnames[n][0]
@@ -333,6 +399,10 @@ struct globals_misc {
333# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] 399# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
334# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] 400# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
335#endif 401#endif
402#if ENABLE_PLATFORM_MINGW32
403# define noconsole optlist[14 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
404# define winxp optlist[15 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
405#endif
336 406
337 /* trap handler commands */ 407 /* trap handler commands */
338 /* 408 /*
@@ -2410,10 +2480,22 @@ path_advance(const char **path, const char *name)
2410 if (*path == NULL) 2480 if (*path == NULL)
2411 return NULL; 2481 return NULL;
2412 start = *path; 2482 start = *path;
2483#if ENABLE_PLATFORM_MINGW32
2484 p = next_path_sep(start);
2485 q = strchr(start, '%');
2486 if ((p && q && q < p) || (!p && q))
2487 p = q;
2488 if (!p)
2489 for (p = start; *p; p++)
2490 continue;
2491#else
2413 for (p = start; *p && *p != ':' && *p != '%'; p++) 2492 for (p = start; *p && *p != ':' && *p != '%'; p++)
2414 continue; 2493 continue;
2494#endif
2415 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2495 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2416 while (stackblocksize() < len) 2496
2497 /* preserve space for .exe too */
2498 while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len))
2417 growstackblock(); 2499 growstackblock();
2418 q = stackblock(); 2500 q = stackblock();
2419 if (p != start) { 2501 if (p != start) {
@@ -2425,10 +2507,19 @@ path_advance(const char **path, const char *name)
2425 pathopt = NULL; 2507 pathopt = NULL;
2426 if (*p == '%') { 2508 if (*p == '%') {
2427 pathopt = ++p; 2509 pathopt = ++p;
2510#if ENABLE_PLATFORM_MINGW32
2511 p = next_path_sep(start);
2512
2513 /* *p != ':' and '*' would suffice */
2514 if (!p)
2515 p = pathopt - 1;
2516#else
2428 while (*p && *p != ':') 2517 while (*p && *p != ':')
2429 p++; 2518 p++;
2519#endif
2430 } 2520 }
2431 if (*p == ':') 2521 if (*p == ':' ||
2522 (ENABLE_PLATFORM_MINGW32 && *p == ';'))
2432 *path = p + 1; 2523 *path = p + 1;
2433 else 2524 else
2434 *path = NULL; 2525 *path = NULL;
@@ -2529,6 +2620,106 @@ cdopt(void)
2529static const char * 2620static const char *
2530updatepwd(const char *dir) 2621updatepwd(const char *dir)
2531{ 2622{
2623#if ENABLE_PLATFORM_MINGW32
2624#define is_path_sep(x) ((x) == '/' || (x) == '\\')
2625#define is_unc_path(x) (is_path_sep(x[0]) && is_path_sep(x[1]))
2626 /*
2627 * Due to Windows drive notion, getting pwd is a completely
2628 * different thing. Handle it in a separate routine
2629 */
2630
2631 char *new;
2632 char *p;
2633 char *cdcomppath;
2634 const char *lim;
2635 /*
2636 * There are five cases that make some kind of sense
2637 * absdrive + abspath: c:/path
2638 * absdrive + !abspath: c:path
2639 * !absdrive + abspath: /path
2640 * !absdrive + uncpath: //host/share
2641 * !absdrive + !abspath: path
2642 *
2643 * Damn DOS!
2644 * c:path behaviour is "undefined"
2645 * To properly handle this case, I have to keep track of cwd
2646 * of every drive, which is too painful to do.
2647 * So when c:path is given, I assume it's c:${curdir}path
2648 * with ${curdir} comes from the current drive
2649 */
2650 int absdrive = *dir && dir[1] == ':';
2651 int abspath = absdrive ? is_path_sep(dir[2]) : is_path_sep(*dir);
2652
2653 cdcomppath = ststrdup(dir);
2654 STARTSTACKSTR(new);
2655 if (!absdrive && curdir == nullstr)
2656 return 0;
2657 if (!abspath) {
2658 if (curdir == nullstr)
2659 return 0;
2660 new = stack_putstr(curdir, new);
2661 }
2662 new = makestrspace(strlen(dir) + 2, new);
2663
2664 if ( is_unc_path(dir) || (!absdrive && !abspath && is_unc_path(curdir)) ) {
2665 lim = (char *)stackblock() + 1;
2666 }
2667 else {
2668 char *drive = stackblock();
2669 if (absdrive) {
2670 *drive = *dir;
2671 cdcomppath += 2;
2672 dir += 2;
2673 } else {
2674 *drive = *curdir;
2675 }
2676 drive[1] = ':'; /* in case of absolute drive+path */
2677
2678 if (abspath)
2679 new = drive + 2;
2680 lim = drive + 3;
2681 }
2682
2683 if (!abspath) {
2684 if (!is_path_sep(new[-1]))
2685 USTPUTC('/', new);
2686 if (new > lim && is_path_sep(*lim))
2687 lim++;
2688 } else {
2689 USTPUTC('/', new);
2690 cdcomppath ++;
2691 if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) {
2692 USTPUTC('/', new);
2693 cdcomppath++;
2694 lim++;
2695 }
2696 }
2697 p = strtok(cdcomppath, "/\\");
2698 while (p) {
2699 switch (*p) {
2700 case '.':
2701 if (p[1] == '.' && p[2] == '\0') {
2702 while (new > lim) {
2703 STUNPUTC(new);
2704 if (is_path_sep(new[-1]))
2705 break;
2706 }
2707 break;
2708 }
2709 if (p[1] == '\0')
2710 break;
2711 /* fall through */
2712 default:
2713 new = stack_putstr(p, new);
2714 USTPUTC('/', new);
2715 }
2716 p = strtok(0, "/\\");
2717 }
2718 if (new > lim)
2719 STUNPUTC(new);
2720 *new = 0;
2721 return stackblock();
2722#else
2532 char *new; 2723 char *new;
2533 char *p; 2724 char *p;
2534 char *cdcomppath; 2725 char *cdcomppath;
@@ -2582,6 +2773,7 @@ updatepwd(const char *dir)
2582 STUNPUTC(new); 2773 STUNPUTC(new);
2583 *new = 0; 2774 *new = 0;
2584 return stackblock(); 2775 return stackblock();
2776#endif
2585} 2777}
2586 2778
2587/* 2779/*
@@ -2676,7 +2868,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2676 } 2868 }
2677 if (!dest) 2869 if (!dest)
2678 dest = nullstr; 2870 dest = nullstr;
2679 if (*dest == '/') 2871 if (is_absolute_path(dest))
2680 goto step7; 2872 goto step7;
2681 if (*dest == '.') { 2873 if (*dest == '.') {
2682 c = dest[1]; 2874 c = dest[1];
@@ -3376,6 +3568,9 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3376 */ 3568 */
3377struct procstat { 3569struct procstat {
3378 pid_t ps_pid; /* process id */ 3570 pid_t ps_pid; /* process id */
3571#if ENABLE_PLATFORM_MINGW32
3572 HANDLE ps_proc;
3573#endif
3379 int ps_status; /* last process status from wait() */ 3574 int ps_status; /* last process status from wait() */
3380 char *ps_cmd; /* text of command being run */ 3575 char *ps_cmd; /* text of command being run */
3381}; 3576};
@@ -3403,7 +3598,9 @@ struct job {
3403}; 3598};
3404 3599
3405static struct job *makejob(/*union node *,*/ int); 3600static struct job *makejob(/*union node *,*/ int);
3601#if !ENABLE_PLATFORM_MINGW32
3406static int forkshell(struct job *, union node *, int); 3602static int forkshell(struct job *, union node *, int);
3603#endif
3407static int waitforjob(struct job *); 3604static int waitforjob(struct job *);
3408 3605
3409#if !JOBS 3606#if !JOBS
@@ -3458,6 +3655,8 @@ setsignal(int signo)
3458 char cur_act, new_act; 3655 char cur_act, new_act;
3459 struct sigaction act; 3656 struct sigaction act;
3460 3657
3658 if (ENABLE_PLATFORM_MINGW32)
3659 return;
3461 t = trap[signo]; 3660 t = trap[signo];
3462 new_act = S_DFL; 3661 new_act = S_DFL;
3463 if (t != NULL) { /* trap for this sig is set */ 3662 if (t != NULL) { /* trap for this sig is set */
@@ -3973,6 +4172,95 @@ sprint_status48(char *s, int status, int sigonly)
3973 return col; 4172 return col;
3974} 4173}
3975 4174
4175#if ENABLE_PLATFORM_MINGW32
4176
4177HANDLE hSIGINT; /* Ctrl-C is pressed */
4178
4179static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
4180{
4181 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
4182 SetEvent(hSIGINT);
4183 return TRUE;
4184 }
4185 return FALSE;
4186}
4187
4188/*
4189 * Windows does not know about parent-child relationship
4190 * They don't support waitpid(-1)
4191 */
4192static pid_t
4193waitpid_child(int *status, int wait_flags)
4194{
4195 pid_t *pidlist;
4196 HANDLE *proclist;
4197 int pid_nr = 0;
4198 pid_t pid;
4199 DWORD win_status, idx;
4200 struct job *jb;
4201
4202 for (jb = curjob; jb; jb = jb->prev_job) {
4203 if (jb->state != JOBDONE)
4204 pid_nr += jb->nprocs;
4205 }
4206 if ( pid_nr++ == 0 )
4207 return -1;
4208
4209 pidlist = ckmalloc(sizeof(*pidlist)*pid_nr);
4210 proclist = ckmalloc(sizeof(*proclist)*pid_nr);
4211
4212 pidlist[0] = -1;
4213 proclist[0] = hSIGINT;
4214 pid_nr = 1;
4215 for (jb = curjob; jb; jb = jb->prev_job) {
4216 struct procstat *ps, *psend;
4217 if (jb->state == JOBDONE)
4218 continue;
4219 ps = jb->ps;
4220 psend = ps + jb->nprocs;
4221 while (ps < psend) {
4222 if (ps->ps_pid != -1 && ps->ps_proc != NULL) {
4223 pidlist[pid_nr] = ps->ps_pid;
4224 proclist[pid_nr++] = ps->ps_proc;
4225 }
4226 ps++;
4227 }
4228 }
4229
4230 if (pid_nr == 1) {
4231 free(pidlist);
4232 free(proclist);
4233 return -1;
4234 }
4235
4236 idx = WaitForMultipleObjects(pid_nr, proclist, FALSE,
4237 wait_flags|WNOHANG ? 1 : INFINITE);
4238 if (idx >= pid_nr) {
4239 free(pidlist);
4240 free(proclist);
4241 return -1;
4242 }
4243 if (!idx) { /* hSIGINT */
4244 int i;
4245 ResetEvent(hSIGINT);
4246 for (i = 1; i < pid_nr; i++)
4247 TerminateProcess(proclist[i], 1);
4248 pid = pidlist[1];
4249 free(pidlist);
4250 free(proclist);
4251 *status = 260; /* terminated by a signal */
4252 return pid;
4253 }
4254 GetExitCodeProcess(proclist[idx], &win_status);
4255 pid = pidlist[idx];
4256 free(pidlist);
4257 free(proclist);
4258 *status = (int)win_status;
4259 return pid;
4260}
4261#define waitpid(p, s, f) waitpid_child(s, f)
4262#endif
4263
3976static int 4264static int
3977dowait(int wait_flags, struct job *job) 4265dowait(int wait_flags, struct job *job)
3978{ 4266{
@@ -4012,6 +4300,11 @@ dowait(int wait_flags, struct job *job)
4012 jobno(jp), pid, ps->ps_status, status)); 4300 jobno(jp), pid, ps->ps_status, status));
4013 ps->ps_status = status; 4301 ps->ps_status = status;
4014 thisjob = jp; 4302 thisjob = jp;
4303 if (ENABLE_PLATFORM_MINGW32) {
4304 ps->ps_pid = -1;
4305 CloseHandle(ps->ps_proc);
4306 ps->ps_proc = NULL;
4307 }
4015 } 4308 }
4016 if (ps->ps_status == -1) 4309 if (ps->ps_status == -1)
4017 jobstate = JOBRUNNING; 4310 jobstate = JOBRUNNING;
@@ -4692,6 +4985,7 @@ commandtext(union node *n)
4692 * 4985 *
4693 * Called with interrupts off. 4986 * Called with interrupts off.
4694 */ 4987 */
4988#if !ENABLE_PLATFORM_MINGW32
4695/* 4989/*
4696 * Clear traps on a fork. 4990 * Clear traps on a fork.
4697 */ 4991 */
@@ -4840,16 +5134,24 @@ forkchild(struct job *jp, union node *n, int mode)
4840 freejob(jp); 5134 freejob(jp);
4841 jobless = 0; 5135 jobless = 0;
4842} 5136}
5137#endif
4843 5138
4844/* Called after fork(), in parent */ 5139/* Called after fork(), in parent */
4845#if !JOBS 5140#if !JOBS
4846#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) 5141#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4847#endif 5142#endif
4848static void 5143static void
5144#if !ENABLE_PLATFORM_MINGW32
4849forkparent(struct job *jp, union node *n, int mode, pid_t pid) 5145forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5146#else
5147forkparent(struct job *jp, union node *n, int mode, HANDLE proc)
5148#endif
4850{ 5149{
5150#if ENABLE_PLATFORM_MINGW32
5151 pid_t pid = GetProcessId(proc);
5152#endif
4851 TRACE(("In parent shell: child = %d\n", pid)); 5153 TRACE(("In parent shell: child = %d\n", pid));
4852 if (!jp) { 5154 if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */
4853 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) 5155 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4854 continue; 5156 continue;
4855 jobless++; 5157 jobless++;
@@ -4874,6 +5176,9 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4874 if (jp) { 5176 if (jp) {
4875 struct procstat *ps = &jp->ps[jp->nprocs++]; 5177 struct procstat *ps = &jp->ps[jp->nprocs++];
4876 ps->ps_pid = pid; 5178 ps->ps_pid = pid;
5179#if ENABLE_PLATFORM_MINGW32
5180 ps->ps_proc = proc;
5181#endif
4877 ps->ps_status = -1; 5182 ps->ps_status = -1;
4878 ps->ps_cmd = nullstr; 5183 ps->ps_cmd = nullstr;
4879#if JOBS 5184#if JOBS
@@ -4883,6 +5188,7 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4883 } 5188 }
4884} 5189}
4885 5190
5191#if !ENABLE_PLATFORM_MINGW32
4886static int 5192static int
4887forkshell(struct job *jp, union node *n, int mode) 5193forkshell(struct job *jp, union node *n, int mode)
4888{ 5194{
@@ -4904,6 +5210,7 @@ forkshell(struct job *jp, union node *n, int mode)
4904 } 5210 }
4905 return pid; 5211 return pid;
4906} 5212}
5213#endif
4907 5214
4908/* 5215/*
4909 * Wait for job to finish. 5216 * Wait for job to finish.
@@ -5096,6 +5403,7 @@ openhere(union node *redir)
5096{ 5403{
5097 int pip[2]; 5404 int pip[2];
5098 size_t len = 0; 5405 size_t len = 0;
5406 IF_PLATFORM_MINGW32(struct forkshell fs);
5099 5407
5100 if (pipe(pip) < 0) 5408 if (pipe(pip) < 0)
5101 ash_msg_and_raise_error("pipe call failed"); 5409 ash_msg_and_raise_error("pipe call failed");
@@ -5106,6 +5414,15 @@ openhere(union node *redir)
5106 goto out; 5414 goto out;
5107 } 5415 }
5108 } 5416 }
5417#if ENABLE_PLATFORM_MINGW32
5418 memset(&fs, 0, sizeof(fs));
5419 fs.fpid = FS_OPENHERE;
5420 fs.n = redir;
5421 fs.fd[0] = pip[0];
5422 fs.fd[1] = pip[1];
5423 if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0)
5424 ash_msg_and_raise_error("unable to spawn shell");
5425#else
5109 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 5426 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5110 /* child */ 5427 /* child */
5111 close(pip[0]); 5428 close(pip[0]);
@@ -5120,6 +5437,7 @@ openhere(union node *redir)
5120 expandhere(redir->nhere.doc, pip[1]); 5437 expandhere(redir->nhere.doc, pip[1]);
5121 _exit(EXIT_SUCCESS); 5438 _exit(EXIT_SUCCESS);
5122 } 5439 }
5440#endif
5123 out: 5441 out:
5124 close(pip[1]); 5442 close(pip[1]);
5125 return pip[0]; 5443 return pip[0];
@@ -5145,6 +5463,31 @@ openredirect(union node *redir)
5145 * allocated space. Do it only when we know it is safe. 5463 * allocated space. Do it only when we know it is safe.
5146 */ 5464 */
5147 fname = redir->nfile.expfname; 5465 fname = redir->nfile.expfname;
5466#if ENABLE_PLATFORM_MINGW32
5467 /* Support for /dev/null */
5468 switch (redir->nfile.type) {
5469 case NFROM:
5470 if (!strcmp(fname, "/dev/null"))
5471 return open("nul",O_RDWR);
5472 if (!strncmp(fname, "/dev/", 5)) {
5473 ash_msg("Unhandled device %s\n", fname);
5474 return -1;
5475 }
5476 break;
5477
5478 case NFROMTO:
5479 case NTO:
5480 case NCLOBBER:
5481 case NAPPEND:
5482 if (!strcmp(fname, "/dev/null"))
5483 return open("nul",O_RDWR);
5484 if (!strncmp(fname, "/dev/", 5)) {
5485 ash_msg("Unhandled device %s\n", fname);
5486 return -1;
5487 }
5488 break;
5489 }
5490#endif
5148 5491
5149 switch (redir->nfile.type) { 5492 switch (redir->nfile.type) {
5150 default: 5493 default:
@@ -5182,6 +5525,9 @@ openredirect(union node *redir)
5182 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); 5525 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5183 if (f < 0) 5526 if (f < 0)
5184 goto ecreate; 5527 goto ecreate;
5528#if ENABLE_PLATFORM_MINGW32
5529 lseek(f, 0, SEEK_END);
5530#endif
5185 break; 5531 break;
5186 } 5532 }
5187 5533
@@ -5879,6 +6225,7 @@ struct backcmd { /* result of evalbackcmd */
5879 int fd; /* file descriptor to read from */ 6225 int fd; /* file descriptor to read from */
5880 int nleft; /* number of chars in buffer */ 6226 int nleft; /* number of chars in buffer */
5881 char *buf; /* buffer */ 6227 char *buf; /* buffer */
6228 IF_PLATFORM_MINGW32(struct forkshell fs);
5882 struct job *jp; /* job structure for command */ 6229 struct job *jp; /* job structure for command */
5883}; 6230};
5884 6231
@@ -5894,6 +6241,7 @@ evalbackcmd(union node *n, struct backcmd *result)
5894 result->fd = -1; 6241 result->fd = -1;
5895 result->buf = NULL; 6242 result->buf = NULL;
5896 result->nleft = 0; 6243 result->nleft = 0;
6244 IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs)));
5897 result->jp = NULL; 6245 result->jp = NULL;
5898 if (n == NULL) 6246 if (n == NULL)
5899 goto out; 6247 goto out;
@@ -5908,6 +6256,14 @@ evalbackcmd(union node *n, struct backcmd *result)
5908 if (pipe(pip) < 0) 6256 if (pipe(pip) < 0)
5909 ash_msg_and_raise_error("pipe call failed"); 6257 ash_msg_and_raise_error("pipe call failed");
5910 jp = makejob(/*n,*/ 1); 6258 jp = makejob(/*n,*/ 1);
6259#if ENABLE_PLATFORM_MINGW32
6260 result->fs.fpid = FS_EVALBACKCMD;
6261 result->fs.n = n;
6262 result->fs.fd[0] = pip[0];
6263 result->fs.fd[1] = pip[1];
6264 if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0)
6265 ash_msg_and_raise_error("unable to spawn shell");
6266#else
5911 if (forkshell(jp, n, FORK_NOJOB) == 0) { 6267 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5912 FORCE_INT_ON; 6268 FORCE_INT_ON;
5913 close(pip[0]); 6269 close(pip[0]);
@@ -5920,6 +6276,7 @@ evalbackcmd(union node *n, struct backcmd *result)
5920 evaltree(n, EV_EXIT); /* actually evaltreenr... */ 6276 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5921 /* NOTREACHED */ 6277 /* NOTREACHED */
5922 } 6278 }
6279#endif
5923 close(pip[1]); 6280 close(pip[1]);
5924 result->fd = pip[0]; 6281 result->fd = pip[0];
5925 result->jp = jp; 6282 result->jp = jp;
@@ -5976,7 +6333,8 @@ expbackq(union node *cmd, int flag)
5976 6333
5977 /* Eat all trailing newlines */ 6334 /* Eat all trailing newlines */
5978 dest = expdest; 6335 dest = expdest;
5979 for (; dest > (char *)stackblock() && dest[-1] == '\n';) 6336 for (; dest > (char *)stackblock() && (dest[-1] == '\n' ||
6337 (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));)
5980 STUNPUTC(dest); 6338 STUNPUTC(dest);
5981 expdest = dest; 6339 expdest = dest;
5982 6340
@@ -7565,7 +7923,7 @@ shellexec(char **argv, const char *path, int idx)
7565 7923
7566 clearredir(/*drop:*/ 1); 7924 clearredir(/*drop:*/ 1);
7567 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); 7925 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7568 if (strchr(argv[0], '/') != NULL 7926 if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\')))
7569#if ENABLE_FEATURE_SH_STANDALONE 7927#if ENABLE_FEATURE_SH_STANDALONE
7570 || (applet_no = find_applet_by_name(argv[0])) >= 0 7928 || (applet_no = find_applet_by_name(argv[0])) >= 0
7571#endif 7929#endif
@@ -7579,6 +7937,11 @@ shellexec(char **argv, const char *path, int idx)
7579 goto try_PATH; 7937 goto try_PATH;
7580 } 7938 }
7581 e = errno; 7939 e = errno;
7940#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE
7941 } else if (strcmp(argv[0], "busybox") == 0) {
7942 tryexec(-1, bb_busybox_exec_path, argv, envp);
7943 e = errno;
7944#endif
7582 } else { 7945 } else {
7583 try_PATH: 7946 try_PATH:
7584 e = ENOENT; 7947 e = ENOENT;
@@ -8159,10 +8522,14 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8159#endif 8522#endif
8160 8523
8161 8524
8162/*static int funcblocksize; // size of structures in function */ 8525static int funcblocksize; /* size of structures in function */
8163/*static int funcstringsize; // size of strings in node */ 8526static int funcstringsize; /* size of strings in node */
8164static void *funcblock; /* block to allocate function from */ 8527static void *funcblock; /* block to allocate function from */
8165static char *funcstring_end; /* end of block to allocate strings from */ 8528static char *funcstring; /* block to allocate strings from */
8529#if ENABLE_PLATFORM_MINGW32
8530static int nodeptrsize;
8531static char **nodeptr;
8532#endif
8166 8533
8167/* flags in argument to evaltree */ 8534/* flags in argument to evaltree */
8168#define EV_EXIT 01 /* exit after evaluating tree */ 8535#define EV_EXIT 01 /* exit after evaluating tree */
@@ -8200,72 +8567,81 @@ static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8200 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)), 8567 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
8201}; 8568};
8202 8569
8203static int calcsize(int funcblocksize, union node *n); 8570static void calcsize(union node *n);
8204 8571
8205static int 8572static void
8206sizenodelist(int funcblocksize, struct nodelist *lp) 8573sizenodelist(struct nodelist *lp)
8207{ 8574{
8208 while (lp) { 8575 while (lp) {
8209 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 8576 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8210 funcblocksize = calcsize(funcblocksize, lp->n); 8577 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8578 calcsize(lp->n);
8211 lp = lp->next; 8579 lp = lp->next;
8212 } 8580 }
8213 return funcblocksize;
8214} 8581}
8215 8582
8216static int 8583static void
8217calcsize(int funcblocksize, union node *n) 8584calcsize(union node *n)
8218{ 8585{
8219 if (n == NULL) 8586 if (n == NULL)
8220 return funcblocksize; 8587 return;
8221 funcblocksize += nodesize[n->type]; 8588 funcblocksize += nodesize[n->type];
8222 switch (n->type) { 8589 switch (n->type) {
8223 case NCMD: 8590 case NCMD:
8224 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect); 8591 calcsize(n->ncmd.redirect);
8225 funcblocksize = calcsize(funcblocksize, n->ncmd.args); 8592 calcsize(n->ncmd.args);
8226 funcblocksize = calcsize(funcblocksize, n->ncmd.assign); 8593 calcsize(n->ncmd.assign);
8594 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8227 break; 8595 break;
8228 case NPIPE: 8596 case NPIPE:
8229 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist); 8597 sizenodelist(n->npipe.cmdlist);
8598 IF_PLATFORM_MINGW32(nodeptrsize++);
8230 break; 8599 break;
8231 case NREDIR: 8600 case NREDIR:
8232 case NBACKGND: 8601 case NBACKGND:
8233 case NSUBSHELL: 8602 case NSUBSHELL:
8234 funcblocksize = calcsize(funcblocksize, n->nredir.redirect); 8603 calcsize(n->nredir.redirect);
8235 funcblocksize = calcsize(funcblocksize, n->nredir.n); 8604 calcsize(n->nredir.n);
8605 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8236 break; 8606 break;
8237 case NAND: 8607 case NAND:
8238 case NOR: 8608 case NOR:
8239 case NSEMI: 8609 case NSEMI:
8240 case NWHILE: 8610 case NWHILE:
8241 case NUNTIL: 8611 case NUNTIL:
8242 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2); 8612 calcsize(n->nbinary.ch2);
8243 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1); 8613 calcsize(n->nbinary.ch1);
8614 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8244 break; 8615 break;
8245 case NIF: 8616 case NIF:
8246 funcblocksize = calcsize(funcblocksize, n->nif.elsepart); 8617 calcsize(n->nif.elsepart);
8247 funcblocksize = calcsize(funcblocksize, n->nif.ifpart); 8618 calcsize(n->nif.ifpart);
8248 funcblocksize = calcsize(funcblocksize, n->nif.test); 8619 calcsize(n->nif.test);
8620 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8249 break; 8621 break;
8250 case NFOR: 8622 case NFOR:
8251 funcblocksize += strlen(n->nfor.var) + 1; /* was funcstringsize += ... */ 8623 funcstringsize += strlen(n->nfor.var) + 1;
8252 funcblocksize = calcsize(funcblocksize, n->nfor.body); 8624 calcsize(n->nfor.body);
8253 funcblocksize = calcsize(funcblocksize, n->nfor.args); 8625 calcsize(n->nfor.args);
8626 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8254 break; 8627 break;
8255 case NCASE: 8628 case NCASE:
8256 funcblocksize = calcsize(funcblocksize, n->ncase.cases); 8629 calcsize(n->ncase.cases);
8257 funcblocksize = calcsize(funcblocksize, n->ncase.expr); 8630 calcsize(n->ncase.expr);
8631 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8258 break; 8632 break;
8259 case NCLIST: 8633 case NCLIST:
8260 funcblocksize = calcsize(funcblocksize, n->nclist.body); 8634 calcsize(n->nclist.body);
8261 funcblocksize = calcsize(funcblocksize, n->nclist.pattern); 8635 calcsize(n->nclist.pattern);
8262 funcblocksize = calcsize(funcblocksize, n->nclist.next); 8636 calcsize(n->nclist.next);
8637 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8263 break; 8638 break;
8264 case NDEFUN: 8639 case NDEFUN:
8265 case NARG: 8640 case NARG:
8266 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote); 8641 sizenodelist(n->narg.backquote);
8267 funcblocksize += strlen(n->narg.text) + 1; /* was funcstringsize += ... */ 8642 funcstringsize += strlen(n->narg.text) + 1;
8268 funcblocksize = calcsize(funcblocksize, n->narg.next); 8643 calcsize(n->narg.next);
8644 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8269 break; 8645 break;
8270 case NTO: 8646 case NTO:
8271#if ENABLE_ASH_BASH_COMPAT 8647#if ENABLE_ASH_BASH_COMPAT
@@ -8275,35 +8651,55 @@ calcsize(int funcblocksize, union node *n)
8275 case NFROM: 8651 case NFROM:
8276 case NFROMTO: 8652 case NFROMTO:
8277 case NAPPEND: 8653 case NAPPEND:
8278 funcblocksize = calcsize(funcblocksize, n->nfile.fname); 8654 calcsize(n->nfile.fname);
8279 funcblocksize = calcsize(funcblocksize, n->nfile.next); 8655 calcsize(n->nfile.next);
8656 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8280 break; 8657 break;
8281 case NTOFD: 8658 case NTOFD:
8282 case NFROMFD: 8659 case NFROMFD:
8283 funcblocksize = calcsize(funcblocksize, n->ndup.vname); 8660 calcsize(n->ndup.vname);
8284 funcblocksize = calcsize(funcblocksize, n->ndup.next); 8661 calcsize(n->ndup.next);
8662 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8285 break; 8663 break;
8286 case NHERE: 8664 case NHERE:
8287 case NXHERE: 8665 case NXHERE:
8288 funcblocksize = calcsize(funcblocksize, n->nhere.doc); 8666 calcsize(n->nhere.doc);
8289 funcblocksize = calcsize(funcblocksize, n->nhere.next); 8667 calcsize(n->nhere.next);
8668 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8290 break; 8669 break;
8291 case NNOT: 8670 case NNOT:
8292 funcblocksize = calcsize(funcblocksize, n->nnot.com); 8671 calcsize(n->nnot.com);
8672 IF_PLATFORM_MINGW32(nodeptrsize++);
8293 break; 8673 break;
8294 }; 8674 };
8295 return funcblocksize;
8296} 8675}
8297 8676
8298static char * 8677static char *
8299nodeckstrdup(char *s) 8678nodeckstrdup(const char *s)
8300{ 8679{
8301 funcstring_end -= strlen(s) + 1; 8680 char *rtn = funcstring;
8302 return strcpy(funcstring_end, s); 8681
8682 if (!s)
8683 return NULL;
8684 strcpy(funcstring, s);
8685 funcstring += strlen(s) + 1;
8686 return rtn;
8303} 8687}
8304 8688
8305static union node *copynode(union node *); 8689static union node *copynode(union node *);
8306 8690
8691#if ENABLE_PLATFORM_MINGW32
8692# define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (char *)&(dst);}
8693# define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);}}
8694# define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);}}
8695# define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);*nodeptr++ = (char *)&(dst4);}}
8696#else
8697# define SAVE_PTR(dst)
8698# define SAVE_PTR2(dst,dst2)
8699# define SAVE_PTR3(dst,dst2,dst3)
8700# define SAVE_PTR4(dst,dst2,dst3,dst4)
8701#endif
8702
8307static struct nodelist * 8703static struct nodelist *
8308copynodelist(struct nodelist *lp) 8704copynodelist(struct nodelist *lp)
8309{ 8705{
@@ -8315,6 +8711,7 @@ copynodelist(struct nodelist *lp)
8315 *lpp = funcblock; 8711 *lpp = funcblock;
8316 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); 8712 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8317 (*lpp)->n = copynode(lp->n); 8713 (*lpp)->n = copynode(lp->n);
8714 SAVE_PTR2((*lpp)->n, (*lpp)->next);
8318 lp = lp->next; 8715 lp = lp->next;
8319 lpp = &(*lpp)->next; 8716 lpp = &(*lpp)->next;
8320 } 8717 }
@@ -8337,16 +8734,19 @@ copynode(union node *n)
8337 new->ncmd.redirect = copynode(n->ncmd.redirect); 8734 new->ncmd.redirect = copynode(n->ncmd.redirect);
8338 new->ncmd.args = copynode(n->ncmd.args); 8735 new->ncmd.args = copynode(n->ncmd.args);
8339 new->ncmd.assign = copynode(n->ncmd.assign); 8736 new->ncmd.assign = copynode(n->ncmd.assign);
8737 SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign);
8340 break; 8738 break;
8341 case NPIPE: 8739 case NPIPE:
8342 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 8740 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8343 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; 8741 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8742 SAVE_PTR(new->npipe.cmdlist);
8344 break; 8743 break;
8345 case NREDIR: 8744 case NREDIR:
8346 case NBACKGND: 8745 case NBACKGND:
8347 case NSUBSHELL: 8746 case NSUBSHELL:
8348 new->nredir.redirect = copynode(n->nredir.redirect); 8747 new->nredir.redirect = copynode(n->nredir.redirect);
8349 new->nredir.n = copynode(n->nredir.n); 8748 new->nredir.n = copynode(n->nredir.n);
8749 SAVE_PTR2(new->nredir.redirect,new->nredir.n);
8350 break; 8750 break;
8351 case NAND: 8751 case NAND:
8352 case NOR: 8752 case NOR:
@@ -8355,31 +8755,37 @@ copynode(union node *n)
8355 case NUNTIL: 8755 case NUNTIL:
8356 new->nbinary.ch2 = copynode(n->nbinary.ch2); 8756 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8357 new->nbinary.ch1 = copynode(n->nbinary.ch1); 8757 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8758 SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2);
8358 break; 8759 break;
8359 case NIF: 8760 case NIF:
8360 new->nif.elsepart = copynode(n->nif.elsepart); 8761 new->nif.elsepart = copynode(n->nif.elsepart);
8361 new->nif.ifpart = copynode(n->nif.ifpart); 8762 new->nif.ifpart = copynode(n->nif.ifpart);
8362 new->nif.test = copynode(n->nif.test); 8763 new->nif.test = copynode(n->nif.test);
8764 SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test);
8363 break; 8765 break;
8364 case NFOR: 8766 case NFOR:
8365 new->nfor.var = nodeckstrdup(n->nfor.var); 8767 new->nfor.var = nodeckstrdup(n->nfor.var);
8366 new->nfor.body = copynode(n->nfor.body); 8768 new->nfor.body = copynode(n->nfor.body);
8367 new->nfor.args = copynode(n->nfor.args); 8769 new->nfor.args = copynode(n->nfor.args);
8770 SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args);
8368 break; 8771 break;
8369 case NCASE: 8772 case NCASE:
8370 new->ncase.cases = copynode(n->ncase.cases); 8773 new->ncase.cases = copynode(n->ncase.cases);
8371 new->ncase.expr = copynode(n->ncase.expr); 8774 new->ncase.expr = copynode(n->ncase.expr);
8775 SAVE_PTR2(new->ncase.cases,new->ncase.expr);
8372 break; 8776 break;
8373 case NCLIST: 8777 case NCLIST:
8374 new->nclist.body = copynode(n->nclist.body); 8778 new->nclist.body = copynode(n->nclist.body);
8375 new->nclist.pattern = copynode(n->nclist.pattern); 8779 new->nclist.pattern = copynode(n->nclist.pattern);
8376 new->nclist.next = copynode(n->nclist.next); 8780 new->nclist.next = copynode(n->nclist.next);
8781 SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next);
8377 break; 8782 break;
8378 case NDEFUN: 8783 case NDEFUN:
8379 case NARG: 8784 case NARG:
8380 new->narg.backquote = copynodelist(n->narg.backquote); 8785 new->narg.backquote = copynodelist(n->narg.backquote);
8381 new->narg.text = nodeckstrdup(n->narg.text); 8786 new->narg.text = nodeckstrdup(n->narg.text);
8382 new->narg.next = copynode(n->narg.next); 8787 new->narg.next = copynode(n->narg.next);
8788 SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next);
8383 break; 8789 break;
8384 case NTO: 8790 case NTO:
8385#if ENABLE_ASH_BASH_COMPAT 8791#if ENABLE_ASH_BASH_COMPAT
@@ -8392,6 +8798,7 @@ copynode(union node *n)
8392 new->nfile.fname = copynode(n->nfile.fname); 8798 new->nfile.fname = copynode(n->nfile.fname);
8393 new->nfile.fd = n->nfile.fd; 8799 new->nfile.fd = n->nfile.fd;
8394 new->nfile.next = copynode(n->nfile.next); 8800 new->nfile.next = copynode(n->nfile.next);
8801 SAVE_PTR2(new->nfile.fname,new->nfile.next);
8395 break; 8802 break;
8396 case NTOFD: 8803 case NTOFD:
8397 case NFROMFD: 8804 case NFROMFD:
@@ -8399,15 +8806,18 @@ copynode(union node *n)
8399 new->ndup.dupfd = n->ndup.dupfd; 8806 new->ndup.dupfd = n->ndup.dupfd;
8400 new->ndup.fd = n->ndup.fd; 8807 new->ndup.fd = n->ndup.fd;
8401 new->ndup.next = copynode(n->ndup.next); 8808 new->ndup.next = copynode(n->ndup.next);
8809 SAVE_PTR2(new->ndup.vname,new->ndup.next);
8402 break; 8810 break;
8403 case NHERE: 8811 case NHERE:
8404 case NXHERE: 8812 case NXHERE:
8405 new->nhere.doc = copynode(n->nhere.doc); 8813 new->nhere.doc = copynode(n->nhere.doc);
8406 new->nhere.fd = n->nhere.fd; 8814 new->nhere.fd = n->nhere.fd;
8407 new->nhere.next = copynode(n->nhere.next); 8815 new->nhere.next = copynode(n->nhere.next);
8816 SAVE_PTR2(new->nhere.doc,new->nhere.next);
8408 break; 8817 break;
8409 case NNOT: 8818 case NNOT:
8410 new->nnot.com = copynode(n->nnot.com); 8819 new->nnot.com = copynode(n->nnot.com);
8820 SAVE_PTR(new->nnot.com);
8411 break; 8821 break;
8412 }; 8822 };
8413 new->type = n->type; 8823 new->type = n->type;
@@ -8423,13 +8833,16 @@ copyfunc(union node *n)
8423 struct funcnode *f; 8833 struct funcnode *f;
8424 size_t blocksize; 8834 size_t blocksize;
8425 8835
8426 /*funcstringsize = 0;*/ 8836 funcblocksize = offsetof(struct funcnode, n);
8427 blocksize = offsetof(struct funcnode, n) + calcsize(0, n); 8837 funcstringsize = 0;
8428 f = ckzalloc(blocksize /* + funcstringsize */); 8838 calcsize(n);
8839 blocksize = funcblocksize;
8840 f = ckmalloc(blocksize + funcstringsize);
8429 funcblock = (char *) f + offsetof(struct funcnode, n); 8841 funcblock = (char *) f + offsetof(struct funcnode, n);
8430 funcstring_end = (char *) f + blocksize; 8842 funcstring = (char *) f + blocksize;
8843 IF_PLATFORM_MINGW32(nodeptr = NULL);
8431 copynode(n); 8844 copynode(n);
8432 /* f->count = 0; - ckzalloc did it */ 8845 f->count = 0;
8433 return f; 8846 return f;
8434} 8847}
8435 8848
@@ -8799,6 +9212,7 @@ evalcase(union node *n, int flags)
8799static int 9212static int
8800evalsubshell(union node *n, int flags) 9213evalsubshell(union node *n, int flags)
8801{ 9214{
9215 IF_PLATFORM_MINGW32(struct forkshell fs;)
8802 struct job *jp; 9216 struct job *jp;
8803 int backgnd = (n->type == NBACKGND); 9217 int backgnd = (n->type == NBACKGND);
8804 int status; 9218 int status;
@@ -8808,12 +9222,22 @@ evalsubshell(union node *n, int flags)
8808 goto nofork; 9222 goto nofork;
8809 INT_OFF; 9223 INT_OFF;
8810 jp = makejob(/*n,*/ 1); 9224 jp = makejob(/*n,*/ 1);
9225#if ENABLE_PLATFORM_MINGW32
9226 memset(&fs, 0, sizeof(fs));
9227 fs.fpid = FS_EVALSUBSHELL;
9228 fs.n = n;
9229 fs.flags = flags;
9230 if (spawn_forkshell(jp, &fs, backgnd) < 0)
9231 ash_msg_and_raise_error("unable to spawn shell");
9232 if ( 0 ) {
9233#else
8811 if (forkshell(jp, n, backgnd) == 0) { 9234 if (forkshell(jp, n, backgnd) == 0) {
8812 /* child */ 9235 /* child */
8813 INT_ON; 9236 INT_ON;
8814 flags |= EV_EXIT; 9237 flags |= EV_EXIT;
8815 if (backgnd) 9238 if (backgnd)
8816 flags &= ~EV_TESTED; 9239 flags &= ~EV_TESTED;
9240#endif
8817 nofork: 9241 nofork:
8818 redirect(n->nredir.redirect, 0); 9242 redirect(n->nredir.redirect, 0);
8819 evaltreenr(n->nredir.n, flags); 9243 evaltreenr(n->nredir.n, flags);
@@ -8899,6 +9323,7 @@ expredir(union node *n)
8899static int 9323static int
8900evalpipe(union node *n, int flags) 9324evalpipe(union node *n, int flags)
8901{ 9325{
9326 IF_PLATFORM_MINGW32(struct forkshell fs;)
8902 struct job *jp; 9327 struct job *jp;
8903 struct nodelist *lp; 9328 struct nodelist *lp;
8904 int pipelen; 9329 int pipelen;
@@ -8923,6 +9348,17 @@ evalpipe(union node *n, int flags)
8923 ash_msg_and_raise_error("pipe call failed"); 9348 ash_msg_and_raise_error("pipe call failed");
8924 } 9349 }
8925 } 9350 }
9351#if ENABLE_PLATFORM_MINGW32
9352 memset(&fs, 0, sizeof(fs));
9353 fs.fpid = FS_EVALPIPE;
9354 fs.flags = flags;
9355 fs.n = lp->n;
9356 fs.fd[0] = pip[0];
9357 fs.fd[1] = pip[1];
9358 fs.fd[2] = prevfd;
9359 if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0)
9360 ash_msg_and_raise_error("unable to spawn shell");
9361#else
8926 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { 9362 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8927 INT_ON; 9363 INT_ON;
8928 if (pip[1] >= 0) { 9364 if (pip[1] >= 0) {
@@ -8939,6 +9375,7 @@ evalpipe(union node *n, int flags)
8939 evaltreenr(lp->n, flags); 9375 evaltreenr(lp->n, flags);
8940 /* never returns */ 9376 /* never returns */
8941 } 9377 }
9378#endif
8942 if (prevfd >= 0) 9379 if (prevfd >= 0)
8943 close(prevfd); 9380 close(prevfd);
8944 prevfd = pip[0]; 9381 prevfd = pip[0];
@@ -9404,6 +9841,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9404 * as POSIX mandates */ 9841 * as POSIX mandates */
9405 return back_exitstatus; 9842 return back_exitstatus;
9406} 9843}
9844
9407static int 9845static int
9408evalcommand(union node *cmd, int flags) 9846evalcommand(union node *cmd, int flags)
9409{ 9847{
@@ -9584,6 +10022,27 @@ evalcommand(union node *cmd, int flags)
9584 * in a script or a subshell does not need forking, 10022 * in a script or a subshell does not need forking,
9585 * we can just exec it. 10023 * we can just exec it.
9586 */ 10024 */
10025#if ENABLE_PLATFORM_MINGW32
10026 if (!(flags & EV_EXIT) || trap[0]) {
10027 /* No, forking off a child is necessary */
10028 struct forkshell fs;
10029
10030 memset(&fs, 0, sizeof(fs));
10031 fs.fpid = FS_SHELLEXEC;
10032 fs.argv = argv;
10033 fs.string = (char*)path;
10034 fs.fd[0] = cmdentry.u.index;
10035 fs.strlist = varlist.list;
10036 jp = makejob(/*cmd,*/ 1);
10037 if (spawn_forkshell(jp, &fs, FORK_FG) < 0)
10038 ash_msg_and_raise_error("unable to spawn shell");
10039 exitstatus = waitforjob(jp);
10040 INT_ON;
10041 TRACE(("forked child exited with %d\n", exitstatus));
10042 break;
10043 }
10044 /* goes through to shellexec() */
10045#else
9587 if (!(flags & EV_EXIT) || may_have_traps) { 10046 if (!(flags & EV_EXIT) || may_have_traps) {
9588 /* No, forking off a child is necessary */ 10047 /* No, forking off a child is necessary */
9589 INT_OFF; 10048 INT_OFF;
@@ -9599,6 +10058,7 @@ evalcommand(union node *cmd, int flags)
9599 FORCE_INT_ON; 10058 FORCE_INT_ON;
9600 /* fall through to exec'ing external program */ 10059 /* fall through to exec'ing external program */
9601 } 10060 }
10061#endif
9602 listsetvar(varlist.list, VEXPORT|VSTACK); 10062 listsetvar(varlist.list, VEXPORT|VSTACK);
9603 shellexec(argv, path, cmdentry.u.index); 10063 shellexec(argv, path, cmdentry.u.index);
9604 /* NOTREACHED */ 10064 /* NOTREACHED */
@@ -9990,7 +10450,7 @@ preadbuffer(void)
9990 more--; 10450 more--;
9991 10451
9992 c = *q; 10452 c = *q;
9993 if (c == '\0') { 10453 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) {
9994 memmove(q, q + 1, more); 10454 memmove(q, q + 1, more);
9995 } else { 10455 } else {
9996 q++; 10456 q++;
@@ -10174,6 +10634,7 @@ popallfiles(void)
10174 popfile(); 10634 popfile();
10175} 10635}
10176 10636
10637#if !ENABLE_PLATFORM_MINGW32
10177/* 10638/*
10178 * Close the file(s) that the shell is reading commands from. Called 10639 * Close the file(s) that the shell is reading commands from. Called
10179 * after a fork is done. 10640 * after a fork is done.
@@ -10187,6 +10648,7 @@ closescript(void)
10187 g_parsefile->pf_fd = 0; 10648 g_parsefile->pf_fd = 0;
10188 } 10649 }
10189} 10650}
10651#endif
10190 10652
10191/* 10653/*
10192 * Like setinputfile, but takes an open file descriptor. Call this with 10654 * Like setinputfile, but takes an open file descriptor. Call this with
@@ -12437,7 +12899,7 @@ find_dot_file(char *name)
12437 struct stat statb; 12899 struct stat statb;
12438 12900
12439 /* don't try this for absolute or relative paths */ 12901 /* don't try this for absolute or relative paths */
12440 if (strchr(name, '/')) 12902 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\')))
12441 return name; 12903 return name;
12442 12904
12443 /* IIRC standards do not say whether . is to be searched. 12905 /* IIRC standards do not say whether . is to be searched.
@@ -12558,10 +13020,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12558 struct stat statb; 13020 struct stat statb;
12559 int e; 13021 int e;
12560 int updatetbl; 13022 int updatetbl;
13023 IF_PLATFORM_MINGW32(int len;)
12561 struct builtincmd *bcmd; 13024 struct builtincmd *bcmd;
12562 13025
12563 /* If name contains a slash, don't use PATH or hash table */ 13026 /* If name contains a slash, don't use PATH or hash table */
12564 if (strchr(name, '/') != NULL) { 13027 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) {
12565 entry->u.index = -1; 13028 entry->u.index = -1;
12566 if (act & DO_ABS) { 13029 if (act & DO_ABS) {
12567 while (stat(name, &statb) < 0) { 13030 while (stat(name, &statb) < 0) {
@@ -12630,7 +13093,9 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12630#if ENABLE_FEATURE_SH_STANDALONE 13093#if ENABLE_FEATURE_SH_STANDALONE
12631 { 13094 {
12632 int applet_no = find_applet_by_name(name); 13095 int applet_no = find_applet_by_name(name);
12633 if (applet_no >= 0) { 13096 if (applet_no >= 0 ||
13097 /* requires find_applet_by_name to return -1 on no match */
13098 (ENABLE_PLATFORM_MINGW32 && strcmp(name, "busybox") == 0)) {
12634 entry->cmdtype = CMDNORMAL; 13099 entry->cmdtype = CMDNORMAL;
12635 entry->u.index = -2 - applet_no; 13100 entry->u.index = -2 - applet_no;
12636 return; 13101 return;
@@ -12668,12 +13133,48 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12668 } 13133 }
12669 } 13134 }
12670 /* if rehash, don't redo absolute path names */ 13135 /* if rehash, don't redo absolute path names */
12671 if (fullname[0] == '/' && idx <= prev) { 13136 if (is_absolute_path(fullname) && idx <= prev) {
12672 if (idx < prev) 13137 if (idx < prev)
12673 continue; 13138 continue;
12674 TRACE(("searchexec \"%s\": no change\n", name)); 13139 TRACE(("searchexec \"%s\": no change\n", name));
12675 goto success; 13140 goto success;
12676 } 13141 }
13142#if ENABLE_PLATFORM_MINGW32
13143 len = strlen(fullname);
13144 if (len > 4 &&
13145 (!strcasecmp(fullname+len-4, ".exe") ||
13146 !strcasecmp(fullname+len-4, ".com"))) {
13147 if (stat(fullname, &statb) < 0) {
13148 if (errno != ENOENT && errno != ENOTDIR)
13149 e = errno;
13150 goto loop;
13151 }
13152 }
13153 else {
13154 /* path_advance() has reserved space for .exe */
13155 memcpy(fullname+len, ".exe", 5);
13156 if (stat(fullname, &statb) < 0) {
13157 if (errno != ENOENT && errno != ENOTDIR)
13158 e = errno;
13159 memcpy(fullname+len, ".com", 5);
13160 if (stat(fullname, &statb) < 0) {
13161 if (errno != ENOENT && errno != ENOTDIR)
13162 e = errno;
13163 fullname[len] = '\0';
13164 if (stat(fullname, &statb) < 0) {
13165 if (errno != ENOENT && errno != ENOTDIR)
13166 e = errno;
13167 goto loop;
13168 }
13169 if (!file_is_executable(fullname)) {
13170 e = ENOEXEC;
13171 goto loop;
13172 }
13173 }
13174 }
13175 fullname[len] = '\0';
13176 }
13177#else
12677 while (stat(fullname, &statb) < 0) { 13178 while (stat(fullname, &statb) < 0) {
12678#ifdef SYSV 13179#ifdef SYSV
12679 if (errno == EINTR) 13180 if (errno == EINTR)
@@ -12683,6 +13184,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12683 e = errno; 13184 e = errno;
12684 goto loop; 13185 goto loop;
12685 } 13186 }
13187#endif
12686 e = EACCES; /* if we fail, this will be the error */ 13188 e = EACCES; /* if we fail, this will be the error */
12687 if (!S_ISREG(statb.st_mode)) 13189 if (!S_ISREG(statb.st_mode))
12688 continue; 13190 continue;
@@ -13189,7 +13691,11 @@ exitshell(void)
13189} 13691}
13190 13692
13191static void 13693static void
13694#if ENABLE_PLATFORM_MINGW32
13695init(int xp)
13696#else
13192init(void) 13697init(void)
13698#endif
13193{ 13699{
13194 /* we will never free this */ 13700 /* we will never free this */
13195 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); 13701 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
@@ -13206,6 +13712,86 @@ init(void)
13206 struct stat st1, st2; 13712 struct stat st1, st2;
13207 13713
13208 initvar(); 13714 initvar();
13715
13716#if ENABLE_PLATFORM_MINGW32
13717 /*
13718 * case insensitive env names from Windows world
13719 *
13720 * Some standard env names such as PATH is named Path and so on
13721 * ash itself is case sensitive, so "Path" will confuse it, as
13722 * MSVC getenv() is case insensitive.
13723 *
13724 * We may end up having both Path and PATH. Then Path will be chosen
13725 * because it appears first.
13726 */
13727 for (envp = environ; envp && *envp; envp++) {
13728 if (strncasecmp(*envp, "PATH=", 5) == 0 &&
13729 strncmp(*envp, "PATH=", 5) != 0) {
13730 break;
13731 }
13732 }
13733
13734 if (envp && *envp) {
13735 /*
13736 * If we get here it's because the environment contains a path
13737 * variable called something other than PATH. This suggests we
13738 * haven't been invoked from an earlier instance of BusyBox.
13739 */
13740 char *start, *end, *s;
13741 struct passwd *pw;
13742
13743 for (envp = environ; envp && *envp; envp++) {
13744 if (!(end=strchr(*envp, '=')))
13745 continue;
13746
13747 /* make all variable names uppercase */
13748 for (start = *envp;start < end;start++)
13749 *start = toupper(*start);
13750
13751 /* skip conversion of variables known to cause problems */
13752 if ( strncmp(*envp, "SYSTEMROOT=", 11) == 0 ||
13753 strncmp(*envp, "COMSPEC=", 8) == 0 ) {
13754 continue;
13755 }
13756
13757 /* convert backslashes to forward slashes in value */
13758 if (!xp) {
13759 for ( s=end+1; *s; ++s ) {
13760 if ( *s == '\\' ) {
13761 *s = '/';
13762 }
13763 }
13764 }
13765
13766 /* check for invalid characters in name */
13767 for (start = *envp;start < end;start++) {
13768 if (!isdigit(*start) && !isalpha(*start) && *start != '_') {
13769 break;
13770 }
13771 }
13772
13773 if (start != end) {
13774 /*
13775 * Make a copy of the variable, replacing invalid
13776 * characters in the name with underscores.
13777 */
13778 char *var = xstrdup(*envp);
13779
13780 for (start = var;*start != '=';start++) {
13781 if (!isdigit(*start) && !isalpha(*start)) {
13782 *start = '_';
13783 }
13784 }
13785 setvareq(var, VEXPORT|VNOSAVE);
13786 }
13787 }
13788
13789 /* some initialisation normally performed at login */
13790 pw = xgetpwuid(getuid());
13791 setup_environment(pw->pw_shell,
13792 SETUP_ENV_CHANGEENV|SETUP_ENV_NO_CHDIR, pw);
13793 }
13794#endif
13209 for (envp = environ; envp && *envp; envp++) { 13795 for (envp = environ; envp && *envp; envp++) {
13210 p = endofname(*envp); 13796 p = endofname(*envp);
13211 if (p != *envp && *p == '=') { 13797 if (p != *envp && *p == '=') {
@@ -13420,15 +14006,40 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13420#endif 14006#endif
13421 rootpid = getpid(); 14007 rootpid = getpid();
13422 14008
13423 init(); 14009 init(IF_PLATFORM_MINGW32(argc >= 2 && strcmp(argv[1], "-X") == 0));
13424 setstackmark(&smark); 14010 setstackmark(&smark);
14011
14012#if ENABLE_PLATFORM_MINGW32
14013 hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL);
14014 SetConsoleCtrlHandler(ctrl_handler, TRUE);
14015 if (argc == 3 && !strcmp(argv[1], "--forkshell")) {
14016 forkshell_init(argv[2]);
14017
14018 /* NOTREACHED */
14019 bb_error_msg_and_die("subshell ended unexpectedly");
14020 }
14021#endif
13425 procargs(argv); 14022 procargs(argv);
14023#if ENABLE_PLATFORM_MINGW32
14024 if ( noconsole ) {
14025 DWORD dummy;
14026
14027 if ( GetConsoleProcessList(&dummy, 1) == 1 ) {
14028 ShowWindow(GetConsoleWindow(), SW_HIDE);
14029 }
14030 }
14031#endif
13426 14032
13427 if (argv[0] && argv[0][0] == '-') 14033 if (argv[0] && argv[0][0] == '-')
13428 isloginsh = 1; 14034 isloginsh = 1;
13429 if (isloginsh) { 14035 if (isloginsh) {
13430 const char *hp; 14036 const char *hp;
13431 14037
14038#if ENABLE_PLATFORM_MINGW32
14039 chdir(xgetpwuid(getuid())->pw_dir);
14040 setpwd(NULL, 0);
14041#endif
14042
13432 state = 1; 14043 state = 1;
13433 read_profile("/etc/profile"); 14044 read_profile("/etc/profile");
13434 state1: 14045 state1:
@@ -13504,6 +14115,643 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13504 /* NOTREACHED */ 14115 /* NOTREACHED */
13505} 14116}
13506 14117
14118#if ENABLE_PLATFORM_MINGW32
14119static void
14120forkshell_openhere(struct forkshell *fs)
14121{
14122 union node *redir = fs->n;
14123 int pip[2];
14124
14125 pip[0] = fs->fd[0];
14126 pip[1] = fs->fd[1];
14127
14128 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14129
14130 close(pip[0]);
14131 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
14132 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
14133 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
14134 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
14135 signal(SIGPIPE, SIG_DFL);
14136 if (redir->type == NHERE) {
14137 size_t len = strlen(redir->nhere.doc->narg.text);
14138 full_write(pip[1], redir->nhere.doc->narg.text, len);
14139 } else /* NXHERE */
14140 expandhere(redir->nhere.doc, pip[1]);
14141 _exit(EXIT_SUCCESS);
14142}
14143
14144static void
14145forkshell_evalbackcmd(struct forkshell *fs)
14146{
14147 union node *n = fs->n;
14148 int pip[2] = {fs->fd[0], fs->fd[1]};
14149
14150 FORCE_INT_ON;
14151 close(pip[0]);
14152 if (pip[1] != 1) {
14153 /*close(1);*/
14154 copyfd(pip[1], 1 | COPYFD_EXACT);
14155 close(pip[1]);
14156 }
14157 eflag = 0;
14158 evaltree(n, EV_EXIT); /* actually evaltreenr... */
14159 /* NOTREACHED */
14160}
14161
14162static void
14163forkshell_evalsubshell(struct forkshell *fs)
14164{
14165 union node *n = fs->n;
14166 int flags = fs->flags;
14167
14168 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14169 INT_ON;
14170 flags |= EV_EXIT;
14171 expredir(n->nredir.redirect);
14172 redirect(n->nredir.redirect, 0);
14173 evaltreenr(n->nredir.n, flags);
14174 /* never returns */
14175}
14176
14177static void
14178forkshell_evalpipe(struct forkshell *fs)
14179{
14180 union node *n = fs->n;
14181 int flags = fs->flags;
14182 int prevfd = fs->fd[2];
14183 int pip[2] = {fs->fd[0], fs->fd[1]};
14184
14185 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14186 INT_ON;
14187 if (pip[1] >= 0) {
14188 close(pip[0]);
14189 }
14190 if (prevfd > 0) {
14191 dup2(prevfd, 0);
14192 close(prevfd);
14193 }
14194 if (pip[1] > 1) {
14195 dup2(pip[1], 1);
14196 close(pip[1]);
14197 }
14198 evaltreenr(n, flags);
14199}
14200
14201static void
14202forkshell_shellexec(struct forkshell *fs)
14203{
14204 int idx = fs->fd[0];
14205 struct strlist *varlist = fs->strlist;
14206 char **argv = fs->argv;
14207 char *path = fs->string;
14208
14209 listsetvar(varlist, VEXPORT|VSTACK);
14210 shellexec(argv, path, idx);
14211}
14212
14213static void
14214forkshell_child(struct forkshell *fs)
14215{
14216 switch ( fs->fpid ) {
14217 case FS_OPENHERE:
14218 forkshell_openhere(fs);
14219 break;
14220 case FS_EVALBACKCMD:
14221 forkshell_evalbackcmd(fs);
14222 break;
14223 case FS_EVALSUBSHELL:
14224 forkshell_evalsubshell(fs);
14225 break;
14226 case FS_EVALPIPE:
14227 forkshell_evalpipe(fs);
14228 break;
14229 case FS_SHELLEXEC:
14230 forkshell_shellexec(fs);
14231 break;
14232 }
14233}
14234
14235/*
14236 * Reset the pointers to the builtin environment variables in the hash
14237 * table to point to varinit rather than the bogus copy created during
14238 * forkshell_prepare.
14239 */
14240static void
14241reinitvar(void)
14242{
14243 struct var *vp;
14244 struct var *end;
14245 struct var **vpp;
14246 struct var **old;
14247
14248 vp = varinit;
14249 end = vp + ARRAY_SIZE(varinit);
14250 do {
14251 vpp = hashvar(vp->var_text);
14252 if ( (old=findvar(vpp, vp->var_text)) != NULL ) {
14253 vp->next = (*old)->next;
14254 *old = vp;
14255 }
14256 } while (++vp < end);
14257}
14258
14259/* FIXME: should consider running forkparent() and forkchild() */
14260static int
14261spawn_forkshell(struct job *jp, struct forkshell *fs, int mode)
14262{
14263 struct forkshell *new;
14264 char buf[16];
14265 const char *argv[] = { "sh", "--forkshell", NULL, NULL };
14266 intptr_t ret;
14267
14268 new = forkshell_prepare(fs);
14269 sprintf(buf, "%x", (unsigned int)new->hMapFile);
14270 argv[2] = buf;
14271 ret = mingw_spawn_proc(argv);
14272 CloseHandle(new->hMapFile);
14273 UnmapViewOfFile(new);
14274 if (ret == -1) {
14275 free(jp);
14276 return -1;
14277 }
14278 forkparent(jp, fs->node, mode, (HANDLE)ret);
14279 return ret == -1 ? -1 : 0;
14280}
14281
14282/*
14283 * forkshell_prepare() and friends
14284 *
14285 * The sequence is as follows:
14286 * - funcblocksize, funcstringsize, nodeptrsize are initialized
14287 * - forkshell_size(fs) is called to calculate the exact memory needed
14288 * - a new struct is allocated
14289 * - funcblock, funcstring, nodeptr are initialized from the new block
14290 * - forkshell_copy(fs) is called to copy recursively everything over
14291 * it will record all pointers along the way, to nodeptr
14292 *
14293 * When this memory is mapped elsewhere, pointer fixup will be needed
14294 */
14295#define SLIST_SIZE_BEGIN(name,type) \
14296static void \
14297name(type *p) \
14298{ \
14299 while (p) { \
14300 funcblocksize += sizeof(type);
14301 /* do something here with p */
14302#define SLIST_SIZE_END() \
14303 nodeptrsize++; \
14304 p = p->next; \
14305 } \
14306}
14307
14308#define SLIST_COPY_BEGIN(name,type) \
14309static type * \
14310name(type *vp) \
14311{ \
14312 type *start; \
14313 type **vpp; \
14314 vpp = &start; \
14315 while (vp) { \
14316 *vpp = funcblock; \
14317 funcblock = (char *) funcblock + sizeof(type);
14318 /* do something here with vpp and vp */
14319#define SLIST_COPY_END() \
14320 SAVE_PTR((*vpp)->next); \
14321 vp = vp->next; \
14322 vpp = &(*vpp)->next; \
14323 } \
14324 *vpp = NULL; \
14325 return start; \
14326}
14327
14328/*
14329 * struct var
14330 */
14331SLIST_SIZE_BEGIN(var_size,struct var)
14332funcstringsize += strlen(p->var_text) + 1;
14333nodeptrsize++; /* p->text */
14334SLIST_SIZE_END()
14335
14336SLIST_COPY_BEGIN(var_copy,struct var)
14337(*vpp)->var_text = nodeckstrdup(vp->var_text);
14338(*vpp)->flags = vp->flags;
14339/*
14340 * The only place that can set struct var#func is varinit[],
14341 * which will be fixed by forkshell_init()
14342 */
14343(*vpp)->var_func = NULL;
14344SAVE_PTR((*vpp)->var_text);
14345SLIST_COPY_END()
14346
14347/*
14348 * struct strlist
14349 */
14350SLIST_SIZE_BEGIN(strlist_size,struct strlist)
14351funcstringsize += strlen(p->text) + 1;
14352nodeptrsize++; /* p->text */
14353SLIST_SIZE_END()
14354
14355SLIST_COPY_BEGIN(strlist_copy,struct strlist)
14356(*vpp)->text = nodeckstrdup(vp->text);
14357SAVE_PTR((*vpp)->text);
14358SLIST_COPY_END()
14359
14360/*
14361 * struct tblentry
14362 */
14363static void
14364tblentry_size(struct tblentry *tep)
14365{
14366 while (tep) {
14367 funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14368 /* CMDBUILTIN, e->param.cmd needs no pointer relocation */
14369 if (tep->cmdtype == CMDFUNCTION) {
14370 funcblocksize += offsetof(struct funcnode, n);
14371 calcsize(&tep->param.func->n);
14372 nodeptrsize++; /* tep->param.func */
14373 }
14374 nodeptrsize++; /* tep->next */
14375 tep = tep->next;
14376 }
14377}
14378
14379static struct tblentry *
14380tblentry_copy(struct tblentry *tep)
14381{
14382 struct tblentry *start;
14383 struct tblentry **newp;
14384 int size;
14385
14386 newp = &start;
14387 while (tep) {
14388 *newp = funcblock;
14389 size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14390
14391 funcblock = (char *) funcblock + size;
14392 memcpy(*newp, tep, size);
14393 switch (tep->cmdtype) {
14394 case CMDBUILTIN:
14395 /* No pointer saving, this field must be fixed by forkshell_init() */
14396 (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab);
14397 break;
14398 case CMDFUNCTION:
14399 (*newp)->param.func = funcblock;
14400 funcblock = (char *) funcblock + offsetof(struct funcnode, n);
14401 copynode(&tep->param.func->n);
14402 SAVE_PTR((*newp)->param.func);
14403 break;
14404 default:
14405 break;
14406 }
14407 SAVE_PTR((*newp)->next);
14408 tep = tep->next;
14409 newp = &(*newp)->next;
14410 }
14411 *newp = NULL;
14412 return start;
14413}
14414
14415static void
14416cmdtable_size(struct tblentry **cmdtablep)
14417{
14418 int i;
14419 nodeptrsize += CMDTABLESIZE;
14420 funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE;
14421 for (i = 0; i < CMDTABLESIZE; i++)
14422 tblentry_size(cmdtablep[i]);
14423}
14424
14425static struct tblentry **
14426cmdtable_copy(struct tblentry **cmdtablep)
14427{
14428 struct tblentry **new = funcblock;
14429 int i;
14430
14431 funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE;
14432 for (i = 0; i < CMDTABLESIZE; i++) {
14433 new[i] = tblentry_copy(cmdtablep[i]);
14434 SAVE_PTR(new[i]);
14435 }
14436 return new;
14437}
14438
14439/*
14440 * char **
14441 */
14442static void
14443argv_size(char **p)
14444{
14445 while (p && *p) {
14446 funcblocksize += sizeof(char *);
14447 funcstringsize += strlen(*p)+1;
14448 nodeptrsize++;
14449 p++;
14450 }
14451 funcblocksize += sizeof(char *);
14452}
14453
14454static char **
14455argv_copy(char **p)
14456{
14457 char **new, **start = funcblock;
14458
14459 while (p && *p) {
14460 new = funcblock;
14461 funcblock = (char *) funcblock + sizeof(char *);
14462 *new = nodeckstrdup(*p);
14463 SAVE_PTR(*new);
14464 p++;
14465 new++;
14466 }
14467 new = funcblock;
14468 funcblock = (char *) funcblock + sizeof(char *);
14469 *new = NULL;
14470 return start;
14471}
14472
14473/*
14474 * struct redirtab
14475 */
14476static void
14477redirtab_size(struct redirtab *rdtp)
14478{
14479 while (rdtp) {
14480 funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14481 rdtp = rdtp->next;
14482 nodeptrsize++; /* rdtp->next */
14483 }
14484}
14485
14486static struct redirtab *
14487redirtab_copy(struct redirtab *rdtp)
14488{
14489 struct redirtab *start;
14490 struct redirtab **vpp;
14491
14492 vpp = &start;
14493 while (rdtp) {
14494 int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14495 *vpp = funcblock;
14496 funcblock = (char *) funcblock + size;
14497 memcpy(*vpp, rdtp, size);
14498 SAVE_PTR((*vpp)->next);
14499 rdtp = rdtp->next;
14500 vpp = &(*vpp)->next;
14501 }
14502 *vpp = NULL;
14503 return start;
14504}
14505
14506#undef shellparam
14507#undef redirlist
14508#undef varinit
14509#undef vartab
14510static void
14511globals_var_size(struct globals_var *gvp)
14512{
14513 int i;
14514
14515 funcblocksize += sizeof(struct globals_var);
14516 argv_size(gvp->shellparam.p);
14517 redirtab_size(gvp->redirlist);
14518 for (i = 0; i < VTABSIZE; i++)
14519 var_size(gvp->vartab[i]);
14520 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14521 var_size(gvp->varinit+i);
14522 nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */
14523}
14524
14525#undef g_nullredirs
14526#undef preverrout_fd
14527static struct globals_var *
14528globals_var_copy(struct globals_var *gvp)
14529{
14530 int i;
14531 struct globals_var *new;
14532
14533 new = funcblock;
14534 funcblock = (char *) funcblock + sizeof(struct globals_var);
14535
14536 /* shparam */
14537 memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam));
14538 new->shellparam.malloced = 0;
14539 new->shellparam.p = argv_copy(gvp->shellparam.p);
14540 SAVE_PTR(new->shellparam.p);
14541
14542 new->redirlist = redirtab_copy(gvp->redirlist);
14543 SAVE_PTR(new->redirlist);
14544
14545 new->g_nullredirs = gvp->g_nullredirs;
14546 new->preverrout_fd = gvp->preverrout_fd;
14547 for (i = 0; i < VTABSIZE; i++) {
14548 new->vartab[i] = var_copy(gvp->vartab[i]);
14549 SAVE_PTR(new->vartab[i]);
14550 }
14551
14552 /* Can't use var_copy because varinit is already allocated */
14553 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) {
14554 new->varinit[i].next = NULL;
14555 new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text);
14556 SAVE_PTR(new->varinit[i].var_text);
14557 new->varinit[i].flags = gvp->varinit[i].flags;
14558 new->varinit[i].var_func = gvp->varinit[i].var_func;
14559 }
14560 return new;
14561}
14562
14563#undef minusc
14564#undef curdir
14565#undef physdir
14566#undef arg0
14567#undef nullstr
14568static void
14569globals_misc_size(struct globals_misc *p)
14570{
14571 funcblocksize += sizeof(struct globals_misc);
14572 funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1;
14573 if (p->curdir != p->nullstr)
14574 funcstringsize += strlen(p->curdir) + 1;
14575 if (p->physdir != p->nullstr)
14576 funcstringsize += strlen(p->physdir) + 1;
14577 funcstringsize += strlen(p->arg0) + 1;
14578 nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */
14579}
14580
14581static struct globals_misc *
14582globals_misc_copy(struct globals_misc *p)
14583{
14584 struct globals_misc *new = funcblock;
14585
14586 funcblock = (char *) funcblock + sizeof(struct globals_misc);
14587 memcpy(new, p, sizeof(struct globals_misc));
14588
14589 new->minusc = nodeckstrdup(p->minusc);
14590 new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr;
14591 new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr;
14592 new->arg0 = nodeckstrdup(p->arg0);
14593 SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0);
14594 return new;
14595}
14596
14597static void
14598forkshell_size(struct forkshell *fs)
14599{
14600 funcblocksize += sizeof(struct forkshell);
14601 globals_var_size(fs->gvp);
14602 globals_misc_size(fs->gmp);
14603 cmdtable_size(fs->cmdtable);
14604 /* optlist_transfer(sending, fd); */
14605 /* misc_transfer(sending, fd); */
14606
14607 calcsize(fs->n);
14608 argv_size(fs->argv);
14609 funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1;
14610 strlist_size(fs->strlist);
14611
14612 nodeptrsize += 7; /* gvp, gmp, cmdtable, n, argv, string, strlist */
14613}
14614
14615static struct forkshell *
14616forkshell_copy(struct forkshell *fs)
14617{
14618 struct forkshell *new;
14619
14620 new = funcblock;
14621 funcblock = (char *) funcblock + sizeof(struct forkshell);
14622
14623 memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */
14624 new->gvp = globals_var_copy(fs->gvp);
14625 new->gmp = globals_misc_copy(fs->gmp);
14626 new->cmdtable = cmdtable_copy(fs->cmdtable);
14627 SAVE_PTR3(new->gvp, new->gmp, new->cmdtable);
14628
14629 new->n = copynode(fs->n);
14630 new->argv = argv_copy(fs->argv);
14631 new->string = nodeckstrdup(fs->string);
14632 new->strlist = strlist_copy(fs->strlist);
14633 SAVE_PTR4(new->n, new->argv, new->string, new->strlist);
14634 return new;
14635}
14636
14637static struct forkshell *
14638forkshell_prepare(struct forkshell *fs)
14639{
14640 struct forkshell *new;
14641 int size, nodeptr_offset;
14642 HANDLE h;
14643 SECURITY_ATTRIBUTES sa;
14644
14645 /* Calculate size of "new" */
14646 fs->gvp = ash_ptr_to_globals_var;
14647 fs->gmp = ash_ptr_to_globals_misc;
14648 fs->cmdtable = cmdtable;
14649
14650 nodeptrsize = 1; /* NULL terminated */
14651 funcblocksize = 0;
14652 funcstringsize = 0;
14653 forkshell_size(fs);
14654 size = funcblocksize + funcstringsize + nodeptrsize*sizeof(char *);
14655
14656 /* Allocate, initialize pointers */
14657 memset(&sa, 0, sizeof(sa));
14658 sa.nLength = sizeof(sa);
14659 sa.lpSecurityDescriptor = NULL;
14660 sa.bInheritHandle = TRUE;
14661 h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL);
14662 new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14663 /* new = ckmalloc(size); */
14664 funcblock = new;
14665 funcstring = (char *) funcblock + funcblocksize;
14666 nodeptr = (char **)((char *)funcstring + funcstringsize);
14667 nodeptr_offset = (char *)nodeptr - (char *)new;
14668
14669 /* Now pack them all */
14670 forkshell_copy(fs);
14671
14672 /* Finish it up */
14673 *nodeptr = NULL;
14674 new->size = size;
14675 new->nodeptr_offset = nodeptr_offset;
14676 new->old_base = new;
14677 new->hMapFile = h;
14678 return new;
14679}
14680
14681#undef exception_handler
14682#undef trap
14683#undef trap_ptr
14684static void *sticky_mem_start, *sticky_mem_end;
14685static void
14686forkshell_init(const char *idstr)
14687{
14688 struct forkshell *fs;
14689 int map_handle;
14690 HANDLE h;
14691 struct globals_var **gvpp;
14692 struct globals_misc **gmpp;
14693 int i;
14694 char **ptr;
14695
14696 if (sscanf(idstr, "%x", &map_handle) != 1)
14697 bb_error_msg_and_die("invalid forkshell ID");
14698
14699 h = (HANDLE)map_handle;
14700 fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14701 if (!fs)
14702 bb_error_msg_and_die("Invalid forkshell memory");
14703
14704 /* this memory can't be freed */
14705 sticky_mem_start = fs;
14706 sticky_mem_end = (char *) fs + fs->size;
14707
14708 /* pointer fixup */
14709 nodeptr = (char **)((char *)fs + fs->nodeptr_offset);
14710 for ( i=0; nodeptr[i]; ++i ) {
14711 ptr = (char **)((char *)fs + (nodeptr[i] - (char *)fs->old_base));
14712 if (*ptr)
14713 *ptr = (char *)fs + (*ptr - (char *)fs->old_base);
14714 }
14715
14716 /* Now fix up stuff that can't be transferred */
14717 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14718 fs->gvp->varinit[i].var_func = varinit_data[i].var_func;
14719 for (i = 0; i < CMDTABLESIZE; i++) {
14720 struct tblentry *e = fs->cmdtable[i];
14721 while (e) {
14722 if (e->cmdtype == CMDBUILTIN)
14723 e->param.cmd = builtintab + (int)e->param.cmd;
14724 e = e->next;
14725 }
14726 }
14727 fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler;
14728 for (i = 0; i < NSIG; i++)
14729 fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i];
14730 fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr;
14731
14732 /* Switch global variables */
14733 gvpp = (struct globals_var **)&ash_ptr_to_globals_var;
14734 *gvpp = fs->gvp;
14735 gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc;
14736 *gmpp = fs->gmp;
14737 cmdtable = fs->cmdtable;
14738
14739 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
14740
14741 reinitvar();
14742
14743 forkshell_child(fs);
14744}
14745
14746#undef free
14747static void
14748sticky_free(void *base)
14749{
14750 if (base >= sticky_mem_start && base < sticky_mem_end)
14751 return;
14752 free(base);
14753}
14754#endif
13507 14755
13508/*- 14756/*-
13509 * Copyright (c) 1989, 1991, 1993, 1994 14757 * Copyright (c) 1989, 1991, 1993, 1994
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 98d862744..5a5b1780d 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -20,7 +20,11 @@
20#include "shell_common.h" 20#include "shell_common.h"
21#include <sys/resource.h> /* getrlimit */ 21#include <sys/resource.h> /* getrlimit */
22 22
23#if !ENABLE_PLATFORM_MINGW32
23const char defifsvar[] ALIGN1 = "IFS= \t\n"; 24const char defifsvar[] ALIGN1 = "IFS= \t\n";
25#else
26const char defifsvar[] ALIGN1 = "IFS= \t\n\r";
27#endif
24const char defoptindvar[] ALIGN1 = "OPTIND=1"; 28const char defoptindvar[] ALIGN1 = "OPTIND=1";
25 29
26 30
@@ -187,6 +191,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
187 * regardless of SA_RESTART-ness of that signal! 191 * regardless of SA_RESTART-ness of that signal!
188 */ 192 */
189 errno = 0; 193 errno = 0;
194#if !ENABLE_PLATFORM_MINGW32
190 pfd[0].fd = fd; 195 pfd[0].fd = fd;
191 pfd[0].events = POLLIN; 196 pfd[0].events = POLLIN;
192 if (poll(pfd, 1, timeout) != 1) { 197 if (poll(pfd, 1, timeout) != 1) {
@@ -195,6 +200,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
195 retval = (const char *)(uintptr_t)1; 200 retval = (const char *)(uintptr_t)1;
196 goto ret; 201 goto ret;
197 } 202 }
203#endif
198 if (read(fd, &buffer[bufpos], 1) != 1) { 204 if (read(fd, &buffer[bufpos], 1) != 1) {
199 err = errno; 205 err = errno;
200 retval = (const char *)(uintptr_t)1; 206 retval = (const char *)(uintptr_t)1;
@@ -202,7 +208,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
202 } 208 }
203 209
204 c = buffer[bufpos]; 210 c = buffer[bufpos];
205 if (c == '\0') 211 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r'))
206 continue; 212 continue;
207 if (backslash) { 213 if (backslash) {
208 backslash = 0; 214 backslash = 0;
@@ -274,6 +280,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
274 280
275/* ulimit builtin */ 281/* ulimit builtin */
276 282
283#if !ENABLE_PLATFORM_MINGW32
277struct limits { 284struct limits {
278 uint8_t cmd; /* RLIMIT_xxx fit into it */ 285 uint8_t cmd; /* RLIMIT_xxx fit into it */
279 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ 286 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
@@ -498,3 +505,9 @@ shell_builtin_ulimit(char **argv)
498 505
499 return 0; 506 return 0;
500} 507}
508#else
509int FAST_FUNC shell_builtin_ulimit(char **argv UNUSED_PARAM)
510{
511 return 1;
512}
513#endif