1 //===- SystemUtils.cpp - Utilities for low-level system tasks -------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file was developed by the LLVM research group and is distributed under 6 // the University of Illinois Open Source License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file contains functions used to do a variety of low-level, often 11 // system-specific, tasks. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/Support/SystemUtils.h" 16 #include "llvm/System/Program.h" 17 #include "llvm/Config/fcntl.h" 18 #include "llvm/Config/sys/wait.h" 19 #include <algorithm> 20 #include <cerrno> 21 #include <cstdlib> 22 #include <fstream> 23 #include <iostream> 24 #include <signal.h> 25 26 using namespace llvm; 27 28 /// isStandardOutAConsole - Return true if we can tell that the standard output 29 /// stream goes to a terminal window or console. 30 bool llvm::isStandardOutAConsole() { 31 #if HAVE_ISATTY 32 return isatty(1); 33 #endif 34 // If we don't have isatty, just return false. 35 return false; 36 } 37 38 39 /// FindExecutable - Find a named executable, giving the argv[0] of program 40 /// being executed. This allows us to find another LLVM tool if it is built 41 /// into the same directory, but that directory is neither the current 42 /// directory, nor in the PATH. If the executable cannot be found, return an 43 /// empty string. 44 /// 45 #undef FindExecutable // needed on windows :( 46 sys::Path llvm::FindExecutable(const std::string &ExeName, 47 const std::string &ProgramPath) { 48 // First check the directory that the calling program is in. We can do this 49 // if ProgramPath contains at least one / character, indicating that it is a 50 // relative path to bugpoint itself. 51 // 52 sys::Path Result ( ProgramPath ); 53 Result.elideFile(); 54 55 if (!Result.isEmpty()) { 56 Result.appendFile(ExeName); 57 if (Result.executable()) return Result; 58 } 59 60 return sys::Program::FindProgramByName(ExeName); 61 } 62 63 static void RedirectFD(const std::string &File, int FD) { 64 if (File.empty()) return; // Noop 65 66 // Open the file 67 int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666); 68 if (InFD == -1) { 69 std::cerr << "Error opening file '" << File << "' for " 70 << (FD == 0 ? "input" : "output") << "!\n"; 71 exit(1); 72 } 73 74 dup2(InFD, FD); // Install it as the requested FD 75 close(InFD); // Close the original FD 76 } 77 78 static bool Timeout = false; 79 static void TimeOutHandler(int Sig) { 80 Timeout = true; 81 } 82 83 /// RunProgramWithTimeout - This function executes the specified program, with 84 /// the specified null-terminated argument array, with the stdin/out/err fd's 85 /// redirected, with a timeout specified by the last argument. This terminates 86 /// the calling program if there is an error executing the specified program. 87 /// It returns the return value of the program, or -1 if a timeout is detected. 88 /// 89 int llvm::RunProgramWithTimeout(const std::string &ProgramPath, 90 const char **Args, 91 const std::string &StdInFile, 92 const std::string &StdOutFile, 93 const std::string &StdErrFile, 94 unsigned NumSeconds) { 95 #ifdef HAVE_SYS_WAIT_H 96 int Child = fork(); 97 switch (Child) { 98 case -1: 99 std::cerr << "ERROR forking!\n"; 100 exit(1); 101 case 0: // Child 102 RedirectFD(StdInFile, 0); // Redirect file descriptors... 103 RedirectFD(StdOutFile, 1); 104 if (StdOutFile != StdErrFile) 105 RedirectFD(StdErrFile, 2); 106 else 107 dup2(1, 2); 108 109 execv(ProgramPath.c_str(), (char *const *)Args); 110 std::cerr << "Error executing program: '" << ProgramPath; 111 for (; *Args; ++Args) 112 std::cerr << " " << *Args; 113 std::cerr << "'\n"; 114 exit(1); 115 116 default: break; 117 } 118 119 // Make sure all output has been written while waiting 120 std::cout << std::flush; 121 122 // Install a timeout handler. 123 Timeout = false; 124 struct sigaction Act, Old; 125 Act.sa_sigaction = 0; 126 Act.sa_handler = TimeOutHandler; 127 sigemptyset(&Act.sa_mask); 128 Act.sa_flags = 0; 129 sigaction(SIGALRM, &Act, &Old); 130 131 // Set the timeout if one is set. 132 if (NumSeconds) 133 alarm(NumSeconds); 134 135 int Status; 136 while (wait(&Status) != Child) 137 if (errno == EINTR) { 138 if (Timeout) { 139 // Kill the child. 140 kill(Child, SIGKILL); 141 142 if (wait(&Status) != Child) 143 std::cerr << "Something funny happened waiting for the child!\n"; 144 145 alarm(0); 146 sigaction(SIGALRM, &Old, 0); 147 return -1; // Timeout detected 148 } else { 149 std::cerr << "Error waiting for child process!\n"; 150 exit(1); 151 } 152 } 153 154 alarm(0); 155 sigaction(SIGALRM, &Old, 0); 156 return Status; 157 158 #else 159 std::cerr << "RunProgramWithTimeout not implemented on this platform!\n"; 160 return -1; 161 #endif 162 } 163