diff options
author | Philipp Wollermann <philwo@google.com> | 2017-05-16 18:05:14 +0200 |
---|---|---|
committer | Dmitry Lomov <dslomov@google.com> | 2017-05-17 15:20:47 +0200 |
commit | ef32c6aaab1f422b25bb6a9a7729b47422222433 (patch) | |
tree | 72b0878afd82e8316157cd198dce223b6b10e463 /src/main | |
parent | 734d9e5663d86f9802c74a2ebd0e3ad9def0678e (diff) |
Convert process-wrapper to C++.
No functional changes.
Change-Id: Ia87c19b70dd1ff8fa7465ad90c499cf351b9687b
PiperOrigin-RevId: 156188343
Diffstat (limited to 'src/main')
-rw-r--r-- | src/main/tools/BUILD | 20 | ||||
-rw-r--r-- | src/main/tools/build-runfiles.cc | 6 | ||||
-rw-r--r-- | src/main/tools/linux-sandbox-options.cc | 12 | ||||
-rw-r--r-- | src/main/tools/linux-sandbox-options.h | 1 | ||||
-rw-r--r-- | src/main/tools/linux-sandbox-pid1.cc | 64 | ||||
-rw-r--r-- | src/main/tools/linux-sandbox.cc | 17 | ||||
-rw-r--r-- | src/main/tools/process-tools.cc (renamed from src/main/tools/process-tools.c) | 105 | ||||
-rw-r--r-- | src/main/tools/process-tools.h | 43 | ||||
-rw-r--r-- | src/main/tools/process-wrapper.cc (renamed from src/main/tools/process-wrapper.c) | 80 |
9 files changed, 191 insertions, 157 deletions
diff --git a/src/main/tools/BUILD b/src/main/tools/BUILD index 3ddad54f9c..a29b71f03f 100644 --- a/src/main/tools/BUILD +++ b/src/main/tools/BUILD @@ -1,20 +1,28 @@ package(default_visibility = ["//src:__subpackages__"]) +cc_library( + name = "process-tools", + srcs = [ + "process-tools.cc", + "process-tools.h", + ], +) + cc_binary( name = "process-wrapper", srcs = select({ "//src:windows_msvc": ["process-wrapper-windows.cc"], "//conditions:default": [ - "process-tools.c", - "process-tools.h", - "process-wrapper.c", + "process-wrapper.cc", ], }), - copts = select({ + linkopts = ["-lm"], + deps = select({ "//src:windows_msvc": [], - "//conditions:default": ["-std=c99"], + "//conditions:default": [ + ":process-tools", + ], }), - linkopts = ["-lm"], ) cc_binary( diff --git a/src/main/tools/build-runfiles.cc b/src/main/tools/build-runfiles.cc index 8340b92d64..3f3c174d4a 100644 --- a/src/main/tools/build-runfiles.cc +++ b/src/main/tools/build-runfiles.cc @@ -241,7 +241,7 @@ class RunfilesCreator { errno = 0; const std::string prefix = (path == "." ? "" : path + "/"); - while ((entry = readdir(dh)) != NULL) { + while ((entry = readdir(dh)) != nullptr) { if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) continue; std::string entry_path = prefix + entry->d_name; @@ -383,7 +383,7 @@ class RunfilesCreator { PDIE("opendir '%s'", path.c_str()); } errno = 0; - while ((entry = readdir(dh)) != NULL) { + while ((entry = readdir(dh)) != nullptr) { if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) continue; const std::string entry_path = path + '/' + entry->d_name; FileType entry_file_type = DentryToFileType(entry_path, entry->d_type); @@ -441,7 +441,7 @@ int main(int argc, char **argv) { std::string manifest_file = input_filename; if (input_filename[0] != '/') { char cwd_buf[PATH_MAX]; - if (getcwd(cwd_buf, sizeof(cwd_buf)) == NULL) { + if (getcwd(cwd_buf, sizeof(cwd_buf)) == nullptr) { PDIE("getcwd failed"); } manifest_file = std::string(cwd_buf) + '/' + manifest_file; diff --git a/src/main/tools/linux-sandbox-options.cc b/src/main/tools/linux-sandbox-options.cc index 51368247e8..c646cece0f 100644 --- a/src/main/tools/linux-sandbox-options.cc +++ b/src/main/tools/linux-sandbox-options.cc @@ -12,17 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "linux-sandbox-options.h" -#include "linux-sandbox-utils.h" - #define DIE(args...) \ { \ fprintf(stderr, __FILE__ ":" S__LINE__ ": \"" args); \ fprintf(stderr, "\": "); \ - perror(NULL); \ + perror(nullptr); \ exit(EXIT_FAILURE); \ } +#include "src/main/tools/linux-sandbox-options.h" + #include <errno.h> #include <sched.h> #include <stdarg.h> @@ -32,13 +31,14 @@ #include <string.h> #include <sys/wait.h> #include <unistd.h> - #include <fstream> #include <iostream> #include <memory> #include <string> #include <vector> +#include "src/main/tools/linux-sandbox-utils.h" + using std::ifstream; using std::unique_ptr; using std::vector; @@ -260,6 +260,6 @@ void ParseOptions(int argc, char *argv[]) { } if (opt.working_dir.empty()) { - opt.working_dir = getcwd(NULL, 0); + opt.working_dir = getcwd(nullptr, 0); } } diff --git a/src/main/tools/linux-sandbox-options.h b/src/main/tools/linux-sandbox-options.h index a73ca64535..d67a14baa2 100644 --- a/src/main/tools/linux-sandbox-options.h +++ b/src/main/tools/linux-sandbox-options.h @@ -17,7 +17,6 @@ #include <stdbool.h> #include <stddef.h> - #include <string> #include <vector> diff --git a/src/main/tools/linux-sandbox-pid1.cc b/src/main/tools/linux-sandbox-pid1.cc index 0095d7262c..740c8de242 100644 --- a/src/main/tools/linux-sandbox-pid1.cc +++ b/src/main/tools/linux-sandbox-pid1.cc @@ -17,9 +17,9 @@ * mount, UTS, IPC and PID namespace. */ -#include "linux-sandbox-options.h" -#include "linux-sandbox-utils.h" -#include "linux-sandbox.h" +#include "src/main/tools/linux-sandbox-options.h" +#include "src/main/tools/linux-sandbox-utils.h" +#include "src/main/tools/linux-sandbox.h" // Note that we define DIE() here and not in a shared header, because we want to // use _exit() in the @@ -28,7 +28,7 @@ { \ fprintf(stderr, __FILE__ ":" S__LINE__ ": \"" args); \ fprintf(stderr, "\": "); \ - perror(NULL); \ + perror(nullptr); \ _exit(EXIT_FAILURE); \ } @@ -84,14 +84,14 @@ static void SetupSelfDestruction(int *sync_pipe) { static void SetupMountNamespace() { // Fully isolate our mount namespace private from outside events, so that // mounts in the outside environment do not affect our sandbox. - if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) < 0) { + if (mount(nullptr, "/", nullptr, MS_REC | MS_PRIVATE, nullptr) < 0) { DIE("mount"); } } static void WriteFile(const std::string &filename, const char *fmt, ...) { FILE *stream = fopen(filename.c_str(), "w"); - if (stream == NULL) { + if (stream == nullptr) { DIE("fopen(%s)", filename.c_str()); } @@ -130,7 +130,7 @@ static void SetupUserNamespace() { } else if (opt.fake_username) { // Change our username to 'nobody'. struct passwd *pwd = getpwnam("nobody"); - if (pwd == NULL) { + if (pwd == nullptr) { DIE("unable to find passwd entry for user nobody") } @@ -160,8 +160,8 @@ static void MountFilesystems() { for (const std::string &tmpfs_dir : opt.tmpfs_dirs) { PRINT_DEBUG("tmpfs: %s", tmpfs_dir.c_str()); if (mount("tmpfs", tmpfs_dir.c_str(), "tmpfs", - MS_NOSUID | MS_NODEV | MS_NOATIME, NULL) < 0) { - DIE("mount(tmpfs, %s, tmpfs, MS_NOSUID | MS_NODEV | MS_NOATIME, NULL)", + MS_NOSUID | MS_NODEV | MS_NOATIME, nullptr) < 0) { + DIE("mount(tmpfs, %s, tmpfs, MS_NOSUID | MS_NODEV | MS_NOATIME, nullptr)", tmpfs_dir.c_str()); } } @@ -170,9 +170,9 @@ static void MountFilesystems() { // do this is by bind-mounting it upon itself. PRINT_DEBUG("working dir: %s", opt.working_dir.c_str()); - if (mount(opt.working_dir.c_str(), opt.working_dir.c_str(), NULL, MS_BIND, - NULL) < 0) { - DIE("mount(%s, %s, NULL, MS_BIND, NULL)", opt.working_dir.c_str(), + if (mount(opt.working_dir.c_str(), opt.working_dir.c_str(), nullptr, MS_BIND, + nullptr) < 0) { + DIE("mount(%s, %s, nullptr, MS_BIND, nullptr)", opt.working_dir.c_str(), opt.working_dir.c_str()); } @@ -180,16 +180,17 @@ static void MountFilesystems() { std::string source = opt.bind_mount_sources.at(i); std::string target = opt.bind_mount_targets.at(i); PRINT_DEBUG("bind mount: %s -> %s", source.c_str(), target.c_str()); - if (mount(source.c_str(), target.c_str(), NULL, MS_BIND, NULL) < 0) { - DIE("mount(%s, %s, NULL, MS_BIND, NULL)", source.c_str(), target.c_str()); + if (mount(source.c_str(), target.c_str(), nullptr, MS_BIND, nullptr) < 0) { + DIE("mount(%s, %s, nullptr, MS_BIND, nullptr)", source.c_str(), + target.c_str()); } } for (const std::string &writable_file : opt.writable_files) { PRINT_DEBUG("writable: %s", writable_file.c_str()); - if (mount(writable_file.c_str(), writable_file.c_str(), NULL, MS_BIND, - NULL) < 0) { - DIE("mount(%s, %s, NULL, MS_BIND, NULL)", writable_file.c_str(), + if (mount(writable_file.c_str(), writable_file.c_str(), nullptr, MS_BIND, + nullptr) < 0) { + DIE("mount(%s, %s, nullptr, MS_BIND, nullptr)", writable_file.c_str(), writable_file.c_str()); } } @@ -221,34 +222,34 @@ static bool ShouldBeWritable(const std::string &mnt_dir) { // ShouldBeWritable returns true. static void MakeFilesystemMostlyReadOnly() { FILE *mounts = setmntent("/proc/self/mounts", "r"); - if (mounts == NULL) { + if (mounts == nullptr) { DIE("setmntent"); } struct mntent *ent; - while ((ent = getmntent(mounts)) != NULL) { + while ((ent = getmntent(mounts)) != nullptr) { int mountFlags = MS_BIND | MS_REMOUNT; // MS_REMOUNT does not allow us to change certain flags. This means, we have // to first read them out and then pass them in back again. There seems to // be no better way than this (an API for just getting the mount flags of a // mount entry as a bitmask would be great). - if (hasmntopt(ent, "nodev") != NULL) { + if (hasmntopt(ent, "nodev") != nullptr) { mountFlags |= MS_NODEV; } - if (hasmntopt(ent, "noexec") != NULL) { + if (hasmntopt(ent, "noexec") != nullptr) { mountFlags |= MS_NOEXEC; } - if (hasmntopt(ent, "nosuid") != NULL) { + if (hasmntopt(ent, "nosuid") != nullptr) { mountFlags |= MS_NOSUID; } - if (hasmntopt(ent, "noatime") != NULL) { + if (hasmntopt(ent, "noatime") != nullptr) { mountFlags |= MS_NOATIME; } - if (hasmntopt(ent, "nodiratime") != NULL) { + if (hasmntopt(ent, "nodiratime") != nullptr) { mountFlags |= MS_NODIRATIME; } - if (hasmntopt(ent, "relatime") != NULL) { + if (hasmntopt(ent, "relatime") != nullptr) { mountFlags |= MS_RELATIME; } @@ -258,7 +259,7 @@ static void MakeFilesystemMostlyReadOnly() { PRINT_DEBUG("remount %s: %s", (mountFlags & MS_RDONLY) ? "ro" : "rw", ent->mnt_dir); - if (mount(NULL, ent->mnt_dir, NULL, mountFlags, NULL) < 0) { + if (mount(nullptr, ent->mnt_dir, nullptr, mountFlags, nullptr) < 0) { // If we get EACCES or EPERM, this might be a mount-point for which we // don't have read access. Not much we can do about this, but it also // won't do any harm, so let's go on. The same goes for EINVAL or ENOENT, @@ -272,7 +273,8 @@ static void MakeFilesystemMostlyReadOnly() { // should just ignore it. if (errno != EACCES && errno != EPERM && errno != EINVAL && errno != ENOENT && errno != ESTALE) { - DIE("remount(NULL, %s, NULL, %d, NULL)", ent->mnt_dir, mountFlags); + DIE("remount(nullptr, %s, nullptr, %d, nullptr)", ent->mnt_dir, + mountFlags); } } } @@ -283,8 +285,8 @@ static void MakeFilesystemMostlyReadOnly() { static void MountProc() { // Mount a new proc on top of the old one, because the old one still refers to // our parent PID namespace. - if (mount("/proc", "/proc", "proc", MS_NODEV | MS_NOEXEC | MS_NOSUID, NULL) < - 0) { + if (mount("/proc", "/proc", "proc", MS_NODEV | MS_NOEXEC | MS_NOSUID, + nullptr) < 0) { DIE("mount"); } } @@ -345,8 +347,8 @@ static void InstallSignalHandler(int signum, void (*handler)(int)) { } // sigaction may fail for certain reserved signals. Ignore failure in this // case, but report it in debug mode, just in case. - if (sigaction(signum, &sa, NULL) < 0) { - PRINT_DEBUG("sigaction(%d, &sa, NULL) failed", signum); + if (sigaction(signum, &sa, nullptr) < 0) { + PRINT_DEBUG("sigaction(%d, &sa, nullptr) failed", signum); } } diff --git a/src/main/tools/linux-sandbox.cc b/src/main/tools/linux-sandbox.cc index 1f078026d7..b58905e6af 100644 --- a/src/main/tools/linux-sandbox.cc +++ b/src/main/tools/linux-sandbox.cc @@ -37,15 +37,11 @@ * system are invisible. */ -#include "linux-sandbox-options.h" -#include "linux-sandbox-pid1.h" -#include "linux-sandbox-utils.h" - #define DIE(args...) \ { \ fprintf(stderr, __FILE__ ":" S__LINE__ ": \"" args); \ fprintf(stderr, "\": "); \ - perror(NULL); \ + perror(nullptr); \ exit(EXIT_FAILURE); \ } @@ -66,10 +62,13 @@ #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> - #include <string> #include <vector> +#include "src/main/tools/linux-sandbox-options.h" +#include "src/main/tools/linux-sandbox-pid1.h" +#include "src/main/tools/linux-sandbox-utils.h" + int global_outer_uid; int global_outer_gid; @@ -83,7 +82,7 @@ static volatile sig_atomic_t global_signal; static void CloseFds() { DIR *fds = opendir("/proc/self/fd"); - if (fds == NULL) { + if (fds == nullptr) { DIE("opendir"); } @@ -91,7 +90,7 @@ static void CloseFds() { errno = 0; struct dirent *dent = readdir(fds); - if (dent == NULL) { + if (dent == nullptr) { if (errno != 0) { DIE("readdir"); } @@ -125,7 +124,7 @@ static void HandleSignal(int signum, void (*handler)(int)) { if (sigemptyset(&sa.sa_mask) < 0) { DIE("sigemptyset"); } - if (sigaction(signum, &sa, NULL) < 0) { + if (sigaction(signum, &sa, nullptr) < 0) { DIE("sigaction"); } } diff --git a/src/main/tools/process-tools.c b/src/main/tools/process-tools.cc index 9dddfee5f5..a25dbeeb1d 100644 --- a/src/main/tools/process-tools.c +++ b/src/main/tools/process-tools.cc @@ -12,28 +12,30 @@ // See the License for the specific language governing permissions and // limitations under the License. -#define _GNU_SOURCE +#include "src/main/tools/process-tools.h" -#include <unistd.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/wait.h> #include <errno.h> -#include <signal.h> +#include <fcntl.h> #include <math.h> +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <fcntl.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> -#include "process-tools.h" +extern bool global_debug; int SwitchToEuid() { int uid = getuid(); int euid = geteuid(); if (uid != euid) { - CHECK_CALL(setreuid(euid, euid)); + if (setreuid(euid, euid) < 0) { + DIE("setreuid"); + } } return euid; } @@ -42,35 +44,44 @@ int SwitchToEgid() { int gid = getgid(); int egid = getegid(); if (gid != egid) { - CHECK_CALL(setregid(egid, egid)); + if (setregid(egid, egid) < 0) { + DIE("setregid"); + } } return egid; } -void Redirect(const char *target_path, int fd, const char *name) { - if (target_path != NULL && strcmp(target_path, "-") != 0) { - int fd_out; +void Redirect(const std::string &target_path, int fd) { + if (!target_path.empty() && target_path != "-") { const int flags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND; - CHECK_CALL(fd_out = open(target_path, flags, 0666)); - CHECK_CALL(dup2(fd_out, fd)); - CHECK_CALL(close(fd_out)); + int fd_out = open(target_path.c_str(), flags, 0666); + if (fd_out < 0) { + DIE("open(%s)", target_path.c_str()); + } + // If we were launched with less than 3 fds (stdin, stdout, stderr) open, + // but redirection is still requested via a command-line flag, something is + // wacky and the following code would not do what we intend to do, so let's + // bail. + if (fd_out < 3) { + DIE("open(%s) returned a handle that is reserved for stdin / stdout / " + "stderr", + target_path.c_str()); + } + if (dup2(fd_out, fd) < 0) { + DIE("dup2"); + } + if (close(fd_out) < 0) { + DIE("close"); + } } } -void RedirectStdout(const char *stdout_path) { - Redirect(stdout_path, STDOUT_FILENO, "stdout"); -} - -void RedirectStderr(const char *stderr_path) { - Redirect(stderr_path, STDERR_FILENO, "stderr"); -} - -void KillEverything(int pgrp, bool gracefully, double graceful_kill_delay) { +void KillEverything(pid_t pgrp, bool gracefully, double graceful_kill_delay) { if (gracefully) { kill(-pgrp, SIGTERM); // Round up fractional seconds in this polling implementation. - int kill_delay = (int)(ceil(graceful_kill_delay)); + int kill_delay = static_cast<int>(ceil(graceful_kill_delay)); // If the process is still alive, give it some time to die gracefully. while (kill_delay-- > 0 && kill(-pgrp, 0) == 0) { @@ -82,9 +93,14 @@ void KillEverything(int pgrp, bool gracefully, double graceful_kill_delay) { } void HandleSignal(int sig, void (*handler)(int)) { - struct sigaction sa = {.sa_handler = handler}; - CHECK_CALL(sigemptyset(&sa.sa_mask)); - CHECK_CALL(sigaction(sig, &sa, NULL)); + struct sigaction sa = {}; + sa.sa_handler = handler; + if (sigemptyset(&sa.sa_mask) < 0) { + DIE("sigemptyset"); + } + if (sigaction(sig, &sa, nullptr) < 0) { + DIE("sigaction"); + } } void UnHandle(int sig) { @@ -103,19 +119,26 @@ void UnHandle(int sig) { void ClearSignalMask() { // Use an empty signal mask for the process. sigset_t empty_sset; - CHECK_CALL(sigemptyset(&empty_sset)); - CHECK_CALL(sigprocmask(SIG_SETMASK, &empty_sset, NULL)); + if (sigemptyset(&empty_sset) < 0) { + DIE("sigemptyset"); + } + if (sigprocmask(SIG_SETMASK, &empty_sset, nullptr) < 0) { + DIE("sigprocmask"); + } // Set the default signal handler for all signals. for (int i = 1; i < NSIG; ++i) { if (i == SIGKILL || i == SIGSTOP) { continue; } - struct sigaction sa = {.sa_handler = SIG_DFL}; - CHECK_CALL(sigemptyset(&sa.sa_mask)); + struct sigaction sa = {}; + sa.sa_handler = SIG_DFL; + if (sigemptyset(&sa.sa_mask) < 0) { + DIE("sigemptyset"); + } // Ignore possible errors, because we might not be allowed to set the // handler for certain signals, but we still want to try. - sigaction(i, &sa, NULL); + sigaction(i, &sa, nullptr); } } @@ -130,13 +153,15 @@ void SetTimeout(double timeout_secs) { struct itimerval timer; timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 0; - timer.it_value.tv_sec = (long)int_val, - timer.it_value.tv_usec = (long)(fraction_val * 1e6); + timer.it_value.tv_sec = static_cast<time_t>(int_val), + timer.it_value.tv_usec = static_cast<suseconds_t>(fraction_val * 1e6); - CHECK_CALL(setitimer(ITIMER_REAL, &timer, NULL)); + if (setitimer(ITIMER_REAL, &timer, nullptr) < 0) { + DIE("setitimer"); + } } -int WaitChild(pid_t pid, const char *name) { +int WaitChild(pid_t pid) { int err, status; do { @@ -144,7 +169,7 @@ int WaitChild(pid_t pid, const char *name) { } while (err == -1 && errno == EINTR); if (err == -1) { - DIE("wait on %s (pid %d) failed\n", name, pid); + DIE("wait"); } return status; diff --git a/src/main/tools/process-tools.h b/src/main/tools/process-tools.h index a0ba38816d..7a8554d4ea 100644 --- a/src/main/tools/process-tools.h +++ b/src/main/tools/process-tools.h @@ -15,8 +15,9 @@ #ifndef PROCESS_TOOLS_H__ #define PROCESS_TOOLS_H__ -#include <sys/types.h> #include <stdbool.h> +#include <sys/types.h> +#include <string> // see // http://stackoverflow.com/questions/5641427/how-to-make-preprocessor-generate-a-string-for-line-keyword @@ -24,24 +25,21 @@ #define S_(x) S(x) #define S__LINE__ S_(__LINE__) -#define DIE(args...) \ - { \ - fprintf(stderr, __FILE__ ":" S__LINE__ ": " args); \ - exit(EXIT_FAILURE); \ - } - -#define CHECK_CALL(x) \ - if ((x) == -1) { \ - fprintf(stderr, __FILE__ ":" S__LINE__ ": "); \ - perror(#x); \ - exit(EXIT_FAILURE); \ +#define DIE(...) \ + { \ + fprintf(stderr, __FILE__ ":" S__LINE__ ": \"" __VA_ARGS__); \ + fprintf(stderr, "\": "); \ + perror(nullptr); \ + exit(EXIT_FAILURE); \ } -#define CHECK_NOT_NULL(x) \ - if (x == NULL) { \ - perror(#x); \ - exit(EXIT_FAILURE); \ - } +#define PRINT_DEBUG(...) \ + do { \ + if (global_debug) { \ + fprintf(stderr, __FILE__ ":" S__LINE__ ": " __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } \ + } while (0) // Switch completely to the effective uid. // Some programs (notably, bash) ignore the euid and just use the uid. This @@ -52,17 +50,14 @@ int SwitchToEuid(); // Switch completely to the effective gid. int SwitchToEgid(); -// Redirect stdout to the file stdout_path (but not if stdout_path is "-"). -void RedirectStdout(const char *stdout_path); - -// Redirect stderr to the file stdout_path (but not if stderr_path is "-"). -void RedirectStderr(const char *stderr_path); +// Redirect fd to the file target_path (but not if target_path is empty or "-"). +void Redirect(const std::string &target_path, int fd); // Make sure the process group "pgrp" and all its subprocesses are killed. // If "gracefully" is true, sends SIGTERM first and after a timeout of // "graceful_kill_delay" seconds, sends SIGKILL. // If not, send SIGKILL immediately. -void KillEverything(int pgrp, bool gracefully, double graceful_kill_delay); +void KillEverything(pid_t pgrp, bool gracefully, double graceful_kill_delay); // Set up a signal handler for a signal. void HandleSignal(int sig, void (*handler)(int)); @@ -80,6 +75,6 @@ void SetTimeout(double timeout_secs); // Wait for "pid" to exit and return its exit code. // "name" is used for the error message only. -int WaitChild(pid_t pid, const char *name); +int WaitChild(pid_t pid); #endif // PROCESS_TOOLS_H__ diff --git a/src/main/tools/process-wrapper.c b/src/main/tools/process-wrapper.cc index 07ae840a52..6140eba713 100644 --- a/src/main/tools/process-wrapper.c +++ b/src/main/tools/process-wrapper.cc @@ -22,8 +22,6 @@ // die with raise(SIGTERM) even if the child process handles SIGTERM with // exit(0). -#define _GNU_SOURCE - #include <err.h> #include <errno.h> #include <signal.h> @@ -31,57 +29,62 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/types.h> #include <sys/stat.h> +#include <sys/types.h> #include <sys/wait.h> #include <unistd.h> +#include <string> +#include <vector> -#include "process-tools.h" +#include "src/main/tools/process-tools.h" -// Not in headers on OSX. -extern char **environ; +bool global_debug = false; static double global_kill_delay; -static int global_child_pid; +static pid_t global_child_pid; static volatile sig_atomic_t global_signal; // Options parsing result. struct Options { double timeout_secs; double kill_delay_secs; - const char *stdout_path; - const char *stderr_path; - char *const *args; + std::string stdout_path; + std::string stderr_path; + std::vector<char *> args; }; -// Print out a usage error. argc and argv are the argument counter and vector, -// fmt is a format, -// string for the error message to print. -static void Usage(char *const *argv) { +static struct Options opt; + +// Print out a usage error and exit with EXIT_FAILURE. +static void Usage(char *program_name) { fprintf(stderr, "Usage: %s <timeout-secs> <kill-delay-secs> <stdout-redirect> " "<stderr-redirect> <command> [args] ...\n", - argv[0]); + program_name); exit(EXIT_FAILURE); } // Parse the command line flags and return the result in an Options structure // passed as argument. -static void ParseCommandLine(int argc, char *const *argv, struct Options *opt) { - if (argc <= 5) { - Usage(argv); +static void ParseCommandLine(std::vector<char *> args) { + if (args.size() < 5) { + Usage(args.front()); } - argv++; - if (sscanf(*argv++, "%lf", &opt->timeout_secs) != 1) { + int optind = 1; + + if (sscanf(args[optind++], "%lf", &opt.timeout_secs) != 1) { DIE("timeout_secs is not a real number.\n"); } - if (sscanf(*argv++, "%lf", &opt->kill_delay_secs) != 1) { + if (sscanf(args[optind++], "%lf", &opt.kill_delay_secs) != 1) { DIE("kill_delay_secs is not a real number.\n"); } - opt->stdout_path = *argv++; - opt->stderr_path = *argv++; - opt->args = argv; + opt.stdout_path.assign(args[optind++]); + opt.stderr_path.assign(args[optind++]); + opt.args.assign(args.begin() + optind, args.end()); + + // argv[] passed to execve() must be a null-terminated array. + opt.args.push_back(nullptr); } // Called when timeout or signal occurs. @@ -106,11 +109,15 @@ void OnSignal(int sig) { // Run the command specified by the argv array and kill it after timeout // seconds. -static void SpawnCommand(char *const *argv, double timeout_secs) { - CHECK_CALL(global_child_pid = fork()); - if (global_child_pid == 0) { +static void SpawnCommand(const std::vector<char *> &args, double timeout_secs) { + global_child_pid = fork(); + if (global_child_pid < 0) { + DIE("fork"); + } else if (global_child_pid == 0) { // In child. - CHECK_CALL(setsid()); + if (setsid() < 0) { + DIE("setsid"); + } ClearSignalMask(); // Force umask to include read and execute for everyone, to make @@ -118,8 +125,9 @@ static void SpawnCommand(char *const *argv, double timeout_secs) { umask(022); // Does not return unless something went wrong. - execvp(argv[0], argv); - err(EXIT_FAILURE, "execvp(\"%s\", ...)", argv[0]); + if (execvp(args[0], args.data()) < 0) { + DIE("execvp(%s, ...)", args[0]); + } } else { // In parent. @@ -130,7 +138,7 @@ static void SpawnCommand(char *const *argv, double timeout_secs) { HandleSignal(SIGINT, OnSignal); SetTimeout(timeout_secs); - int status = WaitChild(global_child_pid, argv[0]); + int status = WaitChild(global_child_pid); // The child is done for, but may have grandchildren that we still have to // kill. @@ -151,17 +159,15 @@ static void SpawnCommand(char *const *argv, double timeout_secs) { } int main(int argc, char *argv[]) { - struct Options opt; - memset(&opt, 0, sizeof(opt)); - - ParseCommandLine(argc, argv, &opt); + std::vector<char *> args(argv, argv + argc); + ParseCommandLine(args); global_kill_delay = opt.kill_delay_secs; SwitchToEuid(); SwitchToEgid(); - RedirectStdout(opt.stdout_path); - RedirectStderr(opt.stderr_path); + Redirect(opt.stdout_path, STDOUT_FILENO); + Redirect(opt.stderr_path, STDERR_FILENO); SpawnCommand(opt.args, opt.timeout_secs); |