aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c1377
1 files changed, 1315 insertions, 62 deletions
diff --git a/shell/ash.c b/shell/ash.c
index e6d02f69c..af1157709 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" 34//config: bool "ash"
20//config: default y 35//config: default y
@@ -202,7 +217,7 @@
202 217
203#include "unicode.h" 218#include "unicode.h"
204#include "shell_common.h" 219#include "shell_common.h"
205#if ENABLE_FEATURE_SH_MATH 220#if CONFIG_FEATURE_SH_MATH
206# include "math.h" 221# include "math.h"
207#endif 222#endif
208#if ENABLE_ASH_RANDOM_SUPPORT 223#if ENABLE_ASH_RANDOM_SUPPORT
@@ -227,10 +242,58 @@
227# define PIPE_BUF 4096 /* amount of buffering in a pipe */ 242# define PIPE_BUF 4096 /* amount of buffering in a pipe */
228#endif 243#endif
229 244
245#if !ENABLE_PLATFORM_MINGW32
246# define is_absolute_path(path) ((path)[0] == '/')
247#endif
248
230#if !BB_MMU 249#if !BB_MMU
231# error "Do not even bother, ash will not run on NOMMU machine" 250# error "Do not even bother, ash will not run on NOMMU machine"
232#endif 251#endif
233 252
253#if ENABLE_PLATFORM_MINGW32
254union node;
255struct strlist;
256struct job;
257
258struct forkshell {
259 /* filled by forkshell_copy() */
260 struct globals_var *gvp;
261 struct globals_misc *gmp;
262 struct tblentry **cmdtable;
263 /* struct alias **atab; */
264 /* struct parsefile *g_parsefile; */
265 HANDLE hMapFile;
266 void *old_base;
267 int nodeptr_offset;
268 int size;
269
270 /* type of forkshell */
271 int fpid;
272
273 /* optional data, used by forkshell_child */
274 int flags;
275 int fd[10];
276 union node *n;
277 char **argv;
278 char *string;
279 struct strlist *strlist;
280};
281
282enum {
283 FS_OPENHERE,
284 FS_EVALBACKCMD,
285 FS_EVALSUBSHELL,
286 FS_EVALPIPE,
287 FS_SHELLEXEC
288};
289
290static struct forkshell* forkshell_prepare(struct forkshell *fs);
291static void forkshell_init(const char *idstr);
292static void forkshell_child(struct forkshell *fs);
293static void sticky_free(void *p);
294#define free(p) sticky_free(p)
295static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode);
296#endif
234 297
235/* ============ Hash table sizes. Configurable. */ 298/* ============ Hash table sizes. Configurable. */
236 299
@@ -263,6 +326,10 @@ static const char *const optletters_optnames[] = {
263 ,"\0" "nolog" 326 ,"\0" "nolog"
264 ,"\0" "debug" 327 ,"\0" "debug"
265#endif 328#endif
329#if ENABLE_PLATFORM_MINGW32
330 ,"\0" "noconsole"
331 ,"X" "winxp"
332#endif
266}; 333};
267 334
268#define optletters(n) optletters_optnames[n][0] 335#define optletters(n) optletters_optnames[n][0]
@@ -342,6 +409,10 @@ struct globals_misc {
342# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] 409# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
343# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] 410# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
344#endif 411#endif
412#if ENABLE_PLATFORM_MINGW32
413# define noconsole optlist[14 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
414# define winxp optlist[15 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
415#endif
345 416
346 /* trap handler commands */ 417 /* trap handler commands */
347 /* 418 /*
@@ -2393,10 +2464,22 @@ path_advance(const char **path, const char *name)
2393 if (*path == NULL) 2464 if (*path == NULL)
2394 return NULL; 2465 return NULL;
2395 start = *path; 2466 start = *path;
2467#if ENABLE_PLATFORM_MINGW32
2468 p = next_path_sep(start);
2469 q = strchr(start, '%');
2470 if ((p && q && q < p) || (!p && q))
2471 p = q;
2472 if (!p)
2473 for (p = start; *p; p++)
2474 continue;
2475#else
2396 for (p = start; *p && *p != ':' && *p != '%'; p++) 2476 for (p = start; *p && *p != ':' && *p != '%'; p++)
2397 continue; 2477 continue;
2478#endif
2398 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2479 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2399 while (stackblocksize() < len) 2480
2481 /* preserve space for .exe too */
2482 while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len))
2400 growstackblock(); 2483 growstackblock();
2401 q = stackblock(); 2484 q = stackblock();
2402 if (p != start) { 2485 if (p != start) {
@@ -2408,10 +2491,19 @@ path_advance(const char **path, const char *name)
2408 pathopt = NULL; 2491 pathopt = NULL;
2409 if (*p == '%') { 2492 if (*p == '%') {
2410 pathopt = ++p; 2493 pathopt = ++p;
2494#if ENABLE_PLATFORM_MINGW32
2495 p = next_path_sep(start);
2496
2497 /* *p != ':' and '*' would suffice */
2498 if (!p)
2499 p = pathopt - 1;
2500#else
2411 while (*p && *p != ':') 2501 while (*p && *p != ':')
2412 p++; 2502 p++;
2503#endif
2413 } 2504 }
2414 if (*p == ':') 2505 if (*p == ':' ||
2506 (ENABLE_PLATFORM_MINGW32 && *p == ';'))
2415 *path = p + 1; 2507 *path = p + 1;
2416 else 2508 else
2417 *path = NULL; 2509 *path = NULL;
@@ -2512,6 +2604,106 @@ cdopt(void)
2512static const char * 2604static const char *
2513updatepwd(const char *dir) 2605updatepwd(const char *dir)
2514{ 2606{
2607#if ENABLE_PLATFORM_MINGW32
2608#define is_path_sep(x) ((x) == '/' || (x) == '\\')
2609#define is_unc_path(x) (is_path_sep(x[0]) && is_path_sep(x[1]))
2610 /*
2611 * Due to Windows drive notion, getting pwd is a completely
2612 * different thing. Handle it in a separate routine
2613 */
2614
2615 char *new;
2616 char *p;
2617 char *cdcomppath;
2618 const char *lim;
2619 /*
2620 * There are five cases that make some kind of sense
2621 * absdrive + abspath: c:/path
2622 * absdrive + !abspath: c:path
2623 * !absdrive + abspath: /path
2624 * !absdrive + uncpath: //host/share
2625 * !absdrive + !abspath: path
2626 *
2627 * Damn DOS!
2628 * c:path behaviour is "undefined"
2629 * To properly handle this case, I have to keep track of cwd
2630 * of every drive, which is too painful to do.
2631 * So when c:path is given, I assume it's c:${curdir}path
2632 * with ${curdir} comes from the current drive
2633 */
2634 int absdrive = *dir && dir[1] == ':';
2635 int abspath = absdrive ? is_path_sep(dir[2]) : is_path_sep(*dir);
2636
2637 cdcomppath = sstrdup(dir);
2638 STARTSTACKSTR(new);
2639 if (!absdrive && curdir == nullstr)
2640 return 0;
2641 if (!abspath) {
2642 if (curdir == nullstr)
2643 return 0;
2644 new = stack_putstr(curdir, new);
2645 }
2646 new = makestrspace(strlen(dir) + 2, new);
2647
2648 if ( is_unc_path(dir) || (!absdrive && !abspath && is_unc_path(curdir)) ) {
2649 lim = (char *)stackblock() + 1;
2650 }
2651 else {
2652 char *drive = stackblock();
2653 if (absdrive) {
2654 *drive = *dir;
2655 cdcomppath += 2;
2656 dir += 2;
2657 } else {
2658 *drive = *curdir;
2659 }
2660 drive[1] = ':'; /* in case of absolute drive+path */
2661
2662 if (abspath)
2663 new = drive + 2;
2664 lim = drive + 3;
2665 }
2666
2667 if (!abspath) {
2668 if (!is_path_sep(new[-1]))
2669 USTPUTC('/', new);
2670 if (new > lim && is_path_sep(*lim))
2671 lim++;
2672 } else {
2673 USTPUTC('/', new);
2674 cdcomppath ++;
2675 if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) {
2676 USTPUTC('/', new);
2677 cdcomppath++;
2678 lim++;
2679 }
2680 }
2681 p = strtok(cdcomppath, "/\\");
2682 while (p) {
2683 switch (*p) {
2684 case '.':
2685 if (p[1] == '.' && p[2] == '\0') {
2686 while (new > lim) {
2687 STUNPUTC(new);
2688 if (is_path_sep(new[-1]))
2689 break;
2690 }
2691 break;
2692 }
2693 if (p[1] == '\0')
2694 break;
2695 /* fall through */
2696 default:
2697 new = stack_putstr(p, new);
2698 USTPUTC('/', new);
2699 }
2700 p = strtok(0, "/\\");
2701 }
2702 if (new > lim)
2703 STUNPUTC(new);
2704 *new = 0;
2705 return stackblock();
2706#else
2515 char *new; 2707 char *new;
2516 char *p; 2708 char *p;
2517 char *cdcomppath; 2709 char *cdcomppath;
@@ -2565,6 +2757,7 @@ updatepwd(const char *dir)
2565 STUNPUTC(new); 2757 STUNPUTC(new);
2566 *new = 0; 2758 *new = 0;
2567 return stackblock(); 2759 return stackblock();
2760#endif
2568} 2761}
2569 2762
2570/* 2763/*
@@ -2659,7 +2852,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2659 } 2852 }
2660 if (!dest) 2853 if (!dest)
2661 dest = nullstr; 2854 dest = nullstr;
2662 if (*dest == '/') 2855 if (is_absolute_path(dest))
2663 goto step6; 2856 goto step6;
2664 if (*dest == '.') { 2857 if (*dest == '.') {
2665 c = dest[1]; 2858 c = dest[1];
@@ -3370,6 +3563,9 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3370 */ 3563 */
3371struct procstat { 3564struct procstat {
3372 pid_t ps_pid; /* process id */ 3565 pid_t ps_pid; /* process id */
3566#if ENABLE_PLATFORM_MINGW32
3567 HANDLE ps_proc;
3568#endif
3373 int ps_status; /* last process status from wait() */ 3569 int ps_status; /* last process status from wait() */
3374 char *ps_cmd; /* text of command being run */ 3570 char *ps_cmd; /* text of command being run */
3375}; 3571};
@@ -3397,7 +3593,9 @@ struct job {
3397}; 3593};
3398 3594
3399static struct job *makejob(/*union node *,*/ int); 3595static struct job *makejob(/*union node *,*/ int);
3596#if !ENABLE_PLATFORM_MINGW32
3400static int forkshell(struct job *, union node *, int); 3597static int forkshell(struct job *, union node *, int);
3598#endif
3401static int waitforjob(struct job *); 3599static int waitforjob(struct job *);
3402 3600
3403#if !JOBS 3601#if !JOBS
@@ -3422,6 +3620,7 @@ ignoresig(int signo)
3422 sigmode[signo - 1] = S_HARD_IGN; 3620 sigmode[signo - 1] = S_HARD_IGN;
3423} 3621}
3424 3622
3623#if !ENABLE_PLATFORM_MINGW32
3425/* 3624/*
3426 * Only one usage site - in setsignal() 3625 * Only one usage site - in setsignal()
3427 */ 3626 */
@@ -3546,6 +3745,9 @@ setsignal(int signo)
3546 3745
3547 *t = new_act; 3746 *t = new_act;
3548} 3747}
3748#else
3749#define setsignal(s)
3750#endif
3549 3751
3550/* mode flags for set_curjob */ 3752/* mode flags for set_curjob */
3551#define CUR_DELETE 2 3753#define CUR_DELETE 2
@@ -3971,6 +4173,97 @@ sprint_status48(char *s, int status, int sigonly)
3971 return col; 4173 return col;
3972} 4174}
3973 4175
4176#if ENABLE_PLATFORM_MINGW32
4177
4178HANDLE hSIGINT; /* Ctrl-C is pressed */
4179
4180static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
4181{
4182 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
4183 SetEvent(hSIGINT);
4184 return TRUE;
4185 }
4186 return FALSE;
4187}
4188
4189/*
4190 * Windows does not know about parent-child relationship
4191 * They don't support waitpid(-1)
4192 */
4193static pid_t
4194waitpid_child(int *status, int wait_flags)
4195{
4196 pid_t *pidlist;
4197 HANDLE *proclist;
4198 int pid_nr = 0;
4199 pid_t pid;
4200 DWORD win_status, idx;
4201 struct job *jb;
4202
4203 for (jb = curjob; jb; jb = jb->prev_job) {
4204 if (jb->state != JOBDONE)
4205 pid_nr += jb->nprocs;
4206 }
4207 if ( pid_nr++ == 0 )
4208 return -1;
4209
4210 pidlist = ckmalloc(sizeof(*pidlist)*pid_nr);
4211 proclist = ckmalloc(sizeof(*proclist)*pid_nr);
4212
4213 pidlist[0] = -1;
4214 proclist[0] = hSIGINT;
4215 pid_nr = 1;
4216 for (jb = curjob; jb; jb = jb->prev_job) {
4217 struct procstat *ps, *psend;
4218 if (jb->state == JOBDONE)
4219 continue;
4220 ps = jb->ps;
4221 psend = ps + jb->nprocs;
4222 while (ps < psend) {
4223 if (ps->ps_pid != -1 && ps->ps_proc != NULL) {
4224 pidlist[pid_nr] = ps->ps_pid;
4225 proclist[pid_nr++] = ps->ps_proc;
4226 }
4227 ps++;
4228 }
4229 }
4230
4231 if (pid_nr == 1) {
4232 free(pidlist);
4233 free(proclist);
4234 return -1;
4235 }
4236
4237 idx = WaitForMultipleObjects(pid_nr, proclist, FALSE,
4238 wait_flags|WNOHANG ? 1 : INFINITE);
4239 if (idx >= pid_nr) {
4240 free(pidlist);
4241 free(proclist);
4242 return -1;
4243 }
4244 if (!idx) { /* hSIGINT */
4245 int i;
4246 ResetEvent(hSIGINT);
4247 for (i = 1; i < pid_nr; i++)
4248 TerminateProcess(proclist[i], 1);
4249 pid = pidlist[1];
4250 free(pidlist);
4251 free(proclist);
4252 *status = 260; /* terminated by a signal */
4253 return pid;
4254 }
4255 GetExitCodeProcess(proclist[idx], &win_status);
4256 pid = pidlist[idx];
4257 free(pidlist);
4258 free(proclist);
4259 *status = (int)win_status;
4260 return pid;
4261}
4262#define waitpid(p, s, f) waitpid_child(s, f)
4263#define wait_block_or_sig(s) waitpid_child(s, 0)
4264
4265#else
4266
3974static int 4267static int
3975wait_block_or_sig(int *status) 4268wait_block_or_sig(int *status)
3976{ 4269{
@@ -4003,6 +4296,7 @@ wait_block_or_sig(int *status)
4003 4296
4004 return pid; 4297 return pid;
4005} 4298}
4299#endif
4006 4300
4007#define DOWAIT_NONBLOCK 0 4301#define DOWAIT_NONBLOCK 0
4008#define DOWAIT_BLOCK 1 4302#define DOWAIT_BLOCK 1
@@ -4071,6 +4365,11 @@ dowait(int block, struct job *job)
4071 jobno(jp), pid, ps->ps_status, status)); 4365 jobno(jp), pid, ps->ps_status, status));
4072 ps->ps_status = status; 4366 ps->ps_status = status;
4073 thisjob = jp; 4367 thisjob = jp;
4368 if (ENABLE_PLATFORM_MINGW32) {
4369 ps->ps_pid = -1;
4370 CloseHandle(ps->ps_proc);
4371 ps->ps_proc = NULL;
4372 }
4074 } 4373 }
4075 if (ps->ps_status == -1) 4374 if (ps->ps_status == -1)
4076 jobstate = JOBRUNNING; 4375 jobstate = JOBRUNNING;
@@ -4743,6 +5042,7 @@ commandtext(union node *n)
4743 * 5042 *
4744 * Called with interrupts off. 5043 * Called with interrupts off.
4745 */ 5044 */
5045#if !ENABLE_PLATFORM_MINGW32
4746/* 5046/*
4747 * Clear traps on a fork. 5047 * Clear traps on a fork.
4748 */ 5048 */
@@ -4892,16 +5192,24 @@ forkchild(struct job *jp, union node *n, int mode)
4892 freejob(jp); 5192 freejob(jp);
4893 jobless = 0; 5193 jobless = 0;
4894} 5194}
5195#endif
4895 5196
4896/* Called after fork(), in parent */ 5197/* Called after fork(), in parent */
4897#if !JOBS 5198#if !JOBS
4898#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) 5199#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4899#endif 5200#endif
4900static void 5201static void
5202#if !ENABLE_PLATFORM_MINGW32
4901forkparent(struct job *jp, union node *n, int mode, pid_t pid) 5203forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5204#else
5205forkparent(struct job *jp, union node *n, int mode, HANDLE proc)
5206#endif
4902{ 5207{
5208#if ENABLE_PLATFORM_MINGW32
5209 pid_t pid = GetProcessId(proc);
5210#endif
4903 TRACE(("In parent shell: child = %d\n", pid)); 5211 TRACE(("In parent shell: child = %d\n", pid));
4904 if (!jp) { 5212 if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */
4905 /* jp is NULL when called by openhere() for heredoc support */ 5213 /* jp is NULL when called by openhere() for heredoc support */
4906 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) 5214 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4907 continue; 5215 continue;
@@ -4927,6 +5235,9 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4927 if (jp) { 5235 if (jp) {
4928 struct procstat *ps = &jp->ps[jp->nprocs++]; 5236 struct procstat *ps = &jp->ps[jp->nprocs++];
4929 ps->ps_pid = pid; 5237 ps->ps_pid = pid;
5238#if ENABLE_PLATFORM_MINGW32
5239 ps->ps_proc = proc;
5240#endif
4930 ps->ps_status = -1; 5241 ps->ps_status = -1;
4931 ps->ps_cmd = nullstr; 5242 ps->ps_cmd = nullstr;
4932#if JOBS 5243#if JOBS
@@ -4936,6 +5247,7 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4936 } 5247 }
4937} 5248}
4938 5249
5250#if !ENABLE_PLATFORM_MINGW32
4939/* jp and n are NULL when called by openhere() for heredoc support */ 5251/* jp and n are NULL when called by openhere() for heredoc support */
4940static int 5252static int
4941forkshell(struct job *jp, union node *n, int mode) 5253forkshell(struct job *jp, union node *n, int mode)
@@ -4958,6 +5270,7 @@ forkshell(struct job *jp, union node *n, int mode)
4958 } 5270 }
4959 return pid; 5271 return pid;
4960} 5272}
5273#endif
4961 5274
4962/* 5275/*
4963 * Wait for job to finish. 5276 * Wait for job to finish.
@@ -5149,6 +5462,7 @@ openhere(union node *redir)
5149{ 5462{
5150 int pip[2]; 5463 int pip[2];
5151 size_t len = 0; 5464 size_t len = 0;
5465 IF_PLATFORM_MINGW32(struct forkshell fs);
5152 5466
5153 if (pipe(pip) < 0) 5467 if (pipe(pip) < 0)
5154 ash_msg_and_raise_error("pipe call failed"); 5468 ash_msg_and_raise_error("pipe call failed");
@@ -5159,6 +5473,15 @@ openhere(union node *redir)
5159 goto out; 5473 goto out;
5160 } 5474 }
5161 } 5475 }
5476#if ENABLE_PLATFORM_MINGW32
5477 memset(&fs, 0, sizeof(fs));
5478 fs.fpid = FS_OPENHERE;
5479 fs.n = redir;
5480 fs.fd[0] = pip[0];
5481 fs.fd[1] = pip[1];
5482 if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0)
5483 ash_msg_and_raise_error("unable to spawn shell");
5484#else
5162 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 5485 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5163 /* child */ 5486 /* child */
5164 close(pip[0]); 5487 close(pip[0]);
@@ -5173,6 +5496,7 @@ openhere(union node *redir)
5173 expandhere(redir->nhere.doc, pip[1]); 5496 expandhere(redir->nhere.doc, pip[1]);
5174 _exit(EXIT_SUCCESS); 5497 _exit(EXIT_SUCCESS);
5175 } 5498 }
5499#endif
5176 out: 5500 out:
5177 close(pip[1]); 5501 close(pip[1]);
5178 return pip[0]; 5502 return pip[0];
@@ -5198,6 +5522,31 @@ openredirect(union node *redir)
5198 * allocated space. Do it only when we know it is safe. 5522 * allocated space. Do it only when we know it is safe.
5199 */ 5523 */
5200 fname = redir->nfile.expfname; 5524 fname = redir->nfile.expfname;
5525#if ENABLE_PLATFORM_MINGW32
5526 /* Support for /dev/null */
5527 switch (redir->nfile.type) {
5528 case NFROM:
5529 if (!strcmp(fname, "/dev/null"))
5530 return open("nul",O_RDWR);
5531 if (!strncmp(fname, "/dev/", 5)) {
5532 ash_msg("Unhandled device %s\n", fname);
5533 return -1;
5534 }
5535 break;
5536
5537 case NFROMTO:
5538 case NTO:
5539 case NCLOBBER:
5540 case NAPPEND:
5541 if (!strcmp(fname, "/dev/null"))
5542 return open("nul",O_RDWR);
5543 if (!strncmp(fname, "/dev/", 5)) {
5544 ash_msg("Unhandled device %s\n", fname);
5545 return -1;
5546 }
5547 break;
5548 }
5549#endif
5201 5550
5202 switch (redir->nfile.type) { 5551 switch (redir->nfile.type) {
5203 default: 5552 default:
@@ -5235,6 +5584,9 @@ openredirect(union node *redir)
5235 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); 5584 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5236 if (f < 0) 5585 if (f < 0)
5237 goto ecreate; 5586 goto ecreate;
5587#if ENABLE_PLATFORM_MINGW32
5588 lseek(f, 0, SEEK_END);
5589#endif
5238 break; 5590 break;
5239 } 5591 }
5240 5592
@@ -6045,6 +6397,7 @@ struct backcmd { /* result of evalbackcmd */
6045 int fd; /* file descriptor to read from */ 6397 int fd; /* file descriptor to read from */
6046 int nleft; /* number of chars in buffer */ 6398 int nleft; /* number of chars in buffer */
6047 char *buf; /* buffer */ 6399 char *buf; /* buffer */
6400 IF_PLATFORM_MINGW32(struct forkshell fs);
6048 struct job *jp; /* job structure for command */ 6401 struct job *jp; /* job structure for command */
6049}; 6402};
6050 6403
@@ -6061,6 +6414,7 @@ evalbackcmd(union node *n, struct backcmd *result)
6061 result->fd = -1; 6414 result->fd = -1;
6062 result->buf = NULL; 6415 result->buf = NULL;
6063 result->nleft = 0; 6416 result->nleft = 0;
6417 IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs)));
6064 result->jp = NULL; 6418 result->jp = NULL;
6065 if (n == NULL) { 6419 if (n == NULL) {
6066 goto out; 6420 goto out;
@@ -6069,6 +6423,14 @@ evalbackcmd(union node *n, struct backcmd *result)
6069 if (pipe(pip) < 0) 6423 if (pipe(pip) < 0)
6070 ash_msg_and_raise_error("pipe call failed"); 6424 ash_msg_and_raise_error("pipe call failed");
6071 jp = makejob(/*n,*/ 1); 6425 jp = makejob(/*n,*/ 1);
6426#if ENABLE_PLATFORM_MINGW32
6427 result->fs.fpid = FS_EVALBACKCMD;
6428 result->fs.n = n;
6429 result->fs.fd[0] = pip[0];
6430 result->fs.fd[1] = pip[1];
6431 if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0)
6432 ash_msg_and_raise_error("unable to spawn shell");
6433#else
6072 if (forkshell(jp, n, FORK_NOJOB) == 0) { 6434 if (forkshell(jp, n, FORK_NOJOB) == 0) {
6073 /* child */ 6435 /* child */
6074 FORCE_INT_ON; 6436 FORCE_INT_ON;
@@ -6091,6 +6453,7 @@ evalbackcmd(union node *n, struct backcmd *result)
6091 evaltree(n, EV_EXIT); /* actually evaltreenr... */ 6453 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6092 /* NOTREACHED */ 6454 /* NOTREACHED */
6093 } 6455 }
6456#endif
6094 /* parent */ 6457 /* parent */
6095 close(pip[1]); 6458 close(pip[1]);
6096 result->fd = pip[0]; 6459 result->fd = pip[0];
@@ -6147,7 +6510,8 @@ expbackq(union node *cmd, int flag)
6147 6510
6148 /* Eat all trailing newlines */ 6511 /* Eat all trailing newlines */
6149 dest = expdest; 6512 dest = expdest;
6150 for (; dest > (char *)stackblock() && dest[-1] == '\n';) 6513 for (; dest > (char *)stackblock() && (dest[-1] == '\n' ||
6514 (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));)
6151 STUNPUTC(dest); 6515 STUNPUTC(dest);
6152 expdest = dest; 6516 expdest = dest;
6153 6517
@@ -7629,7 +7993,7 @@ shellexec(char **argv, const char *path, int idx)
7629 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ 7993 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
7630 7994
7631 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); 7995 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7632 if (strchr(argv[0], '/') != NULL 7996 if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\')))
7633#if ENABLE_FEATURE_SH_STANDALONE 7997#if ENABLE_FEATURE_SH_STANDALONE
7634 || (applet_no = find_applet_by_name(argv[0])) >= 0 7998 || (applet_no = find_applet_by_name(argv[0])) >= 0
7635#endif 7999#endif
@@ -7643,6 +8007,11 @@ shellexec(char **argv, const char *path, int idx)
7643 goto try_PATH; 8007 goto try_PATH;
7644 } 8008 }
7645 e = errno; 8009 e = errno;
8010#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE
8011 } else if (strcmp(argv[0], "busybox") == 0) {
8012 tryexec(-1, bb_busybox_exec_path, argv, envp);
8013 e = errno;
8014#endif
7646 } else { 8015 } else {
7647 try_PATH: 8016 try_PATH:
7648 e = ENOENT; 8017 e = ENOENT;
@@ -8223,10 +8592,14 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8223#endif 8592#endif
8224 8593
8225 8594
8226/*static int funcblocksize; // size of structures in function */ 8595static int funcblocksize; /* size of structures in function */
8227/*static int funcstringsize; // size of strings in node */ 8596static int funcstringsize; /* size of strings in node */
8228static void *funcblock; /* block to allocate function from */ 8597static void *funcblock; /* block to allocate function from */
8229static char *funcstring_end; /* end of block to allocate strings from */ 8598static char *funcstring; /* block to allocate strings from */
8599#if ENABLE_PLATFORM_MINGW32
8600static int nodeptrsize;
8601static char **nodeptr;
8602#endif
8230 8603
8231/* flags in argument to evaltree */ 8604/* flags in argument to evaltree */
8232#define EV_EXIT 01 /* exit after evaluating tree */ 8605#define EV_EXIT 01 /* exit after evaluating tree */
@@ -8264,72 +8637,81 @@ static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8264 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)), 8637 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
8265}; 8638};
8266 8639
8267static int calcsize(int funcblocksize, union node *n); 8640static void calcsize(union node *n);
8268 8641
8269static int 8642static void
8270sizenodelist(int funcblocksize, struct nodelist *lp) 8643sizenodelist(struct nodelist *lp)
8271{ 8644{
8272 while (lp) { 8645 while (lp) {
8273 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 8646 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8274 funcblocksize = calcsize(funcblocksize, lp->n); 8647 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8648 calcsize(lp->n);
8275 lp = lp->next; 8649 lp = lp->next;
8276 } 8650 }
8277 return funcblocksize;
8278} 8651}
8279 8652
8280static int 8653static void
8281calcsize(int funcblocksize, union node *n) 8654calcsize(union node *n)
8282{ 8655{
8283 if (n == NULL) 8656 if (n == NULL)
8284 return funcblocksize; 8657 return;
8285 funcblocksize += nodesize[n->type]; 8658 funcblocksize += nodesize[n->type];
8286 switch (n->type) { 8659 switch (n->type) {
8287 case NCMD: 8660 case NCMD:
8288 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect); 8661 calcsize(n->ncmd.redirect);
8289 funcblocksize = calcsize(funcblocksize, n->ncmd.args); 8662 calcsize(n->ncmd.args);
8290 funcblocksize = calcsize(funcblocksize, n->ncmd.assign); 8663 calcsize(n->ncmd.assign);
8664 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8291 break; 8665 break;
8292 case NPIPE: 8666 case NPIPE:
8293 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist); 8667 sizenodelist(n->npipe.cmdlist);
8668 IF_PLATFORM_MINGW32(nodeptrsize++);
8294 break; 8669 break;
8295 case NREDIR: 8670 case NREDIR:
8296 case NBACKGND: 8671 case NBACKGND:
8297 case NSUBSHELL: 8672 case NSUBSHELL:
8298 funcblocksize = calcsize(funcblocksize, n->nredir.redirect); 8673 calcsize(n->nredir.redirect);
8299 funcblocksize = calcsize(funcblocksize, n->nredir.n); 8674 calcsize(n->nredir.n);
8675 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8300 break; 8676 break;
8301 case NAND: 8677 case NAND:
8302 case NOR: 8678 case NOR:
8303 case NSEMI: 8679 case NSEMI:
8304 case NWHILE: 8680 case NWHILE:
8305 case NUNTIL: 8681 case NUNTIL:
8306 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2); 8682 calcsize(n->nbinary.ch2);
8307 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1); 8683 calcsize(n->nbinary.ch1);
8684 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8308 break; 8685 break;
8309 case NIF: 8686 case NIF:
8310 funcblocksize = calcsize(funcblocksize, n->nif.elsepart); 8687 calcsize(n->nif.elsepart);
8311 funcblocksize = calcsize(funcblocksize, n->nif.ifpart); 8688 calcsize(n->nif.ifpart);
8312 funcblocksize = calcsize(funcblocksize, n->nif.test); 8689 calcsize(n->nif.test);
8690 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8313 break; 8691 break;
8314 case NFOR: 8692 case NFOR:
8315 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */ 8693 funcstringsize += strlen(n->nfor.var) + 1;
8316 funcblocksize = calcsize(funcblocksize, n->nfor.body); 8694 calcsize(n->nfor.body);
8317 funcblocksize = calcsize(funcblocksize, n->nfor.args); 8695 calcsize(n->nfor.args);
8696 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8318 break; 8697 break;
8319 case NCASE: 8698 case NCASE:
8320 funcblocksize = calcsize(funcblocksize, n->ncase.cases); 8699 calcsize(n->ncase.cases);
8321 funcblocksize = calcsize(funcblocksize, n->ncase.expr); 8700 calcsize(n->ncase.expr);
8701 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8322 break; 8702 break;
8323 case NCLIST: 8703 case NCLIST:
8324 funcblocksize = calcsize(funcblocksize, n->nclist.body); 8704 calcsize(n->nclist.body);
8325 funcblocksize = calcsize(funcblocksize, n->nclist.pattern); 8705 calcsize(n->nclist.pattern);
8326 funcblocksize = calcsize(funcblocksize, n->nclist.next); 8706 calcsize(n->nclist.next);
8707 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8327 break; 8708 break;
8328 case NDEFUN: 8709 case NDEFUN:
8329 case NARG: 8710 case NARG:
8330 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote); 8711 sizenodelist(n->narg.backquote);
8331 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */ 8712 funcstringsize += strlen(n->narg.text) + 1;
8332 funcblocksize = calcsize(funcblocksize, n->narg.next); 8713 calcsize(n->narg.next);
8714 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8333 break; 8715 break;
8334 case NTO: 8716 case NTO:
8335#if ENABLE_ASH_BASH_COMPAT 8717#if ENABLE_ASH_BASH_COMPAT
@@ -8339,35 +8721,55 @@ calcsize(int funcblocksize, union node *n)
8339 case NFROM: 8721 case NFROM:
8340 case NFROMTO: 8722 case NFROMTO:
8341 case NAPPEND: 8723 case NAPPEND:
8342 funcblocksize = calcsize(funcblocksize, n->nfile.fname); 8724 calcsize(n->nfile.fname);
8343 funcblocksize = calcsize(funcblocksize, n->nfile.next); 8725 calcsize(n->nfile.next);
8726 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8344 break; 8727 break;
8345 case NTOFD: 8728 case NTOFD:
8346 case NFROMFD: 8729 case NFROMFD:
8347 funcblocksize = calcsize(funcblocksize, n->ndup.vname); 8730 calcsize(n->ndup.vname);
8348 funcblocksize = calcsize(funcblocksize, n->ndup.next); 8731 calcsize(n->ndup.next);
8732 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8349 break; 8733 break;
8350 case NHERE: 8734 case NHERE:
8351 case NXHERE: 8735 case NXHERE:
8352 funcblocksize = calcsize(funcblocksize, n->nhere.doc); 8736 calcsize(n->nhere.doc);
8353 funcblocksize = calcsize(funcblocksize, n->nhere.next); 8737 calcsize(n->nhere.next);
8738 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8354 break; 8739 break;
8355 case NNOT: 8740 case NNOT:
8356 funcblocksize = calcsize(funcblocksize, n->nnot.com); 8741 calcsize(n->nnot.com);
8742 IF_PLATFORM_MINGW32(nodeptrsize++);
8357 break; 8743 break;
8358 }; 8744 };
8359 return funcblocksize;
8360} 8745}
8361 8746
8362static char * 8747static char *
8363nodeckstrdup(char *s) 8748nodeckstrdup(const char *s)
8364{ 8749{
8365 funcstring_end -= SHELL_ALIGN(strlen(s) + 1); 8750 char *rtn = funcstring;
8366 return strcpy(funcstring_end, s); 8751
8752 if (!s)
8753 return NULL;
8754 strcpy(funcstring, s);
8755 funcstring += strlen(s) + 1;
8756 return rtn;
8367} 8757}
8368 8758
8369static union node *copynode(union node *); 8759static union node *copynode(union node *);
8370 8760
8761#if ENABLE_PLATFORM_MINGW32
8762# define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (char *)&(dst);}
8763# define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);}}
8764# define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);}}
8765# define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);*nodeptr++ = (char *)&(dst4);}}
8766#else
8767# define SAVE_PTR(dst)
8768# define SAVE_PTR2(dst,dst2)
8769# define SAVE_PTR3(dst,dst2,dst3)
8770# define SAVE_PTR4(dst,dst2,dst3,dst4)
8771#endif
8772
8371static struct nodelist * 8773static struct nodelist *
8372copynodelist(struct nodelist *lp) 8774copynodelist(struct nodelist *lp)
8373{ 8775{
@@ -8379,6 +8781,7 @@ copynodelist(struct nodelist *lp)
8379 *lpp = funcblock; 8781 *lpp = funcblock;
8380 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); 8782 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8381 (*lpp)->n = copynode(lp->n); 8783 (*lpp)->n = copynode(lp->n);
8784 SAVE_PTR2((*lpp)->n, (*lpp)->next);
8382 lp = lp->next; 8785 lp = lp->next;
8383 lpp = &(*lpp)->next; 8786 lpp = &(*lpp)->next;
8384 } 8787 }
@@ -8401,16 +8804,19 @@ copynode(union node *n)
8401 new->ncmd.redirect = copynode(n->ncmd.redirect); 8804 new->ncmd.redirect = copynode(n->ncmd.redirect);
8402 new->ncmd.args = copynode(n->ncmd.args); 8805 new->ncmd.args = copynode(n->ncmd.args);
8403 new->ncmd.assign = copynode(n->ncmd.assign); 8806 new->ncmd.assign = copynode(n->ncmd.assign);
8807 SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign);
8404 break; 8808 break;
8405 case NPIPE: 8809 case NPIPE:
8406 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 8810 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8407 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; 8811 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8812 SAVE_PTR(new->npipe.cmdlist);
8408 break; 8813 break;
8409 case NREDIR: 8814 case NREDIR:
8410 case NBACKGND: 8815 case NBACKGND:
8411 case NSUBSHELL: 8816 case NSUBSHELL:
8412 new->nredir.redirect = copynode(n->nredir.redirect); 8817 new->nredir.redirect = copynode(n->nredir.redirect);
8413 new->nredir.n = copynode(n->nredir.n); 8818 new->nredir.n = copynode(n->nredir.n);
8819 SAVE_PTR2(new->nredir.redirect,new->nredir.n);
8414 break; 8820 break;
8415 case NAND: 8821 case NAND:
8416 case NOR: 8822 case NOR:
@@ -8419,31 +8825,37 @@ copynode(union node *n)
8419 case NUNTIL: 8825 case NUNTIL:
8420 new->nbinary.ch2 = copynode(n->nbinary.ch2); 8826 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8421 new->nbinary.ch1 = copynode(n->nbinary.ch1); 8827 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8828 SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2);
8422 break; 8829 break;
8423 case NIF: 8830 case NIF:
8424 new->nif.elsepart = copynode(n->nif.elsepart); 8831 new->nif.elsepart = copynode(n->nif.elsepart);
8425 new->nif.ifpart = copynode(n->nif.ifpart); 8832 new->nif.ifpart = copynode(n->nif.ifpart);
8426 new->nif.test = copynode(n->nif.test); 8833 new->nif.test = copynode(n->nif.test);
8834 SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test);
8427 break; 8835 break;
8428 case NFOR: 8836 case NFOR:
8429 new->nfor.var = nodeckstrdup(n->nfor.var); 8837 new->nfor.var = nodeckstrdup(n->nfor.var);
8430 new->nfor.body = copynode(n->nfor.body); 8838 new->nfor.body = copynode(n->nfor.body);
8431 new->nfor.args = copynode(n->nfor.args); 8839 new->nfor.args = copynode(n->nfor.args);
8840 SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args);
8432 break; 8841 break;
8433 case NCASE: 8842 case NCASE:
8434 new->ncase.cases = copynode(n->ncase.cases); 8843 new->ncase.cases = copynode(n->ncase.cases);
8435 new->ncase.expr = copynode(n->ncase.expr); 8844 new->ncase.expr = copynode(n->ncase.expr);
8845 SAVE_PTR2(new->ncase.cases,new->ncase.expr);
8436 break; 8846 break;
8437 case NCLIST: 8847 case NCLIST:
8438 new->nclist.body = copynode(n->nclist.body); 8848 new->nclist.body = copynode(n->nclist.body);
8439 new->nclist.pattern = copynode(n->nclist.pattern); 8849 new->nclist.pattern = copynode(n->nclist.pattern);
8440 new->nclist.next = copynode(n->nclist.next); 8850 new->nclist.next = copynode(n->nclist.next);
8851 SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next);
8441 break; 8852 break;
8442 case NDEFUN: 8853 case NDEFUN:
8443 case NARG: 8854 case NARG:
8444 new->narg.backquote = copynodelist(n->narg.backquote); 8855 new->narg.backquote = copynodelist(n->narg.backquote);
8445 new->narg.text = nodeckstrdup(n->narg.text); 8856 new->narg.text = nodeckstrdup(n->narg.text);
8446 new->narg.next = copynode(n->narg.next); 8857 new->narg.next = copynode(n->narg.next);
8858 SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next);
8447 break; 8859 break;
8448 case NTO: 8860 case NTO:
8449#if ENABLE_ASH_BASH_COMPAT 8861#if ENABLE_ASH_BASH_COMPAT
@@ -8456,6 +8868,7 @@ copynode(union node *n)
8456 new->nfile.fname = copynode(n->nfile.fname); 8868 new->nfile.fname = copynode(n->nfile.fname);
8457 new->nfile.fd = n->nfile.fd; 8869 new->nfile.fd = n->nfile.fd;
8458 new->nfile.next = copynode(n->nfile.next); 8870 new->nfile.next = copynode(n->nfile.next);
8871 SAVE_PTR2(new->nfile.fname,new->nfile.next);
8459 break; 8872 break;
8460 case NTOFD: 8873 case NTOFD:
8461 case NFROMFD: 8874 case NFROMFD:
@@ -8463,15 +8876,18 @@ copynode(union node *n)
8463 new->ndup.dupfd = n->ndup.dupfd; 8876 new->ndup.dupfd = n->ndup.dupfd;
8464 new->ndup.fd = n->ndup.fd; 8877 new->ndup.fd = n->ndup.fd;
8465 new->ndup.next = copynode(n->ndup.next); 8878 new->ndup.next = copynode(n->ndup.next);
8879 SAVE_PTR2(new->ndup.vname,new->ndup.next);
8466 break; 8880 break;
8467 case NHERE: 8881 case NHERE:
8468 case NXHERE: 8882 case NXHERE:
8469 new->nhere.doc = copynode(n->nhere.doc); 8883 new->nhere.doc = copynode(n->nhere.doc);
8470 new->nhere.fd = n->nhere.fd; 8884 new->nhere.fd = n->nhere.fd;
8471 new->nhere.next = copynode(n->nhere.next); 8885 new->nhere.next = copynode(n->nhere.next);
8886 SAVE_PTR2(new->nhere.doc,new->nhere.next);
8472 break; 8887 break;
8473 case NNOT: 8888 case NNOT:
8474 new->nnot.com = copynode(n->nnot.com); 8889 new->nnot.com = copynode(n->nnot.com);
8890 SAVE_PTR(new->nnot.com);
8475 break; 8891 break;
8476 }; 8892 };
8477 new->type = n->type; 8893 new->type = n->type;
@@ -8487,13 +8903,16 @@ copyfunc(union node *n)
8487 struct funcnode *f; 8903 struct funcnode *f;
8488 size_t blocksize; 8904 size_t blocksize;
8489 8905
8490 /*funcstringsize = 0;*/ 8906 funcblocksize = offsetof(struct funcnode, n);
8491 blocksize = offsetof(struct funcnode, n) + calcsize(0, n); 8907 funcstringsize = 0;
8492 f = ckzalloc(blocksize /* + funcstringsize */); 8908 calcsize(n);
8909 blocksize = funcblocksize;
8910 f = ckmalloc(blocksize + funcstringsize);
8493 funcblock = (char *) f + offsetof(struct funcnode, n); 8911 funcblock = (char *) f + offsetof(struct funcnode, n);
8494 funcstring_end = (char *) f + blocksize; 8912 funcstring = (char *) f + blocksize;
8913 IF_PLATFORM_MINGW32(nodeptr = NULL);
8495 copynode(n); 8914 copynode(n);
8496 /* f->count = 0; - ckzalloc did it */ 8915 f->count = 0;
8497 return f; 8916 return f;
8498} 8917}
8499 8918
@@ -8833,6 +9252,7 @@ evalcase(union node *n, int flags)
8833static int 9252static int
8834evalsubshell(union node *n, int flags) 9253evalsubshell(union node *n, int flags)
8835{ 9254{
9255 IF_PLATFORM_MINGW32(struct forkshell fs;)
8836 struct job *jp; 9256 struct job *jp;
8837 int backgnd = (n->type == NBACKGND); 9257 int backgnd = (n->type == NBACKGND);
8838 int status; 9258 int status;
@@ -8842,12 +9262,22 @@ evalsubshell(union node *n, int flags)
8842 goto nofork; 9262 goto nofork;
8843 INT_OFF; 9263 INT_OFF;
8844 jp = makejob(/*n,*/ 1); 9264 jp = makejob(/*n,*/ 1);
9265#if ENABLE_PLATFORM_MINGW32
9266 memset(&fs, 0, sizeof(fs));
9267 fs.fpid = FS_EVALSUBSHELL;
9268 fs.n = n;
9269 fs.flags = flags;
9270 if (spawn_forkshell(jp, &fs, backgnd) < 0)
9271 ash_msg_and_raise_error("unable to spawn shell");
9272 if ( 0 ) {
9273#else
8845 if (forkshell(jp, n, backgnd) == 0) { 9274 if (forkshell(jp, n, backgnd) == 0) {
8846 /* child */ 9275 /* child */
8847 INT_ON; 9276 INT_ON;
8848 flags |= EV_EXIT; 9277 flags |= EV_EXIT;
8849 if (backgnd) 9278 if (backgnd)
8850 flags &= ~EV_TESTED; 9279 flags &= ~EV_TESTED;
9280#endif
8851 nofork: 9281 nofork:
8852 redirect(n->nredir.redirect, 0); 9282 redirect(n->nredir.redirect, 0);
8853 evaltreenr(n->nredir.n, flags); 9283 evaltreenr(n->nredir.n, flags);
@@ -8934,6 +9364,7 @@ expredir(union node *n)
8934static int 9364static int
8935evalpipe(union node *n, int flags) 9365evalpipe(union node *n, int flags)
8936{ 9366{
9367 IF_PLATFORM_MINGW32(struct forkshell fs;)
8937 struct job *jp; 9368 struct job *jp;
8938 struct nodelist *lp; 9369 struct nodelist *lp;
8939 int pipelen; 9370 int pipelen;
@@ -8958,6 +9389,17 @@ evalpipe(union node *n, int flags)
8958 ash_msg_and_raise_error("pipe call failed"); 9389 ash_msg_and_raise_error("pipe call failed");
8959 } 9390 }
8960 } 9391 }
9392#if ENABLE_PLATFORM_MINGW32
9393 memset(&fs, 0, sizeof(fs));
9394 fs.fpid = FS_EVALPIPE;
9395 fs.flags = flags;
9396 fs.n = lp->n;
9397 fs.fd[0] = pip[0];
9398 fs.fd[1] = pip[1];
9399 fs.fd[2] = prevfd;
9400 if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0)
9401 ash_msg_and_raise_error("unable to spawn shell");
9402#else
8961 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { 9403 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8962 /* child */ 9404 /* child */
8963 INT_ON; 9405 INT_ON;
@@ -8975,6 +9417,7 @@ evalpipe(union node *n, int flags)
8975 evaltreenr(lp->n, flags); 9417 evaltreenr(lp->n, flags);
8976 /* never returns */ 9418 /* never returns */
8977 } 9419 }
9420#endif
8978 /* parent */ 9421 /* parent */
8979 if (prevfd >= 0) 9422 if (prevfd >= 0)
8980 close(prevfd); 9423 close(prevfd);
@@ -9442,6 +9885,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9442 * as POSIX mandates */ 9885 * as POSIX mandates */
9443 return back_exitstatus; 9886 return back_exitstatus;
9444} 9887}
9888
9445static int 9889static int
9446evalcommand(union node *cmd, int flags) 9890evalcommand(union node *cmd, int flags)
9447{ 9891{
@@ -9626,6 +10070,27 @@ evalcommand(union node *cmd, int flags)
9626 * in a script or a subshell does not need forking, 10070 * in a script or a subshell does not need forking,
9627 * we can just exec it. 10071 * we can just exec it.
9628 */ 10072 */
10073#if ENABLE_PLATFORM_MINGW32
10074 if (!(flags & EV_EXIT) || trap[0]) {
10075 /* No, forking off a child is necessary */
10076 struct forkshell fs;
10077
10078 memset(&fs, 0, sizeof(fs));
10079 fs.fpid = FS_SHELLEXEC;
10080 fs.argv = argv;
10081 fs.string = (char*)path;
10082 fs.fd[0] = cmdentry.u.index;
10083 fs.strlist = varlist.list;
10084 jp = makejob(/*cmd,*/ 1);
10085 if (spawn_forkshell(jp, &fs, FORK_FG) < 0)
10086 ash_msg_and_raise_error("unable to spawn shell");
10087 status = waitforjob(jp);
10088 INT_ON;
10089 TRACE(("forked child exited with %d\n", exitstatus));
10090 break;
10091 }
10092 /* goes through to shellexec() */
10093#else
9629 if (!(flags & EV_EXIT) || may_have_traps) { 10094 if (!(flags & EV_EXIT) || may_have_traps) {
9630 /* No, forking off a child is necessary */ 10095 /* No, forking off a child is necessary */
9631 INT_OFF; 10096 INT_OFF;
@@ -9641,6 +10106,7 @@ evalcommand(union node *cmd, int flags)
9641 FORCE_INT_ON; 10106 FORCE_INT_ON;
9642 /* fall through to exec'ing external program */ 10107 /* fall through to exec'ing external program */
9643 } 10108 }
10109#endif
9644 listsetvar(varlist.list, VEXPORT|VSTACK); 10110 listsetvar(varlist.list, VEXPORT|VSTACK);
9645 shellexec(argv, path, cmdentry.u.index); 10111 shellexec(argv, path, cmdentry.u.index);
9646 /* NOTREACHED */ 10112 /* NOTREACHED */
@@ -10026,7 +10492,7 @@ preadbuffer(void)
10026 more--; 10492 more--;
10027 10493
10028 c = *q; 10494 c = *q;
10029 if (c == '\0') { 10495 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) {
10030 memmove(q, q + 1, more); 10496 memmove(q, q + 1, more);
10031 } else { 10497 } else {
10032 q++; 10498 q++;
@@ -10213,6 +10679,7 @@ popallfiles(void)
10213 popfile(); 10679 popfile();
10214} 10680}
10215 10681
10682#if !ENABLE_PLATFORM_MINGW32
10216/* 10683/*
10217 * Close the file(s) that the shell is reading commands from. Called 10684 * Close the file(s) that the shell is reading commands from. Called
10218 * after a fork is done. 10685 * after a fork is done.
@@ -10226,6 +10693,7 @@ closescript(void)
10226 g_parsefile->pf_fd = 0; 10693 g_parsefile->pf_fd = 0;
10227 } 10694 }
10228} 10695}
10696#endif
10229 10697
10230/* 10698/*
10231 * Like setinputfile, but takes an open file descriptor. Call this with 10699 * Like setinputfile, but takes an open file descriptor. Call this with
@@ -12505,7 +12973,7 @@ find_dot_file(char *name)
12505 struct stat statb; 12973 struct stat statb;
12506 12974
12507 /* don't try this for absolute or relative paths */ 12975 /* don't try this for absolute or relative paths */
12508 if (strchr(name, '/')) 12976 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\')))
12509 return name; 12977 return name;
12510 12978
12511 /* IIRC standards do not say whether . is to be searched. 12979 /* IIRC standards do not say whether . is to be searched.
@@ -12626,10 +13094,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12626 struct stat statb; 13094 struct stat statb;
12627 int e; 13095 int e;
12628 int updatetbl; 13096 int updatetbl;
13097 IF_PLATFORM_MINGW32(int len;)
12629 struct builtincmd *bcmd; 13098 struct builtincmd *bcmd;
12630 13099
12631 /* If name contains a slash, don't use PATH or hash table */ 13100 /* If name contains a slash, don't use PATH or hash table */
12632 if (strchr(name, '/') != NULL) { 13101 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) {
12633 entry->u.index = -1; 13102 entry->u.index = -1;
12634 if (act & DO_ABS) { 13103 if (act & DO_ABS) {
12635 while (stat(name, &statb) < 0) { 13104 while (stat(name, &statb) < 0) {
@@ -12698,7 +13167,9 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12698#if ENABLE_FEATURE_SH_STANDALONE 13167#if ENABLE_FEATURE_SH_STANDALONE
12699 { 13168 {
12700 int applet_no = find_applet_by_name(name); 13169 int applet_no = find_applet_by_name(name);
12701 if (applet_no >= 0) { 13170 if (applet_no >= 0 ||
13171 /* requires find_applet_by_name to return -1 on no match */
13172 (ENABLE_PLATFORM_MINGW32 && strcmp(name, "busybox") == 0)) {
12702 entry->cmdtype = CMDNORMAL; 13173 entry->cmdtype = CMDNORMAL;
12703 entry->u.index = -2 - applet_no; 13174 entry->u.index = -2 - applet_no;
12704 return; 13175 return;
@@ -12736,12 +13207,48 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12736 } 13207 }
12737 } 13208 }
12738 /* if rehash, don't redo absolute path names */ 13209 /* if rehash, don't redo absolute path names */
12739 if (fullname[0] == '/' && idx <= prev) { 13210 if (is_absolute_path(fullname) && idx <= prev) {
12740 if (idx < prev) 13211 if (idx < prev)
12741 continue; 13212 continue;
12742 TRACE(("searchexec \"%s\": no change\n", name)); 13213 TRACE(("searchexec \"%s\": no change\n", name));
12743 goto success; 13214 goto success;
12744 } 13215 }
13216#if ENABLE_PLATFORM_MINGW32
13217 len = strlen(fullname);
13218 if (len > 4 &&
13219 (!strcasecmp(fullname+len-4, ".exe") ||
13220 !strcasecmp(fullname+len-4, ".com"))) {
13221 if (stat(fullname, &statb) < 0) {
13222 if (errno != ENOENT && errno != ENOTDIR)
13223 e = errno;
13224 goto loop;
13225 }
13226 }
13227 else {
13228 /* path_advance() has reserved space for .exe */
13229 memcpy(fullname+len, ".exe", 5);
13230 if (stat(fullname, &statb) < 0) {
13231 if (errno != ENOENT && errno != ENOTDIR)
13232 e = errno;
13233 memcpy(fullname+len, ".com", 5);
13234 if (stat(fullname, &statb) < 0) {
13235 if (errno != ENOENT && errno != ENOTDIR)
13236 e = errno;
13237 fullname[len] = '\0';
13238 if (stat(fullname, &statb) < 0) {
13239 if (errno != ENOENT && errno != ENOTDIR)
13240 e = errno;
13241 goto loop;
13242 }
13243 if (!file_is_executable(fullname)) {
13244 e = ENOEXEC;
13245 goto loop;
13246 }
13247 }
13248 }
13249 fullname[len] = '\0';
13250 }
13251#else
12745 while (stat(fullname, &statb) < 0) { 13252 while (stat(fullname, &statb) < 0) {
12746#ifdef SYSV 13253#ifdef SYSV
12747 if (errno == EINTR) 13254 if (errno == EINTR)
@@ -12751,6 +13258,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12751 e = errno; 13258 e = errno;
12752 goto loop; 13259 goto loop;
12753 } 13260 }
13261#endif
12754 e = EACCES; /* if we fail, this will be the error */ 13262 e = EACCES; /* if we fail, this will be the error */
12755 if (!S_ISREG(statb.st_mode)) 13263 if (!S_ISREG(statb.st_mode))
12756 continue; 13264 continue;
@@ -13258,7 +13766,11 @@ exitshell(void)
13258} 13766}
13259 13767
13260static void 13768static void
13769#if ENABLE_PLATFORM_MINGW32
13770init(int xp)
13771#else
13261init(void) 13772init(void)
13773#endif
13262{ 13774{
13263 /* we will never free this */ 13775 /* we will never free this */
13264 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); 13776 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
@@ -13277,6 +13789,86 @@ init(void)
13277 struct stat st1, st2; 13789 struct stat st1, st2;
13278 13790
13279 initvar(); 13791 initvar();
13792
13793#if ENABLE_PLATFORM_MINGW32
13794 /*
13795 * case insensitive env names from Windows world
13796 *
13797 * Some standard env names such as PATH is named Path and so on
13798 * ash itself is case sensitive, so "Path" will confuse it, as
13799 * MSVC getenv() is case insensitive.
13800 *
13801 * We may end up having both Path and PATH. Then Path will be chosen
13802 * because it appears first.
13803 */
13804 for (envp = environ; envp && *envp; envp++) {
13805 if (strncasecmp(*envp, "PATH=", 5) == 0 &&
13806 strncmp(*envp, "PATH=", 5) != 0) {
13807 break;
13808 }
13809 }
13810
13811 if (envp && *envp) {
13812 /*
13813 * If we get here it's because the environment contains a path
13814 * variable called something other than PATH. This suggests we
13815 * haven't been invoked from an earlier instance of BusyBox.
13816 */
13817 char *start, *end, *s;
13818 struct passwd *pw;
13819
13820 for (envp = environ; envp && *envp; envp++) {
13821 if (!(end=strchr(*envp, '=')))
13822 continue;
13823
13824 /* make all variable names uppercase */
13825 for (start = *envp;start < end;start++)
13826 *start = toupper(*start);
13827
13828 /* skip conversion of variables known to cause problems */
13829 if ( strncmp(*envp, "SYSTEMROOT=", 11) == 0 ||
13830 strncmp(*envp, "COMSPEC=", 8) == 0 ) {
13831 continue;
13832 }
13833
13834 /* convert backslashes to forward slashes in value */
13835 if (!xp) {
13836 for ( s=end+1; *s; ++s ) {
13837 if ( *s == '\\' ) {
13838 *s = '/';
13839 }
13840 }
13841 }
13842
13843 /* check for invalid characters in name */
13844 for (start = *envp;start < end;start++) {
13845 if (!isdigit(*start) && !isalpha(*start) && *start != '_') {
13846 break;
13847 }
13848 }
13849
13850 if (start != end) {
13851 /*
13852 * Make a copy of the variable, replacing invalid
13853 * characters in the name with underscores.
13854 */
13855 char *var = xstrdup(*envp);
13856
13857 for (start = var;*start != '=';start++) {
13858 if (!isdigit(*start) && !isalpha(*start)) {
13859 *start = '_';
13860 }
13861 }
13862 setvareq(var, VEXPORT|VNOSAVE);
13863 }
13864 }
13865
13866 /* some initialisation normally performed at login */
13867 pw = xgetpwuid(getuid());
13868 setup_environment(pw->pw_shell,
13869 SETUP_ENV_CHANGEENV|SETUP_ENV_NO_CHDIR, pw);
13870 }
13871#endif
13280 for (envp = environ; envp && *envp; envp++) { 13872 for (envp = environ; envp && *envp; envp++) {
13281 p = endofname(*envp); 13873 p = endofname(*envp);
13282 if (p != *envp && *p == '=') { 13874 if (p != *envp && *p == '=') {
@@ -13479,19 +14071,45 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13479 exception_handler = &jmploc; 14071 exception_handler = &jmploc;
13480 rootpid = getpid(); 14072 rootpid = getpid();
13481 14073
13482 init(); 14074 init(IF_PLATFORM_MINGW32(argc >= 2 && strcmp(argv[1], "-X") == 0));
13483 setstackmark(&smark); 14075 setstackmark(&smark);
14076
14077#if ENABLE_PLATFORM_MINGW32
14078 hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL);
14079 SetConsoleCtrlHandler(ctrl_handler, TRUE);
14080 if (argc == 3 && !strcmp(argv[1], "--forkshell")) {
14081 forkshell_init(argv[2]);
14082
14083 /* NOTREACHED */
14084 bb_error_msg_and_die("subshell ended unexpectedly");
14085 }
14086#endif
13484 procargs(argv); 14087 procargs(argv);
13485#if DEBUG 14088#if DEBUG
13486 TRACE(("Shell args: ")); 14089 TRACE(("Shell args: "));
13487 trace_puts_args(argv); 14090 trace_puts_args(argv);
13488#endif 14091#endif
13489 14092
14093#if ENABLE_PLATFORM_MINGW32
14094 if ( noconsole ) {
14095 DWORD dummy;
14096
14097 if ( GetConsoleProcessList(&dummy, 1) == 1 ) {
14098 ShowWindow(GetConsoleWindow(), SW_HIDE);
14099 }
14100 }
14101#endif
14102
13490 if (argv[0] && argv[0][0] == '-') 14103 if (argv[0] && argv[0][0] == '-')
13491 isloginsh = 1; 14104 isloginsh = 1;
13492 if (isloginsh) { 14105 if (isloginsh) {
13493 const char *hp; 14106 const char *hp;
13494 14107
14108#if ENABLE_PLATFORM_MINGW32
14109 chdir(xgetpwuid(getuid())->pw_dir);
14110 setpwd(NULL, 0);
14111#endif
14112
13495 state = 1; 14113 state = 1;
13496 read_profile("/etc/profile"); 14114 read_profile("/etc/profile");
13497 state1: 14115 state1:
@@ -13564,6 +14182,641 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13564 /* NOTREACHED */ 14182 /* NOTREACHED */
13565} 14183}
13566 14184
14185#if ENABLE_PLATFORM_MINGW32
14186static void
14187forkshell_openhere(struct forkshell *fs)
14188{
14189 union node *redir = fs->n;
14190 int pip[2];
14191
14192 pip[0] = fs->fd[0];
14193 pip[1] = fs->fd[1];
14194
14195 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14196
14197 close(pip[0]);
14198 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
14199 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
14200 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
14201 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
14202 signal(SIGPIPE, SIG_DFL);
14203 if (redir->type == NHERE) {
14204 size_t len = strlen(redir->nhere.doc->narg.text);
14205 full_write(pip[1], redir->nhere.doc->narg.text, len);
14206 } else /* NXHERE */
14207 expandhere(redir->nhere.doc, pip[1]);
14208 _exit(EXIT_SUCCESS);
14209}
14210
14211static void
14212forkshell_evalbackcmd(struct forkshell *fs)
14213{
14214 union node *n = fs->n;
14215 int pip[2] = {fs->fd[0], fs->fd[1]};
14216
14217 FORCE_INT_ON;
14218 close(pip[0]);
14219 if (pip[1] != 1) {
14220 /*close(1);*/
14221 dup2_or_raise(pip[1], 1);
14222 close(pip[1]);
14223 }
14224 eflag = 0;
14225 evaltree(n, EV_EXIT); /* actually evaltreenr... */
14226 /* NOTREACHED */
14227}
14228
14229static void
14230forkshell_evalsubshell(struct forkshell *fs)
14231{
14232 union node *n = fs->n;
14233 int flags = fs->flags;
14234
14235 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14236 INT_ON;
14237 flags |= EV_EXIT;
14238 expredir(n->nredir.redirect);
14239 redirect(n->nredir.redirect, 0);
14240 evaltreenr(n->nredir.n, flags);
14241 /* never returns */
14242}
14243
14244static void
14245forkshell_evalpipe(struct forkshell *fs)
14246{
14247 union node *n = fs->n;
14248 int flags = fs->flags;
14249 int prevfd = fs->fd[2];
14250 int pip[2] = {fs->fd[0], fs->fd[1]};
14251
14252 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14253 INT_ON;
14254 if (pip[1] >= 0) {
14255 close(pip[0]);
14256 }
14257 if (prevfd > 0) {
14258 dup2(prevfd, 0);
14259 close(prevfd);
14260 }
14261 if (pip[1] > 1) {
14262 dup2(pip[1], 1);
14263 close(pip[1]);
14264 }
14265 evaltreenr(n, flags);
14266}
14267
14268static void
14269forkshell_shellexec(struct forkshell *fs)
14270{
14271 int idx = fs->fd[0];
14272 struct strlist *varlist = fs->strlist;
14273 char **argv = fs->argv;
14274 char *path = fs->string;
14275
14276 listsetvar(varlist, VEXPORT|VSTACK);
14277 shellexec(argv, path, idx);
14278}
14279
14280static void
14281forkshell_child(struct forkshell *fs)
14282{
14283 switch ( fs->fpid ) {
14284 case FS_OPENHERE:
14285 forkshell_openhere(fs);
14286 break;
14287 case FS_EVALBACKCMD:
14288 forkshell_evalbackcmd(fs);
14289 break;
14290 case FS_EVALSUBSHELL:
14291 forkshell_evalsubshell(fs);
14292 break;
14293 case FS_EVALPIPE:
14294 forkshell_evalpipe(fs);
14295 break;
14296 case FS_SHELLEXEC:
14297 forkshell_shellexec(fs);
14298 break;
14299 }
14300}
14301
14302/*
14303 * Reset the pointers to the builtin environment variables in the hash
14304 * table to point to varinit rather than the bogus copy created during
14305 * forkshell_prepare.
14306 */
14307static void
14308reinitvar(void)
14309{
14310 struct var *vp;
14311 struct var *end;
14312 struct var **vpp;
14313 struct var **old;
14314
14315 vp = varinit;
14316 end = vp + ARRAY_SIZE(varinit);
14317 do {
14318 vpp = hashvar(vp->var_text);
14319 if ( (old=findvar(vpp, vp->var_text)) != NULL ) {
14320 vp->next = (*old)->next;
14321 *old = vp;
14322 }
14323 } while (++vp < end);
14324}
14325
14326/* FIXME: should consider running forkparent() and forkchild() */
14327static int
14328spawn_forkshell(struct job *jp, struct forkshell *fs, int mode)
14329{
14330 struct forkshell *new;
14331 char buf[16];
14332 const char *argv[] = { "sh", "--forkshell", NULL, NULL };
14333 intptr_t ret;
14334
14335 new = forkshell_prepare(fs);
14336 sprintf(buf, "%x", (unsigned int)new->hMapFile);
14337 argv[2] = buf;
14338 ret = mingw_spawn_proc(argv);
14339 CloseHandle(new->hMapFile);
14340 UnmapViewOfFile(new);
14341 if (ret == -1) {
14342 free(jp);
14343 return -1;
14344 }
14345 forkparent(jp, fs->node, mode, (HANDLE)ret);
14346 return ret == -1 ? -1 : 0;
14347}
14348
14349/*
14350 * forkshell_prepare() and friends
14351 *
14352 * The sequence is as follows:
14353 * - funcblocksize, funcstringsize, nodeptrsize are initialized
14354 * - forkshell_size(fs) is called to calculate the exact memory needed
14355 * - a new struct is allocated
14356 * - funcblock, funcstring, nodeptr are initialized from the new block
14357 * - forkshell_copy(fs) is called to copy recursively everything over
14358 * it will record all pointers along the way, to nodeptr
14359 *
14360 * When this memory is mapped elsewhere, pointer fixup will be needed
14361 */
14362#define SLIST_SIZE_BEGIN(name,type) \
14363static void \
14364name(type *p) \
14365{ \
14366 while (p) { \
14367 funcblocksize += sizeof(type);
14368 /* do something here with p */
14369#define SLIST_SIZE_END() \
14370 nodeptrsize++; \
14371 p = p->next; \
14372 } \
14373}
14374
14375#define SLIST_COPY_BEGIN(name,type) \
14376static type * \
14377name(type *vp) \
14378{ \
14379 type *start; \
14380 type **vpp; \
14381 vpp = &start; \
14382 while (vp) { \
14383 *vpp = funcblock; \
14384 funcblock = (char *) funcblock + sizeof(type);
14385 /* do something here with vpp and vp */
14386#define SLIST_COPY_END() \
14387 SAVE_PTR((*vpp)->next); \
14388 vp = vp->next; \
14389 vpp = &(*vpp)->next; \
14390 } \
14391 *vpp = NULL; \
14392 return start; \
14393}
14394
14395/*
14396 * struct var
14397 */
14398SLIST_SIZE_BEGIN(var_size,struct var)
14399funcstringsize += strlen(p->var_text) + 1;
14400nodeptrsize++; /* p->text */
14401SLIST_SIZE_END()
14402
14403SLIST_COPY_BEGIN(var_copy,struct var)
14404(*vpp)->var_text = nodeckstrdup(vp->var_text);
14405(*vpp)->flags = vp->flags;
14406/*
14407 * The only place that can set struct var#func is varinit[],
14408 * which will be fixed by forkshell_init()
14409 */
14410(*vpp)->var_func = NULL;
14411SAVE_PTR((*vpp)->var_text);
14412SLIST_COPY_END()
14413
14414/*
14415 * struct strlist
14416 */
14417SLIST_SIZE_BEGIN(strlist_size,struct strlist)
14418funcstringsize += strlen(p->text) + 1;
14419nodeptrsize++; /* p->text */
14420SLIST_SIZE_END()
14421
14422SLIST_COPY_BEGIN(strlist_copy,struct strlist)
14423(*vpp)->text = nodeckstrdup(vp->text);
14424SAVE_PTR((*vpp)->text);
14425SLIST_COPY_END()
14426
14427/*
14428 * struct tblentry
14429 */
14430static void
14431tblentry_size(struct tblentry *tep)
14432{
14433 while (tep) {
14434 funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14435 /* CMDBUILTIN, e->param.cmd needs no pointer relocation */
14436 if (tep->cmdtype == CMDFUNCTION) {
14437 funcblocksize += offsetof(struct funcnode, n);
14438 calcsize(&tep->param.func->n);
14439 nodeptrsize++; /* tep->param.func */
14440 }
14441 nodeptrsize++; /* tep->next */
14442 tep = tep->next;
14443 }
14444}
14445
14446static struct tblentry *
14447tblentry_copy(struct tblentry *tep)
14448{
14449 struct tblentry *start;
14450 struct tblentry **newp;
14451 int size;
14452
14453 newp = &start;
14454 while (tep) {
14455 *newp = funcblock;
14456 size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14457
14458 funcblock = (char *) funcblock + size;
14459 memcpy(*newp, tep, size);
14460 switch (tep->cmdtype) {
14461 case CMDBUILTIN:
14462 /* No pointer saving, this field must be fixed by forkshell_init() */
14463 (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab);
14464 break;
14465 case CMDFUNCTION:
14466 (*newp)->param.func = funcblock;
14467 funcblock = (char *) funcblock + offsetof(struct funcnode, n);
14468 copynode(&tep->param.func->n);
14469 SAVE_PTR((*newp)->param.func);
14470 break;
14471 default:
14472 break;
14473 }
14474 SAVE_PTR((*newp)->next);
14475 tep = tep->next;
14476 newp = &(*newp)->next;
14477 }
14478 *newp = NULL;
14479 return start;
14480}
14481
14482static void
14483cmdtable_size(struct tblentry **cmdtablep)
14484{
14485 int i;
14486 nodeptrsize += CMDTABLESIZE;
14487 funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE;
14488 for (i = 0; i < CMDTABLESIZE; i++)
14489 tblentry_size(cmdtablep[i]);
14490}
14491
14492static struct tblentry **
14493cmdtable_copy(struct tblentry **cmdtablep)
14494{
14495 struct tblentry **new = funcblock;
14496 int i;
14497
14498 funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE;
14499 for (i = 0; i < CMDTABLESIZE; i++) {
14500 new[i] = tblentry_copy(cmdtablep[i]);
14501 SAVE_PTR(new[i]);
14502 }
14503 return new;
14504}
14505
14506/*
14507 * char **
14508 */
14509static void
14510argv_size(char **p)
14511{
14512 while (p && *p) {
14513 funcblocksize += sizeof(char *);
14514 funcstringsize += strlen(*p)+1;
14515 nodeptrsize++;
14516 p++;
14517 }
14518 funcblocksize += sizeof(char *);
14519}
14520
14521static char **
14522argv_copy(char **p)
14523{
14524 char **new, **start = funcblock;
14525
14526 while (p && *p) {
14527 new = funcblock;
14528 funcblock = (char *) funcblock + sizeof(char *);
14529 *new = nodeckstrdup(*p);
14530 SAVE_PTR(*new);
14531 p++;
14532 new++;
14533 }
14534 new = funcblock;
14535 funcblock = (char *) funcblock + sizeof(char *);
14536 *new = NULL;
14537 return start;
14538}
14539
14540/*
14541 * struct redirtab
14542 */
14543static void
14544redirtab_size(struct redirtab *rdtp)
14545{
14546 while (rdtp) {
14547 funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14548 rdtp = rdtp->next;
14549 nodeptrsize++; /* rdtp->next */
14550 }
14551}
14552
14553static struct redirtab *
14554redirtab_copy(struct redirtab *rdtp)
14555{
14556 struct redirtab *start;
14557 struct redirtab **vpp;
14558
14559 vpp = &start;
14560 while (rdtp) {
14561 int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14562 *vpp = funcblock;
14563 funcblock = (char *) funcblock + size;
14564 memcpy(*vpp, rdtp, size);
14565 SAVE_PTR((*vpp)->next);
14566 rdtp = rdtp->next;
14567 vpp = &(*vpp)->next;
14568 }
14569 *vpp = NULL;
14570 return start;
14571}
14572
14573#undef shellparam
14574#undef redirlist
14575#undef varinit
14576#undef vartab
14577static void
14578globals_var_size(struct globals_var *gvp)
14579{
14580 int i;
14581
14582 funcblocksize += sizeof(struct globals_var);
14583 argv_size(gvp->shellparam.p);
14584 redirtab_size(gvp->redirlist);
14585 for (i = 0; i < VTABSIZE; i++)
14586 var_size(gvp->vartab[i]);
14587 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14588 var_size(gvp->varinit+i);
14589 nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */
14590}
14591
14592#undef preverrout_fd
14593static struct globals_var *
14594globals_var_copy(struct globals_var *gvp)
14595{
14596 int i;
14597 struct globals_var *new;
14598
14599 new = funcblock;
14600 funcblock = (char *) funcblock + sizeof(struct globals_var);
14601
14602 /* shparam */
14603 memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam));
14604 new->shellparam.malloced = 0;
14605 new->shellparam.p = argv_copy(gvp->shellparam.p);
14606 SAVE_PTR(new->shellparam.p);
14607
14608 new->redirlist = redirtab_copy(gvp->redirlist);
14609 SAVE_PTR(new->redirlist);
14610
14611 new->preverrout_fd = gvp->preverrout_fd;
14612 for (i = 0; i < VTABSIZE; i++) {
14613 new->vartab[i] = var_copy(gvp->vartab[i]);
14614 SAVE_PTR(new->vartab[i]);
14615 }
14616
14617 /* Can't use var_copy because varinit is already allocated */
14618 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) {
14619 new->varinit[i].next = NULL;
14620 new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text);
14621 SAVE_PTR(new->varinit[i].var_text);
14622 new->varinit[i].flags = gvp->varinit[i].flags;
14623 new->varinit[i].var_func = gvp->varinit[i].var_func;
14624 }
14625 return new;
14626}
14627
14628#undef minusc
14629#undef curdir
14630#undef physdir
14631#undef arg0
14632#undef nullstr
14633static void
14634globals_misc_size(struct globals_misc *p)
14635{
14636 funcblocksize += sizeof(struct globals_misc);
14637 funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1;
14638 if (p->curdir != p->nullstr)
14639 funcstringsize += strlen(p->curdir) + 1;
14640 if (p->physdir != p->nullstr)
14641 funcstringsize += strlen(p->physdir) + 1;
14642 funcstringsize += strlen(p->arg0) + 1;
14643 nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */
14644}
14645
14646static struct globals_misc *
14647globals_misc_copy(struct globals_misc *p)
14648{
14649 struct globals_misc *new = funcblock;
14650
14651 funcblock = (char *) funcblock + sizeof(struct globals_misc);
14652 memcpy(new, p, sizeof(struct globals_misc));
14653
14654 new->minusc = nodeckstrdup(p->minusc);
14655 new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr;
14656 new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr;
14657 new->arg0 = nodeckstrdup(p->arg0);
14658 SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0);
14659 return new;
14660}
14661
14662static void
14663forkshell_size(struct forkshell *fs)
14664{
14665 funcblocksize += sizeof(struct forkshell);
14666 globals_var_size(fs->gvp);
14667 globals_misc_size(fs->gmp);
14668 cmdtable_size(fs->cmdtable);
14669 /* optlist_transfer(sending, fd); */
14670 /* misc_transfer(sending, fd); */
14671
14672 calcsize(fs->n);
14673 argv_size(fs->argv);
14674 funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1;
14675 strlist_size(fs->strlist);
14676
14677 nodeptrsize += 7; /* gvp, gmp, cmdtable, n, argv, string, strlist */
14678}
14679
14680static struct forkshell *
14681forkshell_copy(struct forkshell *fs)
14682{
14683 struct forkshell *new;
14684
14685 new = funcblock;
14686 funcblock = (char *) funcblock + sizeof(struct forkshell);
14687
14688 memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */
14689 new->gvp = globals_var_copy(fs->gvp);
14690 new->gmp = globals_misc_copy(fs->gmp);
14691 new->cmdtable = cmdtable_copy(fs->cmdtable);
14692 SAVE_PTR3(new->gvp, new->gmp, new->cmdtable);
14693
14694 new->n = copynode(fs->n);
14695 new->argv = argv_copy(fs->argv);
14696 new->string = nodeckstrdup(fs->string);
14697 new->strlist = strlist_copy(fs->strlist);
14698 SAVE_PTR4(new->n, new->argv, new->string, new->strlist);
14699 return new;
14700}
14701
14702static struct forkshell *
14703forkshell_prepare(struct forkshell *fs)
14704{
14705 struct forkshell *new;
14706 int size, nodeptr_offset;
14707 HANDLE h;
14708 SECURITY_ATTRIBUTES sa;
14709
14710 /* Calculate size of "new" */
14711 fs->gvp = ash_ptr_to_globals_var;
14712 fs->gmp = ash_ptr_to_globals_misc;
14713 fs->cmdtable = cmdtable;
14714
14715 nodeptrsize = 1; /* NULL terminated */
14716 funcblocksize = 0;
14717 funcstringsize = 0;
14718 forkshell_size(fs);
14719 size = funcblocksize + funcstringsize + nodeptrsize*sizeof(char *);
14720
14721 /* Allocate, initialize pointers */
14722 memset(&sa, 0, sizeof(sa));
14723 sa.nLength = sizeof(sa);
14724 sa.lpSecurityDescriptor = NULL;
14725 sa.bInheritHandle = TRUE;
14726 h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL);
14727 new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14728 /* new = ckmalloc(size); */
14729 funcblock = new;
14730 funcstring = (char *) funcblock + funcblocksize;
14731 nodeptr = (char **)((char *)funcstring + funcstringsize);
14732 nodeptr_offset = (char *)nodeptr - (char *)new;
14733
14734 /* Now pack them all */
14735 forkshell_copy(fs);
14736
14737 /* Finish it up */
14738 *nodeptr = NULL;
14739 new->size = size;
14740 new->nodeptr_offset = nodeptr_offset;
14741 new->old_base = new;
14742 new->hMapFile = h;
14743 return new;
14744}
14745
14746#undef exception_handler
14747#undef trap
14748#undef trap_ptr
14749static void *sticky_mem_start, *sticky_mem_end;
14750static void
14751forkshell_init(const char *idstr)
14752{
14753 struct forkshell *fs;
14754 int map_handle;
14755 HANDLE h;
14756 struct globals_var **gvpp;
14757 struct globals_misc **gmpp;
14758 int i;
14759 char **ptr;
14760
14761 if (sscanf(idstr, "%x", &map_handle) != 1)
14762 bb_error_msg_and_die("invalid forkshell ID");
14763
14764 h = (HANDLE)map_handle;
14765 fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14766 if (!fs)
14767 bb_error_msg_and_die("Invalid forkshell memory");
14768
14769 /* this memory can't be freed */
14770 sticky_mem_start = fs;
14771 sticky_mem_end = (char *) fs + fs->size;
14772
14773 /* pointer fixup */
14774 nodeptr = (char **)((char *)fs + fs->nodeptr_offset);
14775 for ( i=0; nodeptr[i]; ++i ) {
14776 ptr = (char **)((char *)fs + (nodeptr[i] - (char *)fs->old_base));
14777 if (*ptr)
14778 *ptr = (char *)fs + (*ptr - (char *)fs->old_base);
14779 }
14780
14781 /* Now fix up stuff that can't be transferred */
14782 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14783 fs->gvp->varinit[i].var_func = varinit_data[i].var_func;
14784 for (i = 0; i < CMDTABLESIZE; i++) {
14785 struct tblentry *e = fs->cmdtable[i];
14786 while (e) {
14787 if (e->cmdtype == CMDBUILTIN)
14788 e->param.cmd = builtintab + (int)e->param.cmd;
14789 e = e->next;
14790 }
14791 }
14792 fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler;
14793 for (i = 0; i < NSIG; i++)
14794 fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i];
14795 fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr;
14796
14797 /* Switch global variables */
14798 gvpp = (struct globals_var **)&ash_ptr_to_globals_var;
14799 *gvpp = fs->gvp;
14800 gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc;
14801 *gmpp = fs->gmp;
14802 cmdtable = fs->cmdtable;
14803
14804 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
14805
14806 reinitvar();
14807
14808 forkshell_child(fs);
14809}
14810
14811#undef free
14812static void
14813sticky_free(void *base)
14814{
14815 if (base >= sticky_mem_start && base < sticky_mem_end)
14816 return;
14817 free(base);
14818}
14819#endif
13567 14820
13568/*- 14821/*-
13569 * Copyright (c) 1989, 1991, 1993, 1994 14822 * Copyright (c) 1989, 1991, 1993, 1994