/* dir_access_unix.cpp */ #include "sub_process_unix.h" #ifdef UNIX_ENABLED #include #include #include #include #include #include #include Error SubProcessUnix::start() { #ifdef __EMSCRIPTEN__ // Don't compile this code at all to avoid undefined references. // Actual virtual call goes to OS_JavaScript. ERR_FAIL_V(ERR_BUG); #else if (_executable_path.empty()) { return ERR_FILE_BAD_PATH; } if (is_process_running()) { return ERR_BUSY; } if (_blocking && _read_output) { String argss; argss = "\"" + _executable_path + "\""; for (int i = 0; i < _arguments.size(); i++) { argss += String(" \"") + _arguments[i] + "\""; } if (_read_std_err) { argss += " 2>&1"; // Read stderr too } else { argss += " 2>/dev/null"; //silence stderr } FILE *f = popen(argss.utf8().get_data(), "r"); ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot pipe stream from process running with following arguments '" + argss + "'."); char buf[65535]; while (fgets(buf, 65535, f)) { if (_pipe_mutex) { _pipe_mutex->lock(); } _pipe += String::utf8(buf); if (_pipe_mutex) { _pipe_mutex->unlock(); } } int rv = pclose(f); _exitcode = WEXITSTATUS(rv); return OK; } if (!_blocking && _read_output) { String argss; argss = "\"" + _executable_path + "\""; for (int i = 0; i < _arguments.size(); i++) { argss += String(" \"") + _arguments[i] + "\""; } if (_read_std_err) { argss += " 2>&1"; // Read stderr too } else { argss += " 2>/dev/null"; //silence stderr } _process_fp = popen(argss.utf8().get_data(), "r"); ERR_FAIL_COND_V_MSG(!_process_fp, ERR_CANT_OPEN, "Cannot pipe stream from process running with following arguments '" + argss + "'."); return OK; } // We just run it, no need to worry about output pid_t pid = fork(); ERR_FAIL_COND_V(pid < 0, ERR_CANT_FORK); if (pid == 0) { // is child if (!_blocking) { // For non blocking calls, create a new session-ID so parent won't wait for it. // This ensures the process won't go zombie at end. setsid(); } Vector cs; cs.push_back(_executable_path.utf8()); for (int i = 0; i < _arguments.size(); i++) { cs.push_back(_arguments[i].utf8()); } Vector args; for (int i = 0; i < cs.size(); i++) { args.push_back((char *)cs[i].get_data()); } args.push_back(0); execvp(_executable_path.utf8().get_data(), &args[0]); // still alive? something failed.. fprintf(stderr, "**ERROR** SubProcessUnix::execute - Could not create child process while executing: %s\n", _executable_path.utf8().get_data()); raise(SIGKILL); } if (_blocking) { int status; waitpid(pid, &status, 0); _exitcode = WIFEXITED(status) ? WEXITSTATUS(status) : status; } else { _process_id = pid; } return OK; #endif } Error SubProcessUnix::stop() { #ifdef __EMSCRIPTEN__ // Don't compile this code at all to avoid undefined references. // Actual virtual call goes to OS_JavaScript. ERR_FAIL_V(ERR_BUG); #else if (_process_fp) { int rv = pclose(_process_fp); _process_fp = NULL; _exitcode = WEXITSTATUS(rv); _process_id = 0; return OK; } if (_process_id) { int ret = ::kill(_process_id, SIGKILL); if (!ret) { //avoid zombie process int st; ::waitpid(_process_id, &st, 0); } _process_id = 0; return ret ? ERR_INVALID_PARAMETER : OK; } return OK; #endif } Error SubProcessUnix::poll() { #ifdef __EMSCRIPTEN__ // Don't compile this code at all to avoid undefined references. // Actual virtual call goes to OS_JavaScript. ERR_FAIL_V(ERR_BUG); #else if (_process_fp) { if (fgets(_process_buf, 65535, _process_fp)) { if (_pipe_mutex) { _pipe_mutex->lock(); } _pipe = String::utf8(_process_buf); if (_pipe_mutex) { _pipe_mutex->unlock(); } } else { // The process finished // Cleanup: stop(); return ERR_FILE_EOF; } } return OK; #endif } Error SubProcessUnix::send_signal(const int p_signal) { //Not Yet Impl ERR_FAIL_V(ERR_BUG); } Error SubProcessUnix::send_data(const String &p_data) { //Not Yet Impl ERR_FAIL_V(ERR_BUG); } bool SubProcessUnix::is_process_running() const { #ifdef __EMSCRIPTEN__ // Don't compile this code at all to avoid undefined references. // Actual virtual call goes to OS_JavaScript. ERR_FAIL_V(false); #else if (_process_fp) { return !feof(_process_fp); } if (_process_id == 0) { return false; } int status = 0; if (waitpid(_process_id, &status, WNOHANG) != 0) { return false; } return true; #endif } SubProcessUnix::SubProcessUnix() : SubProcess() { _process_fp = NULL; } SubProcessUnix::~SubProcessUnix() { stop(); } #endif //posix_enabled