| // 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; | 
 | } |