dosexec.c

来自「UNIX下SH的实现源码」· C语言 代码 · 共 1,146 行 · 第 1/3 页

C
1,146
字号
/* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details *//* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details *//* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details *//* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details *//* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details *//* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */#include <libc/stubs.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <signal.h>#include <limits.h>#include <fcntl.h>#include <unistd.h>#include <process.h>#include <go32.h>#include <dpmi.h>#include <ctype.h>#include <sys/system.h>#include <sys/movedata.h>#include <libc/dosexec.h>#include <libc/unconst.h>#include <libc/dosio.h>#include <libc/farptrgs.h>/* FIXME: this is not LFN-clean.  Win95 has a way to   pass long command lines, but we don't support it here.  */#define CMDLEN_LIMIT 125extern char **environ;int __dosexec_in_system = 0;typedef struct {  unsigned short eseg;  unsigned short argoff;  unsigned short argseg;  unsigned short fcb1_off;  unsigned short fcb1_seg;  unsigned short fcb2_off;  unsigned short fcb2_seg;} Execp;static Execp parm;static unsigned long tbuf_ptr;static unsigned long tbuf_beg;static unsigned long tbuf_end;static unsigned long tbuf_len;#if 0static int	     tbuf_selector;#endifstatic int script_exec(const char *, char **, char **);/* Allocate AMT bytes off the transfer buffer.  */static unsigned long talloc(size_t amt){  unsigned long rv = tbuf_ptr;  tbuf_ptr += amt;  return rv;}/* Make sure we can allocate AMT bytes off the transfer buffer   without overflowing it.  Return non-zero if we can, zero otherwise.   WARNING: This can relocate the data already in the transfer buffer,	    so all linear addresses which use it should be relative to	    TBUF_BEG!  */static int check_talloc(size_t amt){  int retval = 1;  if (tbuf_ptr + amt > tbuf_end)  {#if 0    /* Code that reallocs the transfer buffer; currently disabled.  */    unsigned long new_tb;    unsigned long min_len = tbuf_len + amt;    unsigned long max_len = 0x10000; /* 64KB */    int old_selector = tbuf_selector;    int max_avail;    int e = errno;    errno = E2BIG;    /* Try to allocate new, larger DOS buffer, upto 64KB.  */    if (min_len > max_len)    {      retval = 0;      goto done;    }    while (tbuf_len <= max_len && tbuf_len < min_len)      tbuf_len *= 2;    if (tbuf_len < min_len)    {      retval = 0;      goto done;    }    tbuf_len = (tbuf_len + 15) & 0xffff0; /* round to nearest paragraph */    if ((new_tb =	 __dpmi_allocate_dos_memory(tbuf_len/16, &max_avail)) == -1)    {      if (max_avail*16 < min_len	  || (new_tb =	      __dpmi_allocate_dos_memory(max_avail, &tbuf_selector)) == -1)      {	retval = 0;	goto done;      }      tbuf_len = max_avail*16;    }    else      tbuf_selector = max_avail;    new_tb *= 16;  /* convert to linear address */    movedata (_dos_ds, tbuf_beg, _dos_ds, new_tb, tbuf_ptr - tbuf_beg);    tbuf_ptr = new_tb + tbuf_ptr - tbuf_beg;    tbuf_beg = new_tb;    tbuf_end = tbuf_beg + tbuf_len - 1;    errno = e;  done:    /* Assume caller will return immediately in case of       failure to reallocate, so they won't need the old data.  */    if (!retval)      tbuf_selector = 0;    if (old_selector)      __dpmi_free_dos_memory(old_selector);#else    errno = E2BIG;    retval = 0;#endif  }  return retval;}extern char   __PROXY[];	/* defined on crt0/crt1.c */extern size_t __PROXY_LEN;/* Functions that call `direct_exec_tail' after they've put   some data into the transfer buffer, should set LFN parameter   to either 0 (no LFN support) or 1 (LFN supported), but NOT 2!   if LFN is 2, there is a possiblity that the contents of the   transfer buffer will be overrun!  */static intdirect_exec_tail(const char *program, const char *args,		 char * const envp[], const char *proxy, int lfn){  __dpmi_regs r;  unsigned long program_la;  unsigned long arg_la;  unsigned long parm_la;  unsigned long env_la, env_e_la;  size_t proxy_len = proxy ? strlen(proxy)+1 : 0;  int seen_proxy = 0;  char arg_header[3];  char short_name[FILENAME_MAX];  const char *progname;  unsigned proglen;  int i;  unsigned long fcb1_la, fcb2_la, fname_la;    /* This used to just call sync().  But `sync' flushes the disk     cache nowadays, and that can slow down the child tremendously,     since some caches (e.g. SmartDrv) invalidate all of their     buffers when `_flush_disk_cache' is called.  */  for (i = 0; i < 255; i++)    fsync(i);  if (lfn == 2)		/* don't know yet */    lfn = _USE_LFN;  /* The pathname of the executable to run.  */  proglen = strlen(program)+1;  if (!check_talloc(proglen))    return -1;  /* Make sure any magic names, like /dev/c/foo, are converted to the     usual DOS form, and, under LFN, to the short 8+3 alias.  */  _put_path2(program, tbuf_beg == __tb ? tbuf_ptr - tbuf_beg : 0);  if(lfn) {    r.x.ax = 0x7160;			/* Truename */    r.x.cx = 1;				/* Get short name */    r.x.ds = r.x.es = tbuf_ptr / 16;    r.x.si = r.x.di = tbuf_ptr & 15;    __dpmi_int(0x21, &r);    if (r.x.flags & 1)    {      errno = __doserr_to_errno(r.x.ax);      return -1;    }  }  dosmemget(tbuf_beg == __tb ? tbuf_ptr : __tb, FILENAME_MAX, short_name);  progname = short_name;  proglen = strlen(short_name)+1;  if (!check_talloc(proglen + strlen(args) + 3 + sizeof(Execp) + 48))    return -1;  program_la = talloc(proglen);  arg_la     = talloc(strlen(args)+3);  parm_la    = talloc(sizeof(Execp));  dosmemput(progname, proglen, program_la);  /* The command-line tail.  */  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));  /* The 2 FCBs.  Some programs (like XCOPY from DOS 6.x) need them.  */  fcb1_la = talloc(16);	       /* allocate space for 1st FCB */  fname_la = arg_la + 1;       /* first character of command tail */  r.x.ax = 0x2901;	       /* AL = 1 means skip leading separators */  r.x.ds = fname_la / 16;      /* pointer to 1st cmd argument */  r.x.si = fname_la & 15;  r.x.es = fcb1_la / 16;       /* pointer to FCB buffer */  r.x.di = fcb1_la & 15;  __dpmi_int (0x21, &r);  /* We cannot be sure that Int 21h/AX=2901h parsed the entire     first command-line argument (it might not be a filename     at all!).  We need to get to the next command-line arg     before calling 2901 again.  2901 returns the pointer to     first unparsed character in DS:SI.     Note that, in case there is no second command-line argument,     the following loop is terminated by the trailing CR which     ends the command-line tail.  */  for (_farsetsel(_dos_ds), fname_la = ((unsigned)r.x.ds) * 16 + r.x.si;       !isspace(_farnspeekb(fname_la));       fname_la++)    ;  fcb2_la = talloc(16);  r.x.ax = 0x2901;  r.x.ds = fname_la / 16;      /* begin parsing 2nd arg from here */  r.x.si = fname_la & 15;  r.x.es = fcb2_la / 16;  r.x.di = fcb2_la & 15;  __dpmi_int (0x21, &r);  /* The environment must be on a segment boundary, so get     to the first location in the transfer buffer whose     linear address is divisable by 16.  */  do {    env_la = talloc(1);  } while (env_la & 15);  talloc(-1);#if 0  /* Convert to relative, since `check_talloc' may relocate.  */  arg_la  -= tbuf_beg;  env_la  -= tbuf_beg;  fcb1_la -= tbuf_beg;  fcb2_la -= tbuf_beg;  parm_la -= tbuf_beg;  program_la -= tbuf_beg;#endif  /* The environment.  Replace the !proxy variable, if there is     one (for nested programs) if we are called from `system',     or skip it, if we are called from `spawnXX'.  */  for (i=0; envp[i]; i++)  {    const char *ep = envp[i];    size_t env_len = strlen(ep)+1;    if (strncmp(ep, __PROXY, __PROXY_LEN) == 0 && ep[__PROXY_LEN] == '=')    {      seen_proxy = 1;      if (proxy)      {	ep = proxy;	env_len = proxy_len;      }      else	continue;    }    if (!check_talloc(env_len))      return -1;    env_e_la = talloc(env_len);    dosmemput(ep, env_len, env_e_la);  }  /* If no !proxy variable was found, create one.  */  if (proxy && !seen_proxy)  {    if (!check_talloc(proxy_len))      return -1;    env_e_la = talloc(proxy_len);    dosmemput(proxy, proxy_len, env_e_la);  }  /* Terminate by an extra NULL char.  */  arg_header[0] = 0;  /* The name of the program that owns the environment.  */  arg_header[1] = 1;	/* the number of strings (1, little-endian) */  arg_header[2] = 0;  if (!check_talloc(3 + proglen))    return -1;  dosmemput(arg_header, 3, talloc(3));  env_e_la = talloc(proglen);  dosmemput(progname, proglen, env_e_la);  /* Prepare the parameter block and call Int 21h/AX=4B00h.  */#if 0  arg_la  += tbuf_beg;  env_la  += tbuf_beg;  fcb1_la += tbuf_beg;  fcb2_la += tbuf_beg;  parm_la += tbuf_beg;  program_la += tbuf_beg;#endif  parm.eseg     = env_la / 16;  parm.argseg	= arg_la / 16;  parm.argoff	= arg_la & 15;  parm.fcb1_seg = fcb1_la / 16;  parm.fcb1_off = fcb1_la & 15;  parm.fcb2_seg = fcb2_la / 16;  parm.fcb2_off = fcb2_la & 15;  dosmemput(&parm, sizeof(parm), parm_la);  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;  __dpmi_int(0x21, &r);#if 0  if (tbuf_selector)    __dpmi_free_dos_memory (tbuf_selector);  tbuf_selector = 0;#endif  if (r.x.flags & 1)  {    errno = __doserr_to_errno(r.x.ax);    return -1;  }    r.h.ah = 0x4d;  __dpmi_int(0x21, &r);    if (r.x.flags & 1)  {    errno = __doserr_to_errno(r.x.ax);    return -1;  }  /* AH holds the ``system exit code'' which is non-zero if the     child was aborted by Ctrl-C, or Critical Device error (also     if the child installs itself as a TSR).  */  if (r.h.ah && r.h.ah != 3) /* 3 means it exited as TSR (is it ``normal''?) */    {      errno = EINTR;	/* what else can we put in `errno'? */      return ( ((r.h.ah == 1 ? SIGINT : SIGABRT) << 8) | r.h.al );    }  return r.h.al;	/* AL holds the child exit code */}int_dos_exec(const char *program, const char *args, char * const envp[]){  tbuf_beg = tbuf_ptr = __tb;  tbuf_len = _go32_info_block.size_of_transfer_buffer;  tbuf_end = tbuf_beg + tbuf_len - 1;  return direct_exec_tail(program, args, envp, 0, 2);}static char GO32_V2_STRING[] = "go32-v2.exe";static char GO32_STRING[]    = "go32.exe";/* A list of known shells which require we DON'T quote command   lines that are passed to them with the /c or -c switch.  */static const char *shell_brokets[] = {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?