2538c0e3cdcfa612848109bc076851f7a9ed3188
[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 <unistd.h>
18 #include <wait.h>
19 #include <sys/fcntl.h>
20 #include <algorithm>
21 #include <cerrno>
22 #include <cstdlib>
23 #include <fstream>
24 #include <iostream>
25 #include <signal.h>
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
164
165 // ExecWait - executes a program with the specified arguments and environment.
166 // It then waits for the progarm to termiante and then returns to the caller.
167 //
168 // Inputs:
169 //  argv - The arguments to the program as an array of C strings.  The first
170 //         argument should be the name of the program to execute, and the
171 //         last argument should be a pointer to NULL.
172 //
173 //  envp - The environment passes to the program as an array of C strings in
174 //         the form of "name=value" pairs.  The last element should be a
175 //         pointer to NULL.
176 //
177 // Outputs:
178 //  None.
179 //
180 // Return value:
181 //  0 - No errors.
182 //  1 - The program could not be executed.
183 //  1 - The program returned a non-zero exit status.
184 //  1 - The program terminated abnormally.
185 //
186 // Notes:
187 //  The program will inherit the stdin, stdout, and stderr file descriptors
188 //  as well as other various configuration settings (umask).
189 //
190 //  This function should not print anything to stdout/stderr on its own.  It is
191 //  a generic library function.  The caller or executed program should report
192 //  errors in the way it sees fit.
193 //
194 //  This function does not use $PATH to find programs.
195 //
196 int llvm::ExecWait(const char * const old_argv[],
197                    const char * const old_envp[]) {
198 #ifdef HAVE_SYS_WAIT_H
199   // Create local versions of the parameters that can be passed into execve()
200   // without creating const problems.
201   char ** const argv = (char ** const) old_argv;
202   char ** const envp = (char ** const) old_envp;
203
204   // Create a child process.
205   switch (fork()) {
206     // An error occured:  Return to the caller.
207     case -1:
208       return 1;
209       break;
210
211     // Child process: Execute the program.
212     case 0:
213       execve (argv[0], argv, envp);
214       // If the execve() failed, we should exit and let the parent pick up
215       // our non-zero exit status.
216       exit (1);
217
218     // Parent process: Break out of the switch to do our processing.
219     default:
220       break;
221   }
222
223   // Parent process: Wait for the child process to terminate.
224   int status;
225   if ((wait (&status)) == -1)
226     return 1;
227
228   // If the program exited normally with a zero exit status, return success!
229   if (WIFEXITED (status) && (WEXITSTATUS(status) == 0))
230     return 0;
231 #else
232   std::cerr << "llvm::ExecWait not implemented on this platform!\n";
233 #endif
234
235   // Otherwise, return failure.
236   return 1;
237 }