Пример #1
0
void
CPCD::Process::do_exec() {
  unsigned i;

#ifdef _WIN32
  Vector<BaseString> saved;
  char *cwd = 0;
  save_environment(m_env.c_str(), saved);
#endif

  setup_environment(m_env.c_str());

  char **argv = BaseString::argify(m_path.c_str(), m_args.c_str());

  if(strlen(m_cwd.c_str()) > 0) {
#ifdef _WIN32
    cwd = getcwd(0, 0);
    if(!cwd)
    {
      logger.critical("Couldn't getcwd before spawn");
    }
#endif
    int err = chdir(m_cwd.c_str());
    if(err == -1) {
      BaseString err;
      logger.error("%s: %s\n", m_cwd.c_str(), strerror(errno));
      _exit(1);
    }
  }
#ifndef _WIN32
  Vector<BaseString> ulimit;
  m_ulimit.split(ulimit);
  for(i = 0; i<ulimit.size(); i++){
    if(ulimit[i].trim().length() > 0 && set_ulimit(ulimit[i]) != 0){
      _exit(1);
    }
  }
#endif

  const char *nul = IF_WIN("nul:", "/dev/null");
  int fdnull = open(nul, O_RDWR, 0);
  if(fdnull == -1) {
    logger.error("Cannot open `%s': %s\n", nul, strerror(errno));
    _exit(1);
  }
  
  BaseString * redirects[] = { &m_stdin, &m_stdout, &m_stderr };
  int fds[3];
#ifdef _WIN32
  int std_dups[3];
#endif
  for (i = 0; i < 3; i++) {
#ifdef _WIN32
    std_dups[i] = dup(i);
#endif
    if (redirects[i]->empty()) {
#ifndef DEBUG
      dup2(fdnull, i);
#endif
      continue;
    }
    
    if((* redirects[i]) == "2>&1" && i == 2){
      dup2(fds[1], 2);
      continue;
    }
    
    /**
     * Make file
     */
    int flags = 0;
    int mode = S_IRUSR | S_IWUSR ;
    if(i == 0){
      flags |= O_RDONLY;
    } else {
      flags |= O_WRONLY | O_CREAT | O_APPEND;
    }
    int f = fds[i]= open(redirects[i]->c_str(), flags, mode);
    if(f == -1){
      logger.error("Cannot redirect %u to/from '%s' : %s\n", i,
		   redirects[i]->c_str(), strerror(errno));
      _exit(1);
    }
    dup2(f, i);
#ifdef _WIN32
    close(f);
#endif
  }

#ifndef _WIN32
  /* Close all filedescriptors */
  for(i = STDERR_FILENO+1; (int)i < getdtablesize(); i++)
    close(i);

  execv(m_path.c_str(), argv);
  /* XXX If we reach this point, an error has occurred, but it's kind of hard
   * to report it, because we've closed all files... So we should probably
   * create a new logger here */
  logger.error("Exec failed: %s\n", strerror(errno));
  /* NOTREACHED */
#else

  // Get full path to cygwins shell
  FILE *fpipe = _popen("sh -c 'cygpath -w `which sh`'", "rt");
  char buf[MAX_PATH];

  require(fgets(buf, MAX_PATH - 1, fpipe));
  fclose(fpipe);

  BaseString sh;
  sh.assign(buf);
  sh.trim("\n");
  sh.append(".exe");

  BaseString shcmd;
  shcmd.assfmt("%s -c '%s %s'", sh.c_str(), m_path.c_str(), m_args.c_str());

  PROCESS_INFORMATION pi = {0};
  STARTUPINFO si = {sizeof(STARTUPINFO), 0};

  si.dwFlags   |=  STARTF_USESTDHANDLES;
  si.hStdInput  = (HANDLE)_get_osfhandle(0);
  si.hStdOutput = (HANDLE)_get_osfhandle(1);
  si.hStdError  = (HANDLE)_get_osfhandle(2);

  if(!CreateProcessA(sh.c_str(),
                     (LPSTR)shcmd.c_str(),
                     NULL,
                     NULL,
                     TRUE,
                     CREATE_SUSPENDED, // Resumed after assigned to Job
                     NULL,
                     NULL,
                     &si,
                     &pi))
  {
    char* message;
    DWORD err = GetLastError();

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                  FORMAT_MESSAGE_FROM_SYSTEM |
                  FORMAT_MESSAGE_IGNORE_INSERTS,
                  NULL,
                  err,
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                  (LPTSTR)&message,
                  0, NULL );

    logger.error("CreateProcess failed, error: %d, message: '%s'",
                 err, message);
    LocalFree(message);

  }

  HANDLE proc = pi.hProcess;
  require(proc);

  // Job control
  require(m_job = CreateJobObject(0, 0));
  require(AssignProcessToJobObject(m_job, proc));

  // Resum process after it has been added to Job
  ResumeThread(pi.hThread);
  CloseHandle(pi.hThread);


  // go back up to original cwd
  if(chdir(cwd))
  {
    logger.critical("Couldn't go back to saved cwd after spawn()");
    logger.critical("errno: %d, strerror: %s", errno, strerror(errno));
  }
  free(cwd);

  // get back to original std i/o
  for(i = 0; i < 3; i++) {
    dup2(std_dups[i], i);
    close(std_dups[i]);
  }

  for (i = 0; i < saved.size(); i++) {
    putenv(saved[i].c_str());
  }

  logger.debug("'%s' has been started", shcmd.c_str());

  DWORD exitcode;
  BOOL result = GetExitCodeProcess(proc, &exitcode);
  //maybe a short running process
  if (result && exitcode != 259) {
    m_status = STOPPED;
    logger.warning("Process terminated early");
  }

  int pid = GetProcessId(proc);
  if (!pid)
    logger.critical("GetProcessId failed, error: %d!", GetLastError());

  logger.debug("new pid %d", pid);

  CloseHandle(proc);
  m_status = RUNNING;
  writePid(pid);
#endif

  close(fdnull);
}