look through isunordered to inline it into branch blocks.
[oota-llvm.git] / lib / System / Unix / Program.inc
1 //===- llvm/System/Unix/Program.cpp -----------------------------*- C++ -*-===//
2 // 
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by Reid Spencer and is distributed under the 
6 // University of Illinois Open Source License. See LICENSE.TXT for details.
7 // 
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the Unix specific portion of the Program class.
11 //
12 //===----------------------------------------------------------------------===//
13
14 //===----------------------------------------------------------------------===//
15 //=== WARNING: Implementation here must contain only generic UNIX code that
16 //===          is guaranteed to work on *all* UNIX variants.
17 //===----------------------------------------------------------------------===//
18
19 #include <llvm/Config/config.h>
20 #include "Unix.h"
21 #include <iostream>
22 #if HAVE_SYS_STAT_H
23 #include <sys/stat.h>
24 #endif
25 #if HAVE_SIGNAL_H
26 #include <signal.h>
27 #endif
28 #if HAVE_FCNTL_H
29 #include <fcntl.h>
30 #endif
31
32 namespace llvm {
33 using namespace sys;
34
35 // This function just uses the PATH environment variable to find the program.
36 Path
37 Program::FindProgramByName(const std::string& progName) {
38
39   // Check some degenerate cases
40   if (progName.length() == 0) // no program
41     return Path();
42   Path temp;
43   if (!temp.set(progName)) // invalid name
44     return Path();
45   // FIXME: have to check for absolute filename - we cannot assume anything
46   // about "." being in $PATH
47   if (temp.canExecute()) // already executable as is
48     return temp;
49
50   // At this point, the file name is valid and its not executable
51  
52   // Get the path. If its empty, we can't do anything to find it.
53   const char *PathStr = getenv("PATH");
54   if (PathStr == 0) 
55     return Path();
56
57   // Now we have a colon separated list of directories to search; try them.
58   unsigned PathLen = strlen(PathStr);
59   while (PathLen) {
60     // Find the first colon...
61     const char *Colon = std::find(PathStr, PathStr+PathLen, ':');
62
63     // Check to see if this first directory contains the executable...
64     Path FilePath;
65     if (FilePath.set(std::string(PathStr,Colon))) {
66       FilePath.appendComponent(progName);
67       if (FilePath.canExecute())
68         return FilePath;                    // Found the executable!
69     }
70
71     // Nope it wasn't in this directory, check the next path in the list!
72     PathLen -= Colon-PathStr;
73     PathStr = Colon;
74
75     // Advance past duplicate colons
76     while (*PathStr == ':') {
77       PathStr++;
78       PathLen--;
79     }
80   }
81   return Path();
82 }
83
84 static bool RedirectFD(const std::string &File, int FD, std::string* ErrMsg) {
85   if (File.empty()) return false;  // Noop
86
87   // Open the file
88   int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
89   if (InFD == -1) {
90     MakeErrMsg(ErrMsg, "Cannot open file '" + File + "' for "
91               + (FD == 0 ? "input" : "output") + "!\n");
92     return true;
93   }
94
95   // Install it as the requested FD
96   if (-1 == dup2(InFD, FD)) {
97     MakeErrMsg(ErrMsg, "Cannot dup2");
98     return true;
99   }
100   close(InFD);      // Close the original FD
101   return false;
102 }
103
104 static bool Timeout = false;
105 static void TimeOutHandler(int Sig) {
106   Timeout = true;
107 }
108
109 int 
110 Program::ExecuteAndWait(const Path& path, 
111                         const char** args,
112                         const char** envp,
113                         const Path** redirects,
114                         unsigned secondsToWait,
115                         std::string* ErrMsg) 
116 {
117   if (!path.canExecute()) {
118     if (ErrMsg)
119       *ErrMsg = path.toString() + " is not executable";
120     return -1;
121   }
122
123 #ifdef HAVE_SYS_WAIT_H
124   // Create a child process.
125   int child = fork();
126   switch (child) {
127     // An error occured:  Return to the caller.
128     case -1:
129       MakeErrMsg(ErrMsg, "Couldn't fork");
130       return -1;
131
132     // Child process: Execute the program.
133     case 0: {
134       // Redirect file descriptors...
135       if (redirects) {
136         if (redirects[0]) {
137           if (redirects[0]->isEmpty()) {
138             if (RedirectFD("/dev/null",0,ErrMsg)) { return -1; }
139           } else {
140             if (RedirectFD(redirects[0]->toString(), 0,ErrMsg)) { return -1; }
141           }
142         }
143         if (redirects[1]) {
144           if (redirects[1]->isEmpty()) {
145             if (RedirectFD("/dev/null",1,ErrMsg)) { return -1; }
146           } else {
147             if (RedirectFD(redirects[1]->toString(),1,ErrMsg)) { return -1; }
148           }
149         }
150         if (redirects[1] && redirects[2] && 
151             *(redirects[1]) != *(redirects[2])) {
152           if (redirects[2]->isEmpty()) {
153             if (RedirectFD("/dev/null",2,ErrMsg)) { return -1; }
154           } else {
155             if (RedirectFD(redirects[2]->toString(), 2,ErrMsg)) { return -1; }
156           }
157         } else if (-1 == dup2(1,2)) {
158           MakeErrMsg(ErrMsg, "Can't redirect");
159           return -1;
160         }
161       }
162
163       // Execute!
164       if (envp != 0)
165         execve (path.c_str(), (char** const)args, (char**)envp);
166       else
167         execv (path.c_str(), (char** const)args);
168       // If the execve() failed, we should exit and let the parent pick up
169       // our non-zero exit status.
170       exit (errno);
171     }
172
173     // Parent process: Break out of the switch to do our processing.
174     default:
175       break;
176   }
177
178   // Make sure stderr and stdout have been flushed
179   std::cerr << std::flush;
180   std::cout << std::flush;
181   fsync(1);
182   fsync(2);
183
184   struct sigaction Act, Old;
185
186   // Install a timeout handler.
187   if (secondsToWait) {
188     Timeout = false;
189     Act.sa_sigaction = 0;
190     Act.sa_handler = TimeOutHandler;
191     sigemptyset(&Act.sa_mask);
192     Act.sa_flags = 0;
193     sigaction(SIGALRM, &Act, &Old);
194     alarm(secondsToWait);
195   }
196
197   // Parent process: Wait for the child process to terminate.
198   int status;
199   while (wait(&status) != child)
200     if (secondsToWait && errno == EINTR) {
201       // Kill the child.
202       kill(child, SIGKILL);
203         
204       // Turn off the alarm and restore the signal handler
205       alarm(0);
206       sigaction(SIGALRM, &Old, 0);
207
208       // Wait for child to die
209       if (wait(&status) != child)
210         MakeErrMsg(ErrMsg, "Child timed out but wouldn't die");
211         
212       return -1;   // Timeout detected
213     } else {
214       MakeErrMsg(ErrMsg, "Error waiting for child process");
215       return -1;
216     }
217
218   // We exited normally without timeout, so turn off the timer.
219   if (secondsToWait) {
220     alarm(0);
221     sigaction(SIGALRM, &Old, 0);
222   }
223
224   // Return the proper exit status. 0=success, >0 is programs' exit status,
225   // <0 means a signal was returned, -9999999 means the program dumped core.
226   int result = 0;
227   if (WIFEXITED(status))
228     result = WEXITSTATUS(status);
229   else if (WIFSIGNALED(status))
230     result = 0 - WTERMSIG(status);
231 #ifdef WCOREDUMP
232   else if (WCOREDUMP(status))
233     result |= 0x01000000;
234 #endif
235   return result;
236 #else
237   return -99;
238 #endif
239     
240 }
241
242 bool Program::ChangeStdinToBinary(){
243   // Do nothing, as Unix doesn't differentiate between text and binary.
244   return false;
245 }
246
247 bool Program::ChangeStdoutToBinary(){
248   // Do nothing, as Unix doesn't differentiate between text and binary.
249   return false;
250 }
251
252 }