| // 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 <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 <math.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <fcntl.h> |
| |
| #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; |
| } |