| Misha Brukman | ebb0faa | 2004-06-18 15:38:49 +0000 | [diff] [blame] | 1 | //===- SystemUtils.cpp - Utilities for low-level system tasks -------------===// | 
| John Criswell | b576c94 | 2003-10-20 19:43:21 +0000 | [diff] [blame] | 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 | //===----------------------------------------------------------------------===// | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 9 | // | 
 | 10 | // This file contains functions used to do a variety of low-level, often | 
 | 11 | // system-specific, tasks. | 
 | 12 | // | 
 | 13 | //===----------------------------------------------------------------------===// | 
 | 14 |  | 
| Reid Spencer | 551ccae | 2004-09-01 22:55:40 +0000 | [diff] [blame] | 15 | #include "llvm/Support/SystemUtils.h" | 
| Reid Spencer | 9665e8a | 2004-12-13 23:41:37 +0000 | [diff] [blame] | 16 | #include "llvm/System/Program.h" | 
| Reid Spencer | 44f6966 | 2004-12-14 04:18:15 +0000 | [diff] [blame^] | 17 | #include "llvm/Config/fcntl.h" | 
 | 18 | #include "llvm/Config/sys/wait.h" | 
| Chris Lattner | 74b1f45 | 2004-01-10 19:15:14 +0000 | [diff] [blame] | 19 | #include <algorithm> | 
| Misha Brukman | ebb0faa | 2004-06-18 15:38:49 +0000 | [diff] [blame] | 20 | #include <cerrno> | 
 | 21 | #include <cstdlib> | 
| Chris Lattner | 74b1f45 | 2004-01-10 19:15:14 +0000 | [diff] [blame] | 22 | #include <fstream> | 
 | 23 | #include <iostream> | 
| Chris Lattner | d67e439 | 2004-07-25 07:34:00 +0000 | [diff] [blame] | 24 | #include <signal.h> | 
| Reid Spencer | 44f6966 | 2004-12-14 04:18:15 +0000 | [diff] [blame^] | 25 |  | 
| Chris Lattner | 2cdd21c | 2003-12-14 21:35:53 +0000 | [diff] [blame] | 26 | using namespace llvm; | 
| Brian Gaeke | d0fde30 | 2003-11-11 22:41:34 +0000 | [diff] [blame] | 27 |  | 
| Chris Lattner | b234d46 | 2004-04-02 05:04:03 +0000 | [diff] [blame] | 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() { | 
| Brian Gaeke | 8507ecb | 2004-04-02 21:26:04 +0000 | [diff] [blame] | 31 | #if HAVE_ISATTY | 
| Chris Lattner | b234d46 | 2004-04-02 05:04:03 +0000 | [diff] [blame] | 32 |   return isatty(1); | 
| Brian Gaeke | 8507ecb | 2004-04-02 21:26:04 +0000 | [diff] [blame] | 33 | #endif | 
 | 34 |   // If we don't have isatty, just return false. | 
 | 35 |   return false; | 
| Chris Lattner | b234d46 | 2004-04-02 05:04:03 +0000 | [diff] [blame] | 36 | } | 
 | 37 |  | 
 | 38 |  | 
| Misha Brukman | f7066c7 | 2003-08-07 21:34:25 +0000 | [diff] [blame] | 39 | /// FindExecutable - Find a named executable, giving the argv[0] of program | 
| Misha Brukman | 44f8a34 | 2003-09-29 22:40:07 +0000 | [diff] [blame] | 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. | 
| Misha Brukman | f7066c7 | 2003-08-07 21:34:25 +0000 | [diff] [blame] | 44 | ///  | 
| Chris Lattner | 49f61c4 | 2004-05-28 01:20:58 +0000 | [diff] [blame] | 45 | #undef FindExecutable   // needed on windows :( | 
| Reid Spencer | 9665e8a | 2004-12-13 23:41:37 +0000 | [diff] [blame] | 46 | sys::Path llvm::FindExecutable(const std::string &ExeName, | 
| Chris Lattner | 2cdd21c | 2003-12-14 21:35:53 +0000 | [diff] [blame] | 47 |                                  const std::string &ProgramPath) { | 
| Reid Spencer | 9665e8a | 2004-12-13 23:41:37 +0000 | [diff] [blame] | 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 | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 50 |   // relative path to bugpoint itself. | 
 | 51 |   // | 
| Reid Spencer | 9665e8a | 2004-12-13 23:41:37 +0000 | [diff] [blame] | 52 |   sys::Path Result ( ProgramPath ); | 
 | 53 |   Result.elideFile(); | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 54 |  | 
| Reid Spencer | 9665e8a | 2004-12-13 23:41:37 +0000 | [diff] [blame] | 55 |   if (!Result.isEmpty()) { | 
 | 56 |     Result.appendFile(ExeName); | 
 | 57 |     if (Result.executable()) return Result; | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 58 |   } | 
 | 59 |  | 
| Reid Spencer | 9665e8a | 2004-12-13 23:41:37 +0000 | [diff] [blame] | 60 |   return sys::Program::FindProgramByName(ExeName); | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 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 " | 
| Misha Brukman | 44f8a34 | 2003-09-29 22:40:07 +0000 | [diff] [blame] | 70 |               << (FD == 0 ? "input" : "output") << "!\n"; | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 71 |     exit(1); | 
 | 72 |   } | 
 | 73 |  | 
 | 74 |   dup2(InFD, FD);   // Install it as the requested FD | 
 | 75 |   close(InFD);      // Close the original FD | 
 | 76 | } | 
 | 77 |  | 
