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