예제 #1
0
파일: terminals.c 프로젝트: OrkFyurer/gcc
static int
nt_spawnve (char *exe, char **argv, char *env, struct TTY_Process *process)
{
  STARTUPINFO start;
  SECURITY_ATTRIBUTES sec_attrs;
  SECURITY_DESCRIPTOR sec_desc;
  DWORD flags;
  char dir[ MAXPATHLEN ];
  int pid;
  int is_gui, use_cmd;
  char *cmdline, *parg, **targ;
  int do_quoting = 0;
  char escape_char;
  int arglen;

  /* we have to do some conjuring here to put argv and envp into the
     form CreateProcess wants...  argv needs to be a space separated/null
     terminated list of parameters, and envp is a null
     separated/double-null terminated list of parameters.

     Additionally, zero-length args and args containing whitespace or
     quote chars need to be wrapped in double quotes - for this to work,
     embedded quotes need to be escaped as well.  The aim is to ensure
     the child process reconstructs the argv array we start with
     exactly, so we treat quotes at the beginning and end of arguments
     as embedded quotes.

     Note that using backslash to escape embedded quotes requires
     additional special handling if an embedded quote is already
     preceded by backslash, or if an arg requiring quoting ends with
     backslash.  In such cases, the run of escape characters needs to be
     doubled.  For consistency, we apply this special handling as long
     as the escape character is not quote.

     Since we have no idea how large argv and envp are likely to be we
     figure out list lengths on the fly and allocate them.  */

  if (!NILP (Vw32_quote_process_args))
    {
      do_quoting = 1;
      /* Override escape char by binding w32-quote-process-args to
	 desired character, or use t for auto-selection.  */
      if (INTEGERP (Vw32_quote_process_args))
	escape_char = XINT (Vw32_quote_process_args);
      else
	escape_char = '\\';
    }

  /* do argv...  */
  arglen = 0;
  targ = argv;
  while (*targ)
    {
      char *p = *targ;
      int need_quotes = 0;
      int escape_char_run = 0;

      if (*p == 0)
	need_quotes = 1;
      for ( ; *p; p++)
	{
	  if (*p == '"')
	    {
	      /* allow for embedded quotes to be escaped */
	      arglen++;
	      need_quotes = 1;
	      /* handle the case where the embedded quote is already escaped */
	      if (escape_char_run > 0)
		{
		  /* To preserve the arg exactly, we need to double the
		     preceding escape characters (plus adding one to
		     escape the quote character itself).  */
		  arglen += escape_char_run;
		}
	    }
	  else if (*p == ' ' || *p == '\t')
	    {
	      need_quotes = 1;
	    }

	  if (*p == escape_char && escape_char != '"')
	    escape_char_run++;
	  else
	    escape_char_run = 0;
	}
      if (need_quotes)
	{
	  arglen += 2;
	  /* handle the case where the arg ends with an escape char - we
	     must not let the enclosing quote be escaped.  */
	  if (escape_char_run > 0)
	    arglen += escape_char_run;
	}
      arglen += strlen (*targ) + 1;
      targ++;
    }

  is_gui = is_gui_app (argv[0]);
  use_cmd = FALSE;

  if (is_gui == -1) {
    /* could not determine application type. Try launching with "cmd /c" */
    is_gui = FALSE;
    arglen += 7;
    use_cmd = TRUE;
  }

  cmdline = (char*)malloc (arglen + 1);
  targ = argv;
  parg = cmdline;

  if (use_cmd == TRUE) {
    strcpy (parg, "cmd /c ");
    parg += 7;
  }

  while (*targ)
    {
      char * p = *targ;
      int need_quotes = 0;

      if (*p == 0)
	need_quotes = 1;

      if (do_quoting)
	{
	  for ( ; *p; p++)
	    if (*p == ' ' || *p == '\t' || *p == '"')
	      need_quotes = 1;
	}
      if (need_quotes)
	{
	  int escape_char_run = 0;
	  char * first;
	  char * last;

	  p = *targ;
	  first = p;
	  last = p + strlen (p) - 1;
	  *parg++ = '"';
	  for ( ; *p; p++)
	    {
	      if (*p == '"')
		{
		  /* double preceding escape chars if any */
		  while (escape_char_run > 0)
		    {
		      *parg++ = escape_char;
		      escape_char_run--;
		    }
		  /* escape all quote chars, even at beginning or end */
		  *parg++ = escape_char;
		}
	      *parg++ = *p;

	      if (*p == escape_char && escape_char != '"')
		escape_char_run++;
	      else
		escape_char_run = 0;
	    }
	  /* double escape chars before enclosing quote */
	  while (escape_char_run > 0)
	    {
	      *parg++ = escape_char;
	      escape_char_run--;
	    }
	  *parg++ = '"';
	}
      else
	{
	  strcpy (parg, *targ);
	  parg += strlen (*targ);
	}
      *parg++ = ' ';
      targ++;
    }
  *--parg = '\0';

  memset (&start, 0, sizeof (start));
  start.cb = sizeof (start);

  if (process->usePipe == TRUE) {
    start.dwFlags = STARTF_USESTDHANDLES;
    start.hStdInput = process->w_forkin;
    start.hStdOutput = process->w_forkout;
    /* child's stderr is always redirected to outfd */
    start.hStdError = process->w_forkout;
  } else {
    start.dwFlags = STARTF_USESTDHANDLES;
    /* We only need to redirect stderr/stdout here. Stdin will be forced to
       the spawned process console by explaunch */
    start.hStdInput = NULL;
    start.hStdOutput = process->w_forkout;
    start.hStdError = process->w_forkout;
  }

  /* Explicitly specify no security */
  if (!InitializeSecurityDescriptor (&sec_desc, SECURITY_DESCRIPTOR_REVISION))
    goto EH_Fail;
  if (!SetSecurityDescriptorDacl (&sec_desc, TRUE, NULL, FALSE))
    goto EH_Fail;
  sec_attrs.nLength = sizeof (sec_attrs);
  sec_attrs.lpSecurityDescriptor = &sec_desc;
  sec_attrs.bInheritHandle = FALSE;

  /* creating a new console allow easier close. Do not use
     CREATE_NEW_PROCESS_GROUP as this results in disabling Ctrl+C */
  flags = CREATE_NEW_CONSOLE;
  if (NILP (Vw32_start_process_inherit_error_mode))
    flags |= CREATE_DEFAULT_ERROR_MODE;

  /* if app is not a gui application, hide the console */
  if (is_gui == FALSE) {
    start.dwFlags |= STARTF_USESHOWWINDOW;
    start.wShowWindow = SW_HIDE;
  }

  /* Set initial directory to null character to use current directory */
  if (!CreateProcess (NULL, cmdline, &sec_attrs, NULL, TRUE,
		      flags, env, NULL, &start, &process->procinfo))
    goto EH_Fail;

  pid = (int) process->procinfo.hProcess;
  process->pid=pid;

  return pid;

 EH_Fail:
  return -1;
}
예제 #2
0
/*
 * Check that we're linked as a GUI application. Depending on how
 * we where started, we create or attach to parent console before
 * using printf() etc. If using GTK interface (option "-G"), don't
 * create a console.
 */
