For PR789:
[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_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   unsigned 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 RedirectFD(const std::string &File, int FD, std::string* ErrMsg) {
88   if (File.empty()) return false;  // Noop
89
90   // Open the file
91   int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
92   if (InFD == -1) {
93     MakeErrMsg(ErrMsg, "Cannot open file '" + File + "' for "
94               + (FD == 0 ? "input" : "output") + "!\n");
95     return true;
96   }
97
98   // Install it as the requested FD
99   if (-1 == dup2(InFD, FD)) {
100     MakeErrMsg(ErrMsg, "Cannot dup2");
101     return true;
102   }
103   close(InFD);      // Close the original FD
104   return false;
105 }
106
107 static bool Timeout = false;
108 static void TimeOutHandler(int Sig) {
109   Timeout = true;
110 }
111
112 static void SetMemoryLimits (unsigned size)
113 {
114 #if HAVE_SYS_RESOURCE_H
115   struct rlimit r;
116   __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur)) (size) * 1048576;
117
118   // Heap size
119   getrlimit (RLIMIT_DATA, &r);
120   r.rlim_cur = limit;
121   setrlimit (RLIMIT_DATA, &r);
122   // Resident set size.
123   getrlimit (RLIMIT_RSS, &r);
124   r.rlim_cur = limit;
125   setrlimit (RLIMIT_RSS, &r);
126   // Virtual memory.
127   getrlimit (RLIMIT_AS, &r);
128   r.rlim_cur = limit;
129   setrlimit (RLIMIT_AS, &r);
130 #endif
131 }
132
133 int 
134 Program::ExecuteAndWait(const Path& path, 
135                         const char** args,
136                         const char** envp,
137                         const Path** redirects,
138                         unsigned secondsToWait,
139                         unsigned memoryLimit,
140                         std::string* ErrMsg) 
141 {
142   if (!path.canExecute()) {
143     if (ErrMsg)
144       *ErrMsg = path.toString() + " is not executable";
145     return -1;
146   }
147
148 #ifdef HAVE_SYS_WAIT_H
149   // Create a child process.
150   int child = fork();
151   switch (child) {
152     // An error occured:  Return to the caller.
153     case -1:
154       MakeErrMsg(ErrMsg, "Couldn't fork");
155       return -1;
156
157     // Child process: Execute the program.
158     case 0: {
159       // Redirect file descriptors...
160       if (redirects) {
161         if (redirects[0]) {
162           if (redirects[0]->isEmpty()) {
163             if (RedirectFD("/dev/null",0,ErrMsg)) { return -1; }
164           } else {
165             if (RedirectFD(redirects[0]->toString(), 0,ErrMsg)) { return -1; }
166           }
167         }
168         if (redirects[1]) {
169           if (redirects[1]->isEmpty()) {
170             if (RedirectFD("/dev/null",1,ErrMsg)) { return -1; }
171           } else {
172             if (RedirectFD(redirects[1]->toString(),1,ErrMsg)) { return -1; }
173           }
174         }
175         if (redirects[1] && redirects[2] && 
176             *(redirects[1]) != *(redirects[2])) {
177           if (redirects[2]->isEmpty()) {
178             if (RedirectFD("/dev/null",2,ErrMsg)) { return -1; }
179           } else {
180             if (RedirectFD(redirects[2]->toString(), 2,ErrMsg)) { return -1; }
181           }
182         } else if (-1 == dup2(1,2)) {
183           MakeErrMsg(ErrMsg, "Can't redirect");
184           return -1;
185         }
186       }
187
188       // Set memory limits
189       if (memoryLimit!=0) {
190         SetMemoryLimits(memoryLimit);
191       }
192       
193       // Execute!
194       if (envp != 0)
195         execve (path.c_str(), (char** const)args, (char**)envp);
196       else
197         execv (path.c_str(), (char** const)args);
198       // If the execve() failed, we should exit and let the parent pick up
199       // our non-zero exit status.
200       exit (errno);
201     }
202
203     // Parent process: Break out of the switch to do our processing.
204     default:
205       break;
206   }
207
208   // Make sure stderr and stdout have been flushed
209   std::cerr << std::flush;
210   std::cout << std::flush;
211   fsync(1);
212   fsync(2);
213
214   struct sigaction Act, Old;
215
216   // Install a timeout handler.
217   if (secondsToWait) {
218     Timeout = false;
219     Act.sa_sigaction = 0;
220     Act.sa_handler = TimeOutHandler;
221     sigemptyset(&Act.sa_mask);
222     Act.sa_flags = 0;
223     sigaction(SIGALRM, &Act, &Old);
224     alarm(secondsToWait);
225   }
226
227   // Parent process: Wait for the child process to terminate.
228   int status;
229   while (wait(&status) != child)
230     if (secondsToWait && errno == EINTR) {
231       // Kill the child.
232       kill(child, SIGKILL);
233         
234       // Turn off the alarm and restore the signal handler
235       alarm(0);
236       sigaction(SIGALRM, &Old, 0);
237
238       // Wait for child to die
239       if (wait(&status) != child)
240         MakeErrMsg(ErrMsg, "Child timed out but wouldn't die");
241         
242       return -1;   // Timeout detected
243     } else {
244       MakeErrMsg(ErrMsg, "Error waiting for child process");
245       return -1;
246     }
247
248   // We exited normally without timeout, so turn off the timer.
249   if (secondsToWait) {
250     alarm(0);
251     sigaction(SIGALRM, &Old, 0);
252   }
253
254   // Return the proper exit status. 0=success, >0 is programs' exit status,
255   // <0 means a signal was returned, -9999999 means the program dumped core.
256   int result = 0;
257   if (WIFEXITED(status))
258     result = WEXITSTATUS(status);
259   else if (WIFSIGNALED(status))
260     result = 0 - WTERMSIG(status);
261 #ifdef WCOREDUMP
262   else if (WCOREDUMP(status))
263     result |= 0x01000000;
264 #endif
265   return result;
266 #else
267   return -99;
268 #endif
269     
270 }
271
272 bool Program::ChangeStdinToBinary(){
273   // Do nothing, as Unix doesn't differentiate between text and binary.
274   return false;
275 }
276
277 bool Program::ChangeStdoutToBinary(){
278   // Do nothing, as Unix doesn't differentiate between text and binary.
279   return false;
280 }
281
282 }