summaryrefslogtreecommitdiff
path: root/newlib/libc/sys/go32/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'newlib/libc/sys/go32/exec.c')
-rw-r--r--newlib/libc/sys/go32/exec.c509
1 files changed, 509 insertions, 0 deletions
diff --git a/newlib/libc/sys/go32/exec.c b/newlib/libc/sys/go32/exec.c
new file mode 100644
index 00000000000..004666c719d
--- /dev/null
+++ b/newlib/libc/sys/go32/exec.c
@@ -0,0 +1,509 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "go32.h"
+#include "dpmi.h"
+/*#include "process.h"*/
+#if 1
+#define P_WAIT 1
+#define P_NOWAIT 2 /* always generates error */
+#define P_OVERLAY 3
+#endif
+extern const char **environ;
+#define environ ((const char **)environ)
+
+#define scan_ptr() \
+ char const **ptr; \
+ for (ptr = &argv0; *ptr; ptr++); \
+ ptr = (char const **)(*++ptr);
+
+int execl(const char *path, const char *argv0, ...)
+{
+ return spawnve(P_OVERLAY, path, &argv0, environ);
+}
+
+int execle(const char *path, const char *argv0, ... /*, const char **envp */)
+{
+ scan_ptr();
+ return spawnve(P_OVERLAY, path, &argv0, ptr);
+}
+
+int execlp(const char *path, const char *argv0, ...)
+{
+ return spawnvpe(P_OVERLAY, path, &argv0, environ);
+}
+
+int execlpe(const char *path, const char *argv0, ... /*, const char **envp */)
+{
+ scan_ptr();
+ return spawnvpe(P_OVERLAY, path, &argv0, ptr);
+}
+
+/*-------------------------------------------------*/
+
+int execv(const char *path, const char **argv)
+{
+ return spawnve(P_OVERLAY, path, argv, environ);
+}
+
+int execve(const char *path, const char **argv, const char **envp)
+{
+ return spawnve(P_OVERLAY, path, argv, envp);
+}
+
+int execvp(const char *path, const char **argv)
+{
+ return spawnvpe(P_OVERLAY, path, argv, environ);
+}
+
+int execvpe(const char *path, const char **argv, const char **envp)
+{
+ return spawnvpe(P_OVERLAY, path, argv, envp);
+}
+
+/*-------------------------------------------------*/
+
+int spawnl(int mode, const char *path, const char *argv0, ...)
+{
+ return spawnve(mode, path, &argv0, environ);
+}
+
+int spawnle(int mode, const char *path, const char *argv0, ... /*, const char **envp */)
+{
+ scan_ptr();
+ return spawnve(mode, path, &argv0, ptr);
+}
+
+int spawnlp(int mode, const char *path, const char *argv0, ...)
+{
+ return spawnvpe(mode, path, &argv0, environ);
+}
+
+int spawnlpe(int mode, const char *path, const char *argv0, ... /*, const char **envp */)
+{
+ scan_ptr();
+ return spawnvpe(mode, path, &argv0, ptr);
+}
+
+/*-------------------------------------------------*/
+
+typedef struct {
+ u_short eseg;
+ u_short argoff;
+ u_short argseg;
+ u_short fcb1_off;
+ u_short fcb1_seg;
+ u_short fcb2_off;
+ u_short fcb2_seg;
+} Execp;
+
+static Execp parm;
+
+static u_long tbuf;
+
+static u_long talloc(size_t amt)
+{
+ u_long rv = tbuf;
+ tbuf += amt;
+ return rv;
+}
+
+static int direct_exec_tail(const char *program, const char *args, const char **envp)
+{
+ _go32_dpmi_registers r;
+ u_long program_la;
+ u_long arg_la;
+ u_long parm_la;
+ u_long env_la, env_e_la;
+ char arg_header[3];
+ int i;
+
+ program_la = talloc(strlen(program)+1);
+ arg_la = talloc(strlen(args)+3);
+ parm_la = talloc(sizeof(Execp));
+
+ dosmemput(program, strlen(program)+1, program_la);
+
+ arg_header[0] = strlen(args);
+ arg_header[1] = '\r';
+ dosmemput(arg_header, 1, arg_la);
+ dosmemput(args, strlen(args), arg_la+1);
+ dosmemput(arg_header+1, 1, arg_la+1+strlen(args));
+
+ do {
+ env_la = talloc(1);
+ } while (env_la & 15);
+ talloc(-1);
+ for (i=0; envp[i]; i++)
+ {
+ env_e_la = talloc(strlen(envp[i])+1);
+ dosmemput(envp[i], strlen(envp[i])+1, env_e_la);
+ }
+ arg_header[0] = 0;
+ arg_header[1] = 1;
+ arg_header[2] = 0;
+ dosmemput(arg_header, 3, talloc(3));
+ env_e_la = talloc(strlen(program)+1);
+ dosmemput(program, strlen(program)+1, env_e_la);
+
+ parm.eseg = env_la / 16;
+ parm.argseg = arg_la / 16;
+ parm.argoff = arg_la & 15;
+ dosmemput(&parm, sizeof(parm), parm_la);
+
+ memset(&r, 0, sizeof(r));
+ r.x.ax = 0x4b00;
+ r.x.ds = program_la / 16;
+ r.x.dx = program_la & 15;
+ r.x.es = parm_la / 16;
+ r.x.bx = parm_la & 15;
+ _go32_dpmi_simulate_int(0x21, &r);
+ if (r.x.flags & 1)
+ {
+ errno = r.x.ax;
+ return -1;
+ }
+
+ memset(&r, 0, sizeof(r));
+ r.h.ah = 0x4d;
+ _go32_dpmi_simulate_int(0x21, &r);
+
+ if (r.x.flags & 1)
+ {
+ errno = r.x.ax;
+ return -1;
+ }
+ return r.x.ax;
+}
+
+static int direct_exec(const char *program, const char **argv, const char **envp)
+{
+ int i, arglen;
+ char *args, *argp;
+
+ tbuf = _go32_info_block.linear_address_of_transfer_buffer;
+
+ arglen = 0;
+ for (i=1; argv[i]; i++)
+ arglen += strlen(argv[i]) + 1;
+ args = (char *)malloc(arglen+1);
+ argp = args;
+ for (i=1; argv[i]; i++)
+ {
+ const char *p = argv[i];
+ if (argp - args > 125)
+ break;
+ *argp++ = ' ';
+ while (*p)
+ {
+ if (argp - args > 125)
+ break;
+ *argp++ = *p++;
+ }
+ }
+ *argp = 0;
+
+ return direct_exec_tail(program, args, envp);
+}
+
+typedef struct {
+ char magic[16];
+ int struct_length;
+ char go32[16];
+} StubInfo;
+#define STUB_INFO_MAGIC "StubInfoMagic!!"
+
+static int go32_exec(const char *program, const char **argv, const char **envp)
+{
+ int is_stubbed = 0;
+ int found_si = 0;
+ StubInfo si;
+ unsigned short header[3];
+ int pf, has_dot, i;
+ char *go32, *sip;
+ const char *pp, *pe;
+ char rpath[80], *rp;
+ int stub_offset, argc;
+
+ int si_la, rm_la, rm_seg;
+ short *rm_argv;
+ char cmdline[34];
+
+ pf = open(program, O_RDONLY|O_BINARY);
+
+ read(pf, header, sizeof(header));
+ if (header[0] == 0x010b || header[0] == 0x014c)
+ {
+ is_stubbed = 1;
+ }
+ else if (header[0] == 0x5a4d)
+ {
+ int header_offset = (long)header[2]*512L;
+ if (header[1])
+ header_offset += (long)header[1] - 512L;
+ lseek(pf, header_offset - 4, 0);
+ read(pf, &stub_offset, 4);
+ header[0] = 0;
+ read(pf, header, sizeof(header));
+ if (header[0] == 0x010b)
+ is_stubbed = 1;
+ if (header[0] == 0x014c)
+ is_stubbed = 1;
+ lseek(pf, stub_offset, 0);
+ read(pf, &si, sizeof(si));
+ if (memcmp(STUB_INFO_MAGIC, si.magic, 16) == 0)
+ found_si = 1;
+ }
+ if (!is_stubbed)
+ {
+ close(pf);
+ return direct_exec(program, argv, envp);
+ }
+
+ if (found_si)
+ go32 = si.go32;
+ else
+ go32 = "go32.exe";
+ has_dot = 0;
+ for (i=0; go32[i]; i++)
+ if (go32[i] == '.')
+ has_dot = 1;
+ if (!has_dot)
+ strcpy(go32+i, ".exe");
+ for (i=0; envp[i]; i++)
+ if (strncmp(envp[i], "PATH=", 5) == 0)
+ pp = envp[i]+5;
+ strcpy(rpath, go32);
+ while (access(rpath, 0))
+ {
+ char *ptr;
+ rp = rpath;
+ for (pe=pp; *pe && *pe != ';'; pe++)
+ *rp++ = *pe;
+ pp = pe+1;
+ if (rp > rpath && rp[-1] != '/' && rp[-1] != '\\' && rp[-1] != ':')
+ *rp++ = '/';
+ for (ptr = go32; *ptr; ptr++)
+ *rp++ = *ptr;
+ *rp = 0;
+ if (access(rpath, 0) == 0)
+ break;
+ if (*pe == 0)
+ return direct_exec(program, argv, envp); /* give up and just run it */
+ }
+
+ if (found_si)
+ {
+ lseek(pf, stub_offset, 0);
+ sip = (char *)malloc(si.struct_length);
+ read(pf, sip, si.struct_length);
+ }
+ close(pf);
+
+ argv[0] = program; /* since that's where we really found it */
+
+ tbuf = _go32_info_block.linear_address_of_transfer_buffer;
+
+ if (found_si)
+ {
+ si_la = talloc(si.struct_length);
+ dosmemput(sip, si.struct_length, si_la);
+ free(sip);
+ }
+
+ for (argc=0; argv[argc]; argc++);
+ rm_la = talloc(2*(argc+1));
+ rm_seg = (_go32_info_block.linear_address_of_transfer_buffer >> 4) & 0xffff;
+ rm_argv = (short *)malloc((argc+1) * sizeof(short));
+ for (i=0; i<argc; i++)
+ {
+ int sl = strlen(argv[i]) + 1;
+ int q = talloc(sl);
+ dosmemput(argv[i], sl, q);
+ rm_argv[i] = (q - (rm_seg<<4)) & 0xffff;
+ }
+ rm_argv[i] = 0;
+ dosmemput(rm_argv, 2*(argc+1), rm_la);
+
+ sprintf(cmdline, " !proxy %04x %04x %04x %04x %04x",
+ argc, rm_seg, (rm_la - (rm_seg<<4))&0xffff,
+ rm_seg, (si_la - (rm_seg<<4))&0xffff);
+ if (!found_si)
+ cmdline[22] = 0; /* remove stub information */
+
+ return direct_exec_tail(rpath, cmdline, envp);
+}
+
+static int command_exec(const char *program, const char **argv, const char **envp)
+{
+ const char *comspec=0;
+ char *cmdline;
+ char *newargs[3];
+ int cmdlen;
+ int i;
+
+ cmdlen = strlen(program) + 4;
+ for (i=0; argv[i]; i++)
+ cmdlen += strlen(argv[i]) + 1;
+ cmdline = (char *)malloc(cmdlen);
+
+ strcpy(cmdline, "/c ");
+ for (i=0; program[i]; i++)
+ {
+ if (program[i] == '/')
+ cmdline[i+3] = '\\';
+ else
+ cmdline[i+3] = program[i];
+ }
+ cmdline[i+3] = 0;
+ for (i=1; argv[i]; i++)
+ {
+ strcat(cmdline, " ");
+ strcat(cmdline, argv[i]);
+ }
+ for (i=0; envp[i]; i++)
+ if (strncmp(envp[i], "COMSPEC=", 8) == 0)
+ comspec = envp[i]+8;
+ if (!comspec)
+ for (i=0; environ[i]; i++)
+ if (strncmp(environ[i], "COMSPEC=", 8) == 0)
+ comspec = environ[i]+8;
+ if (!comspec)
+ comspec = "c:/command.com";
+ newargs[0] = comspec;
+ newargs[1] = cmdline;
+ newargs[2] = 0;
+ i = direct_exec(comspec, (const char **)newargs, envp);
+ free(cmdline);
+ return i;
+}
+
+static int script_exec(const char *program, const char **argv, const char **envp)
+{
+ return go32_exec(program, argv, envp);
+}
+
+static struct {
+ char *extension;
+ int (*interp)(const char *, const char **, const char **);
+} interpreters[] = {
+ { ".com", direct_exec },
+ { ".exe", go32_exec },
+ { ".bat", command_exec },
+ { 0, script_exec }
+};
+#define INTERP_NO_EXT 3
+
+int spawnv(int mode, const char *path, const char **argv)
+{
+ return spawnve(mode, path, argv, environ);
+}
+
+int spawnve(int mode, const char *path, const char **argv, const char **envp)
+{
+ /* This is the one that does the work! */
+ int i = -1;
+ char rpath[80], *rp, *rd=0;
+ fflush(stdout); /* just in case */
+ for (rp=rpath; *path; *rp++ = *path++)
+ {
+ if (*path == '.')
+ rd = rp;
+ if (*path == '\\' || *path == '/')
+ rd = 0;
+ }
+ *rp = 0;
+ if (rd)
+ {
+ for (i=0; interpreters[i].extension; i++)
+ if (strcasecmp(rd, interpreters[i].extension) == 0)
+ break;
+ }
+ while (access(rpath, 0))
+ {
+ i++;
+ if (interpreters[i].extension == 0 || rd)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+ strcpy(rp, interpreters[i].extension);
+ }
+ if (i == -1)
+ i = INTERP_NO_EXT;
+ i = interpreters[i].interp(rpath, argv, envp);
+ if (mode == P_OVERLAY)
+ exit(i);
+ return i;
+}
+
+int spawnvp(int mode, const char *path, const char **argv)
+{
+ return spawnvpe(mode, path, argv, environ);
+}
+
+int spawnvpe(int mode, const char *path, const char **argv, const char **envp)
+{
+ const char *pp, *pe, *ptr;
+ char rpath[80], *rp, *rd;
+ int hasdot = 0, i, tried_dot = 0;
+
+ for (ptr=path; *ptr; ptr++)
+ {
+ if (*ptr == '.')
+ hasdot = 1;
+ if (*ptr == '/' || *ptr == '\\' || *ptr == ':')
+ return spawnve(mode, path, argv, envp);
+ }
+
+ pp = 0;
+ for (i=0; envp[i]; i++)
+ if (strncmp(envp[i], "PATH=", 5) == 0)
+ pp = envp[i] + 5;
+ if (pp == 0)
+ return spawnve(mode, path, argv, envp);
+
+ while (1)
+ {
+ if (!tried_dot)
+ {
+ rp = rpath;
+ pe = pp;
+ tried_dot = 1;
+ }
+ else
+ {
+ rp = rpath;
+ for (pe = pp; *pe && *pe != ';'; pe++)
+ *rp++ = *pe;
+ pp = pe+1;
+ if (rp > rpath && rp[-1] != '/' && rp[-1] != '\\' && rp[-1] != ':')
+ *rp++ = '/';
+ }
+ for (ptr = path; *ptr; ptr++)
+ *rp++ = *ptr;
+ *rp = 0;
+
+ if (hasdot)
+ {
+ if (access(rpath, 0) == 0)
+ return spawnve(mode, rpath, argv, envp);
+ }
+ else
+ {
+ for (i=0; interpreters[i].extension; i++)
+ {
+ strcpy(rp, interpreters[i].extension);
+ if (access(rpath, 0) == 0)
+ return spawnve(mode, rpath, argv, envp);
+ }
+ }
+ if (*pe == 0)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+ }
+}