dosexec.c

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

C
1,146
字号
  "COMMAND.COM",  "4DOS.COM",  "NDOS.COM",  0};/* A list of Unix-like shells and other non-DJGPP programs   which treat single quote specially.  */static const char *unix_shells[] = {  "SH.EXE",  "-SH.EXE", /* people create `-sh.exe' and `-bash.exe' to have login shells */  "SH16.EXE",  "SH32.EXE",  "TCSH.EXE",  "-TCSH.EXE",  "BASH.EXE",  "-BASH.EXE",  0};static intlist_member (const char *program, const char *program_list[]){  const char *p = program, *ptail = program;  int i;  while (*p)  {    if (*p == '/' || *p == ':' || *p == '\\')      ptail = p + 1;    p++;  }  for (i = 0; program_list[i]; i++)    if (!stricmp (ptail, program_list[i]))      return 1;  return 0;}int_is_unixy_shell (const char *shellpath){  return list_member (shellpath, unix_shells);}int_is_dos_shell (const char *shellpath){  return list_member (shellpath, shell_brokets);}static int direct_exec(const char *program, char **argv, char **envp){  int i, arglen;  char *args, *argp;  int need_quote = !__dosexec_in_system;  int unescape_quote = __dosexec_in_system;  /* PROGRAM can be a shell which expects a single argument     (beyond the /c or -c switch) that is the entire command     line.  With some shells, we must NOT quote that command     line, because that will confuse the shell.     The hard problem is to know when PROGRAM names a shell     that doesn't like its command line quoted...  */  if (need_quote      && argv[1] && !strcmp (argv[1], "/c")      && argv[2] && !argv[3]      && _is_dos_shell (program))    need_quote = 0;  if (unescape_quote && _is_unixy_shell (program))    unescape_quote = 0;  arglen = 0;  for (i=1; argv[i]; i++)    arglen += 2*strlen(argv[i]) + 1 + 2;  args = (char *)alloca(arglen+1);  argp = args;  for (i=1; argv[i]; i++)  {    int quoted = 0;    const char *p = argv[i];    if (argp - args > CMDLEN_LIMIT)      break;    *argp++ = ' ';    /* If invoked by `spawnXX' or `execXX' functions, we need to       quote arguments which include whitespace, so they end up       as a single argument on the child side.       We will invoke PROGRAM directly by DOS Exec function (not       through COMMAND.COM), therefore no need to quote characters       special only to COMMAND.COM.       We also assume that DJGPP programs aren't invoked through       here, so a single quote `\'' is also not special.  The only       programs other than DJGPP that treat a single quote specially       are Unix-like shells, but whoever uses them should know to       escape the quotes himself.  */    if (need_quote && strpbrk(p, " \t") != 0)    {      *argp++ = '"';      quoted = 1;    }    while (*p)    {      if (argp - args > CMDLEN_LIMIT)        break;      if (*p == '"' && (quoted || need_quote))	*argp++ = '\\';      /* Most non-DJGPP programs don't treat `\'' specially,	 but our `system' requires we always escape it, so	 we should undo the quoting here.  */      else if (*p == '\\' && p[1] == '\'' && unescape_quote)	p++;      *argp++ = *p++;    }    if (quoted && argp - args <= CMDLEN_LIMIT)      *argp++ = '"';  }  *argp = 0;  if (argp - args > CMDLEN_LIMIT)    errno = E2BIG;    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 int go32_exec(const char *program, char **argv, char **envp){  const _v2_prog_type * type;  char *save_argv0;  int i;  char *go32, *sip=0;  char rpath[FILENAME_MAX];  int argc=0;  int si_la=0, si_off=0, rm_off, argv_off;  char cmdline[CMDLEN_LIMIT+2], *cmdp = cmdline;  char *pcmd = cmdline, *pproxy = 0, *proxy_cmdline = 0;  int retval;  int lfn = 2;	/* means don't know yet */  type = _check_v2_prog (program, -1);  /* Because this function is called only, when program     exists, I can skip the check for type->valid */#define v2_0 (type->version.v.major > 1)#define is_stubbed (type->exec_format == _V2_EXEC_FORMAT_STUBCOFF)#define is_coff (type->object_format == _V2_OBJECT_FORMAT_COFF)#define found_si (type->has_stubinfo)  if (type->exec_format == _V2_EXEC_FORMAT_UNIXSCRIPT)  {    return script_exec(program, argv, envp);  }  /* Non-DJGPP programs cannot be run by !proxy.  */  if (!is_coff)  {    const char *ext = strrchr(program, '.');    if (type->exec_format == _V2_EXEC_FORMAT_EXE	|| (ext && stricmp(ext, ".com") == 0))      return direct_exec(program, argv, envp);    else      return __dosexec_command_exec (program, argv, envp);  }  if (found_si)    go32 = type->stubinfo->go32;  else if (v2_0 && !is_stubbed)    go32 = GO32_V2_STRING;  else    go32 = GO32_STRING;  if (v2_0 && is_stubbed)  {    strcpy(rpath, program);  }  else  {    int e = errno;    if (!__dosexec_find_on_path(go32, envp, rpath))    {      errno = e;      return direct_exec(program, argv, envp); /* give up and just run it */    }    if (found_si)    {        sip = (char *)type->stubinfo;    }  }  /* V2.0 programs invoked by `system' must be run via     `direct_exec', because otherwise the command-line arguments     won't be globbed correctly by the child.  Only v2.01 and     later knows how to get long command lines from `system' AND     glob them correctly.  But we don't want to check with which     version was the child compiled, so we need to create both the     usual DOS command line and the !proxy one (which will be put     into the environment).  Sigh...  */  save_argv0 = argv[0];  argv[0] = unconst(program, char *); /* since that's where we really found it */  /* Construct the DOS command tail */  for (argc=0; argv[argc]; argc++);  if (__dosexec_in_system && v2_0)  {    /* If PROGRAM is an un-stubbed COFF, its name must be passed       in the command tail as well, since we call GO32 to run it.  */    for (i = (is_stubbed ? 1 : 0); i < argc; i++)    {      const char *p = argv[i];      if (cmdp - cmdline > CMDLEN_LIMIT)	break;      *cmdp++ = ' ';      while (*p)      {	if (cmdp - cmdline > CMDLEN_LIMIT)	  break;	*cmdp++ = *p++;      }    }    *cmdp = '\0';  }  lfn = _USE_LFN;  /* Can't call any functions that use the transfer buffer beyond     this point: they will overwrite the data already in __tb.  */  tbuf_beg = tbuf_ptr = __tb;  tbuf_len = _go32_info_block.size_of_transfer_buffer;  tbuf_end = tbuf_ptr + tbuf_len - 1;  /* If called from `system' and we have a command line shorter     than the DOS limit, we don't need to use !proxy at all.     Note that v1.x programs are always run through !proxy,     to prevent go32.exe from printing its copyright line. */  if (!__dosexec_in_system || !v2_0 || cmdp - cmdline > CMDLEN_LIMIT)  {    if (!check_talloc(found_si ?		      type->stubinfo->struct_length : 0		      + (argc+1)*sizeof(short)))    {      argv[0] = save_argv0;      return -1;    }    if (found_si)    {      si_la = talloc(type->stubinfo->struct_length);      si_off = si_la - tbuf_beg;      dosmemput(sip, type->stubinfo->struct_length, si_la);    }    rm_off = argv_off = talloc((argc+1) * sizeof(short)) - tbuf_beg;#if 0    /* `alloca' could be dangerous with long command lines.  We       will instead move the offsets one by one with `_farpokew'.  */    rm_argv = (short *)alloca((argc+1) * sizeof(short));#endif    for (i=0; i<argc; i++)    {      char *pargv = argv[i];      int sl = strlen(pargv) + 1;      unsigned long q;#if 0      /* Workaround for bug in globbing. glob() allocates a fixed buffer         of 2000 bytes for its path buffer.  If an argument greater than         2000 bytes is passed to a DJGPP program, that program may crash         and under Windows take the DOS VM with it.  */      if (sl >= 2000)      {        argv[0] = save_argv0;        return -1;      }#endif      if (check_talloc(sl))      {	q = talloc(sl);	dosmemput(pargv, sl, q);	_farpokew(_dos_ds, tbuf_beg + argv_off, (q - tbuf_beg) & 0xffff);	argv_off += sizeof(short);      }      else	/* not enough space to pass args */      {	argv[0] = save_argv0;	return -1;      }    }    _farpokew (_dos_ds, tbuf_beg + argv_off, 0);    argv_off += sizeof(short);    argv[0] = save_argv0;    /* Environment variables are all malloced.  */    proxy_cmdline = (char *)malloc (34);    if (!proxy_cmdline)      return -1;        sprintf(proxy_cmdline, "%s=%04x %04x %04x %04x %04x",	     __PROXY, argc,	    (unsigned)(tbuf_beg >> 4), rm_off & 0xffff,	    (unsigned)(tbuf_beg >> 4), si_off & 0xffff);    if (!found_si)      proxy_cmdline[22] = 0; /* remove stubinfo information */    if (__dosexec_in_system && v2_0)      pproxy = proxy_cmdline;    else    {      /* `proxy_cmdline looks like an environment variable " !proxy=value".         This is used as the REAL command line specification by 2.01	 and later executables when called by `system'.  But if that's	 not the case, we need a blank instead of the `='.  */      proxy_cmdline[__PROXY_LEN] = ' ';      pcmd = proxy_cmdline;    }  }  else    argv[0] = save_argv0;  retval = direct_exec_tail(rpath, pcmd, envp, pproxy, lfn);  if (proxy_cmdline)    free(proxy_cmdline);  return retval;}int__dosexec_command_exec(const char *program, char **argv, char **envp){  const char *comspec=0;  char *cmdline;  int cmdlen;  int i;  int was_quoted = 0;	/* was the program name quoted? */  /* Add spare space for possible quote characters.  */  cmdlen = strlen(program) + 4 + 2;  for (i=0; argv[i]; i++)    cmdlen += 2*strlen(argv[i]) + 1;  cmdline = (char *)alloca(cmdlen);  /* FIXME: is this LFN-clean?  What special characters can     the program name have and how should they be quoted?  */  strcpy(cmdline, "/c ");  if (strchr(program, ' ') || strchr(program, '\t'))  {    was_quoted = 1;    cmdline[3] = '"';  }  for (i = 0; program[i] > ' '; i++)  {    /* COMMAND.COM cannot grok program names with forward slashes.  */    if (program[i] == '/')      cmdline[i+3+was_quoted] = '\\';    else      cmdline[i+3+was_quoted] = program[i];  }  for (; program[i]; i++)    cmdline[i+3+was_quoted] = program[i];  if (was_quoted)  {    cmdline[i+3+was_quoted] = '"';    i++;  }  cmdline[i+3+was_quoted] = 0;  for (i=1; argv[i]; i++)  {    strcat(cmdline, " ");    /* If called by `spawnXX' or `execXX' functions, must quote       arguments that have embedded whitespace or characters which       are special to COMMAND.COM and its ilk.  We don't quote all

⌨️ 快捷键说明

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