diff options
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 1165 | ||||
-rw-r--r-- | shell/shell_common.c | 12 |
2 files changed, 1164 insertions, 13 deletions
diff --git a/shell/ash.c b/shell/ash.c index edcb7c028..369bb5bb9 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -17,6 +17,20 @@ | |||
17 | */ | 17 | */ |
18 | 18 | ||
19 | /* | 19 | /* |
20 | * MinGW notes | ||
21 | * | ||
22 | * - Environment variables from Windows will all be turned to uppercase. | ||
23 | * - PATH accepts both ; and : as separator, but can't be mixed | ||
24 | * - command without ".exe" extension is still understood as executable | ||
25 | * - shell scripts on the path are detected by the presence of '#!'; | ||
26 | * the path to the interpreter is ignored, PATH is searched to find it | ||
27 | * - both / and \ are supported in PATH. Usually you must use / | ||
28 | * - trap/job does not work | ||
29 | * - /dev/null is supported for redirection | ||
30 | * - no $PPID | ||
31 | */ | ||
32 | |||
33 | /* | ||
20 | * The following should be set to reflect the type of system you have: | 34 | * The following should be set to reflect the type of system you have: |
21 | * JOBS -> 1 if you have Berkeley job control, 0 otherwise. | 35 | * JOBS -> 1 if you have Berkeley job control, 0 otherwise. |
22 | * define SYSV if you are running under System V. | 36 | * define SYSV if you are running under System V. |
@@ -37,7 +51,10 @@ | |||
37 | 51 | ||
38 | #define JOBS ENABLE_ASH_JOB_CONTROL | 52 | #define JOBS ENABLE_ASH_JOB_CONTROL |
39 | 53 | ||
54 | #include "busybox.h" /* for applet_names */ | ||
55 | #if !ENABLE_PLATFORM_MINGW32 | ||
40 | #include <paths.h> | 56 | #include <paths.h> |
57 | #endif | ||
41 | #include <setjmp.h> | 58 | #include <setjmp.h> |
42 | #include <fnmatch.h> | 59 | #include <fnmatch.h> |
43 | #include <sys/times.h> | 60 | #include <sys/times.h> |
@@ -71,6 +88,10 @@ | |||
71 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ | 88 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ |
72 | #endif | 89 | #endif |
73 | 90 | ||
91 | #if !ENABLE_PLATFORM_MINGW32 | ||
92 | # define is_absolute_path(path) ((path)[0] == '/') | ||
93 | #endif | ||
94 | |||
74 | #if !BB_MMU | 95 | #if !BB_MMU |
75 | # error "Do not even bother, ash will not run on NOMMU machine" | 96 | # error "Do not even bother, ash will not run on NOMMU machine" |
76 | #endif | 97 | #endif |
@@ -193,6 +214,41 @@ | |||
193 | //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o | 214 | //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o |
194 | //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o | 215 | //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o |
195 | 216 | ||
217 | #if ENABLE_PLATFORM_MINGW32 | ||
218 | struct forkshell; | ||
219 | union node; | ||
220 | struct strlist; | ||
221 | struct job; | ||
222 | |||
223 | typedef void (*forkpoint_fn)(struct forkshell *fs); | ||
224 | struct forkshell { | ||
225 | /* filled by forkshell_copy() */ | ||
226 | struct globals_var *gvp; | ||
227 | struct globals_misc *gmp; | ||
228 | struct tblentry **cmdtable; | ||
229 | struct localvar *localvars; | ||
230 | /* struct alias **atab; */ | ||
231 | /* struct parsefile *g_parsefile; */ | ||
232 | int fpid; | ||
233 | HANDLE hMapFile; | ||
234 | void *old_base; | ||
235 | int nodeptr_offset; | ||
236 | int size; | ||
237 | |||
238 | forkpoint_fn fp; | ||
239 | /* optional data, used by forkpoint_fn */ | ||
240 | int flags; | ||
241 | int fd[10]; | ||
242 | union node *n; | ||
243 | char **argv; | ||
244 | char *string; | ||
245 | struct strlist *strlist; | ||
246 | pid_t pid; | ||
247 | }; | ||
248 | static void sticky_free(void *p); | ||
249 | #define free(p) sticky_free(p) | ||
250 | static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode); | ||
251 | #endif | ||
196 | 252 | ||
197 | /* ============ Hash table sizes. Configurable. */ | 253 | /* ============ Hash table sizes. Configurable. */ |
198 | 254 | ||
@@ -2369,10 +2425,22 @@ path_advance(const char **path, const char *name) | |||
2369 | if (*path == NULL) | 2425 | if (*path == NULL) |
2370 | return NULL; | 2426 | return NULL; |
2371 | start = *path; | 2427 | start = *path; |
2428 | #if ENABLE_PLATFORM_MINGW32 | ||
2429 | p = next_path_sep(start); | ||
2430 | q = strchr(start, '%'); | ||
2431 | if ((p && q && q < p) || (!p && q)) | ||
2432 | p = q; | ||
2433 | if (!p) | ||
2434 | for (p = start; *p; p++) | ||
2435 | continue; | ||
2436 | #else | ||
2372 | for (p = start; *p && *p != ':' && *p != '%'; p++) | 2437 | for (p = start; *p && *p != ':' && *p != '%'; p++) |
2373 | continue; | 2438 | continue; |
2439 | #endif | ||
2374 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ | 2440 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ |
2375 | while (stackblocksize() < len) | 2441 | |
2442 | /* preserve space for .exe too */ | ||
2443 | while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len)) | ||
2376 | growstackblock(); | 2444 | growstackblock(); |
2377 | q = stackblock(); | 2445 | q = stackblock(); |
2378 | if (p != start) { | 2446 | if (p != start) { |
@@ -2384,10 +2452,19 @@ path_advance(const char **path, const char *name) | |||
2384 | pathopt = NULL; | 2452 | pathopt = NULL; |
2385 | if (*p == '%') { | 2453 | if (*p == '%') { |
2386 | pathopt = ++p; | 2454 | pathopt = ++p; |
2455 | #if ENABLE_PLATFORM_MINGW32 | ||
2456 | p = next_path_sep(start); | ||
2457 | |||
2458 | /* *p != ':' and '*' would suffice */ | ||
2459 | if (!p) | ||
2460 | p = pathopt - 1; | ||
2461 | #else | ||
2387 | while (*p && *p != ':') | 2462 | while (*p && *p != ':') |
2388 | p++; | 2463 | p++; |
2464 | #endif | ||
2389 | } | 2465 | } |
2390 | if (*p == ':') | 2466 | if (*p == ':' || |
2467 | (ENABLE_PLATFORM_MINGW32 && *p == ';')) | ||
2391 | *path = p + 1; | 2468 | *path = p + 1; |
2392 | else | 2469 | else |
2393 | *path = NULL; | 2470 | *path = NULL; |
@@ -2489,6 +2566,99 @@ cdopt(void) | |||
2489 | static const char * | 2566 | static const char * |
2490 | updatepwd(const char *dir) | 2567 | updatepwd(const char *dir) |
2491 | { | 2568 | { |
2569 | #if ENABLE_PLATFORM_MINGW32 | ||
2570 | #define is_path_sep(x) ((x) == '/' || (x) == '\\') | ||
2571 | /* | ||
2572 | * Due to Windows drive notion, getting pwd is a completely | ||
2573 | * different thing. Handle it in a separate routine | ||
2574 | */ | ||
2575 | |||
2576 | char *new; | ||
2577 | char *p; | ||
2578 | char *cdcomppath; | ||
2579 | const char *lim; | ||
2580 | /* | ||
2581 | * There are four cases | ||
2582 | * absdrive + abspath: c:/path | ||
2583 | * absdrive + !abspath: c:path | ||
2584 | * !absdrive + abspath: /path | ||
2585 | * !absdrive + !abspath: path | ||
2586 | * | ||
2587 | * Damn DOS! | ||
2588 | * c:path behaviour is "undefined" | ||
2589 | * To properly handle this case, I have to keep track of cwd | ||
2590 | * of every drive, which is too painful to do. | ||
2591 | * So when c:path is given, I assume it's c:${curdir}path | ||
2592 | * with ${curdir} comes from the current drive | ||
2593 | */ | ||
2594 | int absdrive = *dir && dir[1] == ':'; | ||
2595 | int abspath = absdrive ? is_path_sep(dir[2]) : is_path_sep(*dir); | ||
2596 | char *drive; | ||
2597 | |||
2598 | cdcomppath = ststrdup(dir); | ||
2599 | STARTSTACKSTR(new); | ||
2600 | if (!absdrive && curdir == nullstr) | ||
2601 | return 0; | ||
2602 | if (!abspath) { | ||
2603 | if (curdir == nullstr) | ||
2604 | return 0; | ||
2605 | new = stack_putstr(curdir, new); | ||
2606 | } | ||
2607 | new = makestrspace(strlen(dir) + 2, new); | ||
2608 | |||
2609 | drive = stackblock(); | ||
2610 | if (absdrive) { | ||
2611 | *drive = *dir; | ||
2612 | cdcomppath += 2; | ||
2613 | dir += 2; | ||
2614 | } else { | ||
2615 | *drive = *curdir; | ||
2616 | } | ||
2617 | drive[1] = ':'; /* in case of absolute drive+path */ | ||
2618 | |||
2619 | if (abspath) | ||
2620 | new = drive + 2; | ||
2621 | lim = drive + 3; | ||
2622 | if (!abspath) { | ||
2623 | if (!is_path_sep(new[-1])) | ||
2624 | USTPUTC('/', new); | ||
2625 | if (new > lim && is_path_sep(*lim)) | ||
2626 | lim++; | ||
2627 | } else { | ||
2628 | USTPUTC('/', new); | ||
2629 | cdcomppath ++; | ||
2630 | if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) { | ||
2631 | USTPUTC('/', new); | ||
2632 | cdcomppath++; | ||
2633 | lim++; | ||
2634 | } | ||
2635 | } | ||
2636 | p = strtok(cdcomppath, "/\\"); | ||
2637 | while (p) { | ||
2638 | switch (*p) { | ||
2639 | case '.': | ||
2640 | if (p[1] == '.' && p[2] == '\0') { | ||
2641 | while (new > lim) { | ||
2642 | STUNPUTC(new); | ||
2643 | if (is_path_sep(new[-1])) | ||
2644 | break; | ||
2645 | } | ||
2646 | break; | ||
2647 | } | ||
2648 | if (p[1] == '\0') | ||
2649 | break; | ||
2650 | /* fall through */ | ||
2651 | default: | ||
2652 | new = stack_putstr(p, new); | ||
2653 | USTPUTC('/', new); | ||
2654 | } | ||
2655 | p = strtok(0, "/\\"); | ||
2656 | } | ||
2657 | if (new > lim) | ||
2658 | STUNPUTC(new); | ||
2659 | *new = 0; | ||
2660 | return stackblock(); | ||
2661 | #else | ||
2492 | char *new; | 2662 | char *new; |
2493 | char *p; | 2663 | char *p; |
2494 | char *cdcomppath; | 2664 | char *cdcomppath; |
@@ -2542,6 +2712,7 @@ updatepwd(const char *dir) | |||
2542 | STUNPUTC(new); | 2712 | STUNPUTC(new); |
2543 | *new = 0; | 2713 | *new = 0; |
2544 | return stackblock(); | 2714 | return stackblock(); |
2715 | #endif | ||
2545 | } | 2716 | } |
2546 | 2717 | ||
2547 | /* | 2718 | /* |
@@ -2636,7 +2807,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2636 | } | 2807 | } |
2637 | if (!dest) | 2808 | if (!dest) |
2638 | dest = nullstr; | 2809 | dest = nullstr; |
2639 | if (*dest == '/') | 2810 | if (is_absolute_path(dest)) |
2640 | goto step7; | 2811 | goto step7; |
2641 | if (*dest == '.') { | 2812 | if (*dest == '.') { |
2642 | c = dest[1]; | 2813 | c = dest[1]; |
@@ -3408,6 +3579,8 @@ setsignal(int signo) | |||
3408 | char cur_act, new_act; | 3579 | char cur_act, new_act; |
3409 | struct sigaction act; | 3580 | struct sigaction act; |
3410 | 3581 | ||
3582 | if (ENABLE_PLATFORM_MINGW32) | ||
3583 | return; | ||
3411 | t = trap[signo]; | 3584 | t = trap[signo]; |
3412 | new_act = S_DFL; | 3585 | new_act = S_DFL; |
3413 | if (t != NULL) { /* trap for this sig is set */ | 3586 | if (t != NULL) { /* trap for this sig is set */ |
@@ -3929,6 +4102,79 @@ sprint_status(char *s, int status, int sigonly) | |||
3929 | return col; | 4102 | return col; |
3930 | } | 4103 | } |
3931 | 4104 | ||
4105 | #if ENABLE_PLATFORM_MINGW32 | ||
4106 | |||
4107 | HANDLE hSIGINT; /* Ctrl-C is pressed */ | ||
4108 | |||
4109 | static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) | ||
4110 | { | ||
4111 | if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { | ||
4112 | SetEvent(hSIGINT); | ||
4113 | return TRUE; | ||
4114 | } | ||
4115 | return FALSE; | ||
4116 | } | ||
4117 | |||
4118 | /* | ||
4119 | * Windows does not know about parent-child relationship | ||
4120 | * They don't support waitpid(-1) | ||
4121 | */ | ||
4122 | static pid_t | ||
4123 | waitpid_child(int *status, int wait_flags) | ||
4124 | { | ||
4125 | HANDLE *pidlist, *pidp; | ||
4126 | int pid_nr = 0; | ||
4127 | pid_t pid; | ||
4128 | DWORD win_status, idx; | ||
4129 | struct job *jb; | ||
4130 | |||
4131 | #define LOOP(stmt) \ | ||
4132 | for (jb = curjob; jb; jb = jb->prev_job) { \ | ||
4133 | struct procstat *ps, *psend; \ | ||
4134 | if (jb->state == JOBDONE) \ | ||
4135 | continue; \ | ||
4136 | ps = jb->ps; \ | ||
4137 | psend = ps + jb->nprocs; \ | ||
4138 | while (ps < psend) { \ | ||
4139 | if (ps->ps_pid != -1) { \ | ||
4140 | stmt; \ | ||
4141 | } \ | ||
4142 | ps++; \ | ||
4143 | } \ | ||
4144 | } | ||
4145 | |||
4146 | LOOP(pid_nr++); | ||
4147 | if (!pid_nr) | ||
4148 | return -1; | ||
4149 | pid_nr++; | ||
4150 | pidp = pidlist = ckmalloc(sizeof(*pidlist)*pid_nr); | ||
4151 | *pidp++ = hSIGINT; | ||
4152 | LOOP(*pidp++ = (HANDLE)ps->ps_pid); | ||
4153 | #undef LOOP | ||
4154 | |||
4155 | idx = WaitForMultipleObjects(pid_nr, pidlist, FALSE, | ||
4156 | wait_flags|WNOHANG ? 0 : INFINITE); | ||
4157 | if (idx >= pid_nr) { | ||
4158 | free(pidlist); | ||
4159 | return -1; | ||
4160 | } | ||
4161 | if (!idx) { /* hSIGINT */ | ||
4162 | int i; | ||
4163 | ResetEvent(hSIGINT); | ||
4164 | for (i = 1; i < pid_nr; i++) | ||
4165 | TerminateProcess(pidlist[i], 1); | ||
4166 | free(pidlist); | ||
4167 | *status = 260; /* terminated by a signal */ | ||
4168 | return pidlist[1]; | ||
4169 | } | ||
4170 | GetExitCodeProcess(pidlist[idx], &win_status); | ||
4171 | pid = (int)pidlist[idx]; | ||
4172 | free(pidlist); | ||
4173 | *status = (int)win_status; | ||
4174 | return pid; | ||
4175 | } | ||
4176 | #endif | ||
4177 | |||
3932 | static int | 4178 | static int |
3933 | dowait(int wait_flags, struct job *job) | 4179 | dowait(int wait_flags, struct job *job) |
3934 | { | 4180 | { |
@@ -3945,7 +4191,11 @@ dowait(int wait_flags, struct job *job) | |||
3945 | * NB: _not_ safe_waitpid, we need to detect EINTR */ | 4191 | * NB: _not_ safe_waitpid, we need to detect EINTR */ |
3946 | if (doing_jobctl) | 4192 | if (doing_jobctl) |
3947 | wait_flags |= WUNTRACED; | 4193 | wait_flags |= WUNTRACED; |
4194 | #if ENABLE_PLATFORM_MINGW32 | ||
4195 | pid = waitpid_child(&status, wait_flags); | ||
4196 | #else | ||
3948 | pid = waitpid(-1, &status, wait_flags); | 4197 | pid = waitpid(-1, &status, wait_flags); |
4198 | #endif | ||
3949 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", | 4199 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", |
3950 | pid, status, errno, strerror(errno))); | 4200 | pid, status, errno, strerror(errno))); |
3951 | if (pid <= 0) | 4201 | if (pid <= 0) |
@@ -3968,6 +4218,8 @@ dowait(int wait_flags, struct job *job) | |||
3968 | jobno(jp), pid, ps->ps_status, status)); | 4218 | jobno(jp), pid, ps->ps_status, status)); |
3969 | ps->ps_status = status; | 4219 | ps->ps_status = status; |
3970 | thisjob = jp; | 4220 | thisjob = jp; |
4221 | if (ENABLE_PLATFORM_MINGW32) | ||
4222 | ps->ps_pid = -1; | ||
3971 | } | 4223 | } |
3972 | if (ps->ps_status == -1) | 4224 | if (ps->ps_status == -1) |
3973 | state = JOBRUNNING; | 4225 | state = JOBRUNNING; |
@@ -4199,6 +4451,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
4199 | int retval; | 4451 | int retval; |
4200 | struct job *jp; | 4452 | struct job *jp; |
4201 | 4453 | ||
4454 | if (ENABLE_PLATFORM_MINGW32) | ||
4455 | return 0; | ||
4456 | |||
4202 | if (pending_sig) | 4457 | if (pending_sig) |
4203 | raise_exception(EXSIG); | 4458 | raise_exception(EXSIG); |
4204 | 4459 | ||
@@ -4811,7 +5066,7 @@ static void | |||
4811 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 5066 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
4812 | { | 5067 | { |
4813 | TRACE(("In parent shell: child = %d\n", pid)); | 5068 | TRACE(("In parent shell: child = %d\n", pid)); |
4814 | if (!jp) { | 5069 | if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */ |
4815 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) | 5070 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) |
4816 | continue; | 5071 | continue; |
4817 | jobless++; | 5072 | jobless++; |
@@ -4851,6 +5106,9 @@ forkshell(struct job *jp, union node *n, int mode) | |||
4851 | int pid; | 5106 | int pid; |
4852 | 5107 | ||
4853 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); | 5108 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); |
5109 | if (ENABLE_PLATFORM_MINGW32) | ||
5110 | return -1; | ||
5111 | |||
4854 | pid = fork(); | 5112 | pid = fork(); |
4855 | if (pid < 0) { | 5113 | if (pid < 0) { |
4856 | TRACE(("Fork failed, errno=%d", errno)); | 5114 | TRACE(("Fork failed, errno=%d", errno)); |
@@ -5053,11 +5311,39 @@ noclobberopen(const char *fname) | |||
5053 | */ | 5311 | */ |
5054 | /* openhere needs this forward reference */ | 5312 | /* openhere needs this forward reference */ |
5055 | static void expandhere(union node *arg, int fd); | 5313 | static void expandhere(union node *arg, int fd); |
5314 | #if ENABLE_PLATFORM_MINGW32 | ||
5315 | static void | ||
5316 | forkshell_openhere(struct forkshell *fs) | ||
5317 | { | ||
5318 | union node *redir = fs->n; | ||
5319 | int pip[2]; | ||
5320 | |||
5321 | pip[0] = fs->fd[0]; | ||
5322 | pip[1] = fs->fd[1]; | ||
5323 | |||
5324 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
5325 | |||
5326 | close(pip[0]); | ||
5327 | ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); | ||
5328 | ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); | ||
5329 | ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); | ||
5330 | ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); | ||
5331 | signal(SIGPIPE, SIG_DFL); | ||
5332 | if (redir->type == NHERE) { | ||
5333 | size_t len = strlen(redir->nhere.doc->narg.text); | ||
5334 | full_write(pip[1], redir->nhere.doc->narg.text, len); | ||
5335 | } else /* NXHERE */ | ||
5336 | expandhere(redir->nhere.doc, pip[1]); | ||
5337 | _exit(EXIT_SUCCESS); | ||
5338 | } | ||
5339 | #endif | ||
5340 | |||
5056 | static int | 5341 | static int |
5057 | openhere(union node *redir) | 5342 | openhere(union node *redir) |
5058 | { | 5343 | { |
5059 | int pip[2]; | 5344 | int pip[2]; |
5060 | size_t len = 0; | 5345 | size_t len = 0; |
5346 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5061 | 5347 | ||
5062 | if (pipe(pip) < 0) | 5348 | if (pipe(pip) < 0) |
5063 | ash_msg_and_raise_error("pipe call failed"); | 5349 | ash_msg_and_raise_error("pipe call failed"); |
@@ -5068,6 +5354,16 @@ openhere(union node *redir) | |||
5068 | goto out; | 5354 | goto out; |
5069 | } | 5355 | } |
5070 | } | 5356 | } |
5357 | #if ENABLE_PLATFORM_MINGW32 | ||
5358 | memset(&fs, 0, sizeof(fs)); | ||
5359 | fs.fp = forkshell_openhere; | ||
5360 | fs.flags = 0; | ||
5361 | fs.n = redir; | ||
5362 | fs.fd[0] = pip[0]; | ||
5363 | fs.fd[1] = pip[1]; | ||
5364 | if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0) | ||
5365 | ash_msg_and_raise_error("unable to spawn shell"); | ||
5366 | #endif | ||
5071 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | 5367 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { |
5072 | /* child */ | 5368 | /* child */ |
5073 | close(pip[0]); | 5369 | close(pip[0]); |
@@ -5094,6 +5390,31 @@ openredirect(union node *redir) | |||
5094 | int f; | 5390 | int f; |
5095 | 5391 | ||
5096 | fname = redir->nfile.expfname; | 5392 | fname = redir->nfile.expfname; |
5393 | #if ENABLE_PLATFORM_MINGW32 | ||
5394 | /* Support for /dev/null */ | ||
5395 | switch (redir->nfile.type) { | ||
5396 | case NFROM: | ||
5397 | if (!strcmp(fname, "/dev/null")) | ||
5398 | return open("nul",O_RDWR); | ||
5399 | if (!strncmp(fname, "/dev/", 5)) { | ||
5400 | ash_msg("Unhandled device %s\n", fname); | ||
5401 | return -1; | ||
5402 | } | ||
5403 | break; | ||
5404 | |||
5405 | case NFROMTO: | ||
5406 | case NTO: | ||
5407 | case NCLOBBER: | ||
5408 | case NAPPEND: | ||
5409 | if (!strcmp(fname, "/dev/null")) | ||
5410 | return open("nul",O_RDWR); | ||
5411 | if (!strncmp(fname, "/dev/", 5)) { | ||
5412 | ash_msg("Unhandled device %s\n", fname); | ||
5413 | return -1; | ||
5414 | } | ||
5415 | break; | ||
5416 | } | ||
5417 | #endif | ||
5097 | switch (redir->nfile.type) { | 5418 | switch (redir->nfile.type) { |
5098 | case NFROM: | 5419 | case NFROM: |
5099 | f = open(fname, O_RDONLY); | 5420 | f = open(fname, O_RDONLY); |
@@ -5791,6 +6112,8 @@ exptilde(char *startp, char *p, int flags) | |||
5791 | if (*name == '\0') { | 6112 | if (*name == '\0') { |
5792 | home = lookupvar("HOME"); | 6113 | home = lookupvar("HOME"); |
5793 | } else { | 6114 | } else { |
6115 | if (ENABLE_PLATFORM_MINGW32) | ||
6116 | goto lose; | ||
5794 | pw = getpwnam(name); | 6117 | pw = getpwnam(name); |
5795 | if (pw == NULL) | 6118 | if (pw == NULL) |
5796 | goto lose; | 6119 | goto lose; |
@@ -5818,6 +6141,7 @@ struct backcmd { /* result of evalbackcmd */ | |||
5818 | int fd; /* file descriptor to read from */ | 6141 | int fd; /* file descriptor to read from */ |
5819 | int nleft; /* number of chars in buffer */ | 6142 | int nleft; /* number of chars in buffer */ |
5820 | char *buf; /* buffer */ | 6143 | char *buf; /* buffer */ |
6144 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5821 | struct job *jp; /* job structure for command */ | 6145 | struct job *jp; /* job structure for command */ |
5822 | }; | 6146 | }; |
5823 | 6147 | ||
@@ -5826,6 +6150,25 @@ static uint8_t back_exitstatus; /* exit status of backquoted command */ | |||
5826 | #define EV_EXIT 01 /* exit after evaluating tree */ | 6150 | #define EV_EXIT 01 /* exit after evaluating tree */ |
5827 | static void evaltree(union node *, int); | 6151 | static void evaltree(union node *, int); |
5828 | 6152 | ||
6153 | #if ENABLE_PLATFORM_MINGW32 | ||
6154 | static void | ||
6155 | forkshell_evalbackcmd(struct forkshell *fs) | ||
6156 | { | ||
6157 | union node *n = fs->n; | ||
6158 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
6159 | |||
6160 | FORCE_INT_ON; | ||
6161 | close(pip[0]); | ||
6162 | if (pip[1] != 1) { | ||
6163 | /*close(1);*/ | ||
6164 | copyfd(pip[1], 1 | COPYFD_EXACT); | ||
6165 | close(pip[1]); | ||
6166 | } | ||
6167 | eflag = 0; | ||
6168 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ | ||
6169 | /* NOTREACHED */ | ||
6170 | } | ||
6171 | #endif | ||
5829 | static void FAST_FUNC | 6172 | static void FAST_FUNC |
5830 | evalbackcmd(union node *n, struct backcmd *result) | 6173 | evalbackcmd(union node *n, struct backcmd *result) |
5831 | { | 6174 | { |
@@ -5834,6 +6177,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5834 | result->fd = -1; | 6177 | result->fd = -1; |
5835 | result->buf = NULL; | 6178 | result->buf = NULL; |
5836 | result->nleft = 0; | 6179 | result->nleft = 0; |
6180 | IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs))); | ||
5837 | result->jp = NULL; | 6181 | result->jp = NULL; |
5838 | if (n == NULL) | 6182 | if (n == NULL) |
5839 | goto out; | 6183 | goto out; |
@@ -5848,6 +6192,14 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5848 | if (pipe(pip) < 0) | 6192 | if (pipe(pip) < 0) |
5849 | ash_msg_and_raise_error("pipe call failed"); | 6193 | ash_msg_and_raise_error("pipe call failed"); |
5850 | jp = makejob(/*n,*/ 1); | 6194 | jp = makejob(/*n,*/ 1); |
6195 | #if ENABLE_PLATFORM_MINGW32 | ||
6196 | result->fs.fp = forkshell_evalbackcmd; | ||
6197 | result->fs.n = n; | ||
6198 | result->fs.fd[0] = pip[0]; | ||
6199 | result->fs.fd[1] = pip[1]; | ||
6200 | if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0) | ||
6201 | ash_msg_and_raise_error("unable to spawn shell"); | ||
6202 | #endif | ||
5851 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 6203 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
5852 | FORCE_INT_ON; | 6204 | FORCE_INT_ON; |
5853 | close(pip[0]); | 6205 | close(pip[0]); |
@@ -5918,7 +6270,8 @@ expbackq(union node *cmd, int quoted, int quotes) | |||
5918 | 6270 | ||
5919 | /* Eat all trailing newlines */ | 6271 | /* Eat all trailing newlines */ |
5920 | dest = expdest; | 6272 | dest = expdest; |
5921 | for (; dest > (char *)stackblock() && dest[-1] == '\n';) | 6273 | for (; dest > (char *)stackblock() && (dest[-1] == '\n' || |
6274 | (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));) | ||
5922 | STUNPUTC(dest); | 6275 | STUNPUTC(dest); |
5923 | expdest = dest; | 6276 | expdest = dest; |
5924 | 6277 | ||
@@ -7465,7 +7818,7 @@ shellexec(char **argv, const char *path, int idx) | |||
7465 | 7818 | ||
7466 | clearredir(/*drop:*/ 1); | 7819 | clearredir(/*drop:*/ 1); |
7467 | envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); | 7820 | envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); |
7468 | if (strchr(argv[0], '/') != NULL | 7821 | if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\'))) |
7469 | #if ENABLE_FEATURE_SH_STANDALONE | 7822 | #if ENABLE_FEATURE_SH_STANDALONE |
7470 | || (applet_no = find_applet_by_name(argv[0])) >= 0 | 7823 | || (applet_no = find_applet_by_name(argv[0])) >= 0 |
7471 | #endif | 7824 | #endif |
@@ -7976,6 +8329,10 @@ static int funcblocksize; /* size of structures in function */ | |||
7976 | static int funcstringsize; /* size of strings in node */ | 8329 | static int funcstringsize; /* size of strings in node */ |
7977 | static void *funcblock; /* block to allocate function from */ | 8330 | static void *funcblock; /* block to allocate function from */ |
7978 | static char *funcstring; /* block to allocate strings from */ | 8331 | static char *funcstring; /* block to allocate strings from */ |
8332 | #if ENABLE_PLATFORM_MINGW32 | ||
8333 | static int nodeptrsize; | ||
8334 | static int *nodeptr; | ||
8335 | #endif | ||
7979 | 8336 | ||
7980 | /* flags in argument to evaltree */ | 8337 | /* flags in argument to evaltree */ |
7981 | #define EV_EXIT 01 /* exit after evaluating tree */ | 8338 | #define EV_EXIT 01 /* exit after evaluating tree */ |
@@ -8021,6 +8378,7 @@ sizenodelist(struct nodelist *lp) | |||
8021 | { | 8378 | { |
8022 | while (lp) { | 8379 | while (lp) { |
8023 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); | 8380 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); |
8381 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8024 | calcsize(lp->n); | 8382 | calcsize(lp->n); |
8025 | lp = lp->next; | 8383 | lp = lp->next; |
8026 | } | 8384 | } |
@@ -8037,15 +8395,18 @@ calcsize(union node *n) | |||
8037 | calcsize(n->ncmd.redirect); | 8395 | calcsize(n->ncmd.redirect); |
8038 | calcsize(n->ncmd.args); | 8396 | calcsize(n->ncmd.args); |
8039 | calcsize(n->ncmd.assign); | 8397 | calcsize(n->ncmd.assign); |
8398 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8040 | break; | 8399 | break; |
8041 | case NPIPE: | 8400 | case NPIPE: |
8042 | sizenodelist(n->npipe.cmdlist); | 8401 | sizenodelist(n->npipe.cmdlist); |
8402 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
8043 | break; | 8403 | break; |
8044 | case NREDIR: | 8404 | case NREDIR: |
8045 | case NBACKGND: | 8405 | case NBACKGND: |
8046 | case NSUBSHELL: | 8406 | case NSUBSHELL: |
8047 | calcsize(n->nredir.redirect); | 8407 | calcsize(n->nredir.redirect); |
8048 | calcsize(n->nredir.n); | 8408 | calcsize(n->nredir.n); |
8409 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8049 | break; | 8410 | break; |
8050 | case NAND: | 8411 | case NAND: |
8051 | case NOR: | 8412 | case NOR: |
@@ -8054,31 +8415,37 @@ calcsize(union node *n) | |||
8054 | case NUNTIL: | 8415 | case NUNTIL: |
8055 | calcsize(n->nbinary.ch2); | 8416 | calcsize(n->nbinary.ch2); |
8056 | calcsize(n->nbinary.ch1); | 8417 | calcsize(n->nbinary.ch1); |
8418 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8057 | break; | 8419 | break; |
8058 | case NIF: | 8420 | case NIF: |
8059 | calcsize(n->nif.elsepart); | 8421 | calcsize(n->nif.elsepart); |
8060 | calcsize(n->nif.ifpart); | 8422 | calcsize(n->nif.ifpart); |
8061 | calcsize(n->nif.test); | 8423 | calcsize(n->nif.test); |
8424 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8062 | break; | 8425 | break; |
8063 | case NFOR: | 8426 | case NFOR: |
8064 | funcstringsize += strlen(n->nfor.var) + 1; | 8427 | funcstringsize += strlen(n->nfor.var) + 1; |
8065 | calcsize(n->nfor.body); | 8428 | calcsize(n->nfor.body); |
8066 | calcsize(n->nfor.args); | 8429 | calcsize(n->nfor.args); |
8430 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8067 | break; | 8431 | break; |
8068 | case NCASE: | 8432 | case NCASE: |
8069 | calcsize(n->ncase.cases); | 8433 | calcsize(n->ncase.cases); |
8070 | calcsize(n->ncase.expr); | 8434 | calcsize(n->ncase.expr); |
8435 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8071 | break; | 8436 | break; |
8072 | case NCLIST: | 8437 | case NCLIST: |
8073 | calcsize(n->nclist.body); | 8438 | calcsize(n->nclist.body); |
8074 | calcsize(n->nclist.pattern); | 8439 | calcsize(n->nclist.pattern); |
8075 | calcsize(n->nclist.next); | 8440 | calcsize(n->nclist.next); |
8441 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8076 | break; | 8442 | break; |
8077 | case NDEFUN: | 8443 | case NDEFUN: |
8078 | case NARG: | 8444 | case NARG: |
8079 | sizenodelist(n->narg.backquote); | 8445 | sizenodelist(n->narg.backquote); |
8080 | funcstringsize += strlen(n->narg.text) + 1; | 8446 | funcstringsize += strlen(n->narg.text) + 1; |
8081 | calcsize(n->narg.next); | 8447 | calcsize(n->narg.next); |
8448 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8082 | break; | 8449 | break; |
8083 | case NTO: | 8450 | case NTO: |
8084 | #if ENABLE_ASH_BASH_COMPAT | 8451 | #if ENABLE_ASH_BASH_COMPAT |
@@ -8090,28 +8457,34 @@ calcsize(union node *n) | |||
8090 | case NAPPEND: | 8457 | case NAPPEND: |
8091 | calcsize(n->nfile.fname); | 8458 | calcsize(n->nfile.fname); |
8092 | calcsize(n->nfile.next); | 8459 | calcsize(n->nfile.next); |
8460 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8093 | break; | 8461 | break; |
8094 | case NTOFD: | 8462 | case NTOFD: |
8095 | case NFROMFD: | 8463 | case NFROMFD: |
8096 | calcsize(n->ndup.vname); | 8464 | calcsize(n->ndup.vname); |
8097 | calcsize(n->ndup.next); | 8465 | calcsize(n->ndup.next); |
8466 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8098 | break; | 8467 | break; |
8099 | case NHERE: | 8468 | case NHERE: |
8100 | case NXHERE: | 8469 | case NXHERE: |
8101 | calcsize(n->nhere.doc); | 8470 | calcsize(n->nhere.doc); |
8102 | calcsize(n->nhere.next); | 8471 | calcsize(n->nhere.next); |
8472 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8103 | break; | 8473 | break; |
8104 | case NNOT: | 8474 | case NNOT: |
8105 | calcsize(n->nnot.com); | 8475 | calcsize(n->nnot.com); |
8476 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
8106 | break; | 8477 | break; |
8107 | }; | 8478 | }; |
8108 | } | 8479 | } |
8109 | 8480 | ||
8110 | static char * | 8481 | static char * |
8111 | nodeckstrdup(char *s) | 8482 | nodeckstrdup(const char *s) |
8112 | { | 8483 | { |
8113 | char *rtn = funcstring; | 8484 | char *rtn = funcstring; |
8114 | 8485 | ||
8486 | if (!s) | ||
8487 | return NULL; | ||
8115 | strcpy(funcstring, s); | 8488 | strcpy(funcstring, s); |
8116 | funcstring += strlen(s) + 1; | 8489 | funcstring += strlen(s) + 1; |
8117 | return rtn; | 8490 | return rtn; |
@@ -8119,6 +8492,18 @@ nodeckstrdup(char *s) | |||
8119 | 8492 | ||
8120 | static union node *copynode(union node *); | 8493 | static union node *copynode(union node *); |
8121 | 8494 | ||
8495 | #if ENABLE_PLATFORM_MINGW32 | ||
8496 | # define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (int)&(dst);} | ||
8497 | # define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);}} | ||
8498 | # define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);}} | ||
8499 | # define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);*nodeptr++ = (int)&(dst4);}} | ||
8500 | #else | ||
8501 | # define SAVE_PTR(dst) | ||
8502 | # define SAVE_PTR2(dst,dst2) | ||
8503 | # define SAVE_PTR3(dst,dst2,dst3) | ||
8504 | # define SAVE_PTR4(dst,dst2,dst3,dst4) | ||
8505 | #endif | ||
8506 | |||
8122 | static struct nodelist * | 8507 | static struct nodelist * |
8123 | copynodelist(struct nodelist *lp) | 8508 | copynodelist(struct nodelist *lp) |
8124 | { | 8509 | { |
@@ -8130,6 +8515,7 @@ copynodelist(struct nodelist *lp) | |||
8130 | *lpp = funcblock; | 8515 | *lpp = funcblock; |
8131 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); | 8516 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); |
8132 | (*lpp)->n = copynode(lp->n); | 8517 | (*lpp)->n = copynode(lp->n); |
8518 | SAVE_PTR2((*lpp)->n, (*lpp)->next); | ||
8133 | lp = lp->next; | 8519 | lp = lp->next; |
8134 | lpp = &(*lpp)->next; | 8520 | lpp = &(*lpp)->next; |
8135 | } | 8521 | } |
@@ -8152,16 +8538,19 @@ copynode(union node *n) | |||
8152 | new->ncmd.redirect = copynode(n->ncmd.redirect); | 8538 | new->ncmd.redirect = copynode(n->ncmd.redirect); |
8153 | new->ncmd.args = copynode(n->ncmd.args); | 8539 | new->ncmd.args = copynode(n->ncmd.args); |
8154 | new->ncmd.assign = copynode(n->ncmd.assign); | 8540 | new->ncmd.assign = copynode(n->ncmd.assign); |
8541 | SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign); | ||
8155 | break; | 8542 | break; |
8156 | case NPIPE: | 8543 | case NPIPE: |
8157 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | 8544 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); |
8158 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; | 8545 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; |
8546 | SAVE_PTR(new->npipe.cmdlist); | ||
8159 | break; | 8547 | break; |
8160 | case NREDIR: | 8548 | case NREDIR: |
8161 | case NBACKGND: | 8549 | case NBACKGND: |
8162 | case NSUBSHELL: | 8550 | case NSUBSHELL: |
8163 | new->nredir.redirect = copynode(n->nredir.redirect); | 8551 | new->nredir.redirect = copynode(n->nredir.redirect); |
8164 | new->nredir.n = copynode(n->nredir.n); | 8552 | new->nredir.n = copynode(n->nredir.n); |
8553 | SAVE_PTR2(new->nredir.redirect,new->nredir.n); | ||
8165 | break; | 8554 | break; |
8166 | case NAND: | 8555 | case NAND: |
8167 | case NOR: | 8556 | case NOR: |
@@ -8170,31 +8559,37 @@ copynode(union node *n) | |||
8170 | case NUNTIL: | 8559 | case NUNTIL: |
8171 | new->nbinary.ch2 = copynode(n->nbinary.ch2); | 8560 | new->nbinary.ch2 = copynode(n->nbinary.ch2); |
8172 | new->nbinary.ch1 = copynode(n->nbinary.ch1); | 8561 | new->nbinary.ch1 = copynode(n->nbinary.ch1); |
8562 | SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2); | ||
8173 | break; | 8563 | break; |
8174 | case NIF: | 8564 | case NIF: |
8175 | new->nif.elsepart = copynode(n->nif.elsepart); | 8565 | new->nif.elsepart = copynode(n->nif.elsepart); |
8176 | new->nif.ifpart = copynode(n->nif.ifpart); | 8566 | new->nif.ifpart = copynode(n->nif.ifpart); |
8177 | new->nif.test = copynode(n->nif.test); | 8567 | new->nif.test = copynode(n->nif.test); |
8568 | SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test); | ||
8178 | break; | 8569 | break; |
8179 | case NFOR: | 8570 | case NFOR: |
8180 | new->nfor.var = nodeckstrdup(n->nfor.var); | 8571 | new->nfor.var = nodeckstrdup(n->nfor.var); |
8181 | new->nfor.body = copynode(n->nfor.body); | 8572 | new->nfor.body = copynode(n->nfor.body); |
8182 | new->nfor.args = copynode(n->nfor.args); | 8573 | new->nfor.args = copynode(n->nfor.args); |
8574 | SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args); | ||
8183 | break; | 8575 | break; |
8184 | case NCASE: | 8576 | case NCASE: |
8185 | new->ncase.cases = copynode(n->ncase.cases); | 8577 | new->ncase.cases = copynode(n->ncase.cases); |
8186 | new->ncase.expr = copynode(n->ncase.expr); | 8578 | new->ncase.expr = copynode(n->ncase.expr); |
8579 | SAVE_PTR2(new->ncase.cases,new->ncase.expr); | ||
8187 | break; | 8580 | break; |
8188 | case NCLIST: | 8581 | case NCLIST: |
8189 | new->nclist.body = copynode(n->nclist.body); | 8582 | new->nclist.body = copynode(n->nclist.body); |
8190 | new->nclist.pattern = copynode(n->nclist.pattern); | 8583 | new->nclist.pattern = copynode(n->nclist.pattern); |
8191 | new->nclist.next = copynode(n->nclist.next); | 8584 | new->nclist.next = copynode(n->nclist.next); |
8585 | SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next); | ||
8192 | break; | 8586 | break; |
8193 | case NDEFUN: | 8587 | case NDEFUN: |
8194 | case NARG: | 8588 | case NARG: |
8195 | new->narg.backquote = copynodelist(n->narg.backquote); | 8589 | new->narg.backquote = copynodelist(n->narg.backquote); |
8196 | new->narg.text = nodeckstrdup(n->narg.text); | 8590 | new->narg.text = nodeckstrdup(n->narg.text); |
8197 | new->narg.next = copynode(n->narg.next); | 8591 | new->narg.next = copynode(n->narg.next); |
8592 | SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next); | ||
8198 | break; | 8593 | break; |
8199 | case NTO: | 8594 | case NTO: |
8200 | #if ENABLE_ASH_BASH_COMPAT | 8595 | #if ENABLE_ASH_BASH_COMPAT |
@@ -8207,6 +8602,7 @@ copynode(union node *n) | |||
8207 | new->nfile.fname = copynode(n->nfile.fname); | 8602 | new->nfile.fname = copynode(n->nfile.fname); |
8208 | new->nfile.fd = n->nfile.fd; | 8603 | new->nfile.fd = n->nfile.fd; |
8209 | new->nfile.next = copynode(n->nfile.next); | 8604 | new->nfile.next = copynode(n->nfile.next); |
8605 | SAVE_PTR2(new->nfile.fname,new->nfile.next); | ||
8210 | break; | 8606 | break; |
8211 | case NTOFD: | 8607 | case NTOFD: |
8212 | case NFROMFD: | 8608 | case NFROMFD: |
@@ -8214,15 +8610,18 @@ copynode(union node *n) | |||
8214 | new->ndup.dupfd = n->ndup.dupfd; | 8610 | new->ndup.dupfd = n->ndup.dupfd; |
8215 | new->ndup.fd = n->ndup.fd; | 8611 | new->ndup.fd = n->ndup.fd; |
8216 | new->ndup.next = copynode(n->ndup.next); | 8612 | new->ndup.next = copynode(n->ndup.next); |
8613 | SAVE_PTR2(new->ndup.vname,new->ndup.next); | ||
8217 | break; | 8614 | break; |
8218 | case NHERE: | 8615 | case NHERE: |
8219 | case NXHERE: | 8616 | case NXHERE: |
8220 | new->nhere.doc = copynode(n->nhere.doc); | 8617 | new->nhere.doc = copynode(n->nhere.doc); |
8221 | new->nhere.fd = n->nhere.fd; | 8618 | new->nhere.fd = n->nhere.fd; |
8222 | new->nhere.next = copynode(n->nhere.next); | 8619 | new->nhere.next = copynode(n->nhere.next); |
8620 | SAVE_PTR2(new->nhere.doc,new->nhere.next); | ||
8223 | break; | 8621 | break; |
8224 | case NNOT: | 8622 | case NNOT: |
8225 | new->nnot.com = copynode(n->nnot.com); | 8623 | new->nnot.com = copynode(n->nnot.com); |
8624 | SAVE_PTR(new->nnot.com); | ||
8226 | break; | 8625 | break; |
8227 | }; | 8626 | }; |
8228 | new->type = n->type; | 8627 | new->type = n->type; |
@@ -8245,6 +8644,7 @@ copyfunc(union node *n) | |||
8245 | f = ckmalloc(blocksize + funcstringsize); | 8644 | f = ckmalloc(blocksize + funcstringsize); |
8246 | funcblock = (char *) f + offsetof(struct funcnode, n); | 8645 | funcblock = (char *) f + offsetof(struct funcnode, n); |
8247 | funcstring = (char *) f + blocksize; | 8646 | funcstring = (char *) f + blocksize; |
8647 | IF_PLATFORM_MINGW32(nodeptr = NULL); | ||
8248 | copynode(n); | 8648 | copynode(n); |
8249 | f->count = 0; | 8649 | f->count = 0; |
8250 | return f; | 8650 | return f; |
@@ -8601,9 +9001,26 @@ evalcase(union node *n, int flags) | |||
8601 | /* | 9001 | /* |
8602 | * Kick off a subshell to evaluate a tree. | 9002 | * Kick off a subshell to evaluate a tree. |
8603 | */ | 9003 | */ |
9004 | #if ENABLE_PLATFORM_MINGW32 | ||
9005 | static void | ||
9006 | forkshell_evalsubshell(struct forkshell *fs) | ||
9007 | { | ||
9008 | union node *n = fs->n; | ||
9009 | int flags = fs->flags; | ||
9010 | |||
9011 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
9012 | INT_ON; | ||
9013 | flags |= EV_EXIT; | ||
9014 | expredir(n->nredir.redirect); | ||
9015 | redirect(n->nredir.redirect, 0); | ||
9016 | evaltreenr(n->nredir.n, flags); | ||
9017 | /* never returns */ | ||
9018 | } | ||
9019 | #endif | ||
8604 | static void | 9020 | static void |
8605 | evalsubshell(union node *n, int flags) | 9021 | evalsubshell(union node *n, int flags) |
8606 | { | 9022 | { |
9023 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
8607 | struct job *jp; | 9024 | struct job *jp; |
8608 | int backgnd = (n->type == NBACKGND); | 9025 | int backgnd = (n->type == NBACKGND); |
8609 | int status; | 9026 | int status; |
@@ -8613,6 +9030,14 @@ evalsubshell(union node *n, int flags) | |||
8613 | goto nofork; | 9030 | goto nofork; |
8614 | INT_OFF; | 9031 | INT_OFF; |
8615 | jp = makejob(/*n,*/ 1); | 9032 | jp = makejob(/*n,*/ 1); |
9033 | #if ENABLE_PLATFORM_MINGW32 | ||
9034 | memset(&fs, 0, sizeof(fs)); | ||
9035 | fs.fp = forkshell_evalsubshell; | ||
9036 | fs.n = n; | ||
9037 | fs.flags = flags; | ||
9038 | if (spawn_forkshell(jp, &fs, backgnd) < 0) | ||
9039 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9040 | #endif | ||
8616 | if (forkshell(jp, n, backgnd) == 0) { | 9041 | if (forkshell(jp, n, backgnd) == 0) { |
8617 | /* child */ | 9042 | /* child */ |
8618 | INT_ON; | 9043 | INT_ON; |
@@ -8701,9 +9126,35 @@ expredir(union node *n) | |||
8701 | * of the shell, which make the last process in a pipeline the parent | 9126 | * of the shell, which make the last process in a pipeline the parent |
8702 | * of all the rest.) | 9127 | * of all the rest.) |
8703 | */ | 9128 | */ |
9129 | #if ENABLE_PLATFORM_MINGW32 | ||
9130 | static void | ||
9131 | forkshell_evalpipe(struct forkshell *fs) | ||
9132 | { | ||
9133 | union node *n = fs->n; | ||
9134 | int flags = fs->flags; | ||
9135 | int prevfd = fs->fd[2]; | ||
9136 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
9137 | |||
9138 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
9139 | INT_ON; | ||
9140 | if (pip[1] >= 0) { | ||
9141 | close(pip[0]); | ||
9142 | } | ||
9143 | if (prevfd > 0) { | ||
9144 | dup2(prevfd, 0); | ||
9145 | close(prevfd); | ||
9146 | } | ||
9147 | if (pip[1] > 1) { | ||
9148 | dup2(pip[1], 1); | ||
9149 | close(pip[1]); | ||
9150 | } | ||
9151 | evaltreenr(n, flags); | ||
9152 | } | ||
9153 | #endif | ||
8704 | static void | 9154 | static void |
8705 | evalpipe(union node *n, int flags) | 9155 | evalpipe(union node *n, int flags) |
8706 | { | 9156 | { |
9157 | IF_PLATFORM_MINGW32(struct forkshell fs;) | ||
8707 | struct job *jp; | 9158 | struct job *jp; |
8708 | struct nodelist *lp; | 9159 | struct nodelist *lp; |
8709 | int pipelen; | 9160 | int pipelen; |
@@ -8727,6 +9178,17 @@ evalpipe(union node *n, int flags) | |||
8727 | ash_msg_and_raise_error("pipe call failed"); | 9178 | ash_msg_and_raise_error("pipe call failed"); |
8728 | } | 9179 | } |
8729 | } | 9180 | } |
9181 | #if ENABLE_PLATFORM_MINGW32 | ||
9182 | memset(&fs, 0, sizeof(fs)); | ||
9183 | fs.fp = forkshell_evalpipe; | ||
9184 | fs.flags = flags; | ||
9185 | fs.n = lp->n; | ||
9186 | fs.fd[0] = pip[0]; | ||
9187 | fs.fd[1] = pip[1]; | ||
9188 | fs.fd[2] = prevfd; | ||
9189 | if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0) | ||
9190 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9191 | #endif | ||
8730 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { | 9192 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { |
8731 | INT_ON; | 9193 | INT_ON; |
8732 | if (pip[1] >= 0) { | 9194 | if (pip[1] >= 0) { |
@@ -9195,6 +9657,20 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
9195 | * as POSIX mandates */ | 9657 | * as POSIX mandates */ |
9196 | return back_exitstatus; | 9658 | return back_exitstatus; |
9197 | } | 9659 | } |
9660 | |||
9661 | #if ENABLE_PLATFORM_MINGW32 | ||
9662 | static void | ||
9663 | forkshell_shellexec(struct forkshell *fs) | ||
9664 | { | ||
9665 | int idx = fs->fd[0]; | ||
9666 | struct strlist *varlist = fs->strlist; | ||
9667 | char **argv = fs->argv; | ||
9668 | char *path = fs->string; | ||
9669 | |||
9670 | listsetvar(varlist, VEXPORT|VSTACK); | ||
9671 | shellexec(argv, path, idx); | ||
9672 | } | ||
9673 | #endif | ||
9198 | static void | 9674 | static void |
9199 | evalcommand(union node *cmd, int flags) | 9675 | evalcommand(union node *cmd, int flags) |
9200 | { | 9676 | { |
@@ -9372,6 +9848,27 @@ evalcommand(union node *cmd, int flags) | |||
9372 | * in a script or a subshell does not need forking, | 9848 | * in a script or a subshell does not need forking, |
9373 | * we can just exec it. | 9849 | * we can just exec it. |
9374 | */ | 9850 | */ |
9851 | #if ENABLE_PLATFORM_MINGW32 | ||
9852 | if (!(flags & EV_EXIT) || trap[0]) { | ||
9853 | /* No, forking off a child is necessary */ | ||
9854 | struct forkshell fs; | ||
9855 | |||
9856 | memset(&fs, 0, sizeof(fs)); | ||
9857 | fs.fp = forkshell_shellexec; | ||
9858 | fs.argv = argv; | ||
9859 | fs.string = (char*)path; | ||
9860 | fs.fd[0] = cmdentry.u.index; | ||
9861 | fs.strlist = varlist.list; | ||
9862 | jp = makejob(/*cmd,*/ 1); | ||
9863 | if (spawn_forkshell(jp, &fs, FORK_FG) < 0) | ||
9864 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9865 | exitstatus = waitforjob(jp); | ||
9866 | INT_ON; | ||
9867 | TRACE(("forked child exited with %d\n", exitstatus)); | ||
9868 | break; | ||
9869 | } | ||
9870 | /* goes through to shellexec() */ | ||
9871 | #else | ||
9375 | if (!(flags & EV_EXIT) || may_have_traps) { | 9872 | if (!(flags & EV_EXIT) || may_have_traps) { |
9376 | /* No, forking off a child is necessary */ | 9873 | /* No, forking off a child is necessary */ |
9377 | INT_OFF; | 9874 | INT_OFF; |
@@ -9387,6 +9884,7 @@ evalcommand(union node *cmd, int flags) | |||
9387 | FORCE_INT_ON; | 9884 | FORCE_INT_ON; |
9388 | /* fall through to exec'ing external program */ | 9885 | /* fall through to exec'ing external program */ |
9389 | } | 9886 | } |
9887 | #endif | ||
9390 | listsetvar(varlist.list, VEXPORT|VSTACK); | 9888 | listsetvar(varlist.list, VEXPORT|VSTACK); |
9391 | shellexec(argv, path, cmdentry.u.index); | 9889 | shellexec(argv, path, cmdentry.u.index); |
9392 | /* NOTREACHED */ | 9890 | /* NOTREACHED */ |
@@ -9779,7 +10277,7 @@ preadbuffer(void) | |||
9779 | more--; | 10277 | more--; |
9780 | 10278 | ||
9781 | c = *q; | 10279 | c = *q; |
9782 | if (c == '\0') { | 10280 | if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) { |
9783 | memmove(q, q + 1, more); | 10281 | memmove(q, q + 1, more); |
9784 | } else { | 10282 | } else { |
9785 | q++; | 10283 | q++; |
@@ -12211,7 +12709,7 @@ find_dot_file(char *name) | |||
12211 | struct stat statb; | 12709 | struct stat statb; |
12212 | 12710 | ||
12213 | /* don't try this for absolute or relative paths */ | 12711 | /* don't try this for absolute or relative paths */ |
12214 | if (strchr(name, '/')) | 12712 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) |
12215 | return name; | 12713 | return name; |
12216 | 12714 | ||
12217 | /* IIRC standards do not say whether . is to be searched. | 12715 | /* IIRC standards do not say whether . is to be searched. |
@@ -12327,10 +12825,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12327 | struct stat statb; | 12825 | struct stat statb; |
12328 | int e; | 12826 | int e; |
12329 | int updatetbl; | 12827 | int updatetbl; |
12828 | IF_PLATFORM_MINGW32(int len;) | ||
12330 | struct builtincmd *bcmd; | 12829 | struct builtincmd *bcmd; |
12331 | 12830 | ||
12332 | /* If name contains a slash, don't use PATH or hash table */ | 12831 | /* If name contains a slash, don't use PATH or hash table */ |
12333 | if (strchr(name, '/') != NULL) { | 12832 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) { |
12334 | entry->u.index = -1; | 12833 | entry->u.index = -1; |
12335 | if (act & DO_ABS) { | 12834 | if (act & DO_ABS) { |
12336 | while (stat(name, &statb) < 0) { | 12835 | while (stat(name, &statb) < 0) { |
@@ -12437,12 +12936,48 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12437 | } | 12936 | } |
12438 | } | 12937 | } |
12439 | /* if rehash, don't redo absolute path names */ | 12938 | /* if rehash, don't redo absolute path names */ |
12440 | if (fullname[0] == '/' && idx <= prev) { | 12939 | if (is_absolute_path(fullname) && idx <= prev) { |
12441 | if (idx < prev) | 12940 | if (idx < prev) |
12442 | continue; | 12941 | continue; |
12443 | TRACE(("searchexec \"%s\": no change\n", name)); | 12942 | TRACE(("searchexec \"%s\": no change\n", name)); |
12444 | goto success; | 12943 | goto success; |
12445 | } | 12944 | } |
12945 | #if ENABLE_PLATFORM_MINGW32 | ||
12946 | len = strlen(fullname); | ||
12947 | if (len > 4 && | ||
12948 | (!strcasecmp(fullname+len-4, ".exe") || | ||
12949 | !strcasecmp(fullname+len-4, ".com"))) { | ||
12950 | if (stat(fullname, &statb) < 0) { | ||
12951 | if (errno != ENOENT && errno != ENOTDIR) | ||
12952 | e = errno; | ||
12953 | goto loop; | ||
12954 | } | ||
12955 | } | ||
12956 | else { | ||
12957 | /* path_advance() has reserved space for .exe */ | ||
12958 | memcpy(fullname+len, ".exe", 5); | ||
12959 | if (stat(fullname, &statb) < 0) { | ||
12960 | if (errno != ENOENT && errno != ENOTDIR) | ||
12961 | e = errno; | ||
12962 | memcpy(fullname+len, ".com", 5); | ||
12963 | if (stat(fullname, &statb) < 0) { | ||
12964 | if (errno != ENOENT && errno != ENOTDIR) | ||
12965 | e = errno; | ||
12966 | fullname[len] = '\0'; | ||
12967 | if (stat(fullname, &statb) < 0) { | ||
12968 | if (errno != ENOENT && errno != ENOTDIR) | ||
12969 | e = errno; | ||
12970 | goto loop; | ||
12971 | } | ||
12972 | if (!execable_file(fullname)) { | ||
12973 | e = ENOEXEC; | ||
12974 | goto loop; | ||
12975 | } | ||
12976 | } | ||
12977 | } | ||
12978 | fullname[len] = '\0'; | ||
12979 | } | ||
12980 | #else | ||
12446 | while (stat(fullname, &statb) < 0) { | 12981 | while (stat(fullname, &statb) < 0) { |
12447 | #ifdef SYSV | 12982 | #ifdef SYSV |
12448 | if (errno == EINTR) | 12983 | if (errno == EINTR) |
@@ -12452,6 +12987,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12452 | e = errno; | 12987 | e = errno; |
12453 | goto loop; | 12988 | goto loop; |
12454 | } | 12989 | } |
12990 | #endif | ||
12455 | e = EACCES; /* if we fail, this will be the error */ | 12991 | e = EACCES; /* if we fail, this will be the error */ |
12456 | if (!S_ISREG(statb.st_mode)) | 12992 | if (!S_ISREG(statb.st_mode)) |
12457 | continue; | 12993 | continue; |
@@ -12722,6 +13258,8 @@ unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12722 | return ret & 1; | 13258 | return ret & 1; |
12723 | } | 13259 | } |
12724 | 13260 | ||
13261 | #if !ENABLE_PLATFORM_MINGW32 | ||
13262 | |||
12725 | static const unsigned char timescmd_str[] ALIGN1 = { | 13263 | static const unsigned char timescmd_str[] ALIGN1 = { |
12726 | ' ', offsetof(struct tms, tms_utime), | 13264 | ' ', offsetof(struct tms, tms_utime), |
12727 | '\n', offsetof(struct tms, tms_stime), | 13265 | '\n', offsetof(struct tms, tms_stime), |
@@ -12753,6 +13291,13 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12753 | 13291 | ||
12754 | return 0; | 13292 | return 0; |
12755 | } | 13293 | } |
13294 | #else | ||
13295 | static int FAST_FUNC | ||
13296 | timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | ||
13297 | { | ||
13298 | return 0; | ||
13299 | } | ||
13300 | #endif | ||
12756 | 13301 | ||
12757 | #if ENABLE_SH_MATH_SUPPORT | 13302 | #if ENABLE_SH_MATH_SUPPORT |
12758 | /* | 13303 | /* |
@@ -12986,13 +13531,64 @@ init(void) | |||
12986 | struct stat st1, st2; | 13531 | struct stat st1, st2; |
12987 | 13532 | ||
12988 | initvar(); | 13533 | initvar(); |
13534 | |||
13535 | #if ENABLE_PLATFORM_MINGW32 | ||
13536 | /* | ||
13537 | * case insensitive env names from Windows world | ||
13538 | * | ||
13539 | * Some standard env names such as PATH is named Path and so on | ||
13540 | * ash itself is case sensitive, so "Path" will confuse it, as | ||
13541 | * MSVC getenv() is case insensitive. | ||
13542 | * | ||
13543 | * We may end up having both Path and PATH. Then Path will be chosen | ||
13544 | * because it appears first. | ||
13545 | */ | ||
13546 | for (envp = environ; envp && *envp; envp++) { | ||
13547 | if (strncasecmp(*envp, "PATH=", 5) == 0 && | ||
13548 | strncmp(*envp, "PATH=", 5) != 0) { | ||
13549 | break; | ||
13550 | } | ||
13551 | } | ||
13552 | |||
13553 | if (envp && *envp) { | ||
13554 | /* | ||
13555 | * If we get here it's because the environment contains a path | ||
13556 | * variable called something other than PATH. This suggests we | ||
13557 | * haven't been invoked from an earlier instance of BusyBox. | ||
13558 | */ | ||
13559 | char *start, *end; | ||
13560 | struct passwd *pw; | ||
13561 | |||
13562 | for (envp = environ; envp && *envp; envp++) { | ||
13563 | end = strchr(*envp, '='); | ||
13564 | if (!end) | ||
13565 | continue; | ||
13566 | |||
13567 | /* make all variable names uppercase */ | ||
13568 | for (start = *envp;start < end;start++) | ||
13569 | *start = toupper(*start); | ||
13570 | |||
13571 | /* convert backslashes to forward slashes */ | ||
13572 | for ( ++end; *end; ++end ) { | ||
13573 | if ( *end == '\\' ) { | ||
13574 | *end = '/'; | ||
13575 | } | ||
13576 | } | ||
13577 | } | ||
13578 | |||
13579 | /* some initialisation normally performed at login */ | ||
13580 | pw = xgetpwuid(getuid()); | ||
13581 | setup_environment(pw->pw_shell, SETUP_ENV_CHANGEENV, pw); | ||
13582 | } | ||
13583 | #endif | ||
12989 | for (envp = environ; envp && *envp; envp++) { | 13584 | for (envp = environ; envp && *envp; envp++) { |
12990 | if (strchr(*envp, '=')) { | 13585 | if (strchr(*envp, '=')) { |
12991 | setvareq(*envp, VEXPORT|VTEXTFIXED); | 13586 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
12992 | } | 13587 | } |
12993 | } | 13588 | } |
12994 | 13589 | ||
12995 | setvar("PPID", utoa(getppid()), 0); | 13590 | if (!ENABLE_PLATFORM_MINGW32) |
13591 | setvar("PPID", utoa(getppid()), 0); | ||
12996 | 13592 | ||
12997 | p = lookupvar("PWD"); | 13593 | p = lookupvar("PWD"); |
12998 | if (p) { | 13594 | if (p) { |
@@ -13126,6 +13722,20 @@ static short profile_buf[16384]; | |||
13126 | extern int etext(); | 13722 | extern int etext(); |
13127 | #endif | 13723 | #endif |
13128 | 13724 | ||
13725 | #if ENABLE_PLATFORM_MINGW32 | ||
13726 | static const forkpoint_fn forkpoints[] = { | ||
13727 | forkshell_openhere, | ||
13728 | forkshell_evalbackcmd, | ||
13729 | forkshell_evalsubshell, | ||
13730 | forkshell_evalpipe, | ||
13731 | forkshell_shellexec, | ||
13732 | NULL | ||
13733 | }; | ||
13734 | |||
13735 | static struct forkshell* forkshell_prepare(struct forkshell *fs); | ||
13736 | static void forkshell_init(const char *idstr); | ||
13737 | #endif | ||
13738 | |||
13129 | /* | 13739 | /* |
13130 | * Main routine. We initialize things, parse the arguments, execute | 13740 | * Main routine. We initialize things, parse the arguments, execute |
13131 | * profiles if we're a login shell, and then call cmdloop to execute | 13741 | * profiles if we're a login shell, and then call cmdloop to execute |
@@ -13195,6 +13805,17 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13195 | 13805 | ||
13196 | init(); | 13806 | init(); |
13197 | setstackmark(&smark); | 13807 | setstackmark(&smark); |
13808 | |||
13809 | #if ENABLE_PLATFORM_MINGW32 | ||
13810 | hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL); | ||
13811 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
13812 | if (argc == 3 && !strcmp(argv[1], "--forkshell")) { | ||
13813 | forkshell_init(argv[2]); | ||
13814 | |||
13815 | /* NOTREACHED */ | ||
13816 | bb_error_msg_and_die("subshell ended unexpectedly"); | ||
13817 | } | ||
13818 | #endif | ||
13198 | procargs(argv); | 13819 | procargs(argv); |
13199 | 13820 | ||
13200 | if (argv[0] && argv[0][0] == '-') | 13821 | if (argv[0] && argv[0][0] == '-') |
@@ -13277,6 +13898,526 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13277 | /* NOTREACHED */ | 13898 | /* NOTREACHED */ |
13278 | } | 13899 | } |
13279 | 13900 | ||
13901 | #if ENABLE_PLATFORM_MINGW32 | ||
13902 | /* FIXME: should consider running forkparent() and forkchild() */ | ||
13903 | static int | ||
13904 | spawn_forkshell(struct job *jp, struct forkshell *fs, int mode) | ||
13905 | { | ||
13906 | const char *argv[] = { "sh", "--forkshell", NULL, NULL }; | ||
13907 | char buf[16]; | ||
13908 | |||
13909 | struct forkshell *new; | ||
13910 | new = forkshell_prepare(fs); | ||
13911 | sprintf(buf, "%x", (unsigned int)new->hMapFile); | ||
13912 | argv[2] = buf; | ||
13913 | fs->pid = mingw_spawn_applet(P_NOWAIT, "sh", argv, | ||
13914 | (const char *const *)environ); | ||
13915 | CloseHandle(new->hMapFile); | ||
13916 | UnmapViewOfFile(new); | ||
13917 | if (fs->pid == -1) { | ||
13918 | free(jp); | ||
13919 | return -1; | ||
13920 | } | ||
13921 | forkparent(jp, fs->node, mode, fs->pid); | ||
13922 | return fs->pid; | ||
13923 | } | ||
13924 | |||
13925 | /* | ||
13926 | * forkshell_prepare() and friends | ||
13927 | * | ||
13928 | * The sequence is as follows: | ||
13929 | * - funcblocksize, funcstringsize, nodeptrsize are initialized | ||
13930 | * - forkshell_size(fs) is called to calculate the exact memory needed | ||
13931 | * - a new struct is allocated | ||
13932 | * - funcblock, funcstring, nodeptr are initialized from the new block | ||
13933 | * - forkshell_copy(fs) is called to copy recursively everything over | ||
13934 | * it will record all pointers along the way, to nodeptr | ||
13935 | * | ||
13936 | * When this memory is mapped elsewhere, pointer fixup will be needed | ||
13937 | */ | ||
13938 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
13939 | static void \ | ||
13940 | name(type *p) \ | ||
13941 | { \ | ||
13942 | while (p) { \ | ||
13943 | funcblocksize += sizeof(type); | ||
13944 | /* do something here with p */ | ||
13945 | #define SLIST_SIZE_END() \ | ||
13946 | nodeptrsize++; \ | ||
13947 | p = p->next; \ | ||
13948 | } \ | ||
13949 | } | ||
13950 | |||
13951 | #define SLIST_COPY_BEGIN(name,type) \ | ||
13952 | static type * \ | ||
13953 | name(type *vp) \ | ||
13954 | { \ | ||
13955 | type *start; \ | ||
13956 | type **vpp; \ | ||
13957 | vpp = &start; \ | ||
13958 | while (vp) { \ | ||
13959 | *vpp = funcblock; \ | ||
13960 | funcblock = (char *) funcblock + sizeof(type); | ||
13961 | /* do something here with vpp and vp */ | ||
13962 | #define SLIST_COPY_END() \ | ||
13963 | SAVE_PTR((*vpp)->next); \ | ||
13964 | vp = vp->next; \ | ||
13965 | vpp = &(*vpp)->next; \ | ||
13966 | } \ | ||
13967 | *vpp = NULL; \ | ||
13968 | return start; \ | ||
13969 | } | ||
13970 | |||
13971 | /* | ||
13972 | * struct var | ||
13973 | */ | ||
13974 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
13975 | funcstringsize += strlen(p->var_text) + 1; | ||
13976 | nodeptrsize++; /* p->text */ | ||
13977 | SLIST_SIZE_END() | ||
13978 | |||
13979 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
13980 | (*vpp)->var_text = nodeckstrdup(vp->var_text); | ||
13981 | (*vpp)->flags = vp->flags; | ||
13982 | /* | ||
13983 | * The only place that can set struct var#func is varinit[], | ||
13984 | * which will be fixed by forkshell_init() | ||
13985 | */ | ||
13986 | (*vpp)->var_func = NULL; | ||
13987 | SAVE_PTR((*vpp)->var_text); | ||
13988 | SLIST_COPY_END() | ||
13989 | |||
13990 | /* | ||
13991 | * struct localvar | ||
13992 | */ | ||
13993 | SLIST_SIZE_BEGIN(localvar_size,struct localvar) | ||
13994 | var_size(p->vp); | ||
13995 | funcstringsize += strlen(p->text) + 1; | ||
13996 | nodeptrsize += 2; /* p->vp, p->text */ | ||
13997 | SLIST_SIZE_END() | ||
13998 | |||
13999 | SLIST_COPY_BEGIN(localvar_copy,struct localvar) | ||
14000 | (*vpp)->text = nodeckstrdup(vp->text); | ||
14001 | (*vpp)->flags = vp->flags; | ||
14002 | (*vpp)->vp = var_copy(vp->vp); | ||
14003 | SAVE_PTR2((*vpp)->vp, (*vpp)->text); | ||
14004 | SLIST_COPY_END() | ||
14005 | |||
14006 | /* | ||
14007 | * struct strlist | ||
14008 | */ | ||
14009 | SLIST_SIZE_BEGIN(strlist_size,struct strlist) | ||
14010 | funcstringsize += strlen(p->text) + 1; | ||
14011 | nodeptrsize++; /* p->text */ | ||
14012 | SLIST_SIZE_END() | ||
14013 | |||
14014 | SLIST_COPY_BEGIN(strlist_copy,struct strlist) | ||
14015 | (*vpp)->text = nodeckstrdup(vp->text); | ||
14016 | SAVE_PTR((*vpp)->text); | ||
14017 | SLIST_COPY_END() | ||
14018 | |||
14019 | /* | ||
14020 | * struct tblentry | ||
14021 | */ | ||
14022 | static void | ||
14023 | tblentry_size(struct tblentry *tep) | ||
14024 | { | ||
14025 | while (tep) { | ||
14026 | funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
14027 | /* CMDBUILTIN, e->param.cmd needs no pointer relocation */ | ||
14028 | if (tep->cmdtype == CMDFUNCTION) { | ||
14029 | funcblocksize += offsetof(struct funcnode, n); | ||
14030 | calcsize(&tep->param.func->n); | ||
14031 | nodeptrsize++; /* tep->param.func */ | ||
14032 | } | ||
14033 | nodeptrsize++; /* tep->next */ | ||
14034 | tep = tep->next; | ||
14035 | } | ||
14036 | } | ||
14037 | |||
14038 | static struct tblentry * | ||
14039 | tblentry_copy(struct tblentry *tep) | ||
14040 | { | ||
14041 | struct tblentry *start; | ||
14042 | struct tblentry **newp; | ||
14043 | int size; | ||
14044 | |||
14045 | newp = &start; | ||
14046 | while (tep) { | ||
14047 | *newp = funcblock; | ||
14048 | size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
14049 | |||
14050 | funcblock = (char *) funcblock + size; | ||
14051 | memcpy(*newp, tep, size); | ||
14052 | switch (tep->cmdtype) { | ||
14053 | case CMDBUILTIN: | ||
14054 | /* No pointer saving, this field must be fixed by forkshell_init() */ | ||
14055 | (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab); | ||
14056 | break; | ||
14057 | case CMDFUNCTION: | ||
14058 | (*newp)->param.func = funcblock; | ||
14059 | funcblock = (char *) funcblock + offsetof(struct funcnode, n); | ||
14060 | copynode(&tep->param.func->n); | ||
14061 | SAVE_PTR((*newp)->param.func); | ||
14062 | break; | ||
14063 | default: | ||
14064 | break; | ||
14065 | } | ||
14066 | SAVE_PTR((*newp)->next); | ||
14067 | tep = tep->next; | ||
14068 | newp = &(*newp)->next; | ||
14069 | } | ||
14070 | *newp = NULL; | ||
14071 | return start; | ||
14072 | } | ||
14073 | |||
14074 | static void | ||
14075 | cmdtable_size(struct tblentry **cmdtablep) | ||
14076 | { | ||
14077 | int i; | ||
14078 | nodeptrsize += CMDTABLESIZE; | ||
14079 | funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE; | ||
14080 | for (i = 0; i < CMDTABLESIZE; i++) | ||
14081 | tblentry_size(cmdtablep[i]); | ||
14082 | } | ||
14083 | |||
14084 | static struct tblentry ** | ||
14085 | cmdtable_copy(struct tblentry **cmdtablep) | ||
14086 | { | ||
14087 | struct tblentry **new = funcblock; | ||
14088 | int i; | ||
14089 | |||
14090 | funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE; | ||
14091 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
14092 | new[i] = tblentry_copy(cmdtablep[i]); | ||
14093 | SAVE_PTR(new[i]); | ||
14094 | } | ||
14095 | return new; | ||
14096 | } | ||
14097 | |||
14098 | /* | ||
14099 | * char ** | ||
14100 | */ | ||
14101 | static void | ||
14102 | argv_size(char **p) | ||
14103 | { | ||
14104 | while (p && *p) { | ||
14105 | funcblocksize += sizeof(char *); | ||
14106 | funcstringsize += strlen(*p)+1; | ||
14107 | nodeptrsize++; | ||
14108 | p++; | ||
14109 | } | ||
14110 | funcblocksize += sizeof(char *); | ||
14111 | } | ||
14112 | |||
14113 | static char ** | ||
14114 | argv_copy(char **p) | ||
14115 | { | ||
14116 | char **new, **start = funcblock; | ||
14117 | |||
14118 | while (p && *p) { | ||
14119 | new = funcblock; | ||
14120 | funcblock = (char *) funcblock + sizeof(char *); | ||
14121 | *new = nodeckstrdup(*p); | ||
14122 | SAVE_PTR(*new); | ||
14123 | p++; | ||
14124 | new++; | ||
14125 | } | ||
14126 | new = funcblock; | ||
14127 | funcblock = (char *) funcblock + sizeof(char *); | ||
14128 | *new = NULL; | ||
14129 | return start; | ||
14130 | } | ||
14131 | |||
14132 | /* | ||
14133 | * struct redirtab | ||
14134 | */ | ||
14135 | static void | ||
14136 | redirtab_size(struct redirtab *rdtp) | ||
14137 | { | ||
14138 | while (rdtp) { | ||
14139 | funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
14140 | rdtp = rdtp->next; | ||
14141 | nodeptrsize++; /* rdtp->next */ | ||
14142 | } | ||
14143 | } | ||
14144 | |||
14145 | static struct redirtab * | ||
14146 | redirtab_copy(struct redirtab *rdtp) | ||
14147 | { | ||
14148 | struct redirtab *start; | ||
14149 | struct redirtab **vpp; | ||
14150 | |||
14151 | vpp = &start; | ||
14152 | while (rdtp) { | ||
14153 | int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
14154 | *vpp = funcblock; | ||
14155 | funcblock = (char *) funcblock + size; | ||
14156 | memcpy(*vpp, rdtp, size); | ||
14157 | SAVE_PTR((*vpp)->next); | ||
14158 | rdtp = rdtp->next; | ||
14159 | vpp = &(*vpp)->next; | ||
14160 | } | ||
14161 | *vpp = NULL; | ||
14162 | return start; | ||
14163 | } | ||
14164 | |||
14165 | #undef shellparam | ||
14166 | #undef redirlist | ||
14167 | #undef varinit | ||
14168 | #undef vartab | ||
14169 | static void | ||
14170 | globals_var_size(struct globals_var *gvp) | ||
14171 | { | ||
14172 | int i; | ||
14173 | |||
14174 | funcblocksize += sizeof(struct globals_var); | ||
14175 | argv_size(gvp->shellparam.p); | ||
14176 | redirtab_size(gvp->redirlist); | ||
14177 | for (i = 0; i < VTABSIZE; i++) | ||
14178 | var_size(gvp->vartab[i]); | ||
14179 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
14180 | var_size(gvp->varinit+i); | ||
14181 | nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */ | ||
14182 | } | ||
14183 | |||
14184 | #undef g_nullredirs | ||
14185 | #undef preverrout_fd | ||
14186 | static struct globals_var * | ||
14187 | globals_var_copy(struct globals_var *gvp) | ||
14188 | { | ||
14189 | int i; | ||
14190 | struct globals_var *new; | ||
14191 | |||
14192 | new = funcblock; | ||
14193 | funcblock = (char *) funcblock + sizeof(struct globals_var); | ||
14194 | |||
14195 | /* shparam */ | ||
14196 | memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam)); | ||
14197 | new->shellparam.malloced = 0; | ||
14198 | new->shellparam.p = argv_copy(gvp->shellparam.p); | ||
14199 | SAVE_PTR(new->shellparam.p); | ||
14200 | |||
14201 | new->redirlist = redirtab_copy(gvp->redirlist); | ||
14202 | SAVE_PTR(new->redirlist); | ||
14203 | |||
14204 | new->g_nullredirs = gvp->g_nullredirs; | ||
14205 | new->preverrout_fd = gvp->preverrout_fd; | ||
14206 | for (i = 0; i < VTABSIZE; i++) { | ||
14207 | new->vartab[i] = var_copy(gvp->vartab[i]); | ||
14208 | SAVE_PTR(new->vartab[i]); | ||
14209 | } | ||
14210 | |||
14211 | /* Can't use var_copy because varinit is already allocated */ | ||
14212 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { | ||
14213 | new->varinit[i].next = NULL; | ||
14214 | new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text); | ||
14215 | SAVE_PTR(new->varinit[i].var_text); | ||
14216 | new->varinit[i].flags = gvp->varinit[i].flags; | ||
14217 | new->varinit[i].var_func = gvp->varinit[i].var_func; | ||
14218 | } | ||
14219 | return new; | ||
14220 | } | ||
14221 | |||
14222 | #undef minusc | ||
14223 | #undef curdir | ||
14224 | #undef physdir | ||
14225 | #undef arg0 | ||
14226 | #undef nullstr | ||
14227 | static void | ||
14228 | globals_misc_size(struct globals_misc *p) | ||
14229 | { | ||
14230 | funcblocksize += sizeof(struct globals_misc); | ||
14231 | funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1; | ||
14232 | if (p->curdir != p->nullstr) | ||
14233 | funcstringsize += strlen(p->curdir) + 1; | ||
14234 | if (p->physdir != p->nullstr) | ||
14235 | funcstringsize += strlen(p->physdir) + 1; | ||
14236 | funcstringsize += strlen(p->arg0) + 1; | ||
14237 | nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */ | ||
14238 | } | ||
14239 | |||
14240 | static struct globals_misc * | ||
14241 | globals_misc_copy(struct globals_misc *p) | ||
14242 | { | ||
14243 | struct globals_misc *new = funcblock; | ||
14244 | |||
14245 | funcblock = (char *) funcblock + sizeof(struct globals_misc); | ||
14246 | memcpy(new, p, sizeof(struct globals_misc)); | ||
14247 | |||
14248 | new->minusc = nodeckstrdup(p->minusc); | ||
14249 | new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr; | ||
14250 | new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr; | ||
14251 | new->arg0 = nodeckstrdup(p->arg0); | ||
14252 | SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0); | ||
14253 | return new; | ||
14254 | } | ||
14255 | |||
14256 | static void | ||
14257 | forkshell_size(struct forkshell *fs) | ||
14258 | { | ||
14259 | funcblocksize += sizeof(struct forkshell); | ||
14260 | globals_var_size(fs->gvp); | ||
14261 | globals_misc_size(fs->gmp); | ||
14262 | cmdtable_size(fs->cmdtable); | ||
14263 | localvar_size(fs->localvars); | ||
14264 | /* optlist_transfer(sending, fd); */ | ||
14265 | /* misc_transfer(sending, fd); */ | ||
14266 | |||
14267 | calcsize(fs->n); | ||
14268 | argv_size(fs->argv); | ||
14269 | funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1; | ||
14270 | strlist_size(fs->strlist); | ||
14271 | |||
14272 | nodeptrsize += 8; /* gvp, gmp, cmdtable, localvars, n, argv, string, strlist */ | ||
14273 | } | ||
14274 | |||
14275 | static struct forkshell * | ||
14276 | forkshell_copy(struct forkshell *fs) | ||
14277 | { | ||
14278 | struct forkshell *new; | ||
14279 | |||
14280 | new = funcblock; | ||
14281 | funcblock = (char *) funcblock + sizeof(struct forkshell); | ||
14282 | |||
14283 | memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */ | ||
14284 | new->gvp = globals_var_copy(fs->gvp); | ||
14285 | new->gmp = globals_misc_copy(fs->gmp); | ||
14286 | new->cmdtable = cmdtable_copy(fs->cmdtable); | ||
14287 | new->localvars = localvar_copy(fs->localvars); | ||
14288 | SAVE_PTR4(new->gvp, new->gmp, new->cmdtable, new->localvars); | ||
14289 | |||
14290 | /* new->fs will be reconstructed from new->fpid */ | ||
14291 | new->n = copynode(fs->n); | ||
14292 | new->argv = argv_copy(fs->argv); | ||
14293 | new->string = nodeckstrdup(fs->string); | ||
14294 | new->strlist = strlist_copy(fs->strlist); | ||
14295 | SAVE_PTR4(new->n, new->argv, new->string, new->strlist); | ||
14296 | return new; | ||
14297 | } | ||
14298 | |||
14299 | static struct forkshell * | ||
14300 | forkshell_prepare(struct forkshell *fs) | ||
14301 | { | ||
14302 | struct forkshell *new; | ||
14303 | int size, fp, nodeptr_offset; | ||
14304 | HANDLE h; | ||
14305 | SECURITY_ATTRIBUTES sa; | ||
14306 | |||
14307 | for (fp = 0; forkpoints[fp] && forkpoints[fp] != fs->fp; fp++) | ||
14308 | ; | ||
14309 | |||
14310 | if (!forkpoints[fp]) | ||
14311 | bb_error_msg_and_die("invalid forkpoint %08x", (int)fs->fp); | ||
14312 | fs->fpid = fp; | ||
14313 | |||
14314 | /* Calculate size of "new" */ | ||
14315 | fs->gvp = ash_ptr_to_globals_var; | ||
14316 | fs->gmp = ash_ptr_to_globals_misc; | ||
14317 | fs->cmdtable = cmdtable; | ||
14318 | fs->localvars = localvars; | ||
14319 | |||
14320 | nodeptrsize = 1; /* NULL terminated */ | ||
14321 | funcblocksize = 0; | ||
14322 | funcstringsize = 0; | ||
14323 | forkshell_size(fs); | ||
14324 | size = funcblocksize + funcstringsize + nodeptrsize*sizeof(int); | ||
14325 | |||
14326 | /* Allocate, initialize pointers */ | ||
14327 | memset(&sa, 0, sizeof(sa)); | ||
14328 | sa.nLength = sizeof(sa); | ||
14329 | sa.lpSecurityDescriptor = NULL; | ||
14330 | sa.bInheritHandle = TRUE; | ||
14331 | h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL); | ||
14332 | new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
14333 | /* new = ckmalloc(size); */ | ||
14334 | funcblock = new; | ||
14335 | funcstring = (char *) funcblock + funcblocksize; | ||
14336 | nodeptr = (int*)((char *) funcstring + funcstringsize); | ||
14337 | nodeptr_offset = (int) nodeptr - (int) new; | ||
14338 | |||
14339 | /* Now pack them all */ | ||
14340 | forkshell_copy(fs); | ||
14341 | |||
14342 | /* Finish it up */ | ||
14343 | *nodeptr = 0; | ||
14344 | new->size = size; | ||
14345 | new->nodeptr_offset = nodeptr_offset; | ||
14346 | new->old_base = new; | ||
14347 | new->hMapFile = h; | ||
14348 | return new; | ||
14349 | } | ||
14350 | |||
14351 | #undef exception_handler | ||
14352 | #undef trap | ||
14353 | #undef trap_ptr | ||
14354 | static void *sticky_mem_start, *sticky_mem_end; | ||
14355 | static void | ||
14356 | forkshell_init(const char *idstr) | ||
14357 | { | ||
14358 | struct forkshell *fs; | ||
14359 | int map_handle; | ||
14360 | HANDLE h; | ||
14361 | struct globals_var **gvpp; | ||
14362 | struct globals_misc **gmpp; | ||
14363 | int i; | ||
14364 | |||
14365 | if (sscanf(idstr, "%x", &map_handle) != 1) | ||
14366 | bb_error_msg_and_die("invalid forkshell ID"); | ||
14367 | |||
14368 | h = (HANDLE)map_handle; | ||
14369 | fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
14370 | if (!fs) | ||
14371 | bb_error_msg_and_die("Invalid forkshell memory"); | ||
14372 | |||
14373 | /* this memory can't be freed */ | ||
14374 | sticky_mem_start = fs; | ||
14375 | sticky_mem_end = (char *) fs + fs->size; | ||
14376 | /* pointer fixup */ | ||
14377 | nodeptr = (int*)((char*)fs + fs->nodeptr_offset); | ||
14378 | while (*nodeptr) { | ||
14379 | int *ptr = (int*)((char*)fs + (*nodeptr - (int)fs->old_base)); | ||
14380 | if (*ptr) | ||
14381 | *ptr -= ((int)fs->old_base - (int)fs); | ||
14382 | nodeptr++; | ||
14383 | } | ||
14384 | /* Now fix up stuff that can't be transferred */ | ||
14385 | fs->fp = forkpoints[fs->fpid]; | ||
14386 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
14387 | fs->gvp->varinit[i].var_func = varinit_data[i].var_func; | ||
14388 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
14389 | struct tblentry *e = fs->cmdtable[i]; | ||
14390 | while (e) { | ||
14391 | if (e->cmdtype == CMDBUILTIN) | ||
14392 | e->param.cmd = builtintab + (int)e->param.cmd; | ||
14393 | e = e->next; | ||
14394 | } | ||
14395 | } | ||
14396 | fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler; | ||
14397 | for (i = 0; i < NSIG; i++) | ||
14398 | fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i]; | ||
14399 | fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr; | ||
14400 | |||
14401 | /* Switch global variables */ | ||
14402 | gvpp = (struct globals_var **)&ash_ptr_to_globals_var; | ||
14403 | *gvpp = fs->gvp; | ||
14404 | gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc; | ||
14405 | *gmpp = fs->gmp; | ||
14406 | localvars = fs->localvars; | ||
14407 | cmdtable = fs->cmdtable; | ||
14408 | |||
14409 | fs->fp(fs); | ||
14410 | } | ||
14411 | |||
14412 | #undef free | ||
14413 | static void | ||
14414 | sticky_free(void *base) | ||
14415 | { | ||
14416 | if (base >= sticky_mem_start && base < sticky_mem_end) | ||
14417 | return; | ||
14418 | free(base); | ||
14419 | } | ||
14420 | #endif | ||
13280 | 14421 | ||
13281 | /*- | 14422 | /*- |
13282 | * Copyright (c) 1989, 1991, 1993, 1994 | 14423 | * Copyright (c) 1989, 1991, 1993, 1994 |
diff --git a/shell/shell_common.c b/shell/shell_common.c index 0051f21d9..f7503cac5 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c | |||
@@ -18,7 +18,9 @@ | |||
18 | */ | 18 | */ |
19 | #include "libbb.h" | 19 | #include "libbb.h" |
20 | #include "shell_common.h" | 20 | #include "shell_common.h" |
21 | #if !ENABLE_PLATFORM_MINGW32 | ||
21 | #include <sys/resource.h> /* getrlimit */ | 22 | #include <sys/resource.h> /* getrlimit */ |
23 | #endif | ||
22 | 24 | ||
23 | const char defifsvar[] ALIGN1 = "IFS= \t\n"; | 25 | const char defifsvar[] ALIGN1 = "IFS= \t\n"; |
24 | 26 | ||
@@ -201,7 +203,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
201 | } | 203 | } |
202 | 204 | ||
203 | c = buffer[bufpos]; | 205 | c = buffer[bufpos]; |
204 | if (c == '\0') | 206 | if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) |
205 | continue; | 207 | continue; |
206 | if (backslash) { | 208 | if (backslash) { |
207 | backslash = 0; | 209 | backslash = 0; |
@@ -370,6 +372,13 @@ static const char ulimit_opt_string[] = "-HSa" | |||
370 | #endif | 372 | #endif |
371 | ; | 373 | ; |
372 | 374 | ||
375 | #if ENABLE_PLATFORM_MINGW32 | ||
376 | int FAST_FUNC | ||
377 | shell_builtin_ulimit(char **argv) | ||
378 | { | ||
379 | return 1; | ||
380 | } | ||
381 | #else | ||
373 | static void printlim(unsigned opts, const struct rlimit *limit, | 382 | static void printlim(unsigned opts, const struct rlimit *limit, |
374 | const struct limits *l) | 383 | const struct limits *l) |
375 | { | 384 | { |
@@ -498,3 +507,4 @@ shell_builtin_ulimit(char **argv) | |||
498 | 507 | ||
499 | return 0; | 508 | return 0; |
500 | } | 509 | } |
510 | #endif | ||