Fix redirection of stderr in sys::Program::ExecuteAndWait. There was logic
[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 is distributed under the University of Illinois Open Source
6 // 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_SYS_RESOURCE_H
26 #include <sys/resource.h>
27 #endif
28 #if HAVE_SIGNAL_H
29 #include <signal.h>
30 #endif
31 #if HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif
34
35 namespace llvm {
36 using namespace sys;
37
38 // This function just uses the PATH environment variable to find the program.
39 Path
40 Program::FindProgramByName(const std::string& progName) {
41
42   // Check some degenerate cases
43   if (progName.length() == 0) // no program
44     return Path();
45   Path temp;
46   if (!temp.set(progName)) // invalid name
47     return Path();
48   // FIXME: have to check for absolute filename - we cannot assume anything
49   // about "." being in $PATH
50   if (temp.canExecute()) // already executable as is
51     return temp;
52
53   // At this point, the file name is valid and its not executable
54  
55   // Get the path. If its empty, we can't do anything to find it.
56   const char *PathStr = getenv("PATH");
57   if (PathStr == 0) 
58     return Path();
59
60   // Now we have a colon separated list of directories to search; try them.
61   size_t PathLen = strlen(PathStr);
62   while (PathLen) {
63     // Find the first colon...
64     const char *Colon = std::find(PathStr, PathStr+PathLen, ':');
65
66     // Check to see if this first directory contains the executable...
67     Path FilePath;
68     if (FilePath.set(std::string(PathStr,Colon))) {
69       FilePath.appendComponent(progName);
70       if (FilePath.canExecute())
71         return FilePath;                    // Found the executable!
72     }
73
74     // Nope it wasn't in this directory, check the next path in the list!
75     PathLen -= Colon-PathStr;
76     PathStr = Colon;
77
78     // Advance past duplicate colons
79     while (*PathStr == ':') {
80       PathStr++;
81       PathLen--;
82     }
83   }
84   return Path();
85 }
86
87 static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) {
88   if (Path == 0)
89     // Noop
90     return false;
91   std::string File;
92   if (Path->isEmpty())
93     // Redirect empty paths to /dev/null
94     File = "/dev/null";
95   else
96     File = Path->toString();
97
98   // Open the file
99   int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
100   if (InFD == -1) {
101     MakeErrMsg(ErrMsg, "Cannot open file '" + File + "' for "
102               + (FD == 0 ? "input" : "output") + "!\n");
103     return true;
104   }
105
106   // Install it as the requested FD
107   if (-1 == dup2(InFD, FD)) {
108     MakeErrMsg(ErrMsg, "Cannot dup2");
109     return true;
110   }
111   close(InFD);      // Close the original FD
112   return false;
113 }
114
115 static bool Timeout = false;
116 static void TimeOutHandler(int Sig) {
117   Timeout = true;
118 }
119
120 static void SetMemoryLimits (unsigned size)
121 {
122 #if HAVE_SYS_RESOURCE_H
123   struct rlimit r;
124   __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur)) (size) * 1048576;
125
126   // Heap size
127   getrlimit (RLIMIT_DATA, &r);
128   r.rlim_cur = limit;
129   setrlimit (RLIMIT_DATA, &r);
130 #ifdef RLIMIT_RSS
131   // Resident set size.
132   getrlimit (RLIMIT_RSS, &r);
133   r.rlim_cur = limit;
134   setrlimit (RLIMIT_RSS, &r);
135 #endif
136 #ifdef RLIMIT_AS  // e.g. NetBSD doesn't have it.
137   // Virtual memory.
138   getrlimit (RLIMIT_AS, &r);
139   r.rlim_cur = limit;
140   setrlimit (RLIMIT_AS, &r);
141 #endif
142 #endif
143 }
144
145 int 
146 Program::ExecuteAndWait(const Path& path, 
147                         const char** args,
148                         const char** envp,
149                         const Path** redirects,
150                         unsigned secondsToWait,
151                         unsigned memoryLimit,
152                         std::string* ErrMsg) 
153 {
154   if (!path.canExecute()) {
155     if (ErrMsg)
156       *ErrMsg = path.toString() + " is not executable";
157     return -1;
158   }
159
160 #ifdef HAVE_SYS_WAIT_H
161   // Create a child process.
162   int child = fork();
163   switch (child) {
164     // An error occured:  Return to the caller.
165     case -1:
166       MakeErrMsg(ErrMsg, "Couldn't fork");
167       return -1;
168
169     // Child process: Execute the program.
170     case 0: {
171       // Redirect file descriptors...
172       if (redirects) {
173         // Redirect stdin
174         if (RedirectIO(redirects[0], 0, ErrMsg)) { return -1; }
175         // Redirect stdout
176         if (RedirectIO(redirects[1], 1, ErrMsg)) { return -1; }
177         if (redirects[1] && redirects[2] && 
178             *(redirects[1]) == *(redirects[2])) {
179           // If stdout and stderr should go to the same place, redirect stderr
180           // to the FD already open for stdout.
181           if (-1 == dup2(1,2)) {
182             MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout");
183             return -1;
184           }
185         } else {
186           // Just redirect stderr
187           if (RedirectIO(redirects[2], 2, ErrMsg)) { return -1; }
188         }
189       }
190
191       // Set memory limits
192       if (memoryLimit!=0) {
193         SetMemoryLimits(memoryLimit);
194       }
195       
196       // Execute!
197       if (envp != 0)
198         execve (path.c_str(), (char**)args, (char**)envp);
199       else
200         execv (path.c_str(), (char**)args);
201       // If the execve() failed, we should exit and let the parent pick up
202       // our non-zero exit status.
203       exit (errno);
204     }
205
206     // Parent process: Break out of the switch to do our processing.
207     default:
208       break;
209   }
210
211   // Make sure stderr and stdout have been flushed
212   std::cerr << std::flush;
213   std::cout << std::flush;
214   fsync(1);
215   fsync(2);
216
217   struct sigaction Act, Old;
218
219   // Install a timeout handler.
220   if (secondsToWait) {
221     Timeout = false;
222     Act.sa_sigaction = 0;
223     Act.sa_handler = TimeOutHandler;
224     sigemptyset(&Act.sa_mask);
225     Act.sa_flags = 0;
226     sigaction(SIGALRM, &Act, &Old);
227     alarm(secondsToWait);
228   }
229
230   // Parent process: Wait for the child process to terminate.
231   int status;
232   while (wait(&status) != child)
233     if (secondsToWait && errno == EINTR) {
234       // Kill the child.
235       kill(child, SIGKILL);
236         
237       // Turn off the alarm and restore the signal handler
238       alarm(0);
239       sigaction(SIGALRM, &Old, 0);
240
241       // Wait for child to die
242       if (wait(&status) != child)
243         MakeErrMsg(ErrMsg, "Child timed out but wouldn't die");
244       else
245         MakeErrMsg(ErrMsg, "Child timed out", 0);
246
247       return -1;   // Timeout detected
248     } else if (errno != EINTR) {
249       MakeErrMsg(ErrMsg, "Error waiting for child process");
250       return -1;
251     }
252
253   // We exited normally without timeout, so turn off the timer.
254   if (secondsToWait) {
255     alarm(0);
256     sigaction(SIGALRM, &Old, 0);
257   }
258
259   // Return the proper exit status. 0=success, >0 is programs' exit status,
260   // <0 means a signal was returned, -9999999 means the program dumped core.
261   int result = 0;
262   if (WIFEXITED(status))
263     result = WEXITSTATUS(status);
264   else if (WIFSIGNALED(status))
265     result = 0 - WTERMSIG(status);
266 #ifdef WCOREDUMP
267   else if (WCOREDUMP(status))
268     result |= 0x01000000;
269 #endif
270   return result;
271 #else
272   return -99;
273 #endif
274     
275 }
276
277 bool Program::ChangeStdinToBinary(){
278   // Do nothing, as Unix doesn't differentiate between text and binary.
279   return false;
280 }
281
282 bool Program::ChangeStdoutToBinary(){
283   // Do nothing, as Unix doesn't differentiate between text and binary.
284   return false;
285 }
286
287 }