home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2 / DJLSR201.ZIP / src / libc / dos / process / dosexec.c next >
Encoding:
C/C++ Source or Header  |  1996-10-05  |  30.0 KB  |  1,128 lines

  1. /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
  2. /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  3. #include <libc/stubs.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <errno.h>
  8. #include <signal.h>
  9. #include <limits.h>
  10. #include <fcntl.h>
  11. #include <unistd.h>
  12. #include <process.h>
  13. #include <go32.h>
  14. #include <dpmi.h>
  15. #include <ctype.h>
  16. #include <sys/movedata.h>
  17. #include <libc/dosexec.h>
  18. #include <libc/unconst.h>
  19. #include <libc/dosio.h>
  20. #include <libc/farptrgs.h>
  21.  
  22. /* FIXME: this is not LFN-clean.  Win95 has a way to
  23.    pass long command lines, but we don't support it here.  */
  24. #define CMDLEN_LIMIT 125
  25.  
  26. extern char **environ;
  27.  
  28. int __dosexec_in_system = 0;
  29.  
  30. typedef struct {
  31.   unsigned short eseg;
  32.   unsigned short argoff;
  33.   unsigned short argseg;
  34.   unsigned short fcb1_off;
  35.   unsigned short fcb1_seg;
  36.   unsigned short fcb2_off;
  37.   unsigned short fcb2_seg;
  38. } Execp;
  39.  
  40. static Execp parm;
  41.  
  42. static unsigned long tbuf_ptr;
  43. static unsigned long tbuf_beg;
  44. static unsigned long tbuf_end;
  45. static unsigned long tbuf_len;
  46. #if 0
  47. static int         tbuf_selector;
  48. #endif
  49.  
  50. static int script_exec(const char *, char **, char **);
  51.  
  52. /* Allocate AMT bytes off the transfer buffer.  */
  53. static unsigned long talloc(size_t amt)
  54. {
  55.   unsigned long rv = tbuf_ptr;
  56.   tbuf_ptr += amt;
  57.   return rv;
  58. }
  59.  
  60. /* Make sure we can allocate AMT bytes off the transfer buffer
  61.    without overflowing it.  Return non-zero if we can, zero otherwise.
  62.  
  63.    WARNING: This can relocate the data already in the transfer buffer,
  64.         so all linear addresses which use it should be relative to
  65.         TBUF_BEG!  */
  66. static int check_talloc(size_t amt)
  67. {
  68.   int retval = 1;
  69.  
  70.   if (tbuf_ptr + amt > tbuf_end)
  71.   {
  72. #if 0
  73.     /* Code that reallocs the transfer buffer; currently disabled.  */
  74.     unsigned long new_tb;
  75.     unsigned long min_len = tbuf_len + amt;
  76.     unsigned long max_len = 0x10000; /* 64KB */
  77.     int old_selector = tbuf_selector;
  78.     int max_avail;
  79.     int e = errno;
  80.  
  81.     errno = E2BIG;
  82.  
  83.     /* Try to allocate new, larger DOS buffer, upto 64KB.  */
  84.     if (min_len > max_len)
  85.     {
  86.       retval = 0;
  87.       goto done;
  88.     }
  89.     while (tbuf_len <= max_len && tbuf_len < min_len)
  90.       tbuf_len *= 2;
  91.     if (tbuf_len < min_len)
  92.     {
  93.       retval = 0;
  94.       goto done;
  95.     }
  96.  
  97.     tbuf_len = (tbuf_len + 15) & 0xffff0; /* round to nearest paragraph */
  98.  
  99.     if ((new_tb =
  100.      __dpmi_allocate_dos_memory(tbuf_len/16, &max_avail)) == -1)
  101.     {
  102.       if (max_avail*16 < min_len
  103.       || (new_tb =
  104.           __dpmi_allocate_dos_memory(max_avail, &tbuf_selector)) == -1)
  105.       {
  106.     retval = 0;
  107.     goto done;
  108.       }
  109.       tbuf_len = max_avail*16;
  110.     }
  111.     else
  112.       tbuf_selector = max_avail;
  113.  
  114.     new_tb *= 16;  /* convert to linear address */
  115.     movedata (_dos_ds, tbuf_beg, _dos_ds, new_tb, tbuf_ptr - tbuf_beg);
  116.     tbuf_ptr = new_tb + tbuf_ptr - tbuf_beg;
  117.     tbuf_beg = new_tb;
  118.     tbuf_end = tbuf_beg + tbuf_len - 1;
  119.  
  120.     errno = e;
  121.  
  122.   done:
  123.     /* Assume caller will return immediately in case of
  124.        failure to reallocate, so they won't need the old data.  */
  125.     if (!retval)
  126.       tbuf_selector = 0;
  127.     if (old_selector)
  128.       __dpmi_free_dos_memory(old_selector);
  129. #else
  130.     errno = E2BIG;
  131.     retval = 0;
  132. #endif
  133.   }
  134.  
  135.   return retval;
  136. }
  137.  
  138. extern char   __PROXY[];    /* defined on crt0/crt1.c */
  139. extern size_t __PROXY_LEN;
  140.  
  141. /* Functions that call `direct_exec_tail' after they've put
  142.    some data into the transfer buffer, should set LFN parameter
  143.    to either 0 (no LFN support) or 1 (LFN supported), but NOT 2!
  144.    if LFN is 2, there is a possiblity that the contents of the
  145.    transfer buffer will be overrun!  */
  146. static int
  147. direct_exec_tail(const char *program, const char *args,
  148.          char * const envp[], const char *proxy, int lfn)
  149. {
  150.   __dpmi_regs r;
  151.   unsigned long program_la;
  152.   unsigned long arg_la;
  153.   unsigned long parm_la;
  154.   unsigned long env_la, env_e_la;
  155.   size_t proxy_len = proxy ? strlen(proxy)+1 : 0;
  156.   int seen_proxy = 0;
  157.   char arg_header[3];
  158.   char short_name[FILENAME_MAX];
  159.   const char *progname;
  160.   unsigned proglen;
  161.   int i;
  162.   unsigned long fcb1_la, fcb2_la, fname_la;
  163.   
  164.   sync();
  165.  
  166.   if (lfn == 2)        /* don't know yet */
  167.     lfn = _USE_LFN;
  168.  
  169.   /* The pathname of the executable to run.  */
  170.   proglen = strlen(program)+1;
  171.   if (!check_talloc(proglen))
  172.     return -1;
  173.   if(lfn) {
  174.     dosmemput(program, proglen, tbuf_ptr);
  175.     r.x.ax = 0x7160;            /* Truename */
  176.     r.x.cx = 1;                /* Get short name */
  177.     r.x.ds = r.x.es = tbuf_ptr / 16;
  178.     r.x.si = r.x.di = tbuf_ptr & 15;
  179.     __dpmi_int(0x21, &r);
  180.     if (r.x.flags & 1)
  181.     {
  182.       errno = __doserr_to_errno(r.x.ax);
  183.       return -1;
  184.     }
  185.     dosmemget(tbuf_ptr, FILENAME_MAX, short_name);
  186.     progname = short_name;
  187.     proglen = strlen(short_name)+1;
  188.   } else
  189.     progname = program;
  190.  
  191.   if (!check_talloc(proglen + strlen(args) + 3 + sizeof(Execp) + 48))
  192.     return -1;
  193.   program_la = talloc(proglen);
  194.   arg_la     = talloc(strlen(args)+3);
  195.   parm_la    = talloc(sizeof(Execp));
  196.  
  197.   dosmemput(progname, proglen, program_la);
  198.  
  199.   /* The command-line tail.  */
  200.   arg_header[0] = strlen(args);
  201.   arg_header[1] = '\r';
  202.   dosmemput(arg_header, 1, arg_la);
  203.   dosmemput(args, strlen(args), arg_la+1);
  204.   dosmemput(arg_header+1, 1, arg_la+1+strlen(args));
  205.  
  206.   /* The 2 FCBs.  Some programs (like XCOPY from DOS 6.x) need them.  */
  207.   fcb1_la = talloc(16);           /* allocate space for 1st FCB */
  208.   fname_la = arg_la + 1;       /* first character of command tail */
  209.   r.x.ax = 0x2901;           /* AL = 1 means skip leading separators */
  210.   r.x.ds = fname_la / 16;      /* pointer to 1st cmd argument */
  211.   r.x.si = fname_la & 15;
  212.   r.x.es = fcb1_la / 16;       /* pointer to FCB buffer */
  213.   r.x.di = fcb1_la & 15;
  214.   __dpmi_int (0x21, &r);
  215.  
  216.   /* We cannot be sure that Int 21h/AX=2901h parsed the entire
  217.      first command-line argument (it might not be a filename
  218.      at all!).  We need to get to the next command-line arg
  219.      before calling 2901 again.  2901 returns the pointer to
  220.      first unparsed character in DS:SI.
  221.  
  222.      Note that, in case there is no second command-line argument,
  223.      the following loop is terminated by the trailing CR which
  224.      ends the command-line tail.  */
  225.   for (_farsetsel(_dos_ds), fname_la = ((unsigned)r.x.ds) * 16 + r.x.si;
  226.        !isspace(_farnspeekb(fname_la));
  227.        fname_la++)
  228.     ;
  229.  
  230.   fcb2_la = talloc(16);
  231.   r.x.ax = 0x2901;
  232.   r.x.ds = fname_la / 16;      /* begin parsing 2nd arg from here */
  233.   r.x.si = fname_la & 15;
  234.   r.x.es = fcb2_la / 16;
  235.   r.x.di = fcb2_la & 15;
  236.   __dpmi_int (0x21, &r);
  237.  
  238.   /* The environment must be on a segment boundary, so get
  239.      to the first location in the transfer buffer whose
  240.      linear address is divisable by 16.  */
  241.   do {
  242.     env_la = talloc(1);
  243.   } while (env_la & 15);
  244.   talloc(-1);
  245.  
  246. #if 0
  247.   /* Convert to relative, since `check_talloc' may relocate.  */
  248.   arg_la  -= tbuf_beg;
  249.   env_la  -= tbuf_beg;
  250.   fcb1_la -= tbuf_beg;
  251.   fcb2_la -= tbuf_beg;
  252.   parm_la -= tbuf_beg;
  253.   program_la -= tbuf_beg;
  254. #endif
  255.  
  256.   /* The environment.  Replace the !proxy variable, if there is
  257.      one (for nested programs) if we are called from `system',
  258.      or skip it, if we are called from `spawnXX'.  */
  259.   for (i=0; envp[i]; i++)
  260.   {
  261.     const char *ep = envp[i];
  262.     size_t env_len = strlen(ep)+1;
  263.  
  264.     if (strncmp(ep, __PROXY, __PROXY_LEN) == 0 && ep[__PROXY_LEN] == '=')
  265.     {
  266.       seen_proxy = 1;
  267.       if (proxy)
  268.       {
  269.     ep = proxy;
  270.     env_len = proxy_len;
  271.       }
  272.       else
  273.     continue;
  274.     }
  275.     if (!check_talloc(env_len))
  276.       return -1;
  277.     env_e_la = talloc(env_len);
  278.     dosmemput(ep, env_len, env_e_la);
  279.   }
  280.  
  281.   /* If no !proxy variable was found, create one.  */
  282.   if (proxy && !seen_proxy)
  283.   {
  284.     if (!check_talloc(proxy_len))
  285.       return -1;
  286.     env_e_la = talloc(proxy_len);
  287.     dosmemput(proxy, proxy_len, env_e_la);
  288.   }
  289.  
  290.   /* Terminate by an extra NULL char.  */
  291.   arg_header[0] = 0;
  292.  
  293.   /* The name of the program that owns the environment.  */
  294.   arg_header[1] = 1;    /* the number of strings (1, little-endian) */
  295.   arg_header[2] = 0;
  296.   if (!check_talloc(3 + proglen))
  297.     return -1;
  298.   dosmemput(arg_header, 3, talloc(3));
  299.   env_e_la = talloc(proglen);
  300.   dosmemput(progname, proglen, env_e_la);
  301.  
  302.   /* Prepare the parameter block and call Int 21h/AX=4B00h.  */
  303. #if 0
  304.   arg_la  += tbuf_beg;
  305.   env_la  += tbuf_beg;
  306.   fcb1_la += tbuf_beg;
  307.   fcb2_la += tbuf_beg;
  308.   parm_la += tbuf_beg;
  309.   program_la += tbuf_beg;
  310. #endif
  311.   parm.eseg     = env_la / 16;
  312.   parm.argseg    = arg_la / 16;
  313.   parm.argoff    = arg_la & 15;
  314.   parm.fcb1_seg = fcb1_la / 16;
  315.   parm.fcb1_off = fcb1_la & 15;
  316.   parm.fcb2_seg = fcb2_la / 16;
  317.   parm.fcb2_off = fcb2_la & 15;
  318.   dosmemput(&parm, sizeof(parm), parm_la);
  319.  
  320.   r.x.ax = 0x4b00;
  321.   r.x.ds = program_la / 16;
  322.   r.x.dx = program_la & 15;
  323.   r.x.es = parm_la / 16;
  324.   r.x.bx = parm_la & 15;
  325.   __dpmi_int(0x21, &r);
  326. #if 0
  327.   if (tbuf_selector)
  328.     __dpmi_free_dos_memory (tbuf_selector);
  329.   tbuf_selector = 0;
  330. #endif
  331.   if (r.x.flags & 1)
  332.   {
  333.     errno = __doserr_to_errno(r.x.ax);
  334.     return -1;
  335.   }
  336.   
  337.   r.h.ah = 0x4d;
  338.   __dpmi_int(0x21, &r);
  339.   
  340.   if (r.x.flags & 1)
  341.   {
  342.     errno = __doserr_to_errno(r.x.ax);
  343.     return -1;
  344.   }
  345.  
  346.   /* AH holds the ``system exit code'' which is non-zero if the
  347.      child was aborted by Ctrl-C, or Critical Device error (also
  348.      if the child installs itself as a TSR).  */
  349.   if (r.h.ah && r.h.ah != 3) /* 3 means it exited as TSR (is it ``normal''?) */
  350.     {
  351.       errno = EINTR;    /* what else can we put in `errno'? */
  352.       return ( ((r.h.ah == 1 ? SIGINT : SIGABRT) << 8) | r.h.al );
  353.     }
  354.   return r.h.al;    /* AL holds the child exit code */
  355. }
  356.  
  357. int
  358. _dos_exec(const char *program, const char *args, char * const envp[])
  359. {
  360.   tbuf_beg = tbuf_ptr = __tb;
  361.   tbuf_len = _go32_info_block.size_of_transfer_buffer;
  362.   tbuf_end = tbuf_beg + tbuf_len - 1;
  363.   return direct_exec_tail(program, args, envp, 0, 2);
  364. }
  365.  
  366. static char GO32_V2_STRING[] = "go32-v2.exe";
  367. static char GO32_STRING[]    = "go32.exe";
  368.  
  369. /* A list of known shells which require we DON'T quote command
  370.    lines that are passed to them with the /c or -c switch.  */
  371. static const char *shell_brokets[] = {
  372.   "COMMAND.COM",
  373.   "4DOS.COM",
  374.   "NDOS.COM",
  375.   0
  376. };
  377.  
  378. /* A list of Unix-like shells and other non-DJGPP programs
  379.    which treat single quote specially.  */
  380. static const char *unix_shells[] = {
  381.   "SH.EXE",
  382.   "SH16.EXE",
  383.   "SH32.EXE",
  384.   "TCSH.EXE",
  385.   "BASH.EXE",
  386.   0
  387. };
  388.  
  389. static int
  390. list_member (const char *program, const char *program_list[])
  391. {
  392.   const char *p = program, *ptail = program;
  393.   int i;
  394.  
  395.   while (*p)
  396.   {
  397.     if (*p == '/' || *p == ':' || *p == '\\')
  398.       ptail = p + 1;
  399.     p++;
  400.   }
  401.  
  402.   for (i = 0; program_list[i]; i++)
  403.     if (!stricmp (ptail, program_list[i]))
  404.       return 1;
  405.  
  406.   return 0;
  407. }
  408.  
  409. int
  410. _is_unixy_shell (const char *shellpath)
  411. {
  412.   return list_member (shellpath, unix_shells);
  413. }
  414.  
  415. int
  416. _is_dos_shell (const char *shellpath)
  417. {
  418.   return list_member (shellpath, shell_brokets);
  419. }
  420.  
  421. static int direct_exec(const char *program, char **argv, char **envp)
  422. {
  423.   int i, arglen;
  424.   char *args, *argp;
  425.   int need_quote = !__dosexec_in_system;
  426.   int unescape_quote = __dosexec_in_system;
  427.  
  428.   /* PROGRAM can be a shell which expects a single argument
  429.      (beyond the /c or -c switch) that is the entire command
  430.      line.  With some shells, we must NOT quote that command
  431.      line, because that will confuse the shell.
  432.  
  433.      The hard problem is to know when PROGRAM names a shell
  434.      that doesn't like its command line quoted...  */
  435.  
  436.   if (need_quote
  437.       && argv[1] && !strcmp (argv[1], "/c")
  438.       && argv[2] && !argv[3]
  439.       && _is_dos_shell (program))
  440.     need_quote = 0;
  441.  
  442.   if (unescape_quote && _is_unixy_shell (program))
  443.     unescape_quote = 0;
  444.  
  445.   arglen = 0;
  446.   for (i=1; argv[i]; i++)
  447.     arglen += 2*strlen(argv[i]) + 1 + 2;
  448.  
  449.   args = (char *)alloca(arglen+1);
  450.   argp = args;
  451.   for (i=1; argv[i]; i++)
  452.   {
  453.     int quoted = 0;
  454.     const char *p = argv[i];
  455.  
  456.     if (argp - args > CMDLEN_LIMIT)
  457.       break;
  458.     *argp++ = ' ';
  459.     /* If invoked by `spawnXX' or `execXX' functions, we need to
  460.        quote arguments which include whitespace, so they end up
  461.        as a single argument on the child side.
  462.        We will invoke PROGRAM directly by DOS Exec function (not
  463.        through COMMAND.COM), therefore no need to quote characters
  464.        special only to COMMAND.COM.
  465.        We also assume that DJGPP programs aren't invoked through
  466.        here, so a single quote `\'' is also not special.  The only
  467.        programs other than DJGPP that treat a single quote specially
  468.        are Unix-like shells, but whoever uses them should know to
  469.        escape the quotes himself.  */
  470.     if (need_quote && strpbrk(p, " \t") != 0)
  471.     {
  472.       *argp++ = '"';
  473.       quoted = 1;
  474.     }
  475.     while (*p)
  476.     {
  477.       if (argp - args > CMDLEN_LIMIT)
  478.         break;
  479.       if (*p == '"' && (quoted || need_quote))
  480.     *argp++ = '\\';
  481.       /* Most non-DJGPP programs don't treat `\'' specially,
  482.      but our `system' requires we always escape it, so
  483.      we should undo the quoting here.  */
  484.       else if (*p == '\\' && p[1] == '\'' && unescape_quote)
  485.     p++;
  486.       *argp++ = *p++;
  487.     }
  488.     if (quoted && argp - args <= CMDLEN_LIMIT)
  489.       *argp++ = '"';
  490.   }
  491.   *argp = 0;
  492.  
  493.   if (argp - args > CMDLEN_LIMIT)
  494.     errno = E2BIG;
  495.   
  496.   tbuf_beg = tbuf_ptr = __tb;
  497.   tbuf_len = _go32_info_block.size_of_transfer_buffer;
  498.   tbuf_end = tbuf_beg + tbuf_len - 1;
  499.   return direct_exec_tail(program, args, envp, 0, 2);
  500. }
  501.  
  502. typedef struct {
  503.   char magic[16];
  504.   int struct_length;
  505.   char go32[16];
  506. } StubInfo;
  507. #define STUB_INFO_MAGIC "StubInfoMagic!!"
  508.  
  509. static int go32_exec(const char *program, char **argv, char **envp)
  510. {
  511.   char *save_argv0;
  512.   int is_stubbed = 0, is_coff = 0;
  513.   int found_si = 0;
  514.   StubInfo si;
  515.   unsigned short header[3];
  516.   int pf, i;
  517.   char *go32, *sip=0;
  518.   char rpath[FILENAME_MAX];
  519.   int stub_offset, argc=0;
  520.  
  521.   int v2_0 = 0;
  522.   int si_la=0, si_off=0, rm_off, argv_off;
  523.   char cmdline[CMDLEN_LIMIT+2], *cmdp = cmdline;
  524.   char *pcmd = cmdline, *pproxy = 0, *proxy_cmdline = 0;
  525.   int retval;
  526.   int lfn = 2;    /* means don't know yet */
  527.  
  528.   pf = open(program, O_RDONLY|O_BINARY);
  529.  
  530.   read(pf, header, sizeof(header));
  531.   if (header[0] == 0x010b || header[0] == 0x014c)
  532.   {
  533.     unsigned char firstbytes[1];
  534.     unsigned long coffhdr[40];
  535.  
  536.     /* Seems to be an unstubbed COFF.  See what the first opcode
  537.        is to determine if it's v1.x or v2 COFF (or an impostor).
  538.  
  539.        FIXME: the code here assumes that any COFF that's not a V1
  540.        can only be V2.  What about other compilers that use COFF?  */
  541.     is_coff = 1;
  542.     if (lseek(pf, 2, 1) < 0
  543.     || read(pf, coffhdr, sizeof(coffhdr)) != sizeof(coffhdr)
  544.     || lseek(pf, coffhdr[10 + 5], 0) < 0
  545.     || read(pf, firstbytes, 1) != 1) /* scnptr */
  546.       is_coff = 0;    /* "Aha! An impostor!" (The Adventure game) */
  547.     else if (firstbytes[0] != 0xa3) /* opcode of movl %eax, 0x12345678 (V1) */
  548.       v2_0 = 1;
  549.   }
  550.   else if (header[0] == 0x5a4d)    /* "MZ" */
  551.   {
  552.     int header_offset = (long)header[2]*512L;
  553.     is_stubbed = 1;
  554.     if (header[1])
  555.       header_offset += (long)header[1] - 512L;
  556.     lseek(pf, 512, 0);
  557.     read(pf, cmdline, 8);
  558.     cmdline[8] = 0;
  559.     if (strcmp(cmdline, "go32stub") == 0)
  560.     {
  561.       v2_0 = 1;
  562.       is_coff = 1;
  563.     }
  564.     else
  565.     {
  566.       lseek(pf, header_offset - 4, 0);
  567.       read(pf, &stub_offset, 4);
  568.       header[0] = 0;
  569.       read(pf, header, sizeof(header));
  570.       if (header[0] == 0x010b)
  571.     is_coff = 1;
  572.       if (header[0] == 0x014c)
  573.     is_coff = 1;
  574.       lseek(pf, stub_offset, 0);
  575.       read(pf, &si, sizeof(si));
  576.       if (memcmp(STUB_INFO_MAGIC, si.magic, 16) == 0)
  577.     found_si = 1;
  578.     }
  579.   }
  580.   else if (header[0] == 0x2123)    /* "#!" */
  581.   {
  582.     close(pf);
  583.     return script_exec(program, argv, envp);
  584.   }
  585.  
  586.   /* Non-DJGPP programs cannot be run by !proxy.  */
  587.   if (!is_coff)
  588.   {
  589.     close(pf);
  590.     return direct_exec(program, argv, envp);
  591.   }
  592.  
  593.   if (found_si)
  594.     go32 = si.go32;
  595.   else if (v2_0 && !is_stubbed)
  596.     go32 = GO32_V2_STRING;
  597.   else
  598.     go32 = GO32_STRING;
  599.  
  600.   if (v2_0 && is_stubbed)
  601.   {
  602.     strcpy(rpath, program);
  603.   }
  604.   else
  605.   {
  606.     int e = errno;
  607.     if (!__dosexec_find_on_path(go32, envp, rpath))
  608.     {
  609.       close(pf);
  610.       errno = e;
  611.       return direct_exec(program, argv, envp); /* give up and just run it */
  612.     }
  613.  
  614.     if (found_si)
  615.     {  
  616.       lseek(pf, stub_offset, 0);
  617.       sip = (char *)alloca(si.struct_length);
  618.       read(pf, sip, si.struct_length);
  619.     }
  620.   }
  621.   close(pf);
  622.  
  623.   /* V2.0 programs invoked by `system' must be run via
  624.      `direct_exec', because otherwise the command-line arguments
  625.      won't be globbed correctly by the child.  Only v2.01 and
  626.      later knows how to get long command lines from `system' AND
  627.      glob them correctly.  But we don't want to check with which
  628.      version was the child compiled, so we need to create both the
  629.      usual DOS command line and the !proxy one (which will be put
  630.      into the environment).  Sigh...  */
  631.   save_argv0 = argv[0];
  632.   argv[0] = unconst(program, char *); /* since that's where we really found it */
  633.   /* Construct the DOS command tail */
  634.   for (argc=0; argv[argc]; argc++);
  635.  
  636.   if (__dosexec_in_system && v2_0)
  637.   {
  638.     /* If PROGRAM is an un-stubbed COFF, its name must be passed
  639.        in the command tail as well, since we call GO32 to run it.  */
  640.     for (i = (is_stubbed ? 1 : 0); i < argc; i++)
  641.     {
  642.       const char *p = argv[i];
  643.       if (cmdp - cmdline > CMDLEN_LIMIT)
  644.     break;
  645.       *cmdp++ = ' ';
  646.       while (*p)
  647.       {
  648.     if (cmdp - cmdline > CMDLEN_LIMIT)
  649.       break;
  650.     *cmdp++ = *p++;
  651.       }
  652.     }
  653.     *cmdp = '\0';
  654.   }
  655.  
  656.   lfn = _USE_LFN;
  657.  
  658.   /* Can't call any functions that use the transfer buffer beyond
  659.      this point: they will overwrite the data already in __tb.  */
  660.   tbuf_beg = tbuf_ptr = __tb;
  661.   tbuf_len = _go32_info_block.size_of_transfer_buffer;
  662.   tbuf_end = tbuf_ptr + tbuf_len - 1;
  663.  
  664.   /* If called from `system' and we have a command line shorter
  665.      than the DOS limit, we don't need to use !proxy at all.
  666.      Note that v1.x programs are always run through !proxy,
  667.      to prevent go32.exe from printing its copyright line. */
  668.   if (!__dosexec_in_system || !v2_0 || cmdp - cmdline > CMDLEN_LIMIT)
  669.   {
  670.     if (!check_talloc(found_si ?
  671.               si.struct_length : 0
  672.               + (argc+1)*sizeof(short)))
  673.     {
  674.       argv[0] = save_argv0;
  675.       return -1;
  676.     }
  677.     if (found_si)
  678.     {
  679.       si_la = talloc(si.struct_length);
  680.       si_off = si_la - tbuf_beg;
  681.       dosmemput(sip, si.struct_length, si_la);
  682.     }
  683.  
  684.     rm_off = argv_off = talloc((argc+1) * sizeof(short)) - tbuf_beg;
  685. #if 0
  686.     /* `alloca' could be dangerous with long command lines.  We
  687.        will instead move the offsets one by one with `_farpokew'.  */
  688.     rm_argv = (short *)alloca((argc+1) * sizeof(short));
  689. #endif
  690.  
  691.     for (i=0; i<argc; i++)
  692.     {
  693.       char *pargv = argv[i];
  694.       int sl = strlen(pargv) + 1;
  695.       unsigned long q;
  696.  
  697.       if (check_talloc(sl))
  698.       {
  699.     q = talloc(sl);
  700.     dosmemput(pargv, sl, q);
  701.     _farpokew(_dos_ds, tbuf_beg + argv_off, (q - tbuf_beg) & 0xffff);
  702.     argv_off += sizeof(short);
  703.       }
  704.       else    /* not enough space to pass args */
  705.       {
  706.     argv[0] = save_argv0;
  707.     return -1;
  708.       }
  709.     }
  710.  
  711.     _farpokew (_dos_ds, tbuf_beg + argv_off, 0);
  712.     argv_off += sizeof(short);
  713.  
  714.     argv[0] = save_argv0;
  715.     /* Environment variables are all malloced.  */
  716.     proxy_cmdline = (char *)malloc (34);
  717.     if (!proxy_cmdline)
  718.       return -1;
  719.     
  720.     sprintf(proxy_cmdline, "%s=%04x %04x %04x %04x %04x",
  721.          __PROXY, argc,
  722.         (unsigned)(tbuf_beg >> 4), rm_off & 0xffff,
  723.         (unsigned)(tbuf_beg >> 4), si_off & 0xffff);
  724.     if (!found_si)
  725.       proxy_cmdline[22] = 0; /* remove stubinfo information */
  726.  
  727.     if (__dosexec_in_system && v2_0)
  728.       pproxy = proxy_cmdline;
  729.     else
  730.     {
  731.       /* `proxy_cmdline looks like an environment variable " !proxy=value".
  732.          This is used as the REAL command line specification by 2.01
  733.      and later executables when called by `system'.  But if that's
  734.      not the case, we need a blank instead of the `='.  */
  735.       proxy_cmdline[__PROXY_LEN] = ' ';
  736.       pcmd = proxy_cmdline;
  737.     }
  738.   }
  739.   else
  740.     argv[0] = save_argv0;
  741.  
  742.   retval = direct_exec_tail(rpath, pcmd, envp, pproxy, lfn);
  743.   if (proxy_cmdline)
  744.     free(proxy_cmdline);
  745.   return retval;
  746. }
  747.  
  748. int
  749. __dosexec_command_exec(const char *program, char **argv, char **envp)
  750. {
  751.   const char *comspec=0;
  752.   char *cmdline;
  753.   int cmdlen;
  754.   int i;
  755.   int was_quoted = 0;    /* was the program name quoted? */
  756.  
  757.   /* Add spare space for possible quote characters.  */
  758.   cmdlen = strlen(program) + 4 + 2;
  759.   for (i=0; argv[i]; i++)
  760.     cmdlen += 2*strlen(argv[i]) + 1;
  761.   cmdline = (char *)alloca(cmdlen);
  762.  
  763.   /* FIXME: is this LFN-clean?  What special characters can
  764.      the program name have and how should they be quoted?  */
  765.   strcpy(cmdline, "/c ");
  766.   if (strchr(program, ' ') || strchr(program, '\t'))
  767.   {
  768.     was_quoted = 1;
  769.     cmdline[3] = '"';
  770.   }
  771.   for (i = 0; program[i] > ' '; i++)
  772.   {
  773.     /* COMMAND.COM cannot grok program names with forward slashes.  */
  774.     if (program[i] == '/')
  775.       cmdline[i+3+was_quoted] = '\\';
  776.     else
  777.       cmdline[i+3+was_quoted] = program[i];
  778.   }
  779.   for (; program[i]; i++)
  780.     cmdline[i+3+was_quoted] = program[i];
  781.   if (was_quoted)
  782.   {
  783.     cmdline[i+3+was_quoted] = '"';
  784.     i++;
  785.   }
  786.   cmdline[i+3+was_quoted] = 0;
  787.   for (i=1; argv[i]; i++)
  788.   {
  789.     strcat(cmdline, " ");
  790.     /* If called by `spawnXX' or `execXX' functions, must quote
  791.        arguments that have embedded whitespace or characters which
  792.        are special to COMMAND.COM and its ilk.  We don't quote all
  793.        the arguments so the command line won't grow larger than
  794.        the 126-char limit, if it doesn't have to.  */
  795.     if (!__dosexec_in_system && strpbrk(argv[i], " \t<>|'\"%") != 0)
  796.     {
  797.       char *d = cmdline + strlen(cmdline);
  798.       char *s = argv[i];
  799.       /* COMMAND.COM doesn't understand escaped quotes, so we must
  800.      insert additional quotes around redirection characters if
  801.      it would seem to COMMAND.COM we're outside of quoted part.
  802.      This variable keeps track of whether we are in- or outside
  803.      quotes as far as COMMAND.COM is concerned.  */
  804.       int  outside_quote = 0;
  805.  
  806.       *d++ = '"';
  807.       while (*s)
  808.       {
  809.     if (*s == '"')
  810.     {
  811.       outside_quote = !outside_quote;
  812.       *d++ = '\\';
  813.     }
  814.     else if (outside_quote && (*s == '|' || *s == '<' || *s == '>'))
  815.     {
  816.       *d++ = '"';
  817.       *d++ = *s++;
  818.       *d++ = '"';
  819.       continue;
  820.     }
  821.     else if (*s == '%')
  822.       *d++ = '%';
  823.     *d++ = *s++;
  824.       }
  825.       *d++ = '"';
  826.       *d++ = '\0';
  827.     }
  828.     else
  829.       strcat(cmdline, argv[i]);
  830.   }
  831.   for (i=0; envp[i]; i++)
  832.     if (strncmp(envp[i], "COMSPEC=", 8) == 0)
  833.       comspec = envp[i]+8;
  834.   if (!comspec)
  835.     for (i=0; environ[i]; i++)
  836.       if (strncmp(environ[i], "COMSPEC=", 8) == 0)
  837.         comspec = environ[i]+8;
  838.   if (!comspec)
  839.     comspec = "c:\\command.com";
  840.  
  841.   /* FIXME: 126-char limit below isn't LFN-clean.  */
  842.   if (strlen(cmdline) > CMDLEN_LIMIT + 1)
  843.   {
  844.     cmdline[CMDLEN_LIMIT+1] = '\0';
  845.     errno = E2BIG;
  846.   }
  847.  
  848.   tbuf_beg = tbuf_ptr = __tb;
  849.   tbuf_len = _go32_info_block.size_of_transfer_buffer;
  850.   tbuf_end = tbuf_ptr + tbuf_len - 1;
  851.   i = direct_exec_tail(comspec, cmdline, envp, 0, 2);
  852.   return i;
  853. }
  854.  
  855. static int script_exec(const char *program, char **argv, char **envp)
  856. {
  857.   char line[130], interp[FILENAME_MAX], iargs[130];
  858.   FILE *f;
  859.   char **newargs;
  860.   int i, hasargs=0;
  861.   char *base, *p;
  862.   int has_extension = 0, has_drive = 0;
  863.   char pinterp[FILENAME_MAX];
  864.   int (*spawnfunc)(int, const char *, char *const [], char *const []);
  865.  
  866.   f = fopen(program, "rt");
  867.   if (!f)
  868.   {
  869.     errno = ENOENT;
  870.     return -1;
  871.   }
  872.   fgets(line, sizeof(line), f);
  873.   fclose(f);
  874.  
  875.   if (strncmp(line, "#!", 2))        /* prevent infinite loop */
  876.     return go32_exec(program, argv, envp);
  877.  
  878.   /* Paranoia: is this at all a text file?  */
  879.   for (i=0; i < sizeof(line)-1 && line[i] != '\0'; i++)
  880.     if (line[i] < 7 && line[i] >= 0)
  881.       return direct_exec(program, argv, envp);
  882.  
  883.   iargs[0] = 0;
  884.   interp[0] = 0;
  885.   sscanf(line, "#! %s %[^\n]", interp, iargs);
  886.  
  887.   /* If no interpreter, invoke the default shell in $COMSPEC.  */
  888.   if (interp[0] == 0)
  889.     return __dosexec_command_exec(program, argv, envp); /* it couldn't be .exe or .com if here */
  890.   if (iargs[0])
  891.     hasargs=1;
  892.  
  893.   for (i=0; argv[i]; i++);
  894.   newargs = (char **)alloca((i+2+hasargs)*sizeof(char *));
  895.   for (i=0; argv[i]; i++)
  896.     newargs[i+1+hasargs] = unconst(argv[i], char *);
  897.   newargs[i+1+hasargs] = 0;
  898.   /* Some interpreters might have their own ideas about $PATH.
  899.      Therefore, pass them the full pathname of the script.  */
  900.   newargs[0] = newargs[1+hasargs] = unconst(program, char *);
  901.   if (hasargs)
  902.     newargs[1] = iargs;
  903.  
  904.   /* If INTERP is a Unix-style pathname, like "/bin/sh", we will try
  905.      it with the usual extensions and, if that fails, will further
  906.      search for the basename of the shell along the PATH; this
  907.      allows to run Unix shell scripts without editing their first line.  */
  908.   for (base=p=interp; *p; p++)
  909.   {
  910.     if (*p == '.')
  911.       has_extension = 1;
  912.     if (*p == '/' || *p == '\\' || *p == ':')
  913.     {
  914.       if (*p == ':')
  915.     has_drive = 1;
  916.       has_extension = 0;
  917.       base = p + 1;
  918.     }
  919.   }
  920.  
  921.   if (has_drive || has_extension)
  922.   {
  923.     strcpy (pinterp, interp);
  924.     spawnfunc = spawnvpe;
  925.   }
  926.   else if (__dosexec_find_on_path(interp, (char **)0, pinterp)
  927.        || __dosexec_find_on_path(base, envp, pinterp))
  928.     spawnfunc = spawnve;    /* no need to search on PATH: we've found it */
  929.   else
  930.     return -1;
  931.  
  932.   i = (*spawnfunc)(P_WAIT, pinterp, newargs, envp);
  933.   return i;
  934. }
  935.  
  936. /* Note: the following list is not supposed to mention *every*
  937.    possible extension of an executable file.  It only mentions
  938.    those extensions that can be *omitted* when you invoke the
  939.    executable from one of the shells used on MSDOS.  */
  940. static struct {
  941.   const char *extension;
  942.   int (*interp)(const char *, char **, char **);
  943. } interpreters[] = {
  944.   { ".com", direct_exec },
  945.   { ".exe", go32_exec },
  946.   { ".bat", __dosexec_command_exec },
  947.   { ".btm", __dosexec_command_exec },
  948.   { ".sh",  script_exec },  /* for compatibility with ms_sh */
  949.   { ".ksh", script_exec },
  950.   { ".pl", script_exec },   /* Perl */
  951.   { ".sed", script_exec },
  952.   { "",     go32_exec },
  953.   { 0,      script_exec },  /* every extension not mentioned above calls it */
  954.   { 0,      0 },
  955. };
  956.  
  957. /* This is the index into the above array of the interpreter
  958.    which is called when the program filename has no extension.  */
  959. #define INTERP_NO_EXT (sizeof(interpreters)/sizeof(interpreters[0]) - 3)
  960.  
  961. /*-------------------------------------------------*/
  962.  
  963. char *
  964. __dosexec_find_on_path(const char *program, char *envp[], char *buf)
  965. {
  966.   char *pp, *rp, *pe;
  967.   const char *ptr;
  968.   int i, hasdot=0, haspath=0;
  969.   int tried_dot = 0;
  970.   int e = errno, blen = strlen(program);
  971.  
  972.   if (blen > FILENAME_MAX - 1)
  973.   {
  974.     errno = ENAMETOOLONG;
  975.     return 0;
  976.   }
  977.   strncpy(buf, program, blen + 1);
  978.   rp = buf + blen;
  979.  
  980.   for (ptr=program; *ptr; ptr++)
  981.   {
  982.     if (*ptr == '.')
  983.       hasdot = 1;
  984.     if (*ptr == '/' || *ptr == '\\' || *ptr == ':')
  985.     {
  986.       haspath = 1;
  987.       hasdot = 0;
  988.     }
  989.   }
  990.  
  991.   if (hasdot)
  992.   {
  993.     if (access(buf, 0) == 0 && access(buf, D_OK))
  994.     {
  995.       errno = e;
  996.       return buf;
  997.     }
  998.   }
  999.   else
  1000.     for (i=0; interpreters[i].extension; i++)
  1001.     {
  1002.       strcpy(rp, interpreters[i].extension);
  1003.       if (access(buf, 0) == 0 && access(buf, D_OK))
  1004.       {
  1005.     /* If some of the `access' calls failed, `errno' will hold
  1006.        the reason for the failure which is irrelevant to the
  1007.        caller (we *did* find the execuatble).  Restore the value
  1008.        `errno' had when we were called.  */
  1009.     errno = e;
  1010.     return buf;
  1011.       }
  1012.     }
  1013.  
  1014.   if (haspath || !envp)
  1015.     return 0;
  1016.   *rp = 0;
  1017.  
  1018.   pp = 0;
  1019.   for (i=0; envp[i]; i++)
  1020.     if (strncmp(envp[i], "PATH=", 5) == 0)
  1021.       pp = envp[i] + 5;
  1022.   if (pp == 0)
  1023.     return 0;
  1024.  
  1025.   while (1)
  1026.   {
  1027.     if (!tried_dot)
  1028.     {
  1029.       rp = buf;
  1030.       pe = pp;
  1031.       tried_dot = 1;
  1032.     }
  1033.     else
  1034.     {
  1035.       rp = buf;
  1036.       for (pe = pp; *pe && *pe != ';'; pe++)
  1037.         *rp++ = *pe;
  1038.       pp = pe+1;
  1039.       if (rp > buf && rp[-1] != '/' && rp[-1] != '\\' && rp[-1] != ':')
  1040.         *rp++ = '/';
  1041.     }
  1042.     for (ptr = program; *ptr; ptr++)
  1043.       *rp++ = *ptr;
  1044.     *rp = 0;
  1045.     
  1046.     if (hasdot)
  1047.     {
  1048.       if (access(buf, 0) == 0 && access(buf, D_OK))
  1049.       {
  1050.     errno = e;
  1051.     return buf;
  1052.       }
  1053.     }
  1054.     else
  1055.     {
  1056.       for (i=0; interpreters[i].extension; i++)
  1057.       {
  1058.         strcpy(rp, interpreters[i].extension);
  1059.         if (access(buf, 0) == 0 && access(buf, D_OK))
  1060.     {
  1061.       errno = e;
  1062.           return buf;
  1063.     }
  1064.       }
  1065.     }
  1066.     if (*pe == 0)
  1067.       return 0;
  1068.   }
  1069. }
  1070.  
  1071. int __spawnve(int mode, const char *path, char *const argv[], char *const envp[])
  1072. {
  1073.   /* This is the one that does the work! */
  1074.   union { char *const *x; char **p; } u;
  1075.   int i = -1;
  1076.   char **argvp;
  1077.   char **envpp;
  1078.   char rpath[FILENAME_MAX], *rp, *rd=0;
  1079.   int e = errno;
  1080.  
  1081.   if (path == 0 || argv[0] == 0)
  1082.   {
  1083.     errno = EINVAL;
  1084.     return -1;
  1085.   }
  1086.   if (strlen(path) > FILENAME_MAX - 1)
  1087.   {
  1088.     errno = ENAMETOOLONG;
  1089.     return -1;
  1090.   }
  1091.  
  1092.   u.x = argv; argvp = u.p;
  1093.   u.x = envp; envpp = u.p;
  1094.  
  1095.   fflush(stdout); /* just in case */
  1096.   for (rp=rpath; *path; *rp++ = *path++)
  1097.   {
  1098.     if (*path == '.')
  1099.       rd = rp;
  1100.     if (*path == '\\' || *path == '/')
  1101.       rd = 0;
  1102.   }
  1103.   *rp = 0;
  1104.   if (rd)
  1105.   {
  1106.     for (i=0; interpreters[i].extension; i++)
  1107.       if (stricmp(rd, interpreters[i].extension) == 0)
  1108.         break;
  1109.   }
  1110.   while (access(rpath, 0) && access(rpath, D_OK))
  1111.   {
  1112.     i++;
  1113.     if (interpreters[i].extension == 0 || rd)
  1114.     {
  1115.       errno = ENOENT;
  1116.       return -1;
  1117.     }
  1118.     strcpy(rp, interpreters[i].extension);
  1119.   }
  1120.   errno = e;
  1121.   if (i == -1)
  1122.     i = INTERP_NO_EXT;
  1123.   i = interpreters[i].interp(rpath, argvp, envpp);
  1124.   if (mode == P_OVERLAY)
  1125.     exit(i);
  1126.   return i;
  1127. }
  1128.