aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/tools
diff options
context:
space:
mode:
authorGravatar Philipp Wollermann <philwo@google.com>2017-05-16 18:05:14 +0200
committerGravatar Dmitry Lomov <dslomov@google.com>2017-05-17 15:20:47 +0200
commitef32c6aaab1f422b25bb6a9a7729b47422222433 (patch)
tree72b0878afd82e8316157cd198dce223b6b10e463 /src/main/tools
parent734d9e5663d86f9802c74a2ebd0e3ad9def0678e (diff)
Convert process-wrapper to C++.
No functional changes. Change-Id: Ia87c19b70dd1ff8fa7465ad90c499cf351b9687b PiperOrigin-RevId: 156188343
Diffstat (limited to 'src/main/tools')
-rw-r--r--src/main/tools/BUILD20
-rw-r--r--src/main/tools/build-runfiles.cc6
-rw-r--r--src/main/tools/linux-sandbox-options.cc12
-rw-r--r--src/main/tools/linux-sandbox-options.h1
-rw-r--r--src/main/tools/linux-sandbox-pid1.cc64
-rw-r--r--src/main/tools/linux-sandbox.cc17
-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.h43
-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);