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); }