diff --git a/src/os/unix/crashlog_unix.cpp b/src/os/unix/crashlog_unix.cpp index ac5277c02d..8e4313cd85 100644 --- a/src/os/unix/crashlog_unix.cpp +++ b/src/os/unix/crashlog_unix.cpp @@ -72,16 +72,66 @@ static void LogStacktraceSigSegvHandler(int sig) } #endif +static int GetTemporaryFD() +{ + char name[MAX_PATH]; + extern std::string _personal_dir; + seprintf(name, lastof(name), "%sopenttd-tmp-XXXXXX", _personal_dir.c_str()); + int fd = mkstemp(name); + if (fd != -1) { + /* Unlink file but leave fd open until finished with */ + unlink(name); + } + return fd; +} + +struct ExecReadNullHandler { + int fd[2] = { -1, -1 }; + + bool Init() { + this->fd[0] = open("/dev/null", O_RDWR); + if (this->fd[0] == -1) { + this->fd[0] = GetTemporaryFD(); + if (this->fd[0] == -1) { + return false; + } + this->fd[1] = GetTemporaryFD(); + if (this->fd[1] == -1) { + this->Close(); + return false; + } + } else { + this->fd[1] = this->fd[0]; + } + return true; + } + + void Close() { + if (this->fd[0] != -1) close(this->fd[0]); + if (this->fd[1] != -1 && this->fd[0] != this->fd[1]) close(this->fd[1]); + this->fd[0] = -1; + this->fd[1] = -1; + } +}; + static bool ExecReadStdout(const char *file, char *const *args, char *&buffer, const char *last) { - int null_fd = open("/dev/null", O_RDWR); - if (null_fd == -1) return false; + ExecReadNullHandler nulls; + if (!nulls.Init()) return false; int pipefd[2]; - if (pipe(pipefd) == -1) return false; + if (pipe(pipefd) == -1) { + nulls.Close(); + return false; + } int pid = fork(); - if (pid < 0) return false; + if (pid < 0) { + nulls.Close(); + close(pipefd[0]); + close(pipefd[1]); + return false; + } if (pid == 0) { /* child */ @@ -89,9 +139,9 @@ static bool ExecReadStdout(const char *file, char *const *args, char *&buffer, c close(pipefd[0]); /* Close unused read end */ dup2(pipefd[1], STDOUT_FILENO); close(pipefd[1]); - dup2(null_fd, STDERR_FILENO); - dup2(null_fd, STDIN_FILENO); - close(null_fd); + dup2(nulls.fd[0], STDERR_FILENO); + dup2(nulls.fd[1], STDIN_FILENO); + nulls.Close(); execvp(file, args); exit(42); @@ -99,7 +149,7 @@ static bool ExecReadStdout(const char *file, char *const *args, char *&buffer, c /* parent */ - close(null_fd); + nulls.Close(); close(pipefd[1]); /* Close unused write end */ while (buffer < last) { @@ -130,24 +180,18 @@ static bool ExecReadStdout(const char *file, char *const *args, char *&buffer, c static bool ExecReadStdoutThroughFile(const char *file, char *const *args, char *&buffer, const char *last) { - int null_fd = open("/dev/null", O_RDWR); - if (null_fd == -1) return false; + ExecReadNullHandler nulls; + if (!nulls.Init()) return false; - char name[MAX_PATH]; - extern std::string _personal_dir; - seprintf(name, lastof(name), "%sopenttd-tmp-XXXXXX", _personal_dir.c_str()); - int fd = mkstemp(name); + int fd = GetTemporaryFD(); if (fd == -1) { - close(null_fd); + nulls.Close(); return false; } - /* Unlink file but leave fd open until finished with */ - unlink(name); - int pid = fork(); if (pid < 0) { - close(null_fd); + nulls.Close(); close(fd); return false; } @@ -157,9 +201,9 @@ static bool ExecReadStdoutThroughFile(const char *file, char *const *args, char dup2(fd, STDOUT_FILENO); close(fd); - dup2(null_fd, STDERR_FILENO); - dup2(null_fd, STDIN_FILENO); - close(null_fd); + dup2(nulls.fd[0], STDERR_FILENO); + dup2(nulls.fd[1], STDIN_FILENO); + nulls.Close(); execvp(file, args); exit(42); @@ -167,7 +211,7 @@ static bool ExecReadStdoutThroughFile(const char *file, char *const *args, char /* parent */ - close(null_fd); + nulls.Close(); int status; int wait_ret = waitpid(pid, &status, 0);