static void setup_console (void)
{
#if !defined(BUILDING_UTILS)
    BOOL (WINAPI *_AttachConsole)(DWORD) = NULL;
    HMODULE mod;
    DWORD   rc = 0;
    STARTUPINFO inf;
    const char *cmd_line = GetCommandLine();
    BOOL  is_ec   = (cmd_line && strstr(cmd_line,"ettercap"));
    BOOL  use_gtk = (is_ec && strstr(cmd_line,"-G") != NULL);

    if (!is_ec || use_gtk)  /* GTK UI shouldn't need a console */
        return;

    /* Note: this is true even when started minimized
     * (nCmdShow == SW_MINIMISED), but fails if program started as
     * another user
     */
    memset (&inf, 0, sizeof(inf));
    GetStartupInfo (&inf);

    started_from_a_gui = (inf.dwFlags & STARTF_USESHOWWINDOW);

    /* check if correct linker option used
     */
    if (!is_gui_app()) {
        MessageBox (NULL, "You must relink this application with\n"
                    "\"-Wl,--subsystem,windows\"\n", "Error",
                    MB_ICONEXCLAMATION | MB_SETFOREGROUND);
        exit (-1);
    }

    mod = GetModuleHandle ("kernel32.dll");
    if (mod)
        _AttachConsole = (BOOL (WINAPI*)(DWORD)) GetProcAddress((HINSTANCE)mod, "AttachConsole");

    attached_to_console = FALSE;

    /* If parent doesn't have a console, AttachConsole() will fail and
     * we use AllocConsole() instead.
     * Note: AttachConsole() was introduced in Win-2000, so for Win-ME/9x,
     *       we simply try AllocConsole().
     */
    if (_AttachConsole) {
        if ((*_AttachConsole)(ATTACH_PARENT_PROCESS))
            attached_to_console = TRUE;
        else
            rc = GetLastError();
    }

    if (!attached_to_console && !AllocConsole()) {
        char error[256];

        snprintf (error, 256, "AllocConsole failed; error %lu", GetLastError());
        MessageBox (NULL, error, "Fatal", MB_ICONEXCLAMATION | MB_SETFOREGROUND);
        exit (-1);
    }

    /* Synchronise std-handles with the new console
     */
    freopen ("CONIN$", "rt", stdin);
    freopen ("CONOUT$", "wt", stdout);
    freopen ("CONOUT$", "wt", stderr);

#if 0
    printf ("_AttachConsole %p, rc %lu, started_from_a_gui %d, attached_to_console %d\n",
            _AttachConsole, rc, started_from_a_gui, attached_to_console);
#endif

    has_console = TRUE;
#endif /* BUILDING_UTILS */
}