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