| Chris Lattner | de0213b | 2004-07-24 07:41:31 +0000 | [diff] [blame] | 78 | static bool Timeout = false; | 
 | 79 | static void TimeOutHandler(int Sig) { | 
 | 80 |   Timeout = true; | 
 | 81 | } | 
 | 82 |  | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 83 | /// RunProgramWithTimeout - This function executes the specified program, with | 
 | 84 | /// the specified null-terminated argument array, with the stdin/out/err fd's | 
| Chris Lattner | de0213b | 2004-07-24 07:41:31 +0000 | [diff] [blame] | 85 | /// redirected, with a timeout specified by the last argument.  This terminates | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 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 | /// | 
| Chris Lattner | 2cdd21c | 2003-12-14 21:35:53 +0000 | [diff] [blame] | 89 | int llvm::RunProgramWithTimeout(const std::string &ProgramPath, | 
 | 90 |                                 const char **Args, | 
 | 91 |                                 const std::string &StdInFile, | 
 | 92 |                                 const std::string &StdOutFile, | 
| Chris Lattner | de0213b | 2004-07-24 07:41:31 +0000 | [diff] [blame] | 93 |                                 const std::string &StdErrFile, | 
 | 94 |                                 unsigned NumSeconds) { | 
| Chris Lattner | d895ffe | 2004-05-27 01:20:55 +0000 | [diff] [blame] | 95 | #ifdef HAVE_SYS_WAIT_H | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 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); | 
| Chris Lattner | bf3d2e2 | 2004-04-16 05:35:58 +0000 | [diff] [blame] | 104 |     if (StdOutFile != StdErrFile) | 
 | 105 |       RedirectFD(StdErrFile, 2); | 
 | 106 |     else | 
 | 107 |       dup2(1, 2); | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 108 |  | 
 | 109 |     execv(ProgramPath.c_str(), (char *const *)Args); | 
| Brian Gaeke | 53e557d | 2003-10-15 20:46:58 +0000 | [diff] [blame] | 110 |     std::cerr << "Error executing program: '" << ProgramPath; | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 111 |     for (; *Args; ++Args) | 
 | 112 |       std::cerr << " " << *Args; | 
| Brian Gaeke | 53e557d | 2003-10-15 20:46:58 +0000 | [diff] [blame] | 113 |     std::cerr << "'\n"; | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 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 |  | 
| Chris Lattner | de0213b | 2004-07-24 07:41:31 +0000 | [diff] [blame] | 122 |   // Install a timeout handler. | 
 | 123 |   Timeout = false; | 
 | 124 |   struct sigaction Act, Old; | 
 | 125 |   Act.sa_sigaction = 0; | 
 | 126 |   Act.sa_handler = TimeOutHandler; | 
| Chris Lattner | d67e439 | 2004-07-25 07:34:00 +0000 | [diff] [blame] | 127 |   sigemptyset(&Act.sa_mask); | 
 | 128 |   Act.sa_flags = 0; | 
| Chris Lattner | de0213b | 2004-07-24 07:41:31 +0000 | [diff] [blame] | 129 |   sigaction(SIGALRM, &Act, &Old); | 
 | 130 |  | 
 | 131 |   // Set the timeout if one is set. | 
 | 132 |   if (NumSeconds) | 
 | 133 |     alarm(NumSeconds); | 
 | 134 |  | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 135 |   int Status; | 
| Chris Lattner | 21ddf17 | 2004-07-24 07:50:48 +0000 | [diff] [blame] | 136 |   while (wait(&Status) != Child) | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 137 |     if (errno == EINTR) { | 
| Chris Lattner | de0213b | 2004-07-24 07:41:31 +0000 | [diff] [blame] | 138 |       if (Timeout) { | 
| Chris Lattner | 21ddf17 | 2004-07-24 07:50:48 +0000 | [diff] [blame] | 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); | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 151 |       } | 
| Chris Lattner | de0213b | 2004-07-24 07:41:31 +0000 | [diff] [blame] | 152 |     } | 
| Chris Lattner | de0213b | 2004-07-24 07:41:31 +0000 | [diff] [blame] | 153 |  | 
 | 154 |   alarm(0); | 
 | 155 |   sigaction(SIGALRM, &Old, 0); | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 156 |   return Status; | 
| Chris Lattner | d895ffe | 2004-05-27 01:20:55 +0000 | [diff] [blame] | 157 |  | 
 | 158 | #else | 
 | 159 |   std::cerr << "RunProgramWithTimeout not implemented on this platform!\n"; | 
 | 160 |   return -1; | 
 | 161 | #endif | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 162 | } |