Remove duplication in Program::Execute{And,No}Wait.
[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"));
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 bool
146 Program::Execute(const Path& path,
147                  const char** args,
148                  const char** envp,
149                  const Path** redirects,
150                  unsigned memoryLimit,
151                  std::string* ErrMsg)
152 {
153   if (!path.canExecute()) {
154     if (ErrMsg)
155       *ErrMsg = path.toString() + " is not executable";
156     return false;
157   }
158
159   // Create a child process.
160   int child = fork();
161   switch (child) {
162     // An error occured:  Return to the caller.
163     case -1:
164       MakeErrMsg(ErrMsg, "Couldn't fork");
165       return false;
166
167     // Child process: Execute the program.
168     case 0: {
169       // Redirect file descriptors...
170       if (redirects) {
171         // Redirect stdin
172         if (RedirectIO(redirects[0], 0, ErrMsg)) { return false; }
173         // Redirect stdout
174         if (RedirectIO(redirects[1], 1, ErrMsg)) { return false; }
175         if (redirects[1] && redirects[2] &&
176             *(redirects[1]) == *(redirects[2])) {
177           // If stdout and stderr should go to the same place, redirect stderr
178           // to the FD already open for stdout.
179           if (-1 == dup2(1,2)) {
180             MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout");
181             return false;
182           }
183         } else {
184           // Just redirect stderr
185           if (RedirectIO(redirects[2], 2, ErrMsg)) { return false; }
186         }
187       }
188
189       // Set memory limits
190       if (memoryLimit!=0) {
191         SetMemoryLimits(memoryLimit);
192       }
193
194       // Execute!
195       if (envp != 0)
196         execve (path.c_str(), (char**)args, (char**)envp);
197       else
198         execv (path.c_str(), (char**)args);
199       // If the execve() failed, we should exit and let the parent pick up
200       // our non-zero exit status.
201       exit (errno);
202     }
203
204     // Parent process: Break out of the switch to do our processing.
205     default:
206       break;
207   }
208
209   // Make sure stderr and stdout have been flushed
210   std::cerr << std::flush;
211   std::cout << std::flush;
212   fsync(1);
213   fsync(2);
214
215   Pid_ = child;
216
217   return true;
218 }
219
220 int
221 Program::Wait(unsigned secondsToWait,
222               std::string* ErrMsg)
223 {
224 #ifdef HAVE_SYS_WAIT_H
225   struct sigaction Act, Old;
226
227   if (Pid_ == 0) {
228     MakeErrMsg(ErrMsg, "Process not started!");
229     return -1;
230   }
231
232   // Install a timeout handler.
233   if (secondsToWait) {
234     Timeout = false;
235     Act.sa_sigaction = 0;
236     Act.sa_handler = TimeOutHandler;
237     sigemptyset(&Act.sa_mask);
238     Act.sa_flags = 0;
239     sigaction(SIGALRM, &Act, &Old);
240     alarm(secondsToWait);
241   }
242
243   // Parent process: Wait for the child process to terminate.
244   int status;
245   int child = this->Pid_;
246   while (wait(&status) != child)
247     if (secondsToWait && errno == EINTR) {
248       // Kill the child.
249       kill(child, SIGKILL);
250
251       // Turn off the alarm and restore the signal handler
252       alarm(0);
253       sigaction(SIGALRM, &Old, 0);
254
255       // Wait for child to die
256       if (wait(&status) != child)
257         MakeErrMsg(ErrMsg, "Child timed out but wouldn't die");
258       else
259         MakeErrMsg(ErrMsg, "Child timed out", 0);
260
261       return -1;   // Timeout detected
262     } else if (errno != EINTR) {
263       MakeErrMsg(ErrMsg, "Error waiting for child process");
264       return -1;
265     }
266
267   // We exited normally without timeout, so turn off the timer.
268   if (secondsToWait) {
269     alarm(0);
270     sigaction(SIGALRM, &Old, 0);
271   }
272
273   // Return the proper exit status. 0=success, >0 is programs' exit status,
274   // <0 means a signal was returned, -9999999 means the program dumped core.
275   int result = 0;
276   if (WIFEXITED(status))
277     result = WEXITSTATUS(status);
278   else if (WIFSIGNALED(status))
279     result = 0 - WTERMSIG(status);
280 #ifdef WCOREDUMP
281   else if (WCOREDUMP(status))
282     result |= 0x01000000;
283 #endif
284   return result;
285 #else
286   return -99;
287 #endif
288
289 }
290
291 bool Program::ChangeStdinToBinary(){
292   // Do nothing, as Unix doesn't differentiate between text and binary.
293   return false;
294 }
295
296 bool Program::ChangeStdoutToBinary(){
297   // Do nothing, as Unix doesn't differentiate between text and binary.
298   return false;
299 }
300
301 }