aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c1140
-rw-r--r--shell/builtin_ulimit.c237
-rw-r--r--shell/shell_common.c8
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
206struct forkshell;
207union node;
208struct strlist;
209struct job;
210
211typedef void (*forkpoint_fn)(struct forkshell *fs);
212struct 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};
236static void sticky_free(void *p);
237#define free(p) sticky_free(p)
238static 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
889opentrace(void) 938opentrace(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)
2493static const char * 2563static const char *
2494updatepwd(const char *dir) 2564updatepwd(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
4063HANDLE hSIGINT; /* Ctrl-C is pressed */
4064
4065static 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 */
4078static pid_t
4079waitpid_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
3896static int 4133static int
3897dowait(int wait_flags, struct job *job) 4134dowait(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
4774forkparent(struct job *jp, union node *n, int mode, pid_t pid) 5020forkparent(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 */
5016static void expandhere(union node *arg, int fd); 5265static void expandhere(union node *arg, int fd);
5266#if ENABLE_PLATFORM_MINGW32
5267static void
5268forkshell_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
5017static int 5293static int
5018openhere(union node *redir) 5294openhere(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 */
5787static void evaltree(union node *, int); 6114static void evaltree(union node *, int);
5788 6115
6116#if ENABLE_PLATFORM_MINGW32
6117static void
6118forkshell_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
5789static void FAST_FUNC 6135static void FAST_FUNC
5790evalbackcmd(union node *n, struct backcmd *result) 6136evalbackcmd(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 */
7909static int funcstringsize; /* size of strings in node */ 8264static int funcstringsize; /* size of strings in node */
7910static void *funcblock; /* block to allocate function from */ 8265static void *funcblock; /* block to allocate function from */
7911static char *funcstring; /* block to allocate strings from */ 8266static char *funcstring; /* block to allocate strings from */
8267#if ENABLE_PLATFORM_MINGW32
8268static int nodeptrsize;
8269static 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
8043static char * 8416static char *
8044nodeckstrdup(char *s) 8417nodeckstrdup(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
8053static union node *copynode(union node *); 8428static 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
8055static struct nodelist * 8442static struct nodelist *
8056copynodelist(struct nodelist *lp) 8443copynodelist(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
8940static void
8941forkshell_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
8537static void 8955static void
8538evalsubshell(union node *n, int flags) 8956evalsubshell(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
9053static void
9054forkshell_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
8625static void 9077static void
8626evalpipe(union node *n, int flags) 9078evalpipe(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
9585static void
9586forkshell_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
9119static void 9597static void
9120evalcommand(union node *cmd, int flags) 9598evalcommand(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
12596static const unsigned char timescmd_str[] ALIGN1 = { 13128static 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
13160static int FAST_FUNC
13161timescmd(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];
12971extern int etext(); 13538extern int etext();
12972#endif 13539#endif
12973 13540
13541#if ENABLE_PLATFORM_MINGW32
13542static const forkpoint_fn forkpoints[] = {
13543 forkshell_openhere,
13544 forkshell_evalbackcmd,
13545 forkshell_evalsubshell,
13546 forkshell_evalpipe,
13547 forkshell_shellexec,
13548 NULL
13549};
13550
13551static struct forkshell* forkshell_prepare(struct forkshell *fs);
13552static 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() */
13712static int
13713spawn_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) \
13748static void \
13749name(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) \
13761static type * \
13762name(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 */
13783SLIST_SIZE_BEGIN(var_size,struct var)
13784funcstringsize += strlen(p->var_text) + 1;
13785nodeptrsize++; /* p->text */
13786SLIST_SIZE_END()
13787
13788SLIST_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;
13796SAVE_PTR((*vpp)->var_text);
13797SLIST_COPY_END()
13798
13799/*
13800 * struct localvar
13801 */
13802SLIST_SIZE_BEGIN(localvar_size,struct localvar)
13803var_size(p->vp);
13804funcstringsize += strlen(p->text) + 1;
13805nodeptrsize += 2; /* p->vp, p->text */
13806SLIST_SIZE_END()
13807
13808SLIST_COPY_BEGIN(localvar_copy,struct localvar)
13809(*vpp)->text = nodeckstrdup(vp->text);
13810(*vpp)->flags = vp->flags;
13811(*vpp)->vp = var_copy(vp->vp);
13812SAVE_PTR2((*vpp)->vp, (*vpp)->text);
13813SLIST_COPY_END()
13814
13815/*
13816 * struct strlist
13817 */
13818SLIST_SIZE_BEGIN(strlist_size,struct strlist)
13819funcstringsize += strlen(p->text) + 1;
13820nodeptrsize++; /* p->text */
13821SLIST_SIZE_END()
13822
13823SLIST_COPY_BEGIN(strlist_copy,struct strlist)
13824(*vpp)->text = nodeckstrdup(vp->text);
13825SAVE_PTR((*vpp)->text);
13826SLIST_COPY_END()
13827
13828/*
13829 * struct tblentry
13830 */
13831static void
13832tblentry_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
13847static struct tblentry *
13848tblentry_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
13883static void
13884cmdtable_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
13893static struct tblentry **
13894cmdtable_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 */
13910static void
13911argv_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
13922static char **
13923argv_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 */
13944static void
13945redirtab_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
13954static struct redirtab *
13955redirtab_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
13978static void
13979globals_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
13995static struct globals_var *
13996globals_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
14036static void
14037globals_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
14049static struct globals_misc *
14050globals_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
14065static void
14066forkshell_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
14084static struct forkshell *
14085forkshell_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
14108static struct forkshell *
14109forkshell_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
14163static void *sticky_mem_start, *sticky_mem_end;
14164static void
14165forkshell_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
14222static void
14223sticky_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
21int FAST_FUNC shell_builtin_ulimit(char **argv)
22{
23 return 1;
24}
25#else
26
27#include "builtin_ulimit.h"
28
29
30struct 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
37static 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
73enum {
74 OPT_hard = (1 << 0),
75 OPT_soft = (1 << 1),
76};
77
78/* "-": treat args as parameters of option with ASCII code 1 */
79static 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
115static 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
132int 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
334int FAST_FUNC
335shell_builtin_ulimit(char **argv)
336{
337 return 1;
338}
339#else
333static void printlim(unsigned opts, const struct rlimit *limit, 340static 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