aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-14 11:06:35 +1000
committerNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-14 11:06:35 +1000
commit87911f4fcd86f7abc0aefba8e9cbec2ac9d127e4 (patch)
treec91a4a9a048f3cc2bdae47fa61a02db7a108170d
parentba3cea41689d211093d914212de048cc06d976ce (diff)
parent9375ca983262075d8420fd0d88d00a088916fc10 (diff)
downloadbusybox-w32-87911f4fcd86f7abc0aefba8e9cbec2ac9d127e4.tar.gz
busybox-w32-87911f4fcd86f7abc0aefba8e9cbec2ac9d127e4.tar.bz2
busybox-w32-87911f4fcd86f7abc0aefba8e9cbec2ac9d127e4.zip
Merge branch 'ash'
-rw-r--r--libbb/Kbuild2
-rw-r--r--libbb/lineedit.c10
-rw-r--r--scripts/defconfig.mingw326
-rw-r--r--shell/ash.c1088
-rw-r--r--win32/termios.c27
5 files changed, 1114 insertions, 19 deletions
diff --git a/libbb/Kbuild b/libbb/Kbuild
index eb3cd5039..a8a1da1f9 100644
--- a/libbb/Kbuild
+++ b/libbb/Kbuild
@@ -74,7 +74,6 @@ lib-y += procps.o
74lib-y += progress.o 74lib-y += progress.o
75lib-y += ptr_to_globals.o 75lib-y += ptr_to_globals.o
76lib-y += read.o 76lib-y += read.o
77lib-y += read_key.o
78lib-y += recursive_action.o 77lib-y += recursive_action.o
79lib-y += remove_file.o 78lib-y += remove_file.o
80lib-y += run_shell.o 79lib-y += run_shell.o
@@ -115,6 +114,7 @@ lib-$(CONFIG_PLATFORM_POSIX) += kernel_version.o
115lib-$(CONFIG_PLATFORM_POSIX) += login.o 114lib-$(CONFIG_PLATFORM_POSIX) += login.o
116lib-$(CONFIG_PLATFORM_POSIX) += makedev.o 115lib-$(CONFIG_PLATFORM_POSIX) += makedev.o
117lib-$(CONFIG_PLATFORM_POSIX) += match_fstype.o 116lib-$(CONFIG_PLATFORM_POSIX) += match_fstype.o
117lib-$(CONFIG_PLATFORM_POSIX) += read_key.o
118lib-$(CONFIG_PLATFORM_POSIX) += safe_gethostname.o 118lib-$(CONFIG_PLATFORM_POSIX) += safe_gethostname.o
119lib-$(CONFIG_PLATFORM_POSIX) += signals.o 119lib-$(CONFIG_PLATFORM_POSIX) += signals.o
120lib-$(CONFIG_PLATFORM_POSIX) += udp_io.o 120lib-$(CONFIG_PLATFORM_POSIX) += udp_io.o
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index dc90846f9..9a04c38bf 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -564,7 +564,11 @@ static int path_parse(char ***p, int flags)
564 tmp = (char*)pth; 564 tmp = (char*)pth;
565 npth = 1; /* path component count */ 565 npth = 1; /* path component count */
566 while (1) { 566 while (1) {
567#if ENABLE_PLATFORM_MINGW32
568 tmp = next_path_sep(tmp);
569#else
567 tmp = strchr(tmp, ':'); 570 tmp = strchr(tmp, ':');
571#endif
568 if (!tmp) 572 if (!tmp)
569 break; 573 break;
570 if (*++tmp == '\0') 574 if (*++tmp == '\0')
@@ -576,7 +580,11 @@ static int path_parse(char ***p, int flags)
576 res[0] = tmp = xstrdup(pth); 580 res[0] = tmp = xstrdup(pth);
577 npth = 1; 581 npth = 1;
578 while (1) { 582 while (1) {
583#if ENABLE_PLATFORM_MINGW32
584 tmp = next_path_sep(tmp);
585#else
579 tmp = strchr(tmp, ':'); 586 tmp = strchr(tmp, ':');
587#endif
580 if (!tmp) 588 if (!tmp)
581 break; 589 break;
582 *tmp++ = '\0'; /* ':' -> '\0' */ 590 *tmp++ = '\0'; /* ':' -> '\0' */
@@ -1781,6 +1789,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1781 1789
1782 INIT_S(); 1790 INIT_S();
1783 1791
1792#if !ENABLE_PLATFORM_MINGW32
1784 if (tcgetattr(STDIN_FILENO, &initial_settings) < 0 1793 if (tcgetattr(STDIN_FILENO, &initial_settings) < 0
1785 || !(initial_settings.c_lflag & ECHO) 1794 || !(initial_settings.c_lflag & ECHO)
1786 ) { 1795 ) {
@@ -1794,6 +1803,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1794 DEINIT_S(); 1803 DEINIT_S();
1795 return len; 1804 return len;
1796 } 1805 }
1806#endif
1797 1807
1798 init_unicode(); 1808 init_unicode();
1799 1809
diff --git a/scripts/defconfig.mingw32 b/scripts/defconfig.mingw32
index 37968bbde..356a08226 100644
--- a/scripts/defconfig.mingw32
+++ b/scripts/defconfig.mingw32
@@ -92,12 +92,12 @@ CONFIG_MD5_SIZE_VS_SPEED=2
92# CONFIG_FEATURE_FAST_TOP is not set 92# CONFIG_FEATURE_FAST_TOP is not set
93# CONFIG_FEATURE_ETC_NETWORKS is not set 93# CONFIG_FEATURE_ETC_NETWORKS is not set
94# CONFIG_FEATURE_CYGWIN_TTY is not set 94# CONFIG_FEATURE_CYGWIN_TTY is not set
95# CONFIG_FEATURE_EDITING is not set 95CONFIG_FEATURE_EDITING=y
96CONFIG_FEATURE_EDITING_MAX_LEN=0 96CONFIG_FEATURE_EDITING_MAX_LEN=1024
97# CONFIG_FEATURE_EDITING_VI is not set 97# CONFIG_FEATURE_EDITING_VI is not set
98CONFIG_FEATURE_EDITING_HISTORY=0 98CONFIG_FEATURE_EDITING_HISTORY=0
99# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set 99# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set
100# CONFIG_FEATURE_TAB_COMPLETION is not set 100CONFIG_FEATURE_TAB_COMPLETION=y
101# CONFIG_FEATURE_USERNAME_COMPLETION is not set 101# CONFIG_FEATURE_USERNAME_COMPLETION is not set
102# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set 102# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set
103# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set 103# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
diff --git a/shell/ash.c b/shell/ash.c
index ab935e72a..5d8415a79 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -17,6 +17,18 @@
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" is still understood as executable (option to turn off?)
25 * - both / and \ are supported in PATH. Usually you must use /
26 * - trap/job does not work
27 * - /dev/null is supported for redirection
28 * - no $PPID
29 */
30
31/*
20 * The following should be set to reflect the type of system you have: 32 * The following should be set to reflect the type of system you have:
21 * JOBS -> 1 if you have Berkeley job control, 0 otherwise. 33 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
22 * define SYSV if you are running under System V. 34 * define SYSV if you are running under System V.
@@ -81,6 +93,41 @@
81# error "Do not even bother, ash will not run on NOMMU machine" 93# error "Do not even bother, ash will not run on NOMMU machine"
82#endif 94#endif
83 95
96#if ENABLE_PLATFORM_MINGW32
97struct forkshell;
98union node;
99struct strlist;
100struct job;
101
102typedef void (*forkpoint_fn)(struct forkshell *fs);
103struct forkshell {
104 /* filled by forkshell_copy() */
105 struct globals_var *gvp;
106 struct globals_misc *gmp;
107 struct tblentry **cmdtable;
108 struct localvar *localvars;
109 /* struct alias **atab; */
110 /* struct parsefile *g_parsefile; */
111 int fpid;
112 HANDLE hMapFile;
113 void *old_base;
114 int nodeptr_offset;
115 int size;
116
117 forkpoint_fn fp;
118 /* optional data, used by forkpoint_fn */
119 int flags;
120 int fd[10];
121 union node *n;
122 char **argv;
123 char *string;
124 struct strlist *strlist;
125 pid_t pid;
126};
127static void sticky_free(void *p);
128#define free(p) sticky_free(p)
129static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode);
130#endif
84 131
85/* ============ Hash table sizes. Configurable. */ 132/* ============ Hash table sizes. Configurable. */
86 133
@@ -774,7 +821,7 @@ static void
774opentrace(void) 821opentrace(void)
775{ 822{
776 char s[100]; 823 char s[100];
777#ifdef O_APPEND 824#if defined(O_APPEND) && !ENABLE_PLATFORM_MINGW32
778 int flags; 825 int flags;
779#endif 826#endif
780 827
@@ -799,7 +846,7 @@ opentrace(void)
799 return; 846 return;
800 } 847 }
801 } 848 }
802#ifdef O_APPEND 849#if defined(O_APPEND) && !ENABLE_PLATFORM_MINGW32
803 flags = fcntl(fileno(tracefile), F_GETFL); 850 flags = fcntl(fileno(tracefile), F_GETFL);
804 if (flags >= 0) 851 if (flags >= 0)
805 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); 852 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
@@ -2261,10 +2308,22 @@ path_advance(const char **path, const char *name)
2261 if (*path == NULL) 2308 if (*path == NULL)
2262 return NULL; 2309 return NULL;
2263 start = *path; 2310 start = *path;
2311#if ENABLE_PLATFORM_MINGW32
2312 p = next_path_sep(start);
2313 q = strchr(start, '%');
2314 if ((p && q && q < p) || (!p && q))
2315 p = q;
2316 if (!p)
2317 for (p = start; *p; p++)
2318 continue;
2319#else
2264 for (p = start; *p && *p != ':' && *p != '%'; p++) 2320 for (p = start; *p && *p != ':' && *p != '%'; p++)
2265 continue; 2321 continue;
2322#endif
2266 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2323 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2267 while (stackblocksize() < len) 2324
2325 /* preserve space for .exe too */
2326 while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len))
2268 growstackblock(); 2327 growstackblock();
2269 q = stackblock(); 2328 q = stackblock();
2270 if (p != start) { 2329 if (p != start) {
@@ -2380,6 +2439,98 @@ cdopt(void)
2380static const char * 2439static const char *
2381updatepwd(const char *dir) 2440updatepwd(const char *dir)
2382{ 2441{
2442#if ENABLE_PLATFORM_MINGW32
2443 /*
2444 * Due to Windows drive notion, getting pwd is a completely
2445 * different thing. Handle it in a separate routine
2446 */
2447
2448 char *new;
2449 char *p;
2450 char *cdcomppath;
2451 const char *lim;
2452 /*
2453 * There are four cases
2454 * absdrive + abspath: c:/path
2455 * absdrive + !abspath: c:path
2456 * !absdrive + abspath: /path
2457 * !absdrive + !abspath: path
2458 *
2459 * Damn DOS!
2460 * c:path behaviour is "undefined"
2461 * To properly handle this case, I have to keep track of cwd
2462 * of every drive, which is too painful to do.
2463 * So when c:path is given, I assume it's c:${curdir}path
2464 * with ${curdir} comes from the current drive
2465 */
2466 int absdrive = *dir && dir[1] == ':';
2467 int abspath = absdrive ? dir[2] == '/' : *dir == '/';
2468 char *drive;
2469
2470 cdcomppath = ststrdup(dir);
2471 STARTSTACKSTR(new);
2472 if (!absdrive && curdir == nullstr)
2473 return 0;
2474 if (!abspath) {
2475 if (curdir == nullstr)
2476 return 0;
2477 new = stack_putstr(curdir, new);
2478 }
2479 new = makestrspace(strlen(dir) + 2, new);
2480
2481 drive = stackblock();
2482 if (absdrive) {
2483 *drive = *dir;
2484 cdcomppath += 2;
2485 dir += 2;
2486 } else {
2487 *drive = *curdir;
2488 }
2489 drive[1] = ':'; /* in case of absolute drive+path */
2490
2491 if (abspath)
2492 new = drive + 2;
2493 lim = drive + 3;
2494 if (!abspath) {
2495 if (new[-1] != '/')
2496 USTPUTC('/', new);
2497 if (new > lim && *lim == '/')
2498 lim++;
2499 } else {
2500 USTPUTC('/', new);
2501 cdcomppath ++;
2502 if (dir[1] == '/' && dir[2] != '/') {
2503 USTPUTC('/', new);
2504 cdcomppath++;
2505 lim++;
2506 }
2507 }
2508 p = strtok(cdcomppath, "/");
2509 while (p) {
2510 switch (*p) {
2511 case '.':
2512 if (p[1] == '.' && p[2] == '\0') {
2513 while (new > lim) {
2514 STUNPUTC(new);
2515 if (new[-1] == '/')
2516 break;
2517 }
2518 break;
2519 }
2520 if (p[1] == '\0')
2521 break;
2522 /* fall through */
2523 default:
2524 new = stack_putstr(p, new);
2525 USTPUTC('/', new);
2526 }
2527 p = strtok(0, "/");
2528 }
2529 if (new > lim)
2530 STUNPUTC(new);
2531 *new = 0;
2532 return stackblock();
2533#else
2383 char *new; 2534 char *new;
2384 char *p; 2535 char *p;
2385 char *cdcomppath; 2536 char *cdcomppath;
@@ -2433,6 +2584,7 @@ updatepwd(const char *dir)
2433 STUNPUTC(new); 2584 STUNPUTC(new);
2434 *new = 0; 2585 *new = 0;
2435 return stackblock(); 2586 return stackblock();
2587#endif
2436} 2588}
2437 2589
2438/* 2590/*
@@ -2527,7 +2679,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2527 } 2679 }
2528 if (!dest) 2680 if (!dest)
2529 dest = nullstr; 2681 dest = nullstr;
2530 if (*dest == '/') 2682 if (is_absolute_path(dest))
2531 goto step7; 2683 goto step7;
2532 if (*dest == '.') { 2684 if (*dest == '.') {
2533 c = dest[1]; 2685 c = dest[1];
@@ -3301,6 +3453,8 @@ setsignal(int signo)
3301 char cur_act, new_act; 3453 char cur_act, new_act;
3302 struct sigaction act; 3454 struct sigaction act;
3303 3455
3456 if (ENABLE_PLATFORM_MINGW32)
3457 return;
3304 t = trap[signo]; 3458 t = trap[signo];
3305 new_act = S_DFL; 3459 new_act = S_DFL;
3306 if (t != NULL) { /* trap for this sig is set */ 3460 if (t != NULL) { /* trap for this sig is set */
@@ -3608,7 +3762,7 @@ setjobctl(int on)
3608 if (--fd < 0) 3762 if (--fd < 0)
3609 goto out; 3763 goto out;
3610 } 3764 }
3611 fd = fcntl(fd, F_DUPFD, 10); 3765 fd = copyfd(fd, 10);
3612 if (ofd >= 0) 3766 if (ofd >= 0)
3613 close(ofd); 3767 close(ofd);
3614 if (fd < 0) 3768 if (fd < 0)
@@ -3782,6 +3936,53 @@ sprint_status(char *s, int status, int sigonly)
3782 return col; 3936 return col;
3783} 3937}
3784 3938
3939#if ENABLE_PLATFORM_MINGW32
3940/*
3941 * Windows does not know about parent-child relationship
3942 * They don't support waitpid(-1)
3943 */
3944static pid_t
3945waitpid_child(int *status)
3946{
3947 HANDLE *pidlist, *pidp;
3948 int pid_nr = 0;
3949 pid_t pid;
3950 DWORD win_status, idx;
3951 struct job *jb;
3952
3953 #define LOOP(stmt) \
3954 for (jb = curjob; jb; jb = jb->prev_job) { \
3955 struct procstat *ps, *psend; \
3956 if (jb->state == JOBDONE) \
3957 continue; \
3958 ps = jb->ps; \
3959 psend = ps + jb->nprocs; \
3960 while (ps < psend) { \
3961 if (ps->ps_pid != -1) { \
3962 stmt; \
3963 } \
3964 ps++; \
3965 } \
3966 }
3967
3968 LOOP(pid_nr++);
3969 pidp = pidlist = ckmalloc(sizeof(*pidlist)*pid_nr);
3970 LOOP(*pidp++ = (HANDLE)ps->ps_pid);
3971 #undef LOOP
3972
3973 idx = WaitForMultipleObjects(pid_nr, pidlist, FALSE, INFINITE);
3974 if (idx >= pid_nr) {
3975 free(pidlist);
3976 return -1;
3977 }
3978 GetExitCodeProcess(pidlist[idx], &win_status);
3979 pid = (int)pidlist[idx];
3980 free(pidlist);
3981 *status = (int)win_status;
3982 return pid;
3983}
3984#endif
3985
3785static int 3986static int
3786dowait(int wait_flags, struct job *job) 3987dowait(int wait_flags, struct job *job)
3787{ 3988{
@@ -3798,7 +3999,11 @@ dowait(int wait_flags, struct job *job)
3798 * NB: _not_ safe_waitpid, we need to detect EINTR */ 3999 * NB: _not_ safe_waitpid, we need to detect EINTR */
3799 if (doing_jobctl) 4000 if (doing_jobctl)
3800 wait_flags |= WUNTRACED; 4001 wait_flags |= WUNTRACED;
4002#if ENABLE_PLATFORM_MINGW32
4003 pid = waitpid_child(&status);
4004#else
3801 pid = waitpid(-1, &status, wait_flags); 4005 pid = waitpid(-1, &status, wait_flags);
4006#endif
3802 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", 4007 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3803 pid, status, errno, strerror(errno))); 4008 pid, status, errno, strerror(errno)));
3804 if (pid <= 0) 4009 if (pid <= 0)
@@ -3821,6 +4026,8 @@ dowait(int wait_flags, struct job *job)
3821 jobno(jp), pid, ps->ps_status, status)); 4026 jobno(jp), pid, ps->ps_status, status));
3822 ps->ps_status = status; 4027 ps->ps_status = status;
3823 thisjob = jp; 4028 thisjob = jp;
4029 if (ENABLE_PLATFORM_MINGW32)
4030 ps->ps_pid = -1;
3824 } 4031 }
3825 if (ps->ps_status == -1) 4032 if (ps->ps_status == -1)
3826 state = JOBRUNNING; 4033 state = JOBRUNNING;
@@ -4052,6 +4259,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
4052 int retval; 4259 int retval;
4053 struct job *jp; 4260 struct job *jp;
4054 4261
4262 if (ENABLE_PLATFORM_MINGW32)
4263 return 0;
4264
4055 if (pending_sig) 4265 if (pending_sig)
4056 raise_exception(EXSIG); 4266 raise_exception(EXSIG);
4057 4267
@@ -4655,7 +4865,7 @@ static void
4655forkparent(struct job *jp, union node *n, int mode, pid_t pid) 4865forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4656{ 4866{
4657 TRACE(("In parent shell: child = %d\n", pid)); 4867 TRACE(("In parent shell: child = %d\n", pid));
4658 if (!jp) { 4868 if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */
4659 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) 4869 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4660 continue; 4870 continue;
4661 jobless++; 4871 jobless++;
@@ -4695,6 +4905,9 @@ forkshell(struct job *jp, union node *n, int mode)
4695 int pid; 4905 int pid;
4696 4906
4697 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); 4907 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4908 if (ENABLE_PLATFORM_MINGW32)
4909 return -1;
4910
4698 pid = fork(); 4911 pid = fork();
4699 if (pid < 0) { 4912 if (pid < 0) {
4700 TRACE(("Fork failed, errno=%d", errno)); 4913 TRACE(("Fork failed, errno=%d", errno));
@@ -4891,11 +5104,39 @@ noclobberopen(const char *fname)
4891 */ 5104 */
4892/* openhere needs this forward reference */ 5105/* openhere needs this forward reference */
4893static void expandhere(union node *arg, int fd); 5106static void expandhere(union node *arg, int fd);
5107#if ENABLE_PLATFORM_MINGW32
5108static void
5109forkshell_openhere(struct forkshell *fs)
5110{
5111 union node *redir = fs->n;
5112 int pip[2];
5113
5114 pip[0] = fs->fd[0];
5115 pip[1] = fs->fd[1];
5116
5117 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
5118
5119 close(pip[0]);
5120 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5121 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5122 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5123 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5124 signal(SIGPIPE, SIG_DFL);
5125 if (redir->type == NHERE) {
5126 size_t len = strlen(redir->nhere.doc->narg.text);
5127 full_write(pip[1], redir->nhere.doc->narg.text, len);
5128 } else /* NXHERE */
5129 expandhere(redir->nhere.doc, pip[1]);
5130 _exit(EXIT_SUCCESS);
5131}
5132#endif
5133
4894static int 5134static int
4895openhere(union node *redir) 5135openhere(union node *redir)
4896{ 5136{
4897 int pip[2]; 5137 int pip[2];
4898 size_t len = 0; 5138 size_t len = 0;
5139 IF_PLATFORM_MINGW32(struct forkshell fs);
4899 5140
4900 if (pipe(pip) < 0) 5141 if (pipe(pip) < 0)
4901 ash_msg_and_raise_error("pipe call failed"); 5142 ash_msg_and_raise_error("pipe call failed");
@@ -4906,6 +5147,16 @@ openhere(union node *redir)
4906 goto out; 5147 goto out;
4907 } 5148 }
4908 } 5149 }
5150#if ENABLE_PLATFORM_MINGW32
5151 memset(&fs, 0, sizeof(fs));
5152 fs.fp = forkshell_openhere;
5153 fs.flags = 0;
5154 fs.n = redir;
5155 fs.fd[0] = pip[0];
5156 fs.fd[1] = pip[1];
5157 if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0)
5158 ash_msg_and_raise_error("unable to spawn shell");
5159#endif
4909 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 5160 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4910 /* child */ 5161 /* child */
4911 close(pip[0]); 5162 close(pip[0]);
@@ -4931,6 +5182,31 @@ openredirect(union node *redir)
4931 char *fname; 5182 char *fname;
4932 int f; 5183 int f;
4933 5184
5185#if ENABLE_PLATFORM_MINGW32
5186 /* Support for /dev/null */
5187 switch (redir->nfile.type) {
5188 case NFROM:
5189 if (!strcmp(redir->nfile.expfname, "/dev/null"))
5190 return open("nul",O_RDWR);
5191 if (!strncmp(redir->nfile.expfname, "/dev/", 5)) {
5192 ash_msg("Unhandled device %s\n", redir->nfile.expfname);
5193 return -1;
5194 }
5195 break;
5196
5197 case NFROMTO:
5198 case NTO:
5199 case NCLOBBER:
5200 case NAPPEND:
5201 if (!strcmp(redir->nfile.expfname, "/dev/null"))
5202 return open("nul",O_RDWR);
5203 if (!strncmp(redir->nfile.expfname, "/dev/", 5)) {
5204 ash_msg("Unhandled device %s\n", redir->nfile.expfname);
5205 return -1;
5206 }
5207 break;
5208 }
5209#endif
4934 switch (redir->nfile.type) { 5210 switch (redir->nfile.type) {
4935 case NFROM: 5211 case NFROM:
4936 fname = redir->nfile.expfname; 5212 fname = redir->nfile.expfname;
@@ -5013,6 +5289,18 @@ copyfd(int from, int to)
5013 /*if (from != to)*/ 5289 /*if (from != to)*/
5014 newfd = dup2(from, to); 5290 newfd = dup2(from, to);
5015 } else { 5291 } else {
5292 if (ENABLE_PLATFORM_MINGW32) {
5293 char* fds = ckmalloc(to);
5294 int i,fd;
5295 memset(fds,0,to);
5296 while ((fd = dup(from)) < to && fd >= 0)
5297 fds[fd] = 1;
5298 for (i = 0;i < to;i ++)
5299 if (fds[i])
5300 close(i);
5301 free(fds);
5302 return fd;
5303 }
5016 newfd = fcntl(from, F_DUPFD, to); 5304 newfd = fcntl(from, F_DUPFD, to);
5017 } 5305 }
5018 if (newfd < 0) { 5306 if (newfd < 0) {
@@ -5157,7 +5445,7 @@ redirect(union node *redir, int flags)
5157#endif 5445#endif
5158 if (need_to_remember(sv, fd)) { 5446 if (need_to_remember(sv, fd)) {
5159 /* Copy old descriptor */ 5447 /* Copy old descriptor */
5160 i = fcntl(fd, F_DUPFD, 10); 5448 i = copyfd(fd, 10);
5161/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds 5449/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5162 * are closed in popredir() in the child, preventing them from leaking 5450 * are closed in popredir() in the child, preventing them from leaking
5163 * into child. (popredir() also cleans up the mess in case of failures) 5451 * into child. (popredir() also cleans up the mess in case of failures)
@@ -5618,6 +5906,8 @@ exptilde(char *startp, char *p, int flags)
5618 if (*name == '\0') { 5906 if (*name == '\0') {
5619 home = lookupvar(homestr); 5907 home = lookupvar(homestr);
5620 } else { 5908 } else {
5909 if (ENABLE_PLATFORM_MINGW32)
5910 goto lose;
5621 pw = getpwnam(name); 5911 pw = getpwnam(name);
5622 if (pw == NULL) 5912 if (pw == NULL)
5623 goto lose; 5913 goto lose;
@@ -5645,6 +5935,7 @@ struct backcmd { /* result of evalbackcmd */
5645 int fd; /* file descriptor to read from */ 5935 int fd; /* file descriptor to read from */
5646 int nleft; /* number of chars in buffer */ 5936 int nleft; /* number of chars in buffer */
5647 char *buf; /* buffer */ 5937 char *buf; /* buffer */
5938 IF_PLATFORM_MINGW32(struct forkshell fs);
5648 struct job *jp; /* job structure for command */ 5939 struct job *jp; /* job structure for command */
5649}; 5940};
5650 5941
@@ -5653,6 +5944,25 @@ static uint8_t back_exitstatus; /* exit status of backquoted command */
5653#define EV_EXIT 01 /* exit after evaluating tree */ 5944#define EV_EXIT 01 /* exit after evaluating tree */
5654static void evaltree(union node *, int); 5945static void evaltree(union node *, int);
5655 5946
5947#if ENABLE_PLATFORM_MINGW32
5948static void
5949forkshell_evalbackcmd(struct forkshell *fs)
5950{
5951 union node *n = fs->n;
5952 int pip[2] = {fs->fd[0], fs->fd[1]};
5953
5954 FORCE_INT_ON;
5955 close(pip[0]);
5956 if (pip[1] != 1) {
5957 /*close(1);*/
5958 copyfd(pip[1], 1 | COPYFD_EXACT);
5959 close(pip[1]);
5960 }
5961 eflag = 0;
5962 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5963 /* NOTREACHED */
5964}
5965#endif
5656static void FAST_FUNC 5966static void FAST_FUNC
5657evalbackcmd(union node *n, struct backcmd *result) 5967evalbackcmd(union node *n, struct backcmd *result)
5658{ 5968{
@@ -5661,6 +5971,7 @@ evalbackcmd(union node *n, struct backcmd *result)
5661 result->fd = -1; 5971 result->fd = -1;
5662 result->buf = NULL; 5972 result->buf = NULL;
5663 result->nleft = 0; 5973 result->nleft = 0;
5974 IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs)));
5664 result->jp = NULL; 5975 result->jp = NULL;
5665 if (n == NULL) 5976 if (n == NULL)
5666 goto out; 5977 goto out;
@@ -5675,6 +5986,14 @@ evalbackcmd(union node *n, struct backcmd *result)
5675 if (pipe(pip) < 0) 5986 if (pipe(pip) < 0)
5676 ash_msg_and_raise_error("pipe call failed"); 5987 ash_msg_and_raise_error("pipe call failed");
5677 jp = makejob(/*n,*/ 1); 5988 jp = makejob(/*n,*/ 1);
5989#if ENABLE_PLATFORM_MINGW32
5990 result->fs.fp = forkshell_evalbackcmd;
5991 result->fs.n = n;
5992 result->fs.fd[0] = pip[0];
5993 result->fs.fd[1] = pip[1];
5994 if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0)
5995 ash_msg_and_raise_error("unable to spawn shell");
5996#endif
5678 if (forkshell(jp, n, FORK_NOJOB) == 0) { 5997 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5679 FORCE_INT_ON; 5998 FORCE_INT_ON;
5680 close(pip[0]); 5999 close(pip[0]);
@@ -7290,7 +7609,7 @@ shellexec(char **argv, const char *path, int idx)
7290 7609
7291 clearredir(/*drop:*/ 1); 7610 clearredir(/*drop:*/ 1);
7292 envp = listvars(VEXPORT, VUNSET, 0); 7611 envp = listvars(VEXPORT, VUNSET, 0);
7293 if (strchr(argv[0], '/') != NULL 7612 if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\')))
7294#if ENABLE_FEATURE_SH_STANDALONE 7613#if ENABLE_FEATURE_SH_STANDALONE
7295 || (applet_no = find_applet_by_name(argv[0])) >= 0 7614 || (applet_no = find_applet_by_name(argv[0])) >= 0
7296#endif 7615#endif
@@ -7807,6 +8126,10 @@ static int funcblocksize; /* size of structures in function */
7807static int funcstringsize; /* size of strings in node */ 8126static int funcstringsize; /* size of strings in node */
7808static void *funcblock; /* block to allocate function from */ 8127static void *funcblock; /* block to allocate function from */
7809static char *funcstring; /* block to allocate strings from */ 8128static char *funcstring; /* block to allocate strings from */
8129#if ENABLE_PLATFORM_MINGW32
8130static int nodeptrsize;
8131static int *nodeptr;
8132#endif
7810 8133
7811/* flags in argument to evaltree */ 8134/* flags in argument to evaltree */
7812#define EV_EXIT 01 /* exit after evaluating tree */ 8135#define EV_EXIT 01 /* exit after evaluating tree */
@@ -7852,6 +8175,7 @@ sizenodelist(struct nodelist *lp)
7852{ 8175{
7853 while (lp) { 8176 while (lp) {
7854 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 8177 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8178 IF_PLATFORM_MINGW32(nodeptrsize += 2);
7855 calcsize(lp->n); 8179 calcsize(lp->n);
7856 lp = lp->next; 8180 lp = lp->next;
7857 } 8181 }
@@ -7868,15 +8192,18 @@ calcsize(union node *n)
7868 calcsize(n->ncmd.redirect); 8192 calcsize(n->ncmd.redirect);
7869 calcsize(n->ncmd.args); 8193 calcsize(n->ncmd.args);
7870 calcsize(n->ncmd.assign); 8194 calcsize(n->ncmd.assign);
8195 IF_PLATFORM_MINGW32(nodeptrsize += 3);
7871 break; 8196 break;
7872 case NPIPE: 8197 case NPIPE:
7873 sizenodelist(n->npipe.cmdlist); 8198 sizenodelist(n->npipe.cmdlist);
8199 IF_PLATFORM_MINGW32(nodeptrsize++);
7874 break; 8200 break;
7875 case NREDIR: 8201 case NREDIR:
7876 case NBACKGND: 8202 case NBACKGND:
7877 case NSUBSHELL: 8203 case NSUBSHELL:
7878 calcsize(n->nredir.redirect); 8204 calcsize(n->nredir.redirect);
7879 calcsize(n->nredir.n); 8205 calcsize(n->nredir.n);
8206 IF_PLATFORM_MINGW32(nodeptrsize += 2);
7880 break; 8207 break;
7881 case NAND: 8208 case NAND:
7882 case NOR: 8209 case NOR:
@@ -7885,31 +8212,37 @@ calcsize(union node *n)
7885 case NUNTIL: 8212 case NUNTIL:
7886 calcsize(n->nbinary.ch2); 8213 calcsize(n->nbinary.ch2);
7887 calcsize(n->nbinary.ch1); 8214 calcsize(n->nbinary.ch1);
8215 IF_PLATFORM_MINGW32(nodeptrsize += 2);
7888 break; 8216 break;
7889 case NIF: 8217 case NIF:
7890 calcsize(n->nif.elsepart); 8218 calcsize(n->nif.elsepart);
7891 calcsize(n->nif.ifpart); 8219 calcsize(n->nif.ifpart);
7892 calcsize(n->nif.test); 8220 calcsize(n->nif.test);
8221 IF_PLATFORM_MINGW32(nodeptrsize += 3);
7893 break; 8222 break;
7894 case NFOR: 8223 case NFOR:
7895 funcstringsize += strlen(n->nfor.var) + 1; 8224 funcstringsize += strlen(n->nfor.var) + 1;
7896 calcsize(n->nfor.body); 8225 calcsize(n->nfor.body);
7897 calcsize(n->nfor.args); 8226 calcsize(n->nfor.args);
8227 IF_PLATFORM_MINGW32(nodeptrsize += 3);
7898 break; 8228 break;
7899 case NCASE: 8229 case NCASE:
7900 calcsize(n->ncase.cases); 8230 calcsize(n->ncase.cases);
7901 calcsize(n->ncase.expr); 8231 calcsize(n->ncase.expr);
8232 IF_PLATFORM_MINGW32(nodeptrsize += 2);
7902 break; 8233 break;
7903 case NCLIST: 8234 case NCLIST:
7904 calcsize(n->nclist.body); 8235 calcsize(n->nclist.body);
7905 calcsize(n->nclist.pattern); 8236 calcsize(n->nclist.pattern);
7906 calcsize(n->nclist.next); 8237 calcsize(n->nclist.next);
8238 IF_PLATFORM_MINGW32(nodeptrsize += 3);
7907 break; 8239 break;
7908 case NDEFUN: 8240 case NDEFUN:
7909 case NARG: 8241 case NARG:
7910 sizenodelist(n->narg.backquote); 8242 sizenodelist(n->narg.backquote);
7911 funcstringsize += strlen(n->narg.text) + 1; 8243 funcstringsize += strlen(n->narg.text) + 1;
7912 calcsize(n->narg.next); 8244 calcsize(n->narg.next);
8245 IF_PLATFORM_MINGW32(nodeptrsize += 3);
7913 break; 8246 break;
7914 case NTO: 8247 case NTO:
7915#if ENABLE_ASH_BASH_COMPAT 8248#if ENABLE_ASH_BASH_COMPAT
@@ -7921,28 +8254,34 @@ calcsize(union node *n)
7921 case NAPPEND: 8254 case NAPPEND:
7922 calcsize(n->nfile.fname); 8255 calcsize(n->nfile.fname);
7923 calcsize(n->nfile.next); 8256 calcsize(n->nfile.next);
8257 IF_PLATFORM_MINGW32(nodeptrsize += 2);
7924 break; 8258 break;
7925 case NTOFD: 8259 case NTOFD:
7926 case NFROMFD: 8260 case NFROMFD:
7927 calcsize(n->ndup.vname); 8261 calcsize(n->ndup.vname);
7928 calcsize(n->ndup.next); 8262 calcsize(n->ndup.next);
8263 IF_PLATFORM_MINGW32(nodeptrsize += 2);
7929 break; 8264 break;
7930 case NHERE: 8265 case NHERE:
7931 case NXHERE: 8266 case NXHERE:
7932 calcsize(n->nhere.doc); 8267 calcsize(n->nhere.doc);
7933 calcsize(n->nhere.next); 8268 calcsize(n->nhere.next);
8269 IF_PLATFORM_MINGW32(nodeptrsize += 2);
7934 break; 8270 break;
7935 case NNOT: 8271 case NNOT:
7936 calcsize(n->nnot.com); 8272 calcsize(n->nnot.com);
8273 IF_PLATFORM_MINGW32(nodeptrsize++);
7937 break; 8274 break;
7938 }; 8275 };
7939} 8276}
7940 8277
7941static char * 8278static char *
7942nodeckstrdup(char *s) 8279nodeckstrdup(const char *s)
7943{ 8280{
7944 char *rtn = funcstring; 8281 char *rtn = funcstring;
7945 8282
8283 if (!s)
8284 return NULL;
7946 strcpy(funcstring, s); 8285 strcpy(funcstring, s);
7947 funcstring += strlen(s) + 1; 8286 funcstring += strlen(s) + 1;
7948 return rtn; 8287 return rtn;
@@ -7950,6 +8289,18 @@ nodeckstrdup(char *s)
7950 8289
7951static union node *copynode(union node *); 8290static union node *copynode(union node *);
7952 8291
8292#if ENABLE_PLATFORM_MINGW32
8293# define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (int)&(dst);}
8294# define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);}}
8295# define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);}}
8296# define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);*nodeptr++ = (int)&(dst4);}}
8297#else
8298# define SAVE_PTR(dst)
8299# define SAVE_PTR2(dst,dst2)
8300# define SAVE_PTR3(dst,dst2,dst3)
8301# define SAVE_PTR4(dst,dst2,dst3,dst4)
8302#endif
8303
7953static struct nodelist * 8304static struct nodelist *
7954copynodelist(struct nodelist *lp) 8305copynodelist(struct nodelist *lp)
7955{ 8306{
@@ -7961,6 +8312,7 @@ copynodelist(struct nodelist *lp)
7961 *lpp = funcblock; 8312 *lpp = funcblock;
7962 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); 8313 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7963 (*lpp)->n = copynode(lp->n); 8314 (*lpp)->n = copynode(lp->n);
8315 SAVE_PTR2((*lpp)->n, (*lpp)->next);
7964 lp = lp->next; 8316 lp = lp->next;
7965 lpp = &(*lpp)->next; 8317 lpp = &(*lpp)->next;
7966 } 8318 }
@@ -7983,16 +8335,19 @@ copynode(union node *n)
7983 new->ncmd.redirect = copynode(n->ncmd.redirect); 8335 new->ncmd.redirect = copynode(n->ncmd.redirect);
7984 new->ncmd.args = copynode(n->ncmd.args); 8336 new->ncmd.args = copynode(n->ncmd.args);
7985 new->ncmd.assign = copynode(n->ncmd.assign); 8337 new->ncmd.assign = copynode(n->ncmd.assign);
8338 SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign);
7986 break; 8339 break;
7987 case NPIPE: 8340 case NPIPE:
7988 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 8341 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7989 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; 8342 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8343 SAVE_PTR(new->npipe.cmdlist);
7990 break; 8344 break;
7991 case NREDIR: 8345 case NREDIR:
7992 case NBACKGND: 8346 case NBACKGND:
7993 case NSUBSHELL: 8347 case NSUBSHELL:
7994 new->nredir.redirect = copynode(n->nredir.redirect); 8348 new->nredir.redirect = copynode(n->nredir.redirect);
7995 new->nredir.n = copynode(n->nredir.n); 8349 new->nredir.n = copynode(n->nredir.n);
8350 SAVE_PTR2(new->nredir.redirect,new->nredir.n);
7996 break; 8351 break;
7997 case NAND: 8352 case NAND:
7998 case NOR: 8353 case NOR:
@@ -8001,31 +8356,37 @@ copynode(union node *n)
8001 case NUNTIL: 8356 case NUNTIL:
8002 new->nbinary.ch2 = copynode(n->nbinary.ch2); 8357 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8003 new->nbinary.ch1 = copynode(n->nbinary.ch1); 8358 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8359 SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2);
8004 break; 8360 break;
8005 case NIF: 8361 case NIF:
8006 new->nif.elsepart = copynode(n->nif.elsepart); 8362 new->nif.elsepart = copynode(n->nif.elsepart);
8007 new->nif.ifpart = copynode(n->nif.ifpart); 8363 new->nif.ifpart = copynode(n->nif.ifpart);
8008 new->nif.test = copynode(n->nif.test); 8364 new->nif.test = copynode(n->nif.test);
8365 SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test);
8009 break; 8366 break;
8010 case NFOR: 8367 case NFOR:
8011 new->nfor.var = nodeckstrdup(n->nfor.var); 8368 new->nfor.var = nodeckstrdup(n->nfor.var);
8012 new->nfor.body = copynode(n->nfor.body); 8369 new->nfor.body = copynode(n->nfor.body);
8013 new->nfor.args = copynode(n->nfor.args); 8370 new->nfor.args = copynode(n->nfor.args);
8371 SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args);
8014 break; 8372 break;
8015 case NCASE: 8373 case NCASE:
8016 new->ncase.cases = copynode(n->ncase.cases); 8374 new->ncase.cases = copynode(n->ncase.cases);
8017 new->ncase.expr = copynode(n->ncase.expr); 8375 new->ncase.expr = copynode(n->ncase.expr);
8376 SAVE_PTR2(new->ncase.cases,new->ncase.expr);
8018 break; 8377 break;
8019 case NCLIST: 8378 case NCLIST:
8020 new->nclist.body = copynode(n->nclist.body); 8379 new->nclist.body = copynode(n->nclist.body);
8021 new->nclist.pattern = copynode(n->nclist.pattern); 8380 new->nclist.pattern = copynode(n->nclist.pattern);
8022 new->nclist.next = copynode(n->nclist.next); 8381 new->nclist.next = copynode(n->nclist.next);
8382 SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next);
8023 break; 8383 break;
8024 case NDEFUN: 8384 case NDEFUN:
8025 case NARG: 8385 case NARG:
8026 new->narg.backquote = copynodelist(n->narg.backquote); 8386 new->narg.backquote = copynodelist(n->narg.backquote);
8027 new->narg.text = nodeckstrdup(n->narg.text); 8387 new->narg.text = nodeckstrdup(n->narg.text);
8028 new->narg.next = copynode(n->narg.next); 8388 new->narg.next = copynode(n->narg.next);
8389 SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next);
8029 break; 8390 break;
8030 case NTO: 8391 case NTO:
8031#if ENABLE_ASH_BASH_COMPAT 8392#if ENABLE_ASH_BASH_COMPAT
@@ -8038,6 +8399,7 @@ copynode(union node *n)
8038 new->nfile.fname = copynode(n->nfile.fname); 8399 new->nfile.fname = copynode(n->nfile.fname);
8039 new->nfile.fd = n->nfile.fd; 8400 new->nfile.fd = n->nfile.fd;
8040 new->nfile.next = copynode(n->nfile.next); 8401 new->nfile.next = copynode(n->nfile.next);
8402 SAVE_PTR2(new->nfile.fname,new->nfile.next);
8041 break; 8403 break;
8042 case NTOFD: 8404 case NTOFD:
8043 case NFROMFD: 8405 case NFROMFD:
@@ -8045,15 +8407,18 @@ copynode(union node *n)
8045 new->ndup.dupfd = n->ndup.dupfd; 8407 new->ndup.dupfd = n->ndup.dupfd;
8046 new->ndup.fd = n->ndup.fd; 8408 new->ndup.fd = n->ndup.fd;
8047 new->ndup.next = copynode(n->ndup.next); 8409 new->ndup.next = copynode(n->ndup.next);
8410 SAVE_PTR2(new->ndup.vname,new->ndup.next);
8048 break; 8411 break;
8049 case NHERE: 8412 case NHERE:
8050 case NXHERE: 8413 case NXHERE:
8051 new->nhere.doc = copynode(n->nhere.doc); 8414 new->nhere.doc = copynode(n->nhere.doc);
8052 new->nhere.fd = n->nhere.fd; 8415 new->nhere.fd = n->nhere.fd;
8053 new->nhere.next = copynode(n->nhere.next); 8416 new->nhere.next = copynode(n->nhere.next);
8417 SAVE_PTR2(new->nhere.doc,new->nhere.next);
8054 break; 8418 break;
8055 case NNOT: 8419 case NNOT:
8056 new->nnot.com = copynode(n->nnot.com); 8420 new->nnot.com = copynode(n->nnot.com);
8421 SAVE_PTR(new->nnot.com);
8057 break; 8422 break;
8058 }; 8423 };
8059 new->type = n->type; 8424 new->type = n->type;
@@ -8076,6 +8441,7 @@ copyfunc(union node *n)
8076 f = ckmalloc(blocksize + funcstringsize); 8441 f = ckmalloc(blocksize + funcstringsize);
8077 funcblock = (char *) f + offsetof(struct funcnode, n); 8442 funcblock = (char *) f + offsetof(struct funcnode, n);
8078 funcstring = (char *) f + blocksize; 8443 funcstring = (char *) f + blocksize;
8444 IF_PLATFORM_MINGW32(nodeptr = NULL);
8079 copynode(n); 8445 copynode(n);
8080 f->count = 0; 8446 f->count = 0;
8081 return f; 8447 return f;
@@ -8428,9 +8794,26 @@ evalcase(union node *n, int flags)
8428/* 8794/*
8429 * Kick off a subshell to evaluate a tree. 8795 * Kick off a subshell to evaluate a tree.
8430 */ 8796 */
8797#if ENABLE_PLATFORM_MINGW32
8798static void
8799forkshell_evalsubshell(struct forkshell *fs)
8800{
8801 union node *n = fs->n;
8802 int flags = fs->flags;
8803
8804 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
8805 INT_ON;
8806 flags |= EV_EXIT;
8807 expredir(n->nredir.redirect);
8808 redirect(n->nredir.redirect, 0);
8809 evaltreenr(n->nredir.n, flags);
8810 /* never returns */
8811}
8812#endif
8431static void 8813static void
8432evalsubshell(union node *n, int flags) 8814evalsubshell(union node *n, int flags)
8433{ 8815{
8816 IF_PLATFORM_MINGW32(struct forkshell fs);
8434 struct job *jp; 8817 struct job *jp;
8435 int backgnd = (n->type == NBACKGND); 8818 int backgnd = (n->type == NBACKGND);
8436 int status; 8819 int status;
@@ -8440,6 +8823,14 @@ evalsubshell(union node *n, int flags)
8440 goto nofork; 8823 goto nofork;
8441 INT_OFF; 8824 INT_OFF;
8442 jp = makejob(/*n,*/ 1); 8825 jp = makejob(/*n,*/ 1);
8826#if ENABLE_PLATFORM_MINGW32
8827 memset(&fs, 0, sizeof(fs));
8828 fs.fp = forkshell_evalsubshell;
8829 fs.n = n;
8830 fs.flags = flags;
8831 if (spawn_forkshell(jp, &fs, backgnd) < 0)
8832 ash_msg_and_raise_error("unable to spawn shell");
8833#endif
8443 if (forkshell(jp, n, backgnd) == 0) { 8834 if (forkshell(jp, n, backgnd) == 0) {
8444 INT_ON; 8835 INT_ON;
8445 flags |= EV_EXIT; 8836 flags |= EV_EXIT;
@@ -8515,9 +8906,35 @@ expredir(union node *n)
8515 * of the shell, which make the last process in a pipeline the parent 8906 * of the shell, which make the last process in a pipeline the parent
8516 * of all the rest.) 8907 * of all the rest.)
8517 */ 8908 */
8909#if ENABLE_PLATFORM_MINGW32
8910static void
8911forkshell_evalpipe(struct forkshell *fs)
8912{
8913 union node *n = fs->n;
8914 int flags = fs->flags;
8915 int prevfd = fs->fd[2];
8916 int pip[2] = {fs->fd[0], fs->fd[1]};
8917
8918 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
8919 INT_ON;
8920 if (pip[1] >= 0) {
8921 close(pip[0]);
8922 }
8923 if (prevfd > 0) {
8924 dup2(prevfd, 0);
8925 close(prevfd);
8926 }
8927 if (pip[1] > 1) {
8928 dup2(pip[1], 1);
8929 close(pip[1]);
8930 }
8931 evaltreenr(n, flags);
8932}
8933#endif
8518static void 8934static void
8519evalpipe(union node *n, int flags) 8935evalpipe(union node *n, int flags)
8520{ 8936{
8937 IF_PLATFORM_MINGW32(struct forkshell fs);
8521 struct job *jp; 8938 struct job *jp;
8522 struct nodelist *lp; 8939 struct nodelist *lp;
8523 int pipelen; 8940 int pipelen;
@@ -8541,6 +8958,17 @@ evalpipe(union node *n, int flags)
8541 ash_msg_and_raise_error("pipe call failed"); 8958 ash_msg_and_raise_error("pipe call failed");
8542 } 8959 }
8543 } 8960 }
8961#if ENABLE_PLATFORM_MINGW32
8962 memset(&fs, 0, sizeof(fs));
8963 fs.fp = forkshell_evalpipe;
8964 fs.flags = flags;
8965 fs.n = lp->n;
8966 fs.fd[0] = pip[0];
8967 fs.fd[1] = pip[1];
8968 fs.fd[2] = prevfd;
8969 if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0)
8970 ash_msg_and_raise_error("unable to spawn shell");
8971#endif
8544 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { 8972 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8545 INT_ON; 8973 INT_ON;
8546 if (pip[1] >= 0) { 8974 if (pip[1] >= 0) {
@@ -9007,6 +9435,20 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9007 * as POSIX mandates */ 9435 * as POSIX mandates */
9008 return back_exitstatus; 9436 return back_exitstatus;
9009} 9437}
9438
9439#if ENABLE_PLATFORM_MINGW32
9440static void
9441forkshell_shellexec(struct forkshell *fs)
9442{
9443 int idx = fs->fd[0];
9444 struct strlist *varlist = fs->strlist;
9445 char **argv = fs->argv;
9446 char *path = fs->string;
9447
9448 listsetvar(varlist, VEXPORT|VSTACK);
9449 shellexec(argv, path, idx);
9450}
9451#endif
9010static void 9452static void
9011evalcommand(union node *cmd, int flags) 9453evalcommand(union node *cmd, int flags)
9012{ 9454{
@@ -9183,6 +9625,26 @@ evalcommand(union node *cmd, int flags)
9183 } 9625 }
9184 } 9626 }
9185#endif 9627#endif
9628#if ENABLE_PLATFORM_MINGW32
9629 if (!(flags & EV_EXIT) || trap[0]) {
9630 struct forkshell fs;
9631
9632 memset(&fs, 0, sizeof(fs));
9633 fs.fp = forkshell_shellexec;
9634 fs.argv = argv;
9635 fs.string = (char*)path;
9636 fs.fd[0] = cmdentry.u.index;
9637 fs.strlist = varlist.list;
9638 jp = makejob(/*cmd,*/ 1);
9639 if (spawn_forkshell(jp, &fs, FORK_FG) < 0)
9640 ash_msg_and_raise_error("unable to spawn shell");
9641 exitstatus = waitforjob(jp);
9642 INT_ON;
9643 TRACE(("forked child exited with %d\n", exitstatus));
9644 break;
9645 }
9646 /* goes through to shellexec() */
9647#endif
9186 /* Fork off a child process if necessary. */ 9648 /* Fork off a child process if necessary. */
9187 if (!(flags & EV_EXIT) || trap[0]) { 9649 if (!(flags & EV_EXIT) || trap[0]) {
9188 INT_OFF; 9650 INT_OFF;
@@ -9563,7 +10025,7 @@ preadbuffer(void)
9563 more--; 10025 more--;
9564 10026
9565 c = *q; 10027 c = *q;
9566 if (c == '\0') { 10028 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) {
9567 memmove(q, q + 1, more); 10029 memmove(q, q + 1, more);
9568 } else { 10030 } else {
9569 q++; 10031 q++;
@@ -11990,7 +12452,7 @@ find_dot_file(char *name)
11990 struct stat statb; 12452 struct stat statb;
11991 12453
11992 /* don't try this for absolute or relative paths */ 12454 /* don't try this for absolute or relative paths */
11993 if (strchr(name, '/')) 12455 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\')))
11994 return name; 12456 return name;
11995 12457
11996 /* IIRC standards do not say whether . is to be searched. 12458 /* IIRC standards do not say whether . is to be searched.
@@ -12093,10 +12555,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12093 struct stat statb; 12555 struct stat statb;
12094 int e; 12556 int e;
12095 int updatetbl; 12557 int updatetbl;
12558 IF_PLATFORM_MINGW32(int len);
12096 struct builtincmd *bcmd; 12559 struct builtincmd *bcmd;
12097 12560
12098 /* If name contains a slash, don't use PATH or hash table */ 12561 /* If name contains a slash, don't use PATH or hash table */
12099 if (strchr(name, '/') != NULL) { 12562 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) {
12100 entry->u.index = -1; 12563 entry->u.index = -1;
12101 if (act & DO_ABS) { 12564 if (act & DO_ABS) {
12102 while (stat(name, &statb) < 0) { 12565 while (stat(name, &statb) < 0) {
@@ -12203,12 +12666,39 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12203 } 12666 }
12204 } 12667 }
12205 /* if rehash, don't redo absolute path names */ 12668 /* if rehash, don't redo absolute path names */
12206 if (fullname[0] == '/' && idx <= prev) { 12669 if (is_absolute_path(fullname) && idx <= prev) {
12207 if (idx < prev) 12670 if (idx < prev)
12208 continue; 12671 continue;
12209 TRACE(("searchexec \"%s\": no change\n", name)); 12672 TRACE(("searchexec \"%s\": no change\n", name));
12210 goto success; 12673 goto success;
12211 } 12674 }
12675#if ENABLE_PLATFORM_MINGW32
12676 len = strlen(fullname);
12677 if (len > 4 &&
12678 (!strcasecmp(fullname+len-4, ".exe") ||
12679 !strcasecmp(fullname+len-4, ".com"))) {
12680 if (stat(fullname, &statb) < 0) {
12681 if (errno != ENOENT && errno != ENOTDIR)
12682 e = errno;
12683 goto loop;
12684 }
12685 }
12686 else {
12687 /* path_advance() has reserved space for .exe */
12688 memcpy(fullname+len, ".exe", 5);
12689 if (stat(fullname, &statb) < 0) {
12690 if (errno != ENOENT && errno != ENOTDIR)
12691 e = errno;
12692 memcpy(fullname+len, ".com", 5);
12693 if (stat(fullname, &statb) < 0) {
12694 if (errno != ENOENT && errno != ENOTDIR)
12695 e = errno;
12696 goto loop;
12697 }
12698 }
12699 fullname[len] = '\0';
12700 }
12701#else
12212 while (stat(fullname, &statb) < 0) { 12702 while (stat(fullname, &statb) < 0) {
12213#ifdef SYSV 12703#ifdef SYSV
12214 if (errno == EINTR) 12704 if (errno == EINTR)
@@ -12218,6 +12708,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12218 e = errno; 12708 e = errno;
12219 goto loop; 12709 goto loop;
12220 } 12710 }
12711#endif
12221 e = EACCES; /* if we fail, this will be the error */ 12712 e = EACCES; /* if we fail, this will be the error */
12222 if (!S_ISREG(statb.st_mode)) 12713 if (!S_ISREG(statb.st_mode))
12223 continue; 12714 continue;
@@ -12744,13 +13235,41 @@ init(void)
12744 struct stat st1, st2; 13235 struct stat st1, st2;
12745 13236
12746 initvar(); 13237 initvar();
13238
13239#if ENABLE_PLATFORM_MINGW32
13240 /*
13241 * case insensitive env names from Windows world
13242 *
13243 * Some standard env names such as PATH is named Path and so on
13244 * ash itself is case sensitive, so "Path" will confuse it, as
13245 * MSVC getenv() is case insensitive.
13246 *
13247 * We may end up having both Path and PATH. Then Path will be chosen
13248 * because it appears first.
13249 */
13250 for (envp = environ; envp && *envp; envp++)
13251 if (!strncasecmp(*envp, "PATH=", 5) &&
13252 strncmp(*envp, "PATH=", 5))
13253 break;
13254 if (envp && *envp) {
13255 char *start, *end;
13256 for (envp = environ; envp && *envp; envp++) {
13257 end = strchr(*envp, '=');
13258 if (!end)
13259 continue;
13260 for (start = *envp;start < end;start++)
13261 *start = toupper(*start);
13262 }
13263 }
13264#endif
12747 for (envp = environ; envp && *envp; envp++) { 13265 for (envp = environ; envp && *envp; envp++) {
12748 if (strchr(*envp, '=')) { 13266 if (strchr(*envp, '=')) {
12749 setvareq(*envp, VEXPORT|VTEXTFIXED); 13267 setvareq(*envp, VEXPORT|VTEXTFIXED);
12750 } 13268 }
12751 } 13269 }
12752 13270
12753 setvar("PPID", utoa(getppid()), 0); 13271 if (!ENABLE_PLATFORM_MINGW32)
13272 setvar("PPID", utoa(getppid()), 0);
12754 13273
12755 p = lookupvar("PWD"); 13274 p = lookupvar("PWD");
12756 if (p) 13275 if (p)
@@ -12866,6 +13385,20 @@ static short profile_buf[16384];
12866extern int etext(); 13385extern int etext();
12867#endif 13386#endif
12868 13387
13388#if ENABLE_PLATFORM_MINGW32
13389static const forkpoint_fn forkpoints[] = {
13390 forkshell_openhere,
13391 forkshell_evalbackcmd,
13392 forkshell_evalsubshell,
13393 forkshell_evalpipe,
13394 forkshell_shellexec,
13395 NULL
13396};
13397
13398static struct forkshell* forkshell_prepare(struct forkshell *fs);
13399static void forkshell_init(const char *idstr);
13400#endif
13401
12869/* 13402/*
12870 * Main routine. We initialize things, parse the arguments, execute 13403 * Main routine. We initialize things, parse the arguments, execute
12871 * profiles if we're a login shell, and then call cmdloop to execute 13404 * profiles if we're a login shell, and then call cmdloop to execute
@@ -12933,6 +13466,15 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
12933 13466
12934 init(); 13467 init();
12935 setstackmark(&smark); 13468 setstackmark(&smark);
13469
13470#if ENABLE_PLATFORM_MINGW32
13471 if (argc == 3 && !strcmp(argv[1], "--forkshell")) {
13472 forkshell_init(argv[2]);
13473
13474 /* NOTREACHED */
13475 bb_error_msg_and_die("subshell ended unexpectedly");
13476 }
13477#endif
12936 procargs(argv); 13478 procargs(argv);
12937 13479
12938#if ENABLE_FEATURE_EDITING_SAVEHISTORY 13480#if ENABLE_FEATURE_EDITING_SAVEHISTORY
@@ -13007,6 +13549,524 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13007 /* NOTREACHED */ 13549 /* NOTREACHED */
13008} 13550}
13009 13551
13552/* FIXME: should consider running forkparent() and forkchild() */
13553static int
13554spawn_forkshell(struct job *jp, struct forkshell *fs, int mode)
13555{
13556 const char *argv[] = { "sh", "--forkshell", NULL, NULL };
13557 char buf[16];
13558
13559 struct forkshell *new;
13560 new = forkshell_prepare(fs);
13561 sprintf(buf, "%x", (unsigned int)new->hMapFile);
13562 argv[2] = buf;
13563 fs->pid = mingw_spawn_applet(P_NOWAIT, "sh", argv,
13564 (const char *const *)environ);
13565 CloseHandle(new->hMapFile);
13566 UnmapViewOfFile(new);
13567 if (fs->pid == -1) {
13568 free(jp);
13569 return -1;
13570 }
13571 forkparent(jp, fs->node, mode, fs->pid);
13572 return fs->pid;
13573}
13574
13575/*
13576 * forkshell_prepare() and friends
13577 *
13578 * The sequence is as follows:
13579 * - funcblocksize, funcstringsize, nodeptrsize are initialized
13580 * - forkshell_size(fs) is called to calculate the exact memory needed
13581 * - a new struct is allocated
13582 * - funcblock, funcstring, nodeptr are initialized from the new block
13583 * - forkshell_copy(fs) is called to copy recursively everything over
13584 * it will record all pointers along the way, to nodeptr
13585 *
13586 * When this memory is mapped elsewhere, pointer fixup will be needed
13587 */
13588#define SLIST_SIZE_BEGIN(name,type) \
13589static void \
13590name(type *p) \
13591{ \
13592 while (p) { \
13593 funcblocksize += sizeof(type);
13594 /* do something here with p */
13595#define SLIST_SIZE_END() \
13596 nodeptrsize++; \
13597 p = p->next; \
13598 } \
13599}
13600
13601#define SLIST_COPY_BEGIN(name,type) \
13602static type * \
13603name(type *vp) \
13604{ \
13605 type *start; \
13606 type **vpp; \
13607 vpp = &start; \
13608 while (vp) { \
13609 *vpp = funcblock; \
13610 funcblock = (char *) funcblock + sizeof(type);
13611 /* do something here with vpp and vp */
13612#define SLIST_COPY_END() \
13613 SAVE_PTR((*vpp)->next); \
13614 vp = vp->next; \
13615 vpp = &(*vpp)->next; \
13616 } \
13617 *vpp = NULL; \
13618 return start; \
13619}
13620
13621/*
13622 * struct var
13623 */
13624SLIST_SIZE_BEGIN(var_size,struct var)
13625funcstringsize += strlen(p->text) + 1;
13626nodeptrsize++; /* p->text */
13627SLIST_SIZE_END()
13628
13629SLIST_COPY_BEGIN(var_copy,struct var)
13630(*vpp)->text = nodeckstrdup(vp->text);
13631(*vpp)->flags = vp->flags;
13632/*
13633 * The only place that can set struct var#func is varinit[],
13634 * which will be fixed by forkshell_init()
13635 */
13636(*vpp)->func = NULL;
13637SAVE_PTR((*vpp)->text);
13638SLIST_COPY_END()
13639
13640/*
13641 * struct localvar
13642 */
13643SLIST_SIZE_BEGIN(localvar_size,struct localvar)
13644var_size(p->vp);
13645funcstringsize += strlen(p->text) + 1;
13646nodeptrsize += 2; /* p->vp, p->text */
13647SLIST_SIZE_END()
13648
13649SLIST_COPY_BEGIN(localvar_copy,struct localvar)
13650(*vpp)->text = nodeckstrdup(vp->text);
13651(*vpp)->flags = vp->flags;
13652(*vpp)->vp = var_copy(vp->vp);
13653SAVE_PTR2((*vpp)->vp, (*vpp)->text);
13654SLIST_COPY_END()
13655
13656/*
13657 * struct strlist
13658 */
13659SLIST_SIZE_BEGIN(strlist_size,struct strlist)
13660funcstringsize += strlen(p->text) + 1;
13661nodeptrsize++; /* p->text */
13662SLIST_SIZE_END()
13663
13664SLIST_COPY_BEGIN(strlist_copy,struct strlist)
13665(*vpp)->text = nodeckstrdup(vp->text);
13666SAVE_PTR((*vpp)->text);
13667SLIST_COPY_END()
13668
13669/*
13670 * struct tblentry
13671 */
13672static void
13673tblentry_size(struct tblentry *tep)
13674{
13675 while (tep) {
13676 funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
13677 /* CMDBUILTIN, e->param.cmd needs no pointer relocation */
13678 if (tep->cmdtype == CMDFUNCTION) {
13679 funcblocksize += offsetof(struct funcnode, n);
13680 calcsize(&tep->param.func->n);
13681 nodeptrsize++; /* tep->param.func */
13682 }
13683 nodeptrsize++; /* tep->next */
13684 tep = tep->next;
13685 }
13686}
13687
13688static struct tblentry *
13689tblentry_copy(struct tblentry *tep)
13690{
13691 struct tblentry *start;
13692 struct tblentry **newp;
13693 int size;
13694
13695 newp = &start;
13696 while (tep) {
13697 *newp = funcblock;
13698 size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
13699
13700 funcblock = (char *) funcblock + size;
13701 memcpy(*newp, tep, size);
13702 switch (tep->cmdtype) {
13703 case CMDBUILTIN:
13704 /* No pointer saving, this field must be fixed by forkshell_init() */
13705 (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab);
13706 break;
13707 case CMDFUNCTION:
13708 (*newp)->param.func = funcblock;
13709 funcblock = (char *) funcblock + offsetof(struct funcnode, n);
13710 copynode(&tep->param.func->n);
13711 SAVE_PTR((*newp)->param.func);
13712 break;
13713 default:
13714 break;
13715 }
13716 SAVE_PTR((*newp)->next);
13717 tep = tep->next;
13718 newp = &(*newp)->next;
13719 }
13720 *newp = NULL;
13721 return start;
13722}
13723
13724static void
13725cmdtable_size(struct tblentry **cmdtablep)
13726{
13727 int i;
13728 nodeptrsize += CMDTABLESIZE;
13729 funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE;
13730 for (i = 0; i < CMDTABLESIZE; i++)
13731 tblentry_size(cmdtablep[i]);
13732}
13733
13734static struct tblentry **
13735cmdtable_copy(struct tblentry **cmdtablep)
13736{
13737 struct tblentry **new = funcblock;
13738 int i;
13739
13740 funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE;
13741 for (i = 0; i < CMDTABLESIZE; i++) {
13742 new[i] = tblentry_copy(cmdtablep[i]);
13743 SAVE_PTR(new[i]);
13744 }
13745 return new;
13746}
13747
13748/*
13749 * char **
13750 */
13751static void
13752argv_size(char **p)
13753{
13754 while (p && *p) {
13755 funcblocksize += sizeof(char *);
13756 funcstringsize += strlen(*p)+1;
13757 nodeptrsize++;
13758 p++;
13759 }
13760 funcblocksize += sizeof(char *);
13761}
13762
13763static char **
13764argv_copy(char **p)
13765{
13766 char **new, **start = funcblock;
13767
13768 while (p && *p) {
13769 new = funcblock;
13770 funcblock = (char *) funcblock + sizeof(char *);
13771 *new = nodeckstrdup(*p);
13772 SAVE_PTR(*new);
13773 p++;
13774 new++;
13775 }
13776 new = funcblock;
13777 funcblock = (char *) funcblock + sizeof(char *);
13778 *new = NULL;
13779 return start;
13780}
13781
13782/*
13783 * struct redirtab
13784 */
13785static void
13786redirtab_size(struct redirtab *rdtp)
13787{
13788 while (rdtp) {
13789 funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
13790 rdtp = rdtp->next;
13791 nodeptrsize++; /* rdtp->next */
13792 }
13793}
13794
13795static struct redirtab *
13796redirtab_copy(struct redirtab *rdtp)
13797{
13798 struct redirtab *start;
13799 struct redirtab **vpp;
13800
13801 vpp = &start;
13802 while (rdtp) {
13803 int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
13804 *vpp = funcblock;
13805 funcblock = (char *) funcblock + size;
13806 memcpy(*vpp, rdtp, size);
13807 SAVE_PTR((*vpp)->next);
13808 rdtp = rdtp->next;
13809 vpp = &(*vpp)->next;
13810 }
13811 *vpp = NULL;
13812 return start;
13813}
13814
13815#undef shellparam
13816#undef redirlist
13817#undef varinit
13818#undef vartab
13819static void
13820globals_var_size(struct globals_var *gvp)
13821{
13822 int i;
13823
13824 funcblocksize += sizeof(struct globals_var);
13825 argv_size(gvp->shellparam.p);
13826 redirtab_size(gvp->redirlist);
13827 for (i = 0; i < VTABSIZE; i++)
13828 var_size(gvp->vartab[i]);
13829 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
13830 var_size(gvp->varinit+i);
13831 nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */
13832}
13833
13834#undef g_nullredirs
13835#undef preverrout_fd
13836static struct globals_var *
13837globals_var_copy(struct globals_var *gvp)
13838{
13839 int i;
13840 struct globals_var *new;
13841
13842 new = funcblock;
13843 funcblock = (char *) funcblock + sizeof(struct globals_var);
13844
13845 /* shparam */
13846 memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam));
13847 new->shellparam.malloced = 0;
13848 new->shellparam.p = argv_copy(gvp->shellparam.p);
13849 SAVE_PTR(new->shellparam.p);
13850
13851 new->redirlist = redirtab_copy(gvp->redirlist);
13852 SAVE_PTR(new->redirlist);
13853
13854 new->g_nullredirs = gvp->g_nullredirs;
13855 new->preverrout_fd = gvp->preverrout_fd;
13856 for (i = 0; i < VTABSIZE; i++) {
13857 new->vartab[i] = var_copy(gvp->vartab[i]);
13858 SAVE_PTR(new->vartab[i]);
13859 }
13860
13861 /* Can't use var_copy because varinit is already allocated */
13862 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) {
13863 new->varinit[i].next = NULL;
13864 new->varinit[i].text = nodeckstrdup(gvp->varinit[i].text);
13865 SAVE_PTR(new->varinit[i].text);
13866 new->varinit[i].flags = gvp->varinit[i].flags;
13867 new->varinit[i].func = gvp->varinit[i].func;
13868 }
13869 return new;
13870}
13871
13872#undef minusc
13873#undef curdir
13874#undef physdir
13875#undef arg0
13876#undef nullstr
13877static void
13878globals_misc_size(struct globals_misc *p)
13879{
13880 funcblocksize += sizeof(struct globals_misc);
13881 funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1;
13882 if (p->curdir != p->nullstr)
13883 funcstringsize += strlen(p->curdir) + 1;
13884 if (p->physdir != p->nullstr)
13885 funcstringsize += strlen(p->physdir) + 1;
13886 funcstringsize += strlen(p->arg0) + 1;
13887 nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */
13888}
13889
13890static struct globals_misc *
13891globals_misc_copy(struct globals_misc *p)
13892{
13893 struct globals_misc *new = funcblock;
13894
13895 funcblock = (char *) funcblock + sizeof(struct globals_misc);
13896 memcpy(new, p, sizeof(struct globals_misc));
13897
13898 new->minusc = nodeckstrdup(p->minusc);
13899 new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr;
13900 new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr;
13901 new->arg0 = nodeckstrdup(p->arg0);
13902 SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0);
13903 return new;
13904}
13905
13906static void
13907forkshell_size(struct forkshell *fs)
13908{
13909 funcblocksize += sizeof(struct forkshell);
13910 globals_var_size(fs->gvp);
13911 globals_misc_size(fs->gmp);
13912 cmdtable_size(fs->cmdtable);
13913 localvar_size(fs->localvars);
13914 /* optlist_transfer(sending, fd); */
13915 /* misc_transfer(sending, fd); */
13916
13917 calcsize(fs->n);
13918 argv_size(fs->argv);
13919 funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1;
13920 strlist_size(fs->strlist);
13921
13922 nodeptrsize += 8; /* gvp, gmp, cmdtable, localvars, n, argv, string, strlist */
13923}
13924
13925static struct forkshell *
13926forkshell_copy(struct forkshell *fs)
13927{
13928 struct forkshell *new;
13929
13930 new = funcblock;
13931 funcblock = (char *) funcblock + sizeof(struct forkshell);
13932
13933 memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */
13934 new->gvp = globals_var_copy(fs->gvp);
13935 new->gmp = globals_misc_copy(fs->gmp);
13936 new->cmdtable = cmdtable_copy(fs->cmdtable);
13937 new->localvars = localvar_copy(fs->localvars);
13938 SAVE_PTR4(new->gvp, new->gmp, new->cmdtable, new->localvars);
13939
13940 /* new->fs will be reconstructed from new->fpid */
13941 new->n = copynode(fs->n);
13942 new->argv = argv_copy(fs->argv);
13943 new->string = nodeckstrdup(fs->string);
13944 new->strlist = strlist_copy(fs->strlist);
13945 SAVE_PTR4(new->n, new->argv, new->string, new->strlist);
13946 return new;
13947}
13948
13949static struct forkshell *
13950forkshell_prepare(struct forkshell *fs)
13951{
13952 struct forkshell *new;
13953 int size, fp, nodeptr_offset;
13954 HANDLE h;
13955 SECURITY_ATTRIBUTES sa;
13956
13957 for (fp = 0; forkpoints[fp] && forkpoints[fp] != fs->fp; fp++)
13958 ;
13959
13960 if (!forkpoints[fp])
13961 bb_error_msg_and_die("invalid forkpoint %08x", (int)fs->fp);
13962 fs->fpid = fp;
13963
13964 /* Calculate size of "new" */
13965 fs->gvp = ash_ptr_to_globals_var;
13966 fs->gmp = ash_ptr_to_globals_misc;
13967 fs->cmdtable = cmdtable;
13968 fs->localvars = localvars;
13969
13970 nodeptrsize = 1; /* NULL terminated */
13971 funcblocksize = 0;
13972 funcstringsize = 0;
13973 forkshell_size(fs);
13974 size = funcblocksize + funcstringsize + nodeptrsize*sizeof(int);
13975
13976 /* Allocate, initialize pointers */
13977 memset(&sa, 0, sizeof(sa));
13978 sa.nLength = sizeof(sa);
13979 sa.lpSecurityDescriptor = NULL;
13980 sa.bInheritHandle = TRUE;
13981 h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL);
13982 new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
13983 /* new = ckmalloc(size); */
13984 funcblock = new;
13985 funcstring = (char *) funcblock + funcblocksize;
13986 nodeptr = (int*)((char *) funcstring + funcstringsize);
13987 nodeptr_offset = (int) nodeptr - (int) new;
13988
13989 /* Now pack them all */
13990 forkshell_copy(fs);
13991
13992 /* Finish it up */
13993 *nodeptr = 0;
13994 new->size = size;
13995 new->nodeptr_offset = nodeptr_offset;
13996 new->old_base = new;
13997 new->hMapFile = h;
13998 return new;
13999}
14000
14001#undef exception_handler
14002#undef trap
14003#undef trap_ptr
14004static void *sticky_mem_start, *sticky_mem_end;
14005static void
14006forkshell_init(const char *idstr)
14007{
14008 struct forkshell *fs;
14009 int map_handle;
14010 HANDLE h;
14011 struct globals_var **gvpp;
14012 struct globals_misc **gmpp;
14013 int i;
14014
14015 if (sscanf(idstr, "%x", &map_handle) != 1)
14016 bb_error_msg_and_die("invalid forkshell ID");
14017
14018 h = (HANDLE)map_handle;
14019 fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14020 if (!fs)
14021 bb_error_msg_and_die("Invalid forkshell memory");
14022
14023 /* this memory can't be freed */
14024 sticky_mem_start = fs;
14025 sticky_mem_end = (char *) fs + fs->size;
14026 /* pointer fixup */
14027 nodeptr = (int*)((char*)fs + fs->nodeptr_offset);
14028 while (*nodeptr) {
14029 int *ptr = (int*)((char*)fs + (*nodeptr - (int)fs->old_base));
14030 if (*ptr)
14031 *ptr -= ((int)fs->old_base - (int)fs);
14032 nodeptr++;
14033 }
14034 /* Now fix up stuff that can't be transferred */
14035 fs->fp = forkpoints[fs->fpid];
14036 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14037 fs->gvp->varinit[i].func = varinit_data[i].func;
14038 for (i = 0; i < CMDTABLESIZE; i++) {
14039 struct tblentry *e = fs->cmdtable[i];
14040 while (e) {
14041 if (e->cmdtype == CMDBUILTIN)
14042 e->param.cmd = builtintab + (int)e->param.cmd;
14043 e = e->next;
14044 }
14045 }
14046 fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler;
14047 for (i = 0; i < NSIG; i++)
14048 fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i];
14049 fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr;
14050
14051 /* Switch global variables */
14052 gvpp = (struct globals_var **)&ash_ptr_to_globals_var;
14053 *gvpp = fs->gvp;
14054 gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc;
14055 *gmpp = fs->gmp;
14056 localvars = fs->localvars;
14057 cmdtable = fs->cmdtable;
14058
14059 fs->fp(fs);
14060}
14061
14062#undef free
14063static void
14064sticky_free(void *base)
14065{
14066 if (base >= sticky_mem_start && base < sticky_mem_end)
14067 return;
14068 free(base);
14069}
13010 14070
13011/*- 14071/*-
13012 * Copyright (c) 1989, 1991, 1993, 1994 14072 * Copyright (c) 1989, 1991, 1993, 1994
diff --git a/win32/termios.c b/win32/termios.c
index 0aba48546..6d85ff98e 100644
--- a/win32/termios.c
+++ b/win32/termios.c
@@ -1,4 +1,4 @@
1#include "busybox.h" 1#include "libbb.h"
2 2
3int tcsetattr(int fd UNUSED_PARAM, int mode UNUSED_PARAM, const struct termios *t UNUSED_PARAM) 3int tcsetattr(int fd UNUSED_PARAM, int mode UNUSED_PARAM, const struct termios *t UNUSED_PARAM)
4{ 4{
@@ -9,3 +9,28 @@ int tcgetattr(int fd UNUSED_PARAM, struct termios *t UNUSED_PARAM)
9{ 9{
10 return -1; 10 return -1;
11} 11}
12
13int64_t FAST_FUNC read_key(int fd, char *buf, int timeout UNUSED_PARAM)
14{
15 static int initialized = 0;
16 HANDLE cin = GetStdHandle(STD_INPUT_HANDLE);
17 INPUT_RECORD record;
18 DWORD nevent_out;
19
20 if (fd != 0)
21 bb_error_msg_and_die("read_key only works on stdin");
22 if (cin == INVALID_HANDLE_VALUE)
23 return -1;
24 if (!initialized) {
25 SetConsoleMode(cin, ENABLE_ECHO_INPUT);
26 initialized = 1;
27 }
28
29 while (1) {
30 if (!ReadConsoleInput(cin, &record, 1, &nevent_out))
31 return -1;
32 if (record.EventType != KEY_EVENT || !record.Event.KeyEvent.bKeyDown)
33 continue;
34 return record.Event.KeyEvent.uChar.AsciiChar;
35 }
36}