// Copyright 2015 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include "process-tools.h" int SwitchToEuid() { int uid = getuid(); int euid = geteuid(); if (uid != euid) { CHECK_CALL(setreuid(euid, euid)); } return euid; } int SwitchToEgid() { int gid = getgid(); int egid = getegid(); if (gid != egid) { CHECK_CALL(setregid(egid, egid)); } return egid; } void Redirect(const char *target_path, int fd, const char *name) { if (target_path != NULL && strcmp(target_path, "-") != 0) { int fd_out; 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)); } } 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) { if (gracefully) { kill(-pgrp, SIGTERM); // Round up fractional seconds in this polling implementation. int kill_delay = (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) { sleep(1); } } kill(-pgrp, SIGKILL); } 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)); } void UnHandle(int sig) { switch (sig) { case SIGSTOP: case SIGKILL: // These signals can't be handled, so they'll always have a valid default // handler. In fact, even trying to install SIG_DFL again will result in // EINVAL, so we'll just not do anything for these. return; default: HandleSignal(sig, SIG_DFL); } } 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)); // 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)); // 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); } } void SetTimeout(double timeout_secs) { if (timeout_secs <= 0) { return; } double int_val, fraction_val; fraction_val = modf(timeout_secs, &int_val); 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); CHECK_CALL(setitimer(ITIMER_REAL, &timer, NULL)); } int WaitChild(pid_t pid, const char *name) { int err, status; do { err = waitpid(pid, &status, 0); } while (err == -1 && errno == EINTR); if (err == -1) { DIE("wait on %s (pid %d) failed\n", name, pid); } return status; }