2023-12-17 15:39:29 +01:00
|
|
|
|
2023-12-14 21:54:22 +01:00
|
|
|
/* dir_access_unix.cpp */
|
2023-12-17 15:39:29 +01:00
|
|
|
|
2023-12-14 21:54:22 +01:00
|
|
|
|
|
|
|
#include "sub_process_unix.h"
|
|
|
|
|
|
|
|
#ifdef UNIX_ENABLED
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
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<CharString> cs;
|
|
|
|
cs.push_back(_executable_path.utf8());
|
|
|
|
for (int i = 0; i < _arguments.size(); i++) {
|
|
|
|
cs.push_back(_arguments[i].utf8());
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector<char *> 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
|