For PR351:
[oota-llvm.git] / lib / Support / SystemUtils.cpp
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 }