diff options
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 1140 | ||||
-rw-r--r-- | shell/builtin_ulimit.c | 237 | ||||
-rw-r--r-- | shell/shell_common.c | 8 |
3 files changed, 1370 insertions, 15 deletions
diff --git a/shell/ash.c b/shell/ash.c index fbf3efce2..45ec13097 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -17,6 +17,18 @@ | |||
17 | */ | 17 | */ |
18 | 18 | ||
19 | /* | 19 | /* |
20 | * MinGW notes | ||
21 | * | ||
22 | * - Environment variables from Windows will all be turned to uppercase. | ||
23 | * - PATH accepts both ; and : as separator, but can't be mixed | ||
24 | * - command without ".exe" is still understood as executable (option to turn off?) | ||
25 | * - both / and \ are supported in PATH. Usually you must use / | ||
26 | * - trap/job does not work | ||
27 | * - /dev/null is supported for redirection | ||
28 | * - no $PPID | ||
29 | */ | ||
30 | |||
31 | /* | ||
20 | * The following should be set to reflect the type of system you have: | 32 | * The following should be set to reflect the type of system you have: |
21 | * JOBS -> 1 if you have Berkeley job control, 0 otherwise. | 33 | * JOBS -> 1 if you have Berkeley job control, 0 otherwise. |
22 | * define SYSV if you are running under System V. | 34 | * define SYSV if you are running under System V. |
@@ -37,7 +49,9 @@ | |||
37 | #define JOBS ENABLE_ASH_JOB_CONTROL | 49 | #define JOBS ENABLE_ASH_JOB_CONTROL |
38 | 50 | ||
39 | #include "busybox.h" /* for applet_names */ | 51 | #include "busybox.h" /* for applet_names */ |
52 | #ifndef __MINGW32__ | ||
40 | #include <paths.h> | 53 | #include <paths.h> |
54 | #endif | ||
41 | #include <setjmp.h> | 55 | #include <setjmp.h> |
42 | #include <fnmatch.h> | 56 | #include <fnmatch.h> |
43 | #include <sys/times.h> | 57 | #include <sys/times.h> |
@@ -188,6 +202,41 @@ | |||
188 | //usage:#define bash_trivial_usage NOUSAGE_STR | 202 | //usage:#define bash_trivial_usage NOUSAGE_STR |
189 | //usage:#define bash_full_usage "" | 203 | //usage:#define bash_full_usage "" |
190 | 204 | ||
205 | #if ENABLE_PLATFORM_MINGW32 | ||
206 | struct forkshell; | ||
207 | union node; | ||
208 | struct strlist; | ||
209 | struct job; | ||
210 | |||
211 | typedef void (*forkpoint_fn)(struct forkshell *fs); | ||
212 | struct forkshell { | ||
213 | /* filled by forkshell_copy() */ | ||
214 | struct globals_var *gvp; | ||
215 | struct globals_misc *gmp; | ||
216 | struct tblentry **cmdtable; | ||
217 | struct localvar *localvars; | ||
218 | /* struct alias **atab; */ | ||
219 | /* struct parsefile *g_parsefile; */ | ||
220 | int fpid; | ||
221 | HANDLE hMapFile; | ||
222 | void *old_base; | ||
223 | int nodeptr_offset; | ||
224 | int size; | ||
225 | |||
226 | forkpoint_fn fp; | ||
227 | /* optional data, used by forkpoint_fn */ | ||
228 | int flags; | ||
229 | int fd[10]; | ||
230 | union node *n; | ||
231 | char **argv; | ||
232 | char *string; | ||
233 | struct strlist *strlist; | ||
234 | pid_t pid; | ||
235 | }; | ||
236 | static void sticky_free(void *p); | ||
237 | #define free(p) sticky_free(p) | ||
238 | static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode); | ||
239 | #endif | ||
191 | 240 | ||
192 | /* ============ Hash table sizes. Configurable. */ | 241 | /* ============ Hash table sizes. Configurable. */ |
193 | 242 | ||
@@ -889,7 +938,7 @@ static void | |||
889 | opentrace(void) | 938 | opentrace(void) |
890 | { | 939 | { |
891 | char s[100]; | 940 | char s[100]; |
892 | #ifdef O_APPEND | 941 | #if defined(O_APPEND) && !ENABLE_PLATFORM_MINGW32 |
893 | int flags; | 942 | int flags; |
894 | #endif | 943 | #endif |
895 | 944 | ||
@@ -914,7 +963,7 @@ opentrace(void) | |||
914 | return; | 963 | return; |
915 | } | 964 | } |
916 | } | 965 | } |
917 | #ifdef O_APPEND | 966 | #if defined(O_APPEND) && !ENABLE_PLATFORM_MINGW32 |
918 | flags = fcntl(fileno(tracefile), F_GETFL); | 967 | flags = fcntl(fileno(tracefile), F_GETFL); |
919 | if (flags >= 0) | 968 | if (flags >= 0) |
920 | fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); | 969 | fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); |
@@ -2373,10 +2422,22 @@ path_advance(const char **path, const char *name) | |||
2373 | if (*path == NULL) | 2422 | if (*path == NULL) |
2374 | return NULL; | 2423 | return NULL; |
2375 | start = *path; | 2424 | start = *path; |
2425 | #if ENABLE_PLATFORM_MINGW32 | ||
2426 | p = next_path_sep(start); | ||
2427 | q = strchr(start, '%'); | ||
2428 | if ((p && q && q < p) || (!p && q)) | ||
2429 | p = q; | ||
2430 | if (!p) | ||
2431 | for (p = start; *p; p++) | ||
2432 | continue; | ||
2433 | #else | ||
2376 | for (p = start; *p && *p != ':' && *p != '%'; p++) | 2434 | for (p = start; *p && *p != ':' && *p != '%'; p++) |
2377 | continue; | 2435 | continue; |
2436 | #endif | ||
2378 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ | 2437 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ |
2379 | while (stackblocksize() < len) | 2438 | |
2439 | /* preserve space for .exe too */ | ||
2440 | while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len)) | ||
2380 | growstackblock(); | 2441 | growstackblock(); |
2381 | q = stackblock(); | 2442 | q = stackblock(); |
2382 | if (p != start) { | 2443 | if (p != start) { |
@@ -2388,10 +2449,19 @@ path_advance(const char **path, const char *name) | |||
2388 | pathopt = NULL; | 2449 | pathopt = NULL; |
2389 | if (*p == '%') { | 2450 | if (*p == '%') { |
2390 | pathopt = ++p; | 2451 | pathopt = ++p; |
2452 | #if ENABLE_PLATFORM_MINGW32 | ||
2453 | p = next_path_sep(start); | ||
2454 | |||
2455 | /* *p != ':' and '*' would suffice */ | ||
2456 | if (!p) | ||
2457 | p = pathopt - 1; | ||
2458 | #else | ||
2391 | while (*p && *p != ':') | 2459 | while (*p && *p != ':') |
2392 | p++; | 2460 | p++; |
2461 | #endif | ||
2393 | } | 2462 | } |
2394 | if (*p == ':') | 2463 | if (*p == ':' || |
2464 | (ENABLE_PLATFORM_MINGW32 && *p == ';')) | ||
2395 | *path = p + 1; | 2465 | *path = p + 1; |
2396 | else | 2466 | else |
2397 | *path = NULL; | 2467 | *path = NULL; |
@@ -2493,6 +2563,98 @@ cdopt(void) | |||
2493 | static const char * | 2563 | static const char * |
2494 | updatepwd(const char *dir) | 2564 | updatepwd(const char *dir) |
2495 | { | 2565 | { |
2566 | #if ENABLE_PLATFORM_MINGW32 | ||
2567 | /* | ||
2568 | * Due to Windows drive notion, getting pwd is a completely | ||
2569 | * different thing. Handle it in a separate routine | ||
2570 | */ | ||
2571 | |||
2572 | char *new; | ||
2573 | char *p; | ||
2574 | char *cdcomppath; | ||
2575 | const char *lim; | ||
2576 | /* | ||
2577 | * There are four cases | ||
2578 | * absdrive + abspath: c:/path | ||
2579 | * absdrive + !abspath: c:path | ||
2580 | * !absdrive + abspath: /path | ||
2581 | * !absdrive + !abspath: path | ||
2582 | * | ||
2583 | * Damn DOS! | ||
2584 | * c:path behaviour is "undefined" | ||
2585 | * To properly handle this case, I have to keep track of cwd | ||
2586 | * of every drive, which is too painful to do. | ||
2587 | * So when c:path is given, I assume it's c:${curdir}path | ||
2588 | * with ${curdir} comes from the current drive | ||
2589 | */ | ||
2590 | int absdrive = *dir && dir[1] == ':'; | ||
2591 | int abspath = absdrive ? dir[2] == '/' : *dir == '/'; | ||
2592 | char *drive; | ||
2593 | |||
2594 | cdcomppath = ststrdup(dir); | ||
2595 | STARTSTACKSTR(new); | ||
2596 | if (!absdrive && curdir == nullstr) | ||
2597 | return 0; | ||
2598 | if (!abspath) { | ||
2599 | if (curdir == nullstr) | ||
2600 | return 0; | ||
2601 | new = stack_putstr(curdir, new); | ||
2602 | } | ||
2603 | new = makestrspace(strlen(dir) + 2, new); | ||
2604 | |||
2605 | drive = stackblock(); | ||
2606 | if (absdrive) { | ||
2607 | *drive = *dir; | ||
2608 | cdcomppath += 2; | ||
2609 | dir += 2; | ||
2610 | } else { | ||
2611 | *drive = *curdir; | ||
2612 | } | ||
2613 | drive[1] = ':'; /* in case of absolute drive+path */ | ||
2614 | |||
2615 | if (abspath) | ||
2616 | new = drive + 2; | ||
2617 | lim = drive + 3; | ||
2618 | if (!abspath) { | ||
2619 | if (new[-1] != '/') | ||
2620 | USTPUTC('/', new); | ||
2621 | if (new > lim && *lim == '/') | ||
2622 | lim++; | ||
2623 | } else { | ||
2624 | USTPUTC('/', new); | ||
2625 | cdcomppath ++; | ||
2626 | if (dir[1] == '/' && dir[2] != '/') { | ||
2627 | USTPUTC('/', new); | ||
2628 | cdcomppath++; | ||
2629 | lim++; | ||
2630 | } | ||
2631 | } | ||
2632 | p = strtok(cdcomppath, "/"); | ||
2633 | while (p) { | ||
2634 | switch (*p) { | ||
2635 | case '.': | ||
2636 | if (p[1] == '.' && p[2] == '\0') { | ||
2637 | while (new > lim) { | ||
2638 | STUNPUTC(new); | ||
2639 | if (new[-1] == '/') | ||
2640 | break; | ||
2641 | } | ||
2642 | break; | ||
2643 | } | ||
2644 | if (p[1] == '\0') | ||
2645 | break; | ||
2646 | /* fall through */ | ||
2647 | default: | ||
2648 | new = stack_putstr(p, new); | ||
2649 | USTPUTC('/', new); | ||
2650 | } | ||
2651 | p = strtok(0, "/"); | ||
2652 | } | ||
2653 | if (new > lim) | ||
2654 | STUNPUTC(new); | ||
2655 | *new = 0; | ||
2656 | return stackblock(); | ||
2657 | #else | ||
2496 | char *new; | 2658 | char *new; |
2497 | char *p; | 2659 | char *p; |
2498 | char *cdcomppath; | 2660 | char *cdcomppath; |
@@ -2546,6 +2708,7 @@ updatepwd(const char *dir) | |||
2546 | STUNPUTC(new); | 2708 | STUNPUTC(new); |
2547 | *new = 0; | 2709 | *new = 0; |
2548 | return stackblock(); | 2710 | return stackblock(); |
2711 | #endif | ||
2549 | } | 2712 | } |
2550 | 2713 | ||
2551 | /* | 2714 | /* |
@@ -2640,7 +2803,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2640 | } | 2803 | } |
2641 | if (!dest) | 2804 | if (!dest) |
2642 | dest = nullstr; | 2805 | dest = nullstr; |
2643 | if (*dest == '/') | 2806 | if (is_absolute_path(dest)) |
2644 | goto step7; | 2807 | goto step7; |
2645 | if (*dest == '.') { | 2808 | if (*dest == '.') { |
2646 | c = dest[1]; | 2809 | c = dest[1]; |
@@ -3412,6 +3575,8 @@ setsignal(int signo) | |||
3412 | char cur_act, new_act; | 3575 | char cur_act, new_act; |
3413 | struct sigaction act; | 3576 | struct sigaction act; |
3414 | 3577 | ||
3578 | if (ENABLE_PLATFORM_MINGW32) | ||
3579 | return; | ||
3415 | t = trap[signo]; | 3580 | t = trap[signo]; |
3416 | new_act = S_DFL; | 3581 | new_act = S_DFL; |
3417 | if (t != NULL) { /* trap for this sig is set */ | 3582 | if (t != NULL) { /* trap for this sig is set */ |
@@ -3719,7 +3884,7 @@ setjobctl(int on) | |||
3719 | if (--fd < 0) | 3884 | if (--fd < 0) |
3720 | goto out; | 3885 | goto out; |
3721 | } | 3886 | } |
3722 | fd = fcntl(fd, F_DUPFD, 10); | 3887 | fd = copyfd(fd, 10); |
3723 | if (ofd >= 0) | 3888 | if (ofd >= 0) |
3724 | close(ofd); | 3889 | close(ofd); |
3725 | if (fd < 0) | 3890 | if (fd < 0) |
@@ -3893,6 +4058,78 @@ sprint_status(char *s, int status, int sigonly) | |||
3893 | return col; | 4058 | return col; |
3894 | } | 4059 | } |
3895 | 4060 | ||
4061 | #if ENABLE_PLATFORM_MINGW32 | ||
4062 | |||
4063 | HANDLE hSIGINT; /* Ctrl-C is pressed */ | ||
4064 | |||
4065 | static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) | ||
4066 | { | ||
4067 | if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { | ||
4068 | SetEvent(hSIGINT); | ||
4069 | return TRUE; | ||
4070 | } | ||
4071 | return FALSE; | ||
4072 | } | ||
4073 | |||
4074 | /* | ||
4075 | * Windows does not know about parent-child relationship | ||
4076 | * They don't support waitpid(-1) | ||
4077 | */ | ||
4078 | static pid_t | ||
4079 | waitpid_child(int *status) | ||
4080 | { | ||
4081 | HANDLE *pidlist, *pidp; | ||
4082 | int pid_nr = 0; | ||
4083 | pid_t pid; | ||
4084 | DWORD win_status, idx; | ||
4085 | struct job *jb; | ||
4086 | |||
4087 | #define LOOP(stmt) \ | ||
4088 | for (jb = curjob; jb; jb = jb->prev_job) { \ | ||
4089 | struct procstat *ps, *psend; \ | ||
4090 | if (jb->state == JOBDONE) \ | ||
4091 | continue; \ | ||
4092 | ps = jb->ps; \ | ||
4093 | psend = ps + jb->nprocs; \ | ||
4094 | while (ps < psend) { \ | ||
4095 | if (ps->ps_pid != -1) { \ | ||
4096 | stmt; \ | ||
4097 | } \ | ||
4098 | ps++; \ | ||
4099 | } \ | ||
4100 | } | ||
4101 | |||
4102 | LOOP(pid_nr++); | ||
4103 | if (!pid_nr) | ||
4104 | return -1; | ||
4105 | pid_nr++; | ||
4106 | pidp = pidlist = ckmalloc(sizeof(*pidlist)*pid_nr); | ||
4107 | *pidp++ = hSIGINT; | ||
4108 | LOOP(*pidp++ = (HANDLE)ps->ps_pid); | ||
4109 | #undef LOOP | ||
4110 | |||
4111 | idx = WaitForMultipleObjects(pid_nr, pidlist, FALSE, INFINITE); | ||
4112 | if (idx >= pid_nr) { | ||
4113 | free(pidlist); | ||
4114 | return -1; | ||
4115 | } | ||
4116 | if (!idx) { /* hSIGINT */ | ||
4117 | int i; | ||
4118 | ResetEvent(hSIGINT); | ||
4119 | for (i = 1; i < pid_nr; i++) | ||
4120 | TerminateProcess(pidlist[i], 1); | ||
4121 | free(pidlist); | ||
4122 | *status = 260; /* terminated by a signal */ | ||
4123 | return pidlist[1]; | ||
4124 | } | ||
4125 | GetExitCodeProcess(pidlist[idx], &win_status); | ||
4126 | pid = (int)pidlist[idx]; | ||
4127 | free(pidlist); | ||
4128 | *status = (int)win_status; | ||
4129 | return pid; | ||
4130 | } | ||
4131 | #endif | ||
4132 | |||
3896 | static int | 4133 | static int |
3897 | dowait(int wait_flags, struct job *job) | 4134 | dowait(int wait_flags, struct job *job) |
3898 | { | 4135 | { |
@@ -3909,7 +4146,11 @@ dowait(int wait_flags, struct job *job) | |||
3909 | * NB: _not_ safe_waitpid, we need to detect EINTR */ | 4146 | * NB: _not_ safe_waitpid, we need to detect EINTR */ |
3910 | if (doing_jobctl) | 4147 | if (doing_jobctl) |
3911 | wait_flags |= WUNTRACED; | 4148 | wait_flags |= WUNTRACED; |
4149 | #if ENABLE_PLATFORM_MINGW32 | ||
4150 | pid = waitpid_child(&status); | ||
4151 | #else | ||
3912 | pid = waitpid(-1, &status, wait_flags); | 4152 | pid = waitpid(-1, &status, wait_flags); |
4153 | #endif | ||
3913 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", | 4154 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", |
3914 | pid, status, errno, strerror(errno))); | 4155 | pid, status, errno, strerror(errno))); |
3915 | if (pid <= 0) | 4156 | if (pid <= 0) |
@@ -3932,6 +4173,8 @@ dowait(int wait_flags, struct job *job) | |||
3932 | jobno(jp), pid, ps->ps_status, status)); | 4173 | jobno(jp), pid, ps->ps_status, status)); |
3933 | ps->ps_status = status; | 4174 | ps->ps_status = status; |
3934 | thisjob = jp; | 4175 | thisjob = jp; |
4176 | if (ENABLE_PLATFORM_MINGW32) | ||
4177 | ps->ps_pid = -1; | ||
3935 | } | 4178 | } |
3936 | if (ps->ps_status == -1) | 4179 | if (ps->ps_status == -1) |
3937 | state = JOBRUNNING; | 4180 | state = JOBRUNNING; |
@@ -4163,6 +4406,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
4163 | int retval; | 4406 | int retval; |
4164 | struct job *jp; | 4407 | struct job *jp; |
4165 | 4408 | ||
4409 | if (ENABLE_PLATFORM_MINGW32) | ||
4410 | return 0; | ||
4411 | |||
4166 | if (pending_sig) | 4412 | if (pending_sig) |
4167 | raise_exception(EXSIG); | 4413 | raise_exception(EXSIG); |
4168 | 4414 | ||
@@ -4774,7 +5020,7 @@ static void | |||
4774 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 5020 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
4775 | { | 5021 | { |
4776 | TRACE(("In parent shell: child = %d\n", pid)); | 5022 | TRACE(("In parent shell: child = %d\n", pid)); |
4777 | if (!jp) { | 5023 | if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */ |
4778 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) | 5024 | while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) |
4779 | continue; | 5025 | continue; |
4780 | jobless++; | 5026 | jobless++; |
@@ -4814,6 +5060,9 @@ forkshell(struct job *jp, union node *n, int mode) | |||
4814 | int pid; | 5060 | int pid; |
4815 | 5061 | ||
4816 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); | 5062 | TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); |
5063 | if (ENABLE_PLATFORM_MINGW32) | ||
5064 | return -1; | ||
5065 | |||
4817 | pid = fork(); | 5066 | pid = fork(); |
4818 | if (pid < 0) { | 5067 | if (pid < 0) { |
4819 | TRACE(("Fork failed, errno=%d", errno)); | 5068 | TRACE(("Fork failed, errno=%d", errno)); |
@@ -5014,11 +5263,39 @@ noclobberopen(const char *fname) | |||
5014 | */ | 5263 | */ |
5015 | /* openhere needs this forward reference */ | 5264 | /* openhere needs this forward reference */ |
5016 | static void expandhere(union node *arg, int fd); | 5265 | static void expandhere(union node *arg, int fd); |
5266 | #if ENABLE_PLATFORM_MINGW32 | ||
5267 | static void | ||
5268 | forkshell_openhere(struct forkshell *fs) | ||
5269 | { | ||
5270 | union node *redir = fs->n; | ||
5271 | int pip[2]; | ||
5272 | |||
5273 | pip[0] = fs->fd[0]; | ||
5274 | pip[1] = fs->fd[1]; | ||
5275 | |||
5276 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
5277 | |||
5278 | close(pip[0]); | ||
5279 | ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); | ||
5280 | ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); | ||
5281 | ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); | ||
5282 | ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); | ||
5283 | signal(SIGPIPE, SIG_DFL); | ||
5284 | if (redir->type == NHERE) { | ||
5285 | size_t len = strlen(redir->nhere.doc->narg.text); | ||
5286 | full_write(pip[1], redir->nhere.doc->narg.text, len); | ||
5287 | } else /* NXHERE */ | ||
5288 | expandhere(redir->nhere.doc, pip[1]); | ||
5289 | _exit(EXIT_SUCCESS); | ||
5290 | } | ||
5291 | #endif | ||
5292 | |||
5017 | static int | 5293 | static int |
5018 | openhere(union node *redir) | 5294 | openhere(union node *redir) |
5019 | { | 5295 | { |
5020 | int pip[2]; | 5296 | int pip[2]; |
5021 | size_t len = 0; | 5297 | size_t len = 0; |
5298 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5022 | 5299 | ||
5023 | if (pipe(pip) < 0) | 5300 | if (pipe(pip) < 0) |
5024 | ash_msg_and_raise_error("pipe call failed"); | 5301 | ash_msg_and_raise_error("pipe call failed"); |
@@ -5029,6 +5306,16 @@ openhere(union node *redir) | |||
5029 | goto out; | 5306 | goto out; |
5030 | } | 5307 | } |
5031 | } | 5308 | } |
5309 | #if ENABLE_PLATFORM_MINGW32 | ||
5310 | memset(&fs, 0, sizeof(fs)); | ||
5311 | fs.fp = forkshell_openhere; | ||
5312 | fs.flags = 0; | ||
5313 | fs.n = redir; | ||
5314 | fs.fd[0] = pip[0]; | ||
5315 | fs.fd[1] = pip[1]; | ||
5316 | if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0) | ||
5317 | ash_msg_and_raise_error("unable to spawn shell"); | ||
5318 | #endif | ||
5032 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | 5319 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { |
5033 | /* child */ | 5320 | /* child */ |
5034 | close(pip[0]); | 5321 | close(pip[0]); |
@@ -5054,6 +5341,31 @@ openredirect(union node *redir) | |||
5054 | char *fname; | 5341 | char *fname; |
5055 | int f; | 5342 | int f; |
5056 | 5343 | ||
5344 | #if ENABLE_PLATFORM_MINGW32 | ||
5345 | /* Support for /dev/null */ | ||
5346 | switch (redir->nfile.type) { | ||
5347 | case NFROM: | ||
5348 | if (!strcmp(redir->nfile.expfname, "/dev/null")) | ||
5349 | return open("nul",O_RDWR); | ||
5350 | if (!strncmp(redir->nfile.expfname, "/dev/", 5)) { | ||
5351 | ash_msg("Unhandled device %s\n", redir->nfile.expfname); | ||
5352 | return -1; | ||
5353 | } | ||
5354 | break; | ||
5355 | |||
5356 | case NFROMTO: | ||
5357 | case NTO: | ||
5358 | case NCLOBBER: | ||
5359 | case NAPPEND: | ||
5360 | if (!strcmp(redir->nfile.expfname, "/dev/null")) | ||
5361 | return open("nul",O_RDWR); | ||
5362 | if (!strncmp(redir->nfile.expfname, "/dev/", 5)) { | ||
5363 | ash_msg("Unhandled device %s\n", redir->nfile.expfname); | ||
5364 | return -1; | ||
5365 | } | ||
5366 | break; | ||
5367 | } | ||
5368 | #endif | ||
5057 | switch (redir->nfile.type) { | 5369 | switch (redir->nfile.type) { |
5058 | case NFROM: | 5370 | case NFROM: |
5059 | fname = redir->nfile.expfname; | 5371 | fname = redir->nfile.expfname; |
@@ -5136,6 +5448,18 @@ copyfd(int from, int to) | |||
5136 | /*if (from != to)*/ | 5448 | /*if (from != to)*/ |
5137 | newfd = dup2(from, to); | 5449 | newfd = dup2(from, to); |
5138 | } else { | 5450 | } else { |
5451 | if (ENABLE_PLATFORM_MINGW32) { | ||
5452 | char* fds = ckmalloc(to); | ||
5453 | int i,fd; | ||
5454 | memset(fds,0,to); | ||
5455 | while ((fd = dup(from)) < to && fd >= 0) | ||
5456 | fds[fd] = 1; | ||
5457 | for (i = 0;i < to;i ++) | ||
5458 | if (fds[i]) | ||
5459 | close(i); | ||
5460 | free(fds); | ||
5461 | return fd; | ||
5462 | } | ||
5139 | newfd = fcntl(from, F_DUPFD, to); | 5463 | newfd = fcntl(from, F_DUPFD, to); |
5140 | } | 5464 | } |
5141 | if (newfd < 0) { | 5465 | if (newfd < 0) { |
@@ -5294,7 +5618,7 @@ redirect(union node *redir, int flags) | |||
5294 | /* Careful to not accidentally "save" | 5618 | /* Careful to not accidentally "save" |
5295 | * to the same fd as right side fd in N>&M */ | 5619 | * to the same fd as right side fd in N>&M */ |
5296 | int minfd = right_fd < 10 ? 10 : right_fd + 1; | 5620 | int minfd = right_fd < 10 ? 10 : right_fd + 1; |
5297 | i = fcntl(fd, F_DUPFD, minfd); | 5621 | i = copyfd(fd, minfd); |
5298 | /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds | 5622 | /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds |
5299 | * are closed in popredir() in the child, preventing them from leaking | 5623 | * are closed in popredir() in the child, preventing them from leaking |
5300 | * into child. (popredir() also cleans up the mess in case of failures) | 5624 | * into child. (popredir() also cleans up the mess in case of failures) |
@@ -5751,6 +6075,8 @@ exptilde(char *startp, char *p, int flags) | |||
5751 | if (*name == '\0') { | 6075 | if (*name == '\0') { |
5752 | home = lookupvar("HOME"); | 6076 | home = lookupvar("HOME"); |
5753 | } else { | 6077 | } else { |
6078 | if (ENABLE_PLATFORM_MINGW32) | ||
6079 | goto lose; | ||
5754 | pw = getpwnam(name); | 6080 | pw = getpwnam(name); |
5755 | if (pw == NULL) | 6081 | if (pw == NULL) |
5756 | goto lose; | 6082 | goto lose; |
@@ -5778,6 +6104,7 @@ struct backcmd { /* result of evalbackcmd */ | |||
5778 | int fd; /* file descriptor to read from */ | 6104 | int fd; /* file descriptor to read from */ |
5779 | int nleft; /* number of chars in buffer */ | 6105 | int nleft; /* number of chars in buffer */ |
5780 | char *buf; /* buffer */ | 6106 | char *buf; /* buffer */ |
6107 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
5781 | struct job *jp; /* job structure for command */ | 6108 | struct job *jp; /* job structure for command */ |
5782 | }; | 6109 | }; |
5783 | 6110 | ||
@@ -5786,6 +6113,25 @@ static uint8_t back_exitstatus; /* exit status of backquoted command */ | |||
5786 | #define EV_EXIT 01 /* exit after evaluating tree */ | 6113 | #define EV_EXIT 01 /* exit after evaluating tree */ |
5787 | static void evaltree(union node *, int); | 6114 | static void evaltree(union node *, int); |
5788 | 6115 | ||
6116 | #if ENABLE_PLATFORM_MINGW32 | ||
6117 | static void | ||
6118 | forkshell_evalbackcmd(struct forkshell *fs) | ||
6119 | { | ||
6120 | union node *n = fs->n; | ||
6121 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
6122 | |||
6123 | FORCE_INT_ON; | ||
6124 | close(pip[0]); | ||
6125 | if (pip[1] != 1) { | ||
6126 | /*close(1);*/ | ||
6127 | copyfd(pip[1], 1 | COPYFD_EXACT); | ||
6128 | close(pip[1]); | ||
6129 | } | ||
6130 | eflag = 0; | ||
6131 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ | ||
6132 | /* NOTREACHED */ | ||
6133 | } | ||
6134 | #endif | ||
5789 | static void FAST_FUNC | 6135 | static void FAST_FUNC |
5790 | evalbackcmd(union node *n, struct backcmd *result) | 6136 | evalbackcmd(union node *n, struct backcmd *result) |
5791 | { | 6137 | { |
@@ -5794,6 +6140,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5794 | result->fd = -1; | 6140 | result->fd = -1; |
5795 | result->buf = NULL; | 6141 | result->buf = NULL; |
5796 | result->nleft = 0; | 6142 | result->nleft = 0; |
6143 | IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs))); | ||
5797 | result->jp = NULL; | 6144 | result->jp = NULL; |
5798 | if (n == NULL) | 6145 | if (n == NULL) |
5799 | goto out; | 6146 | goto out; |
@@ -5808,6 +6155,14 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
5808 | if (pipe(pip) < 0) | 6155 | if (pipe(pip) < 0) |
5809 | ash_msg_and_raise_error("pipe call failed"); | 6156 | ash_msg_and_raise_error("pipe call failed"); |
5810 | jp = makejob(/*n,*/ 1); | 6157 | jp = makejob(/*n,*/ 1); |
6158 | #if ENABLE_PLATFORM_MINGW32 | ||
6159 | result->fs.fp = forkshell_evalbackcmd; | ||
6160 | result->fs.n = n; | ||
6161 | result->fs.fd[0] = pip[0]; | ||
6162 | result->fs.fd[1] = pip[1]; | ||
6163 | if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0) | ||
6164 | ash_msg_and_raise_error("unable to spawn shell"); | ||
6165 | #endif | ||
5811 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 6166 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
5812 | FORCE_INT_ON; | 6167 | FORCE_INT_ON; |
5813 | close(pip[0]); | 6168 | close(pip[0]); |
@@ -7406,7 +7761,7 @@ shellexec(char **argv, const char *path, int idx) | |||
7406 | 7761 | ||
7407 | clearredir(/*drop:*/ 1); | 7762 | clearredir(/*drop:*/ 1); |
7408 | envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); | 7763 | envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); |
7409 | if (strchr(argv[0], '/') != NULL | 7764 | if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\'))) |
7410 | #if ENABLE_FEATURE_SH_STANDALONE | 7765 | #if ENABLE_FEATURE_SH_STANDALONE |
7411 | || (applet_no = find_applet_by_name(argv[0])) >= 0 | 7766 | || (applet_no = find_applet_by_name(argv[0])) >= 0 |
7412 | #endif | 7767 | #endif |
@@ -7909,6 +8264,10 @@ static int funcblocksize; /* size of structures in function */ | |||
7909 | static int funcstringsize; /* size of strings in node */ | 8264 | static int funcstringsize; /* size of strings in node */ |
7910 | static void *funcblock; /* block to allocate function from */ | 8265 | static void *funcblock; /* block to allocate function from */ |
7911 | static char *funcstring; /* block to allocate strings from */ | 8266 | static char *funcstring; /* block to allocate strings from */ |
8267 | #if ENABLE_PLATFORM_MINGW32 | ||
8268 | static int nodeptrsize; | ||
8269 | static int *nodeptr; | ||
8270 | #endif | ||
7912 | 8271 | ||
7913 | /* flags in argument to evaltree */ | 8272 | /* flags in argument to evaltree */ |
7914 | #define EV_EXIT 01 /* exit after evaluating tree */ | 8273 | #define EV_EXIT 01 /* exit after evaluating tree */ |
@@ -7954,6 +8313,7 @@ sizenodelist(struct nodelist *lp) | |||
7954 | { | 8313 | { |
7955 | while (lp) { | 8314 | while (lp) { |
7956 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); | 8315 | funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); |
8316 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
7957 | calcsize(lp->n); | 8317 | calcsize(lp->n); |
7958 | lp = lp->next; | 8318 | lp = lp->next; |
7959 | } | 8319 | } |
@@ -7970,15 +8330,18 @@ calcsize(union node *n) | |||
7970 | calcsize(n->ncmd.redirect); | 8330 | calcsize(n->ncmd.redirect); |
7971 | calcsize(n->ncmd.args); | 8331 | calcsize(n->ncmd.args); |
7972 | calcsize(n->ncmd.assign); | 8332 | calcsize(n->ncmd.assign); |
8333 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
7973 | break; | 8334 | break; |
7974 | case NPIPE: | 8335 | case NPIPE: |
7975 | sizenodelist(n->npipe.cmdlist); | 8336 | sizenodelist(n->npipe.cmdlist); |
8337 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
7976 | break; | 8338 | break; |
7977 | case NREDIR: | 8339 | case NREDIR: |
7978 | case NBACKGND: | 8340 | case NBACKGND: |
7979 | case NSUBSHELL: | 8341 | case NSUBSHELL: |
7980 | calcsize(n->nredir.redirect); | 8342 | calcsize(n->nredir.redirect); |
7981 | calcsize(n->nredir.n); | 8343 | calcsize(n->nredir.n); |
8344 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
7982 | break; | 8345 | break; |
7983 | case NAND: | 8346 | case NAND: |
7984 | case NOR: | 8347 | case NOR: |
@@ -7987,31 +8350,37 @@ calcsize(union node *n) | |||
7987 | case NUNTIL: | 8350 | case NUNTIL: |
7988 | calcsize(n->nbinary.ch2); | 8351 | calcsize(n->nbinary.ch2); |
7989 | calcsize(n->nbinary.ch1); | 8352 | calcsize(n->nbinary.ch1); |
8353 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
7990 | break; | 8354 | break; |
7991 | case NIF: | 8355 | case NIF: |
7992 | calcsize(n->nif.elsepart); | 8356 | calcsize(n->nif.elsepart); |
7993 | calcsize(n->nif.ifpart); | 8357 | calcsize(n->nif.ifpart); |
7994 | calcsize(n->nif.test); | 8358 | calcsize(n->nif.test); |
8359 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
7995 | break; | 8360 | break; |
7996 | case NFOR: | 8361 | case NFOR: |
7997 | funcstringsize += strlen(n->nfor.var) + 1; | 8362 | funcstringsize += strlen(n->nfor.var) + 1; |
7998 | calcsize(n->nfor.body); | 8363 | calcsize(n->nfor.body); |
7999 | calcsize(n->nfor.args); | 8364 | calcsize(n->nfor.args); |
8365 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8000 | break; | 8366 | break; |
8001 | case NCASE: | 8367 | case NCASE: |
8002 | calcsize(n->ncase.cases); | 8368 | calcsize(n->ncase.cases); |
8003 | calcsize(n->ncase.expr); | 8369 | calcsize(n->ncase.expr); |
8370 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8004 | break; | 8371 | break; |
8005 | case NCLIST: | 8372 | case NCLIST: |
8006 | calcsize(n->nclist.body); | 8373 | calcsize(n->nclist.body); |
8007 | calcsize(n->nclist.pattern); | 8374 | calcsize(n->nclist.pattern); |
8008 | calcsize(n->nclist.next); | 8375 | calcsize(n->nclist.next); |
8376 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8009 | break; | 8377 | break; |
8010 | case NDEFUN: | 8378 | case NDEFUN: |
8011 | case NARG: | 8379 | case NARG: |
8012 | sizenodelist(n->narg.backquote); | 8380 | sizenodelist(n->narg.backquote); |
8013 | funcstringsize += strlen(n->narg.text) + 1; | 8381 | funcstringsize += strlen(n->narg.text) + 1; |
8014 | calcsize(n->narg.next); | 8382 | calcsize(n->narg.next); |
8383 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | ||
8015 | break; | 8384 | break; |
8016 | case NTO: | 8385 | case NTO: |
8017 | #if ENABLE_ASH_BASH_COMPAT | 8386 | #if ENABLE_ASH_BASH_COMPAT |
@@ -8023,28 +8392,34 @@ calcsize(union node *n) | |||
8023 | case NAPPEND: | 8392 | case NAPPEND: |
8024 | calcsize(n->nfile.fname); | 8393 | calcsize(n->nfile.fname); |
8025 | calcsize(n->nfile.next); | 8394 | calcsize(n->nfile.next); |
8395 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8026 | break; | 8396 | break; |
8027 | case NTOFD: | 8397 | case NTOFD: |
8028 | case NFROMFD: | 8398 | case NFROMFD: |
8029 | calcsize(n->ndup.vname); | 8399 | calcsize(n->ndup.vname); |
8030 | calcsize(n->ndup.next); | 8400 | calcsize(n->ndup.next); |
8401 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8031 | break; | 8402 | break; |
8032 | case NHERE: | 8403 | case NHERE: |
8033 | case NXHERE: | 8404 | case NXHERE: |
8034 | calcsize(n->nhere.doc); | 8405 | calcsize(n->nhere.doc); |
8035 | calcsize(n->nhere.next); | 8406 | calcsize(n->nhere.next); |
8407 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
8036 | break; | 8408 | break; |
8037 | case NNOT: | 8409 | case NNOT: |
8038 | calcsize(n->nnot.com); | 8410 | calcsize(n->nnot.com); |
8411 | IF_PLATFORM_MINGW32(nodeptrsize++); | ||
8039 | break; | 8412 | break; |
8040 | }; | 8413 | }; |
8041 | } | 8414 | } |
8042 | 8415 | ||
8043 | static char * | 8416 | static char * |
8044 | nodeckstrdup(char *s) | 8417 | nodeckstrdup(const char *s) |
8045 | { | 8418 | { |
8046 | char *rtn = funcstring; | 8419 | char *rtn = funcstring; |
8047 | 8420 | ||
8421 | if (!s) | ||
8422 | return NULL; | ||
8048 | strcpy(funcstring, s); | 8423 | strcpy(funcstring, s); |
8049 | funcstring += strlen(s) + 1; | 8424 | funcstring += strlen(s) + 1; |
8050 | return rtn; | 8425 | return rtn; |
@@ -8052,6 +8427,18 @@ nodeckstrdup(char *s) | |||
8052 | 8427 | ||
8053 | static union node *copynode(union node *); | 8428 | static union node *copynode(union node *); |
8054 | 8429 | ||
8430 | #if ENABLE_PLATFORM_MINGW32 | ||
8431 | # define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (int)&(dst);} | ||
8432 | # define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);}} | ||
8433 | # define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);}} | ||
8434 | # define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);*nodeptr++ = (int)&(dst4);}} | ||
8435 | #else | ||
8436 | # define SAVE_PTR(dst) | ||
8437 | # define SAVE_PTR2(dst,dst2) | ||
8438 | # define SAVE_PTR3(dst,dst2,dst3) | ||
8439 | # define SAVE_PTR4(dst,dst2,dst3,dst4) | ||
8440 | #endif | ||
8441 | |||
8055 | static struct nodelist * | 8442 | static struct nodelist * |
8056 | copynodelist(struct nodelist *lp) | 8443 | copynodelist(struct nodelist *lp) |
8057 | { | 8444 | { |
@@ -8063,6 +8450,7 @@ copynodelist(struct nodelist *lp) | |||
8063 | *lpp = funcblock; | 8450 | *lpp = funcblock; |
8064 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); | 8451 | funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); |
8065 | (*lpp)->n = copynode(lp->n); | 8452 | (*lpp)->n = copynode(lp->n); |
8453 | SAVE_PTR2((*lpp)->n, (*lpp)->next); | ||
8066 | lp = lp->next; | 8454 | lp = lp->next; |
8067 | lpp = &(*lpp)->next; | 8455 | lpp = &(*lpp)->next; |
8068 | } | 8456 | } |
@@ -8085,16 +8473,19 @@ copynode(union node *n) | |||
8085 | new->ncmd.redirect = copynode(n->ncmd.redirect); | 8473 | new->ncmd.redirect = copynode(n->ncmd.redirect); |
8086 | new->ncmd.args = copynode(n->ncmd.args); | 8474 | new->ncmd.args = copynode(n->ncmd.args); |
8087 | new->ncmd.assign = copynode(n->ncmd.assign); | 8475 | new->ncmd.assign = copynode(n->ncmd.assign); |
8476 | SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign); | ||
8088 | break; | 8477 | break; |
8089 | case NPIPE: | 8478 | case NPIPE: |
8090 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | 8479 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); |
8091 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; | 8480 | new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; |
8481 | SAVE_PTR(new->npipe.cmdlist); | ||
8092 | break; | 8482 | break; |
8093 | case NREDIR: | 8483 | case NREDIR: |
8094 | case NBACKGND: | 8484 | case NBACKGND: |
8095 | case NSUBSHELL: | 8485 | case NSUBSHELL: |
8096 | new->nredir.redirect = copynode(n->nredir.redirect); | 8486 | new->nredir.redirect = copynode(n->nredir.redirect); |
8097 | new->nredir.n = copynode(n->nredir.n); | 8487 | new->nredir.n = copynode(n->nredir.n); |
8488 | SAVE_PTR2(new->nredir.redirect,new->nredir.n); | ||
8098 | break; | 8489 | break; |
8099 | case NAND: | 8490 | case NAND: |
8100 | case NOR: | 8491 | case NOR: |
@@ -8103,31 +8494,37 @@ copynode(union node *n) | |||
8103 | case NUNTIL: | 8494 | case NUNTIL: |
8104 | new->nbinary.ch2 = copynode(n->nbinary.ch2); | 8495 | new->nbinary.ch2 = copynode(n->nbinary.ch2); |
8105 | new->nbinary.ch1 = copynode(n->nbinary.ch1); | 8496 | new->nbinary.ch1 = copynode(n->nbinary.ch1); |
8497 | SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2); | ||
8106 | break; | 8498 | break; |
8107 | case NIF: | 8499 | case NIF: |
8108 | new->nif.elsepart = copynode(n->nif.elsepart); | 8500 | new->nif.elsepart = copynode(n->nif.elsepart); |
8109 | new->nif.ifpart = copynode(n->nif.ifpart); | 8501 | new->nif.ifpart = copynode(n->nif.ifpart); |
8110 | new->nif.test = copynode(n->nif.test); | 8502 | new->nif.test = copynode(n->nif.test); |
8503 | SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test); | ||
8111 | break; | 8504 | break; |
8112 | case NFOR: | 8505 | case NFOR: |
8113 | new->nfor.var = nodeckstrdup(n->nfor.var); | 8506 | new->nfor.var = nodeckstrdup(n->nfor.var); |
8114 | new->nfor.body = copynode(n->nfor.body); | 8507 | new->nfor.body = copynode(n->nfor.body); |
8115 | new->nfor.args = copynode(n->nfor.args); | 8508 | new->nfor.args = copynode(n->nfor.args); |
8509 | SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args); | ||
8116 | break; | 8510 | break; |
8117 | case NCASE: | 8511 | case NCASE: |
8118 | new->ncase.cases = copynode(n->ncase.cases); | 8512 | new->ncase.cases = copynode(n->ncase.cases); |
8119 | new->ncase.expr = copynode(n->ncase.expr); | 8513 | new->ncase.expr = copynode(n->ncase.expr); |
8514 | SAVE_PTR2(new->ncase.cases,new->ncase.expr); | ||
8120 | break; | 8515 | break; |
8121 | case NCLIST: | 8516 | case NCLIST: |
8122 | new->nclist.body = copynode(n->nclist.body); | 8517 | new->nclist.body = copynode(n->nclist.body); |
8123 | new->nclist.pattern = copynode(n->nclist.pattern); | 8518 | new->nclist.pattern = copynode(n->nclist.pattern); |
8124 | new->nclist.next = copynode(n->nclist.next); | 8519 | new->nclist.next = copynode(n->nclist.next); |
8520 | SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next); | ||
8125 | break; | 8521 | break; |
8126 | case NDEFUN: | 8522 | case NDEFUN: |
8127 | case NARG: | 8523 | case NARG: |
8128 | new->narg.backquote = copynodelist(n->narg.backquote); | 8524 | new->narg.backquote = copynodelist(n->narg.backquote); |
8129 | new->narg.text = nodeckstrdup(n->narg.text); | 8525 | new->narg.text = nodeckstrdup(n->narg.text); |
8130 | new->narg.next = copynode(n->narg.next); | 8526 | new->narg.next = copynode(n->narg.next); |
8527 | SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next); | ||
8131 | break; | 8528 | break; |
8132 | case NTO: | 8529 | case NTO: |
8133 | #if ENABLE_ASH_BASH_COMPAT | 8530 | #if ENABLE_ASH_BASH_COMPAT |
@@ -8140,6 +8537,7 @@ copynode(union node *n) | |||
8140 | new->nfile.fname = copynode(n->nfile.fname); | 8537 | new->nfile.fname = copynode(n->nfile.fname); |
8141 | new->nfile.fd = n->nfile.fd; | 8538 | new->nfile.fd = n->nfile.fd; |
8142 | new->nfile.next = copynode(n->nfile.next); | 8539 | new->nfile.next = copynode(n->nfile.next); |
8540 | SAVE_PTR2(new->nfile.fname,new->nfile.next); | ||
8143 | break; | 8541 | break; |
8144 | case NTOFD: | 8542 | case NTOFD: |
8145 | case NFROMFD: | 8543 | case NFROMFD: |
@@ -8147,15 +8545,18 @@ copynode(union node *n) | |||
8147 | new->ndup.dupfd = n->ndup.dupfd; | 8545 | new->ndup.dupfd = n->ndup.dupfd; |
8148 | new->ndup.fd = n->ndup.fd; | 8546 | new->ndup.fd = n->ndup.fd; |
8149 | new->ndup.next = copynode(n->ndup.next); | 8547 | new->ndup.next = copynode(n->ndup.next); |
8548 | SAVE_PTR2(new->ndup.vname,new->ndup.next); | ||
8150 | break; | 8549 | break; |
8151 | case NHERE: | 8550 | case NHERE: |
8152 | case NXHERE: | 8551 | case NXHERE: |
8153 | new->nhere.doc = copynode(n->nhere.doc); | 8552 | new->nhere.doc = copynode(n->nhere.doc); |
8154 | new->nhere.fd = n->nhere.fd; | 8553 | new->nhere.fd = n->nhere.fd; |
8155 | new->nhere.next = copynode(n->nhere.next); | 8554 | new->nhere.next = copynode(n->nhere.next); |
8555 | SAVE_PTR2(new->nhere.doc,new->nhere.next); | ||
8156 | break; | 8556 | break; |
8157 | case NNOT: | 8557 | case NNOT: |
8158 | new->nnot.com = copynode(n->nnot.com); | 8558 | new->nnot.com = copynode(n->nnot.com); |
8559 | SAVE_PTR(new->nnot.com); | ||
8159 | break; | 8560 | break; |
8160 | }; | 8561 | }; |
8161 | new->type = n->type; | 8562 | new->type = n->type; |
@@ -8178,6 +8579,7 @@ copyfunc(union node *n) | |||
8178 | f = ckmalloc(blocksize + funcstringsize); | 8579 | f = ckmalloc(blocksize + funcstringsize); |
8179 | funcblock = (char *) f + offsetof(struct funcnode, n); | 8580 | funcblock = (char *) f + offsetof(struct funcnode, n); |
8180 | funcstring = (char *) f + blocksize; | 8581 | funcstring = (char *) f + blocksize; |
8582 | IF_PLATFORM_MINGW32(nodeptr = NULL); | ||
8181 | copynode(n); | 8583 | copynode(n); |
8182 | f->count = 0; | 8584 | f->count = 0; |
8183 | return f; | 8585 | return f; |
@@ -8534,9 +8936,26 @@ evalcase(union node *n, int flags) | |||
8534 | /* | 8936 | /* |
8535 | * Kick off a subshell to evaluate a tree. | 8937 | * Kick off a subshell to evaluate a tree. |
8536 | */ | 8938 | */ |
8939 | #if ENABLE_PLATFORM_MINGW32 | ||
8940 | static void | ||
8941 | forkshell_evalsubshell(struct forkshell *fs) | ||
8942 | { | ||
8943 | union node *n = fs->n; | ||
8944 | int flags = fs->flags; | ||
8945 | |||
8946 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
8947 | INT_ON; | ||
8948 | flags |= EV_EXIT; | ||
8949 | expredir(n->nredir.redirect); | ||
8950 | redirect(n->nredir.redirect, 0); | ||
8951 | evaltreenr(n->nredir.n, flags); | ||
8952 | /* never returns */ | ||
8953 | } | ||
8954 | #endif | ||
8537 | static void | 8955 | static void |
8538 | evalsubshell(union node *n, int flags) | 8956 | evalsubshell(union node *n, int flags) |
8539 | { | 8957 | { |
8958 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
8540 | struct job *jp; | 8959 | struct job *jp; |
8541 | int backgnd = (n->type == NBACKGND); | 8960 | int backgnd = (n->type == NBACKGND); |
8542 | int status; | 8961 | int status; |
@@ -8546,6 +8965,14 @@ evalsubshell(union node *n, int flags) | |||
8546 | goto nofork; | 8965 | goto nofork; |
8547 | INT_OFF; | 8966 | INT_OFF; |
8548 | jp = makejob(/*n,*/ 1); | 8967 | jp = makejob(/*n,*/ 1); |
8968 | #if ENABLE_PLATFORM_MINGW32 | ||
8969 | memset(&fs, 0, sizeof(fs)); | ||
8970 | fs.fp = forkshell_evalsubshell; | ||
8971 | fs.n = n; | ||
8972 | fs.flags = flags; | ||
8973 | if (spawn_forkshell(jp, &fs, backgnd) < 0) | ||
8974 | ash_msg_and_raise_error("unable to spawn shell"); | ||
8975 | #endif | ||
8549 | if (forkshell(jp, n, backgnd) == 0) { | 8976 | if (forkshell(jp, n, backgnd) == 0) { |
8550 | /* child */ | 8977 | /* child */ |
8551 | INT_ON; | 8978 | INT_ON; |
@@ -8622,9 +9049,35 @@ expredir(union node *n) | |||
8622 | * of the shell, which make the last process in a pipeline the parent | 9049 | * of the shell, which make the last process in a pipeline the parent |
8623 | * of all the rest.) | 9050 | * of all the rest.) |
8624 | */ | 9051 | */ |
9052 | #if ENABLE_PLATFORM_MINGW32 | ||
9053 | static void | ||
9054 | forkshell_evalpipe(struct forkshell *fs) | ||
9055 | { | ||
9056 | union node *n = fs->n; | ||
9057 | int flags = fs->flags; | ||
9058 | int prevfd = fs->fd[2]; | ||
9059 | int pip[2] = {fs->fd[0], fs->fd[1]}; | ||
9060 | |||
9061 | TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__)); | ||
9062 | INT_ON; | ||
9063 | if (pip[1] >= 0) { | ||
9064 | close(pip[0]); | ||
9065 | } | ||
9066 | if (prevfd > 0) { | ||
9067 | dup2(prevfd, 0); | ||
9068 | close(prevfd); | ||
9069 | } | ||
9070 | if (pip[1] > 1) { | ||
9071 | dup2(pip[1], 1); | ||
9072 | close(pip[1]); | ||
9073 | } | ||
9074 | evaltreenr(n, flags); | ||
9075 | } | ||
9076 | #endif | ||
8625 | static void | 9077 | static void |
8626 | evalpipe(union node *n, int flags) | 9078 | evalpipe(union node *n, int flags) |
8627 | { | 9079 | { |
9080 | IF_PLATFORM_MINGW32(struct forkshell fs); | ||
8628 | struct job *jp; | 9081 | struct job *jp; |
8629 | struct nodelist *lp; | 9082 | struct nodelist *lp; |
8630 | int pipelen; | 9083 | int pipelen; |
@@ -8648,6 +9101,17 @@ evalpipe(union node *n, int flags) | |||
8648 | ash_msg_and_raise_error("pipe call failed"); | 9101 | ash_msg_and_raise_error("pipe call failed"); |
8649 | } | 9102 | } |
8650 | } | 9103 | } |
9104 | #if ENABLE_PLATFORM_MINGW32 | ||
9105 | memset(&fs, 0, sizeof(fs)); | ||
9106 | fs.fp = forkshell_evalpipe; | ||
9107 | fs.flags = flags; | ||
9108 | fs.n = lp->n; | ||
9109 | fs.fd[0] = pip[0]; | ||
9110 | fs.fd[1] = pip[1]; | ||
9111 | fs.fd[2] = prevfd; | ||
9112 | if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0) | ||
9113 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9114 | #endif | ||
8651 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { | 9115 | if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { |
8652 | INT_ON; | 9116 | INT_ON; |
8653 | if (pip[1] >= 0) { | 9117 | if (pip[1] >= 0) { |
@@ -9116,6 +9580,20 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
9116 | * as POSIX mandates */ | 9580 | * as POSIX mandates */ |
9117 | return back_exitstatus; | 9581 | return back_exitstatus; |
9118 | } | 9582 | } |
9583 | |||
9584 | #if ENABLE_PLATFORM_MINGW32 | ||
9585 | static void | ||
9586 | forkshell_shellexec(struct forkshell *fs) | ||
9587 | { | ||
9588 | int idx = fs->fd[0]; | ||
9589 | struct strlist *varlist = fs->strlist; | ||
9590 | char **argv = fs->argv; | ||
9591 | char *path = fs->string; | ||
9592 | |||
9593 | listsetvar(varlist, VEXPORT|VSTACK); | ||
9594 | shellexec(argv, path, idx); | ||
9595 | } | ||
9596 | #endif | ||
9119 | static void | 9597 | static void |
9120 | evalcommand(union node *cmd, int flags) | 9598 | evalcommand(union node *cmd, int flags) |
9121 | { | 9599 | { |
@@ -9293,6 +9771,27 @@ evalcommand(union node *cmd, int flags) | |||
9293 | * in a script or a subshell does not need forking, | 9771 | * in a script or a subshell does not need forking, |
9294 | * we can just exec it. | 9772 | * we can just exec it. |
9295 | */ | 9773 | */ |
9774 | #if ENABLE_PLATFORM_MINGW32 | ||
9775 | if (!(flags & EV_EXIT) || trap[0]) { | ||
9776 | /* No, forking off a child is necessary */ | ||
9777 | struct forkshell fs; | ||
9778 | |||
9779 | memset(&fs, 0, sizeof(fs)); | ||
9780 | fs.fp = forkshell_shellexec; | ||
9781 | fs.argv = argv; | ||
9782 | fs.string = (char*)path; | ||
9783 | fs.fd[0] = cmdentry.u.index; | ||
9784 | fs.strlist = varlist.list; | ||
9785 | jp = makejob(/*cmd,*/ 1); | ||
9786 | if (spawn_forkshell(jp, &fs, FORK_FG) < 0) | ||
9787 | ash_msg_and_raise_error("unable to spawn shell"); | ||
9788 | exitstatus = waitforjob(jp); | ||
9789 | INT_ON; | ||
9790 | TRACE(("forked child exited with %d\n", exitstatus)); | ||
9791 | break; | ||
9792 | } | ||
9793 | /* goes through to shellexec() */ | ||
9794 | #endif | ||
9296 | if (!(flags & EV_EXIT) || may_have_traps) { | 9795 | if (!(flags & EV_EXIT) || may_have_traps) { |
9297 | /* No, forking off a child is necessary */ | 9796 | /* No, forking off a child is necessary */ |
9298 | INT_OFF; | 9797 | INT_OFF; |
@@ -9677,7 +10176,7 @@ preadbuffer(void) | |||
9677 | more--; | 10176 | more--; |
9678 | 10177 | ||
9679 | c = *q; | 10178 | c = *q; |
9680 | if (c == '\0') { | 10179 | if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) { |
9681 | memmove(q, q + 1, more); | 10180 | memmove(q, q + 1, more); |
9682 | } else { | 10181 | } else { |
9683 | q++; | 10182 | q++; |
@@ -12110,7 +12609,7 @@ find_dot_file(char *name) | |||
12110 | struct stat statb; | 12609 | struct stat statb; |
12111 | 12610 | ||
12112 | /* don't try this for absolute or relative paths */ | 12611 | /* don't try this for absolute or relative paths */ |
12113 | if (strchr(name, '/')) | 12612 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) |
12114 | return name; | 12613 | return name; |
12115 | 12614 | ||
12116 | /* IIRC standards do not say whether . is to be searched. | 12615 | /* IIRC standards do not say whether . is to be searched. |
@@ -12220,10 +12719,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12220 | struct stat statb; | 12719 | struct stat statb; |
12221 | int e; | 12720 | int e; |
12222 | int updatetbl; | 12721 | int updatetbl; |
12722 | IF_PLATFORM_MINGW32(int len); | ||
12223 | struct builtincmd *bcmd; | 12723 | struct builtincmd *bcmd; |
12224 | 12724 | ||
12225 | /* If name contains a slash, don't use PATH or hash table */ | 12725 | /* If name contains a slash, don't use PATH or hash table */ |
12226 | if (strchr(name, '/') != NULL) { | 12726 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) { |
12227 | entry->u.index = -1; | 12727 | entry->u.index = -1; |
12228 | if (act & DO_ABS) { | 12728 | if (act & DO_ABS) { |
12229 | while (stat(name, &statb) < 0) { | 12729 | while (stat(name, &statb) < 0) { |
@@ -12330,12 +12830,39 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12330 | } | 12830 | } |
12331 | } | 12831 | } |
12332 | /* if rehash, don't redo absolute path names */ | 12832 | /* if rehash, don't redo absolute path names */ |
12333 | if (fullname[0] == '/' && idx <= prev) { | 12833 | if (is_absolute_path(fullname) && idx <= prev) { |
12334 | if (idx < prev) | 12834 | if (idx < prev) |
12335 | continue; | 12835 | continue; |
12336 | TRACE(("searchexec \"%s\": no change\n", name)); | 12836 | TRACE(("searchexec \"%s\": no change\n", name)); |
12337 | goto success; | 12837 | goto success; |
12338 | } | 12838 | } |
12839 | #if ENABLE_PLATFORM_MINGW32 | ||
12840 | len = strlen(fullname); | ||
12841 | if (len > 4 && | ||
12842 | (!strcasecmp(fullname+len-4, ".exe") || | ||
12843 | !strcasecmp(fullname+len-4, ".com"))) { | ||
12844 | if (stat(fullname, &statb) < 0) { | ||
12845 | if (errno != ENOENT && errno != ENOTDIR) | ||
12846 | e = errno; | ||
12847 | goto loop; | ||
12848 | } | ||
12849 | } | ||
12850 | else { | ||
12851 | /* path_advance() has reserved space for .exe */ | ||
12852 | memcpy(fullname+len, ".exe", 5); | ||
12853 | if (stat(fullname, &statb) < 0) { | ||
12854 | if (errno != ENOENT && errno != ENOTDIR) | ||
12855 | e = errno; | ||
12856 | memcpy(fullname+len, ".com", 5); | ||
12857 | if (stat(fullname, &statb) < 0) { | ||
12858 | if (errno != ENOENT && errno != ENOTDIR) | ||
12859 | e = errno; | ||
12860 | goto loop; | ||
12861 | } | ||
12862 | } | ||
12863 | fullname[len] = '\0'; | ||
12864 | } | ||
12865 | #else | ||
12339 | while (stat(fullname, &statb) < 0) { | 12866 | while (stat(fullname, &statb) < 0) { |
12340 | #ifdef SYSV | 12867 | #ifdef SYSV |
12341 | if (errno == EINTR) | 12868 | if (errno == EINTR) |
@@ -12345,6 +12872,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
12345 | e = errno; | 12872 | e = errno; |
12346 | goto loop; | 12873 | goto loop; |
12347 | } | 12874 | } |
12875 | #endif | ||
12348 | e = EACCES; /* if we fail, this will be the error */ | 12876 | e = EACCES; /* if we fail, this will be the error */ |
12349 | if (!S_ISREG(statb.st_mode)) | 12877 | if (!S_ISREG(statb.st_mode)) |
12350 | continue; | 12878 | continue; |
@@ -12593,6 +13121,10 @@ unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12593 | return ret & 1; | 13121 | return ret & 1; |
12594 | } | 13122 | } |
12595 | 13123 | ||
13124 | /* setmode.c */ | ||
13125 | |||
13126 | #if !ENABLE_PLATFORM_MINGW32 | ||
13127 | |||
12596 | static const unsigned char timescmd_str[] ALIGN1 = { | 13128 | static const unsigned char timescmd_str[] ALIGN1 = { |
12597 | ' ', offsetof(struct tms, tms_utime), | 13129 | ' ', offsetof(struct tms, tms_utime), |
12598 | '\n', offsetof(struct tms, tms_stime), | 13130 | '\n', offsetof(struct tms, tms_stime), |
@@ -12624,6 +13156,13 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12624 | 13156 | ||
12625 | return 0; | 13157 | return 0; |
12626 | } | 13158 | } |
13159 | #else | ||
13160 | static int FAST_FUNC | ||
13161 | timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | ||
13162 | { | ||
13163 | return 0; | ||
13164 | } | ||
13165 | #endif | ||
12627 | 13166 | ||
12628 | #if ENABLE_SH_MATH_SUPPORT | 13167 | #if ENABLE_SH_MATH_SUPPORT |
12629 | /* | 13168 | /* |
@@ -12849,13 +13388,41 @@ init(void) | |||
12849 | struct stat st1, st2; | 13388 | struct stat st1, st2; |
12850 | 13389 | ||
12851 | initvar(); | 13390 | initvar(); |
13391 | |||
13392 | #if ENABLE_PLATFORM_MINGW32 | ||
13393 | /* | ||
13394 | * case insensitive env names from Windows world | ||
13395 | * | ||
13396 | * Some standard env names such as PATH is named Path and so on | ||
13397 | * ash itself is case sensitive, so "Path" will confuse it, as | ||
13398 | * MSVC getenv() is case insensitive. | ||
13399 | * | ||
13400 | * We may end up having both Path and PATH. Then Path will be chosen | ||
13401 | * because it appears first. | ||
13402 | */ | ||
13403 | for (envp = environ; envp && *envp; envp++) | ||
13404 | if (!strncasecmp(*envp, "PATH=", 5) && | ||
13405 | strncmp(*envp, "PATH=", 5)) | ||
13406 | break; | ||
13407 | if (envp && *envp) { | ||
13408 | char *start, *end; | ||
13409 | for (envp = environ; envp && *envp; envp++) { | ||
13410 | end = strchr(*envp, '='); | ||
13411 | if (!end) | ||
13412 | continue; | ||
13413 | for (start = *envp;start < end;start++) | ||
13414 | *start = toupper(*start); | ||
13415 | } | ||
13416 | } | ||
13417 | #endif | ||
12852 | for (envp = environ; envp && *envp; envp++) { | 13418 | for (envp = environ; envp && *envp; envp++) { |
12853 | if (strchr(*envp, '=')) { | 13419 | if (strchr(*envp, '=')) { |
12854 | setvareq(*envp, VEXPORT|VTEXTFIXED); | 13420 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
12855 | } | 13421 | } |
12856 | } | 13422 | } |
12857 | 13423 | ||
12858 | setvar("PPID", utoa(getppid()), 0); | 13424 | if (!ENABLE_PLATFORM_MINGW32) |
13425 | setvar("PPID", utoa(getppid()), 0); | ||
12859 | 13426 | ||
12860 | p = lookupvar("PWD"); | 13427 | p = lookupvar("PWD"); |
12861 | if (p) | 13428 | if (p) |
@@ -12971,6 +13538,20 @@ static short profile_buf[16384]; | |||
12971 | extern int etext(); | 13538 | extern int etext(); |
12972 | #endif | 13539 | #endif |
12973 | 13540 | ||
13541 | #if ENABLE_PLATFORM_MINGW32 | ||
13542 | static const forkpoint_fn forkpoints[] = { | ||
13543 | forkshell_openhere, | ||
13544 | forkshell_evalbackcmd, | ||
13545 | forkshell_evalsubshell, | ||
13546 | forkshell_evalpipe, | ||
13547 | forkshell_shellexec, | ||
13548 | NULL | ||
13549 | }; | ||
13550 | |||
13551 | static struct forkshell* forkshell_prepare(struct forkshell *fs); | ||
13552 | static void forkshell_init(const char *idstr); | ||
13553 | #endif | ||
13554 | |||
12974 | /* | 13555 | /* |
12975 | * Main routine. We initialize things, parse the arguments, execute | 13556 | * Main routine. We initialize things, parse the arguments, execute |
12976 | * profiles if we're a login shell, and then call cmdloop to execute | 13557 | * profiles if we're a login shell, and then call cmdloop to execute |
@@ -13040,6 +13621,17 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13040 | 13621 | ||
13041 | init(); | 13622 | init(); |
13042 | setstackmark(&smark); | 13623 | setstackmark(&smark); |
13624 | |||
13625 | #if ENABLE_PLATFORM_MINGW32 | ||
13626 | hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL); | ||
13627 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
13628 | if (argc == 3 && !strcmp(argv[1], "--forkshell")) { | ||
13629 | forkshell_init(argv[2]); | ||
13630 | |||
13631 | /* NOTREACHED */ | ||
13632 | bb_error_msg_and_die("subshell ended unexpectedly"); | ||
13633 | } | ||
13634 | #endif | ||
13043 | procargs(argv); | 13635 | procargs(argv); |
13044 | 13636 | ||
13045 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 13637 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY |
@@ -13116,6 +13708,524 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13116 | /* NOTREACHED */ | 13708 | /* NOTREACHED */ |
13117 | } | 13709 | } |
13118 | 13710 | ||
13711 | /* FIXME: should consider running forkparent() and forkchild() */ | ||
13712 | static int | ||
13713 | spawn_forkshell(struct job *jp, struct forkshell *fs, int mode) | ||
13714 | { | ||
13715 | const char *argv[] = { "sh", "--forkshell", NULL, NULL }; | ||
13716 | char buf[16]; | ||
13717 | |||
13718 | struct forkshell *new; | ||
13719 | new = forkshell_prepare(fs); | ||
13720 | sprintf(buf, "%x", (unsigned int)new->hMapFile); | ||
13721 | argv[2] = buf; | ||
13722 | fs->pid = mingw_spawn_applet(P_NOWAIT, "sh", argv, | ||
13723 | (const char *const *)environ); | ||
13724 | CloseHandle(new->hMapFile); | ||
13725 | UnmapViewOfFile(new); | ||
13726 | if (fs->pid == -1) { | ||
13727 | free(jp); | ||
13728 | return -1; | ||
13729 | } | ||
13730 | forkparent(jp, fs->node, mode, fs->pid); | ||
13731 | return fs->pid; | ||
13732 | } | ||
13733 | |||
13734 | /* | ||
13735 | * forkshell_prepare() and friends | ||
13736 | * | ||
13737 | * The sequence is as follows: | ||
13738 | * - funcblocksize, funcstringsize, nodeptrsize are initialized | ||
13739 | * - forkshell_size(fs) is called to calculate the exact memory needed | ||
13740 | * - a new struct is allocated | ||
13741 | * - funcblock, funcstring, nodeptr are initialized from the new block | ||
13742 | * - forkshell_copy(fs) is called to copy recursively everything over | ||
13743 | * it will record all pointers along the way, to nodeptr | ||
13744 | * | ||
13745 | * When this memory is mapped elsewhere, pointer fixup will be needed | ||
13746 | */ | ||
13747 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
13748 | static void \ | ||
13749 | name(type *p) \ | ||
13750 | { \ | ||
13751 | while (p) { \ | ||
13752 | funcblocksize += sizeof(type); | ||
13753 | /* do something here with p */ | ||
13754 | #define SLIST_SIZE_END() \ | ||
13755 | nodeptrsize++; \ | ||
13756 | p = p->next; \ | ||
13757 | } \ | ||
13758 | } | ||
13759 | |||
13760 | #define SLIST_COPY_BEGIN(name,type) \ | ||
13761 | static type * \ | ||
13762 | name(type *vp) \ | ||
13763 | { \ | ||
13764 | type *start; \ | ||
13765 | type **vpp; \ | ||
13766 | vpp = &start; \ | ||
13767 | while (vp) { \ | ||
13768 | *vpp = funcblock; \ | ||
13769 | funcblock = (char *) funcblock + sizeof(type); | ||
13770 | /* do something here with vpp and vp */ | ||
13771 | #define SLIST_COPY_END() \ | ||
13772 | SAVE_PTR((*vpp)->next); \ | ||
13773 | vp = vp->next; \ | ||
13774 | vpp = &(*vpp)->next; \ | ||
13775 | } \ | ||
13776 | *vpp = NULL; \ | ||
13777 | return start; \ | ||
13778 | } | ||
13779 | |||
13780 | /* | ||
13781 | * struct var | ||
13782 | */ | ||
13783 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
13784 | funcstringsize += strlen(p->var_text) + 1; | ||
13785 | nodeptrsize++; /* p->text */ | ||
13786 | SLIST_SIZE_END() | ||
13787 | |||
13788 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
13789 | (*vpp)->var_text = nodeckstrdup(vp->var_text); | ||
13790 | (*vpp)->flags = vp->flags; | ||
13791 | /* | ||
13792 | * The only place that can set struct var#func is varinit[], | ||
13793 | * which will be fixed by forkshell_init() | ||
13794 | */ | ||
13795 | (*vpp)->var_func = NULL; | ||
13796 | SAVE_PTR((*vpp)->var_text); | ||
13797 | SLIST_COPY_END() | ||
13798 | |||
13799 | /* | ||
13800 | * struct localvar | ||
13801 | */ | ||
13802 | SLIST_SIZE_BEGIN(localvar_size,struct localvar) | ||
13803 | var_size(p->vp); | ||
13804 | funcstringsize += strlen(p->text) + 1; | ||
13805 | nodeptrsize += 2; /* p->vp, p->text */ | ||
13806 | SLIST_SIZE_END() | ||
13807 | |||
13808 | SLIST_COPY_BEGIN(localvar_copy,struct localvar) | ||
13809 | (*vpp)->text = nodeckstrdup(vp->text); | ||
13810 | (*vpp)->flags = vp->flags; | ||
13811 | (*vpp)->vp = var_copy(vp->vp); | ||
13812 | SAVE_PTR2((*vpp)->vp, (*vpp)->text); | ||
13813 | SLIST_COPY_END() | ||
13814 | |||
13815 | /* | ||
13816 | * struct strlist | ||
13817 | */ | ||
13818 | SLIST_SIZE_BEGIN(strlist_size,struct strlist) | ||
13819 | funcstringsize += strlen(p->text) + 1; | ||
13820 | nodeptrsize++; /* p->text */ | ||
13821 | SLIST_SIZE_END() | ||
13822 | |||
13823 | SLIST_COPY_BEGIN(strlist_copy,struct strlist) | ||
13824 | (*vpp)->text = nodeckstrdup(vp->text); | ||
13825 | SAVE_PTR((*vpp)->text); | ||
13826 | SLIST_COPY_END() | ||
13827 | |||
13828 | /* | ||
13829 | * struct tblentry | ||
13830 | */ | ||
13831 | static void | ||
13832 | tblentry_size(struct tblentry *tep) | ||
13833 | { | ||
13834 | while (tep) { | ||
13835 | funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
13836 | /* CMDBUILTIN, e->param.cmd needs no pointer relocation */ | ||
13837 | if (tep->cmdtype == CMDFUNCTION) { | ||
13838 | funcblocksize += offsetof(struct funcnode, n); | ||
13839 | calcsize(&tep->param.func->n); | ||
13840 | nodeptrsize++; /* tep->param.func */ | ||
13841 | } | ||
13842 | nodeptrsize++; /* tep->next */ | ||
13843 | tep = tep->next; | ||
13844 | } | ||
13845 | } | ||
13846 | |||
13847 | static struct tblentry * | ||
13848 | tblentry_copy(struct tblentry *tep) | ||
13849 | { | ||
13850 | struct tblentry *start; | ||
13851 | struct tblentry **newp; | ||
13852 | int size; | ||
13853 | |||
13854 | newp = &start; | ||
13855 | while (tep) { | ||
13856 | *newp = funcblock; | ||
13857 | size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1; | ||
13858 | |||
13859 | funcblock = (char *) funcblock + size; | ||
13860 | memcpy(*newp, tep, size); | ||
13861 | switch (tep->cmdtype) { | ||
13862 | case CMDBUILTIN: | ||
13863 | /* No pointer saving, this field must be fixed by forkshell_init() */ | ||
13864 | (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab); | ||
13865 | break; | ||
13866 | case CMDFUNCTION: | ||
13867 | (*newp)->param.func = funcblock; | ||
13868 | funcblock = (char *) funcblock + offsetof(struct funcnode, n); | ||
13869 | copynode(&tep->param.func->n); | ||
13870 | SAVE_PTR((*newp)->param.func); | ||
13871 | break; | ||
13872 | default: | ||
13873 | break; | ||
13874 | } | ||
13875 | SAVE_PTR((*newp)->next); | ||
13876 | tep = tep->next; | ||
13877 | newp = &(*newp)->next; | ||
13878 | } | ||
13879 | *newp = NULL; | ||
13880 | return start; | ||
13881 | } | ||
13882 | |||
13883 | static void | ||
13884 | cmdtable_size(struct tblentry **cmdtablep) | ||
13885 | { | ||
13886 | int i; | ||
13887 | nodeptrsize += CMDTABLESIZE; | ||
13888 | funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE; | ||
13889 | for (i = 0; i < CMDTABLESIZE; i++) | ||
13890 | tblentry_size(cmdtablep[i]); | ||
13891 | } | ||
13892 | |||
13893 | static struct tblentry ** | ||
13894 | cmdtable_copy(struct tblentry **cmdtablep) | ||
13895 | { | ||
13896 | struct tblentry **new = funcblock; | ||
13897 | int i; | ||
13898 | |||
13899 | funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE; | ||
13900 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
13901 | new[i] = tblentry_copy(cmdtablep[i]); | ||
13902 | SAVE_PTR(new[i]); | ||
13903 | } | ||
13904 | return new; | ||
13905 | } | ||
13906 | |||
13907 | /* | ||
13908 | * char ** | ||
13909 | */ | ||
13910 | static void | ||
13911 | argv_size(char **p) | ||
13912 | { | ||
13913 | while (p && *p) { | ||
13914 | funcblocksize += sizeof(char *); | ||
13915 | funcstringsize += strlen(*p)+1; | ||
13916 | nodeptrsize++; | ||
13917 | p++; | ||
13918 | } | ||
13919 | funcblocksize += sizeof(char *); | ||
13920 | } | ||
13921 | |||
13922 | static char ** | ||
13923 | argv_copy(char **p) | ||
13924 | { | ||
13925 | char **new, **start = funcblock; | ||
13926 | |||
13927 | while (p && *p) { | ||
13928 | new = funcblock; | ||
13929 | funcblock = (char *) funcblock + sizeof(char *); | ||
13930 | *new = nodeckstrdup(*p); | ||
13931 | SAVE_PTR(*new); | ||
13932 | p++; | ||
13933 | new++; | ||
13934 | } | ||
13935 | new = funcblock; | ||
13936 | funcblock = (char *) funcblock + sizeof(char *); | ||
13937 | *new = NULL; | ||
13938 | return start; | ||
13939 | } | ||
13940 | |||
13941 | /* | ||
13942 | * struct redirtab | ||
13943 | */ | ||
13944 | static void | ||
13945 | redirtab_size(struct redirtab *rdtp) | ||
13946 | { | ||
13947 | while (rdtp) { | ||
13948 | funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
13949 | rdtp = rdtp->next; | ||
13950 | nodeptrsize++; /* rdtp->next */ | ||
13951 | } | ||
13952 | } | ||
13953 | |||
13954 | static struct redirtab * | ||
13955 | redirtab_copy(struct redirtab *rdtp) | ||
13956 | { | ||
13957 | struct redirtab *start; | ||
13958 | struct redirtab **vpp; | ||
13959 | |||
13960 | vpp = &start; | ||
13961 | while (rdtp) { | ||
13962 | int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count; | ||
13963 | *vpp = funcblock; | ||
13964 | funcblock = (char *) funcblock + size; | ||
13965 | memcpy(*vpp, rdtp, size); | ||
13966 | SAVE_PTR((*vpp)->next); | ||
13967 | rdtp = rdtp->next; | ||
13968 | vpp = &(*vpp)->next; | ||
13969 | } | ||
13970 | *vpp = NULL; | ||
13971 | return start; | ||
13972 | } | ||
13973 | |||
13974 | #undef shellparam | ||
13975 | #undef redirlist | ||
13976 | #undef varinit | ||
13977 | #undef vartab | ||
13978 | static void | ||
13979 | globals_var_size(struct globals_var *gvp) | ||
13980 | { | ||
13981 | int i; | ||
13982 | |||
13983 | funcblocksize += sizeof(struct globals_var); | ||
13984 | argv_size(gvp->shellparam.p); | ||
13985 | redirtab_size(gvp->redirlist); | ||
13986 | for (i = 0; i < VTABSIZE; i++) | ||
13987 | var_size(gvp->vartab[i]); | ||
13988 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
13989 | var_size(gvp->varinit+i); | ||
13990 | nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */ | ||
13991 | } | ||
13992 | |||
13993 | #undef g_nullredirs | ||
13994 | #undef preverrout_fd | ||
13995 | static struct globals_var * | ||
13996 | globals_var_copy(struct globals_var *gvp) | ||
13997 | { | ||
13998 | int i; | ||
13999 | struct globals_var *new; | ||
14000 | |||
14001 | new = funcblock; | ||
14002 | funcblock = (char *) funcblock + sizeof(struct globals_var); | ||
14003 | |||
14004 | /* shparam */ | ||
14005 | memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam)); | ||
14006 | new->shellparam.malloced = 0; | ||
14007 | new->shellparam.p = argv_copy(gvp->shellparam.p); | ||
14008 | SAVE_PTR(new->shellparam.p); | ||
14009 | |||
14010 | new->redirlist = redirtab_copy(gvp->redirlist); | ||
14011 | SAVE_PTR(new->redirlist); | ||
14012 | |||
14013 | new->g_nullredirs = gvp->g_nullredirs; | ||
14014 | new->preverrout_fd = gvp->preverrout_fd; | ||
14015 | for (i = 0; i < VTABSIZE; i++) { | ||
14016 | new->vartab[i] = var_copy(gvp->vartab[i]); | ||
14017 | SAVE_PTR(new->vartab[i]); | ||
14018 | } | ||
14019 | |||
14020 | /* Can't use var_copy because varinit is already allocated */ | ||
14021 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { | ||
14022 | new->varinit[i].next = NULL; | ||
14023 | new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text); | ||
14024 | SAVE_PTR(new->varinit[i].var_text); | ||
14025 | new->varinit[i].flags = gvp->varinit[i].flags; | ||
14026 | new->varinit[i].var_func = gvp->varinit[i].var_func; | ||
14027 | } | ||
14028 | return new; | ||
14029 | } | ||
14030 | |||
14031 | #undef minusc | ||
14032 | #undef curdir | ||
14033 | #undef physdir | ||
14034 | #undef arg0 | ||
14035 | #undef nullstr | ||
14036 | static void | ||
14037 | globals_misc_size(struct globals_misc *p) | ||
14038 | { | ||
14039 | funcblocksize += sizeof(struct globals_misc); | ||
14040 | funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1; | ||
14041 | if (p->curdir != p->nullstr) | ||
14042 | funcstringsize += strlen(p->curdir) + 1; | ||
14043 | if (p->physdir != p->nullstr) | ||
14044 | funcstringsize += strlen(p->physdir) + 1; | ||
14045 | funcstringsize += strlen(p->arg0) + 1; | ||
14046 | nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */ | ||
14047 | } | ||
14048 | |||
14049 | static struct globals_misc * | ||
14050 | globals_misc_copy(struct globals_misc *p) | ||
14051 | { | ||
14052 | struct globals_misc *new = funcblock; | ||
14053 | |||
14054 | funcblock = (char *) funcblock + sizeof(struct globals_misc); | ||
14055 | memcpy(new, p, sizeof(struct globals_misc)); | ||
14056 | |||
14057 | new->minusc = nodeckstrdup(p->minusc); | ||
14058 | new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr; | ||
14059 | new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr; | ||
14060 | new->arg0 = nodeckstrdup(p->arg0); | ||
14061 | SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0); | ||
14062 | return new; | ||
14063 | } | ||
14064 | |||
14065 | static void | ||
14066 | forkshell_size(struct forkshell *fs) | ||
14067 | { | ||
14068 | funcblocksize += sizeof(struct forkshell); | ||
14069 | globals_var_size(fs->gvp); | ||
14070 | globals_misc_size(fs->gmp); | ||
14071 | cmdtable_size(fs->cmdtable); | ||
14072 | localvar_size(fs->localvars); | ||
14073 | /* optlist_transfer(sending, fd); */ | ||
14074 | /* misc_transfer(sending, fd); */ | ||
14075 | |||
14076 | calcsize(fs->n); | ||
14077 | argv_size(fs->argv); | ||
14078 | funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1; | ||
14079 | strlist_size(fs->strlist); | ||
14080 | |||
14081 | nodeptrsize += 8; /* gvp, gmp, cmdtable, localvars, n, argv, string, strlist */ | ||
14082 | } | ||
14083 | |||
14084 | static struct forkshell * | ||
14085 | forkshell_copy(struct forkshell *fs) | ||
14086 | { | ||
14087 | struct forkshell *new; | ||
14088 | |||
14089 | new = funcblock; | ||
14090 | funcblock = (char *) funcblock + sizeof(struct forkshell); | ||
14091 | |||
14092 | memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */ | ||
14093 | new->gvp = globals_var_copy(fs->gvp); | ||
14094 | new->gmp = globals_misc_copy(fs->gmp); | ||
14095 | new->cmdtable = cmdtable_copy(fs->cmdtable); | ||
14096 | new->localvars = localvar_copy(fs->localvars); | ||
14097 | SAVE_PTR4(new->gvp, new->gmp, new->cmdtable, new->localvars); | ||
14098 | |||
14099 | /* new->fs will be reconstructed from new->fpid */ | ||
14100 | new->n = copynode(fs->n); | ||
14101 | new->argv = argv_copy(fs->argv); | ||
14102 | new->string = nodeckstrdup(fs->string); | ||
14103 | new->strlist = strlist_copy(fs->strlist); | ||
14104 | SAVE_PTR4(new->n, new->argv, new->string, new->strlist); | ||
14105 | return new; | ||
14106 | } | ||
14107 | |||
14108 | static struct forkshell * | ||
14109 | forkshell_prepare(struct forkshell *fs) | ||
14110 | { | ||
14111 | struct forkshell *new; | ||
14112 | int size, fp, nodeptr_offset; | ||
14113 | HANDLE h; | ||
14114 | SECURITY_ATTRIBUTES sa; | ||
14115 | |||
14116 | for (fp = 0; forkpoints[fp] && forkpoints[fp] != fs->fp; fp++) | ||
14117 | ; | ||
14118 | |||
14119 | if (!forkpoints[fp]) | ||
14120 | bb_error_msg_and_die("invalid forkpoint %08x", (int)fs->fp); | ||
14121 | fs->fpid = fp; | ||
14122 | |||
14123 | /* Calculate size of "new" */ | ||
14124 | fs->gvp = ash_ptr_to_globals_var; | ||
14125 | fs->gmp = ash_ptr_to_globals_misc; | ||
14126 | fs->cmdtable = cmdtable; | ||
14127 | fs->localvars = localvars; | ||
14128 | |||
14129 | nodeptrsize = 1; /* NULL terminated */ | ||
14130 | funcblocksize = 0; | ||
14131 | funcstringsize = 0; | ||
14132 | forkshell_size(fs); | ||
14133 | size = funcblocksize + funcstringsize + nodeptrsize*sizeof(int); | ||
14134 | |||
14135 | /* Allocate, initialize pointers */ | ||
14136 | memset(&sa, 0, sizeof(sa)); | ||
14137 | sa.nLength = sizeof(sa); | ||
14138 | sa.lpSecurityDescriptor = NULL; | ||
14139 | sa.bInheritHandle = TRUE; | ||
14140 | h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL); | ||
14141 | new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
14142 | /* new = ckmalloc(size); */ | ||
14143 | funcblock = new; | ||
14144 | funcstring = (char *) funcblock + funcblocksize; | ||
14145 | nodeptr = (int*)((char *) funcstring + funcstringsize); | ||
14146 | nodeptr_offset = (int) nodeptr - (int) new; | ||
14147 | |||
14148 | /* Now pack them all */ | ||
14149 | forkshell_copy(fs); | ||
14150 | |||
14151 | /* Finish it up */ | ||
14152 | *nodeptr = 0; | ||
14153 | new->size = size; | ||
14154 | new->nodeptr_offset = nodeptr_offset; | ||
14155 | new->old_base = new; | ||
14156 | new->hMapFile = h; | ||
14157 | return new; | ||
14158 | } | ||
14159 | |||
14160 | #undef exception_handler | ||
14161 | #undef trap | ||
14162 | #undef trap_ptr | ||
14163 | static void *sticky_mem_start, *sticky_mem_end; | ||
14164 | static void | ||
14165 | forkshell_init(const char *idstr) | ||
14166 | { | ||
14167 | struct forkshell *fs; | ||
14168 | int map_handle; | ||
14169 | HANDLE h; | ||
14170 | struct globals_var **gvpp; | ||
14171 | struct globals_misc **gmpp; | ||
14172 | int i; | ||
14173 | |||
14174 | if (sscanf(idstr, "%x", &map_handle) != 1) | ||
14175 | bb_error_msg_and_die("invalid forkshell ID"); | ||
14176 | |||
14177 | h = (HANDLE)map_handle; | ||
14178 | fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0); | ||
14179 | if (!fs) | ||
14180 | bb_error_msg_and_die("Invalid forkshell memory"); | ||
14181 | |||
14182 | /* this memory can't be freed */ | ||
14183 | sticky_mem_start = fs; | ||
14184 | sticky_mem_end = (char *) fs + fs->size; | ||
14185 | /* pointer fixup */ | ||
14186 | nodeptr = (int*)((char*)fs + fs->nodeptr_offset); | ||
14187 | while (*nodeptr) { | ||
14188 | int *ptr = (int*)((char*)fs + (*nodeptr - (int)fs->old_base)); | ||
14189 | if (*ptr) | ||
14190 | *ptr -= ((int)fs->old_base - (int)fs); | ||
14191 | nodeptr++; | ||
14192 | } | ||
14193 | /* Now fix up stuff that can't be transferred */ | ||
14194 | fs->fp = forkpoints[fs->fpid]; | ||
14195 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) | ||
14196 | fs->gvp->varinit[i].var_func = varinit_data[i].var_func; | ||
14197 | for (i = 0; i < CMDTABLESIZE; i++) { | ||
14198 | struct tblentry *e = fs->cmdtable[i]; | ||
14199 | while (e) { | ||
14200 | if (e->cmdtype == CMDBUILTIN) | ||
14201 | e->param.cmd = builtintab + (int)e->param.cmd; | ||
14202 | e = e->next; | ||
14203 | } | ||
14204 | } | ||
14205 | fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler; | ||
14206 | for (i = 0; i < NSIG; i++) | ||
14207 | fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i]; | ||
14208 | fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr; | ||
14209 | |||
14210 | /* Switch global variables */ | ||
14211 | gvpp = (struct globals_var **)&ash_ptr_to_globals_var; | ||
14212 | *gvpp = fs->gvp; | ||
14213 | gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc; | ||
14214 | *gmpp = fs->gmp; | ||
14215 | localvars = fs->localvars; | ||
14216 | cmdtable = fs->cmdtable; | ||
14217 | |||
14218 | fs->fp(fs); | ||
14219 | } | ||
14220 | |||
14221 | #undef free | ||
14222 | static void | ||
14223 | sticky_free(void *base) | ||
14224 | { | ||
14225 | if (base >= sticky_mem_start && base < sticky_mem_end) | ||
14226 | return; | ||
14227 | free(base); | ||
14228 | } | ||
13119 | 14229 | ||
13120 | /*- | 14230 | /*- |
13121 | * Copyright (c) 1989, 1991, 1993, 1994 | 14231 | * Copyright (c) 1989, 1991, 1993, 1994 |
diff --git a/shell/builtin_ulimit.c b/shell/builtin_ulimit.c new file mode 100644 index 000000000..7ef17b1b0 --- /dev/null +++ b/shell/builtin_ulimit.c | |||
@@ -0,0 +1,237 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * ulimit builtin | ||
4 | * | ||
5 | * Adapted from ash applet code | ||
6 | * | ||
7 | * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and | ||
8 | * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with | ||
9 | * ash by J.T. Conklin. | ||
10 | * | ||
11 | * Public domain. | ||
12 | * | ||
13 | * Copyright (c) 2010 Tobias Klauser | ||
14 | * Split from ash.c and slightly adapted. | ||
15 | * | ||
16 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. | ||
17 | */ | ||
18 | #include "libbb.h" | ||
19 | |||
20 | #if ENABLE_PLATFORM_MINGW32 | ||
21 | int FAST_FUNC shell_builtin_ulimit(char **argv) | ||
22 | { | ||
23 | return 1; | ||
24 | } | ||
25 | #else | ||
26 | |||
27 | #include "builtin_ulimit.h" | ||
28 | |||
29 | |||
30 | struct limits { | ||
31 | uint8_t cmd; /* RLIMIT_xxx fit into it */ | ||
32 | uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ | ||
33 | char option; | ||
34 | const char *name; | ||
35 | }; | ||
36 | |||
37 | static const struct limits limits_tbl[] = { | ||
38 | #ifdef RLIMIT_FSIZE | ||
39 | { RLIMIT_FSIZE, 9, 'f', "file size (blocks)" }, | ||
40 | #endif | ||
41 | #ifdef RLIMIT_CPU | ||
42 | { RLIMIT_CPU, 0, 't', "cpu time (seconds)" }, | ||
43 | #endif | ||
44 | #ifdef RLIMIT_DATA | ||
45 | { RLIMIT_DATA, 10, 'd', "data seg size (kb)" }, | ||
46 | #endif | ||
47 | #ifdef RLIMIT_STACK | ||
48 | { RLIMIT_STACK, 10, 's', "stack size (kb)" }, | ||
49 | #endif | ||
50 | #ifdef RLIMIT_CORE | ||
51 | { RLIMIT_CORE, 9, 'c', "core file size (blocks)" }, | ||
52 | #endif | ||
53 | #ifdef RLIMIT_RSS | ||
54 | { RLIMIT_RSS, 10, 'm', "resident set size (kb)" }, | ||
55 | #endif | ||
56 | #ifdef RLIMIT_MEMLOCK | ||
57 | { RLIMIT_MEMLOCK, 10, 'l', "locked memory (kb)" }, | ||
58 | #endif | ||
59 | #ifdef RLIMIT_NPROC | ||
60 | { RLIMIT_NPROC, 0, 'p', "processes" }, | ||
61 | #endif | ||
62 | #ifdef RLIMIT_NOFILE | ||
63 | { RLIMIT_NOFILE, 0, 'n', "file descriptors" }, | ||
64 | #endif | ||
65 | #ifdef RLIMIT_AS | ||
66 | { RLIMIT_AS, 10, 'v', "address space (kb)" }, | ||
67 | #endif | ||
68 | #ifdef RLIMIT_LOCKS | ||
69 | { RLIMIT_LOCKS, 0, 'w', "locks" }, | ||
70 | #endif | ||
71 | }; | ||
72 | |||
73 | enum { | ||
74 | OPT_hard = (1 << 0), | ||
75 | OPT_soft = (1 << 1), | ||
76 | }; | ||
77 | |||
78 | /* "-": treat args as parameters of option with ASCII code 1 */ | ||
79 | static const char ulimit_opt_string[] = "-HSa" | ||
80 | #ifdef RLIMIT_FSIZE | ||
81 | "f::" | ||
82 | #endif | ||
83 | #ifdef RLIMIT_CPU | ||
84 | "t::" | ||
85 | #endif | ||
86 | #ifdef RLIMIT_DATA | ||
87 | "d::" | ||
88 | #endif | ||
89 | #ifdef RLIMIT_STACK | ||
90 | "s::" | ||
91 | #endif | ||
92 | #ifdef RLIMIT_CORE | ||
93 | "c::" | ||
94 | #endif | ||
95 | #ifdef RLIMIT_RSS | ||
96 | "m::" | ||
97 | #endif | ||
98 | #ifdef RLIMIT_MEMLOCK | ||
99 | "l::" | ||
100 | #endif | ||
101 | #ifdef RLIMIT_NPROC | ||
102 | "p::" | ||
103 | #endif | ||
104 | #ifdef RLIMIT_NOFILE | ||
105 | "n::" | ||
106 | #endif | ||
107 | #ifdef RLIMIT_AS | ||
108 | "v::" | ||
109 | #endif | ||
110 | #ifdef RLIMIT_LOCKS | ||
111 | "w::" | ||
112 | #endif | ||
113 | ; | ||
114 | |||
115 | static void printlim(unsigned opts, const struct rlimit *limit, | ||
116 | const struct limits *l) | ||
117 | { | ||
118 | rlim_t val; | ||
119 | |||
120 | val = limit->rlim_max; | ||
121 | if (!(opts & OPT_hard)) | ||
122 | val = limit->rlim_cur; | ||
123 | |||
124 | if (val == RLIM_INFINITY) | ||
125 | printf("unlimited\n"); | ||
126 | else { | ||
127 | val >>= l->factor_shift; | ||
128 | printf("%llu\n", (long long) val); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | int FAST_FUNC shell_builtin_ulimit(char **argv) | ||
133 | { | ||
134 | unsigned opts; | ||
135 | unsigned argc; | ||
136 | |||
137 | /* We can't use getopt32: need to handle commands like | ||
138 | * ulimit 123 -c2 -l 456 | ||
139 | */ | ||
140 | |||
141 | /* In case getopt was already called: | ||
142 | * reset the libc getopt() function, which keeps internal state. | ||
143 | */ | ||
144 | #ifdef __GLIBC__ | ||
145 | optind = 0; | ||
146 | #else /* BSD style */ | ||
147 | optind = 1; | ||
148 | /* optreset = 1; */ | ||
149 | #endif | ||
150 | /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */ | ||
151 | |||
152 | argc = 1; | ||
153 | while (argv[argc]) | ||
154 | argc++; | ||
155 | |||
156 | opts = 0; | ||
157 | while (1) { | ||
158 | struct rlimit limit; | ||
159 | const struct limits *l; | ||
160 | int opt_char = getopt(argc, argv, ulimit_opt_string); | ||
161 | |||
162 | if (opt_char == -1) | ||
163 | break; | ||
164 | if (opt_char == 'H') { | ||
165 | opts |= OPT_hard; | ||
166 | continue; | ||
167 | } | ||
168 | if (opt_char == 'S') { | ||
169 | opts |= OPT_soft; | ||
170 | continue; | ||
171 | } | ||
172 | |||
173 | if (opt_char == 'a') { | ||
174 | for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) { | ||
175 | getrlimit(l->cmd, &limit); | ||
176 | printf("-%c: %-30s ", l->option, l->name); | ||
177 | printlim(opts, &limit, l); | ||
178 | } | ||
179 | continue; | ||
180 | } | ||
181 | |||
182 | if (opt_char == 1) | ||
183 | opt_char = 'f'; | ||
184 | for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) { | ||
185 | if (opt_char == l->option) { | ||
186 | char *val_str; | ||
187 | |||
188 | getrlimit(l->cmd, &limit); | ||
189 | |||
190 | val_str = optarg; | ||
191 | if (!val_str && argv[optind] && argv[optind][0] != '-') | ||
192 | val_str = argv[optind++]; /* ++ skips NN in "-c NN" case */ | ||
193 | if (val_str) { | ||
194 | rlim_t val; | ||
195 | |||
196 | if (strcmp(val_str, "unlimited") == 0) | ||
197 | val = RLIM_INFINITY; | ||
198 | else { | ||
199 | if (sizeof(val) == sizeof(int)) | ||
200 | val = bb_strtou(val_str, NULL, 10); | ||
201 | else if (sizeof(val) == sizeof(long)) | ||
202 | val = bb_strtoul(val_str, NULL, 10); | ||
203 | else | ||
204 | val = bb_strtoull(val_str, NULL, 10); | ||
205 | if (errno) { | ||
206 | bb_error_msg("bad number"); | ||
207 | return EXIT_FAILURE; | ||
208 | } | ||
209 | val <<= l->factor_shift; | ||
210 | } | ||
211 | //bb_error_msg("opt %c val_str:'%s' val:%lld", opt_char, val_str, (long long)val); | ||
212 | if (opts & OPT_hard) | ||
213 | limit.rlim_max = val; | ||
214 | if ((opts & OPT_soft) || opts == 0) | ||
215 | limit.rlim_cur = val; | ||
216 | //bb_error_msg("setrlimit(%d, %lld, %lld)", l->cmd, (long long)limit.rlim_cur, (long long)limit.rlim_max); | ||
217 | if (setrlimit(l->cmd, &limit) < 0) { | ||
218 | bb_perror_msg("error setting limit"); | ||
219 | return EXIT_FAILURE; | ||
220 | } | ||
221 | } else { | ||
222 | printlim(opts, &limit, l); | ||
223 | } | ||
224 | break; | ||
225 | } | ||
226 | } /* for (every possible opt) */ | ||
227 | |||
228 | if (l == &limits_tbl[ARRAY_SIZE(limits_tbl)]) { | ||
229 | /* bad option. getopt already complained. */ | ||
230 | break; | ||
231 | } | ||
232 | |||
233 | } /* while (there are options) */ | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | #endif | ||
diff --git a/shell/shell_common.c b/shell/shell_common.c index e9effd2d0..0b9d4ebe6 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c | |||
@@ -330,6 +330,13 @@ static const char ulimit_opt_string[] = "-HSa" | |||
330 | #endif | 330 | #endif |
331 | ; | 331 | ; |
332 | 332 | ||
333 | #if ENABLE_PLATFORM_MINGW32 | ||
334 | int FAST_FUNC | ||
335 | shell_builtin_ulimit(char **argv) | ||
336 | { | ||
337 | return 1; | ||
338 | } | ||
339 | #else | ||
333 | static void printlim(unsigned opts, const struct rlimit *limit, | 340 | static void printlim(unsigned opts, const struct rlimit *limit, |
334 | const struct limits *l) | 341 | const struct limits *l) |
335 | { | 342 | { |
@@ -458,3 +465,4 @@ shell_builtin_ulimit(char **argv) | |||
458 | 465 | ||
459 | return 0; | 466 | return 0; |
460 | } | 467 | } |
468 | #endif | ||