510 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			510 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
| #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;
 | |
|     }
 | |
|   }
 | |
| }
 |