1218885Sdim//===- llvm/Support/Unix/Program.cpp -----------------------------*- C++ -*-===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10218885Sdim// This file implements the Unix specific portion of the Program class.
11218885Sdim//
12218885Sdim//===----------------------------------------------------------------------===//
13218885Sdim
14218885Sdim//===----------------------------------------------------------------------===//
15218885Sdim//=== WARNING: Implementation here must contain only generic UNIX code that
16218885Sdim//===          is guaranteed to work on *all* UNIX variants.
17218885Sdim//===----------------------------------------------------------------------===//
18218885Sdim
19249423Sdim#include "Unix.h"
20249423Sdim#include "llvm/Support/Compiler.h"
21249423Sdim#include "llvm/Support/FileSystem.h"
22218885Sdim#include <llvm/Config/config.h>
23218885Sdim#if HAVE_SYS_STAT_H
24218885Sdim#include <sys/stat.h>
25218885Sdim#endif
26218885Sdim#if HAVE_SYS_RESOURCE_H
27218885Sdim#include <sys/resource.h>
28218885Sdim#endif
29218885Sdim#if HAVE_SIGNAL_H
30218885Sdim#include <signal.h>
31218885Sdim#endif
32218885Sdim#if HAVE_FCNTL_H
33218885Sdim#include <fcntl.h>
34218885Sdim#endif
35251662Sdim#if HAVE_UNISTD_H
36251662Sdim#include <unistd.h>
37251662Sdim#endif
38218885Sdim#ifdef HAVE_POSIX_SPAWN
39218885Sdim#include <spawn.h>
40218885Sdim#if !defined(__APPLE__)
41218885Sdim  extern char **environ;
42218885Sdim#else
43218885Sdim#include <crt_externs.h> // _NSGetEnviron
44218885Sdim#endif
45218885Sdim#endif
46218885Sdim
47218885Sdimnamespace llvm {
48218885Sdimusing namespace sys;
49218885Sdim
50218885SdimProgram::Program() : Data_(0) {}
51218885Sdim
52218885SdimProgram::~Program() {}
53218885Sdim
54218885Sdim// This function just uses the PATH environment variable to find the program.
55218885SdimPath
56218885SdimProgram::FindProgramByName(const std::string& progName) {
57218885Sdim
58218885Sdim  // Check some degenerate cases
59218885Sdim  if (progName.length() == 0) // no program
60218885Sdim    return Path();
61218885Sdim  Path temp;
62218885Sdim  if (!temp.set(progName)) // invalid name
63218885Sdim    return Path();
64218885Sdim  // Use the given path verbatim if it contains any slashes; this matches
65218885Sdim  // the behavior of sh(1) and friends.
66218885Sdim  if (progName.find('/') != std::string::npos)
67218885Sdim    return temp;
68218885Sdim
69218885Sdim  // At this point, the file name is valid and does not contain slashes. Search
70218885Sdim  // for it through the directories specified in the PATH environment variable.
71218885Sdim
72218885Sdim  // Get the path. If its empty, we can't do anything to find it.
73218885Sdim  const char *PathStr = getenv("PATH");
74218885Sdim  if (PathStr == 0)
75218885Sdim    return Path();
76218885Sdim
77218885Sdim  // Now we have a colon separated list of directories to search; try them.
78218885Sdim  size_t PathLen = strlen(PathStr);
79218885Sdim  while (PathLen) {
80218885Sdim    // Find the first colon...
81218885Sdim    const char *Colon = std::find(PathStr, PathStr+PathLen, ':');
82218885Sdim
83218885Sdim    // Check to see if this first directory contains the executable...
84218885Sdim    Path FilePath;
85218885Sdim    if (FilePath.set(std::string(PathStr,Colon))) {
86218885Sdim      FilePath.appendComponent(progName);
87218885Sdim      if (FilePath.canExecute())
88218885Sdim        return FilePath;                    // Found the executable!
89218885Sdim    }
90218885Sdim
91218885Sdim    // Nope it wasn't in this directory, check the next path in the list!
92218885Sdim    PathLen -= Colon-PathStr;
93218885Sdim    PathStr = Colon;
94218885Sdim
95218885Sdim    // Advance past duplicate colons
96218885Sdim    while (*PathStr == ':') {
97218885Sdim      PathStr++;
98218885Sdim      PathLen--;
99218885Sdim    }
100218885Sdim  }
101218885Sdim  return Path();
102218885Sdim}
103218885Sdim
104218885Sdimstatic bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) {
105218885Sdim  if (Path == 0) // Noop
106218885Sdim    return false;
107218885Sdim  const char *File;
108218885Sdim  if (Path->isEmpty())
109218885Sdim    // Redirect empty paths to /dev/null
110218885Sdim    File = "/dev/null";
111218885Sdim  else
112218885Sdim    File = Path->c_str();
113218885Sdim
114218885Sdim  // Open the file
115218885Sdim  int InFD = open(File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
116218885Sdim  if (InFD == -1) {
117218885Sdim    MakeErrMsg(ErrMsg, "Cannot open file '" + std::string(File) + "' for "
118218885Sdim              + (FD == 0 ? "input" : "output"));
119218885Sdim    return true;
120218885Sdim  }
121218885Sdim
122218885Sdim  // Install it as the requested FD
123218885Sdim  if (dup2(InFD, FD) == -1) {
124218885Sdim    MakeErrMsg(ErrMsg, "Cannot dup2");
125218885Sdim    close(InFD);
126218885Sdim    return true;
127218885Sdim  }
128218885Sdim  close(InFD);      // Close the original FD
129218885Sdim  return false;
130218885Sdim}
131218885Sdim
132218885Sdim#ifdef HAVE_POSIX_SPAWN
133218885Sdimstatic bool RedirectIO_PS(const Path *Path, int FD, std::string *ErrMsg,
134221345Sdim                          posix_spawn_file_actions_t *FileActions) {
135218885Sdim  if (Path == 0) // Noop
136218885Sdim    return false;
137218885Sdim  const char *File;
138218885Sdim  if (Path->isEmpty())
139218885Sdim    // Redirect empty paths to /dev/null
140218885Sdim    File = "/dev/null";
141218885Sdim  else
142218885Sdim    File = Path->c_str();
143218885Sdim
144221345Sdim  if (int Err = posix_spawn_file_actions_addopen(FileActions, FD,
145218885Sdim                            File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666))
146218885Sdim    return MakeErrMsg(ErrMsg, "Cannot dup2", Err);
147218885Sdim  return false;
148218885Sdim}
149218885Sdim#endif
150218885Sdim
151218885Sdimstatic void TimeOutHandler(int Sig) {
152218885Sdim}
153218885Sdim
154218885Sdimstatic void SetMemoryLimits (unsigned size)
155218885Sdim{
156218885Sdim#if HAVE_SYS_RESOURCE_H && HAVE_GETRLIMIT && HAVE_SETRLIMIT
157218885Sdim  struct rlimit r;
158218885Sdim  __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur)) (size) * 1048576;
159218885Sdim
160218885Sdim  // Heap size
161218885Sdim  getrlimit (RLIMIT_DATA, &r);
162218885Sdim  r.rlim_cur = limit;
163218885Sdim  setrlimit (RLIMIT_DATA, &r);
164218885Sdim#ifdef RLIMIT_RSS
165218885Sdim  // Resident set size.
166218885Sdim  getrlimit (RLIMIT_RSS, &r);
167218885Sdim  r.rlim_cur = limit;
168218885Sdim  setrlimit (RLIMIT_RSS, &r);
169218885Sdim#endif
170218885Sdim#ifdef RLIMIT_AS  // e.g. NetBSD doesn't have it.
171249423Sdim  // Don't set virtual memory limit if built with any Sanitizer. They need 80Tb
172249423Sdim  // of virtual memory for shadow memory mapping.
173249423Sdim#if !LLVM_MEMORY_SANITIZER_BUILD && !LLVM_ADDRESS_SANITIZER_BUILD
174218885Sdim  // Virtual memory.
175218885Sdim  getrlimit (RLIMIT_AS, &r);
176218885Sdim  r.rlim_cur = limit;
177218885Sdim  setrlimit (RLIMIT_AS, &r);
178218885Sdim#endif
179218885Sdim#endif
180249423Sdim#endif
181218885Sdim}
182218885Sdim
183218885Sdimbool
184218885SdimProgram::Execute(const Path &path, const char **args, const char **envp,
185218885Sdim                 const Path **redirects, unsigned memoryLimit,
186218885Sdim                  std::string *ErrMsg) {
187218885Sdim  // If this OS has posix_spawn and there is no memory limit being implied, use
188218885Sdim  // posix_spawn.  It is more efficient than fork/exec.
189218885Sdim#ifdef HAVE_POSIX_SPAWN
190218885Sdim  if (memoryLimit == 0) {
191221345Sdim    posix_spawn_file_actions_t FileActionsStore;
192221345Sdim    posix_spawn_file_actions_t *FileActions = 0;
193218885Sdim
194218885Sdim    if (redirects) {
195221345Sdim      FileActions = &FileActionsStore;
196221345Sdim      posix_spawn_file_actions_init(FileActions);
197221345Sdim
198218885Sdim      // Redirect stdin/stdout.
199218885Sdim      if (RedirectIO_PS(redirects[0], 0, ErrMsg, FileActions) ||
200218885Sdim          RedirectIO_PS(redirects[1], 1, ErrMsg, FileActions))
201218885Sdim        return false;
202218885Sdim      if (redirects[1] == 0 || redirects[2] == 0 ||
203218885Sdim          *redirects[1] != *redirects[2]) {
204218885Sdim        // Just redirect stderr
205218885Sdim        if (RedirectIO_PS(redirects[2], 2, ErrMsg, FileActions)) return false;
206218885Sdim      } else {
207218885Sdim        // If stdout and stderr should go to the same place, redirect stderr
208218885Sdim        // to the FD already open for stdout.
209221345Sdim        if (int Err = posix_spawn_file_actions_adddup2(FileActions, 1, 2))
210218885Sdim          return !MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout", Err);
211218885Sdim      }
212218885Sdim    }
213218885Sdim
214218885Sdim    if (!envp)
215218885Sdim#if !defined(__APPLE__)
216218885Sdim      envp = const_cast<const char **>(environ);
217218885Sdim#else
218218885Sdim      // environ is missing in dylibs.
219218885Sdim      envp = const_cast<const char **>(*_NSGetEnviron());
220218885Sdim#endif
221218885Sdim
222218885Sdim    // Explicitly initialized to prevent what appears to be a valgrind false
223218885Sdim    // positive.
224218885Sdim    pid_t PID = 0;
225221345Sdim    int Err = posix_spawn(&PID, path.c_str(), FileActions, /*attrp*/0,
226218885Sdim                          const_cast<char **>(args), const_cast<char **>(envp));
227218885Sdim
228221345Sdim    if (FileActions)
229221345Sdim      posix_spawn_file_actions_destroy(FileActions);
230218885Sdim
231218885Sdim    if (Err)
232218885Sdim     return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err);
233218885Sdim
234218885Sdim    Data_ = reinterpret_cast<void*>(PID);
235218885Sdim    return true;
236218885Sdim  }
237218885Sdim#endif
238218885Sdim
239218885Sdim  // Create a child process.
240218885Sdim  int child = fork();
241218885Sdim  switch (child) {
242221345Sdim    // An error occurred:  Return to the caller.
243218885Sdim    case -1:
244218885Sdim      MakeErrMsg(ErrMsg, "Couldn't fork");
245218885Sdim      return false;
246218885Sdim
247218885Sdim    // Child process: Execute the program.
248218885Sdim    case 0: {
249218885Sdim      // Redirect file descriptors...
250218885Sdim      if (redirects) {
251218885Sdim        // Redirect stdin
252218885Sdim        if (RedirectIO(redirects[0], 0, ErrMsg)) { return false; }
253218885Sdim        // Redirect stdout
254218885Sdim        if (RedirectIO(redirects[1], 1, ErrMsg)) { return false; }
255218885Sdim        if (redirects[1] && redirects[2] &&
256218885Sdim            *(redirects[1]) == *(redirects[2])) {
257218885Sdim          // If stdout and stderr should go to the same place, redirect stderr
258218885Sdim          // to the FD already open for stdout.
259218885Sdim          if (-1 == dup2(1,2)) {
260218885Sdim            MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout");
261218885Sdim            return false;
262218885Sdim          }
263218885Sdim        } else {
264218885Sdim          // Just redirect stderr
265218885Sdim          if (RedirectIO(redirects[2], 2, ErrMsg)) { return false; }
266218885Sdim        }
267218885Sdim      }
268218885Sdim
269218885Sdim      // Set memory limits
270218885Sdim      if (memoryLimit!=0) {
271218885Sdim        SetMemoryLimits(memoryLimit);
272218885Sdim      }
273218885Sdim
274218885Sdim      // Execute!
275218885Sdim      if (envp != 0)
276218885Sdim        execve(path.c_str(),
277218885Sdim               const_cast<char **>(args),
278218885Sdim               const_cast<char **>(envp));
279218885Sdim      else
280218885Sdim        execv(path.c_str(),
281218885Sdim              const_cast<char **>(args));
282218885Sdim      // If the execve() failed, we should exit. Follow Unix protocol and
283218885Sdim      // return 127 if the executable was not found, and 126 otherwise.
284218885Sdim      // Use _exit rather than exit so that atexit functions and static
285218885Sdim      // object destructors cloned from the parent process aren't
286218885Sdim      // redundantly run, and so that any data buffered in stdio buffers
287218885Sdim      // cloned from the parent aren't redundantly written out.
288218885Sdim      _exit(errno == ENOENT ? 127 : 126);
289218885Sdim    }
290218885Sdim
291218885Sdim    // Parent process: Break out of the switch to do our processing.
292218885Sdim    default:
293218885Sdim      break;
294218885Sdim  }
295218885Sdim
296218885Sdim  Data_ = reinterpret_cast<void*>(child);
297218885Sdim
298218885Sdim  return true;
299218885Sdim}
300218885Sdim
301218885Sdimint
302218885SdimProgram::Wait(const sys::Path &path,
303218885Sdim              unsigned secondsToWait,
304218885Sdim              std::string* ErrMsg)
305218885Sdim{
306218885Sdim#ifdef HAVE_SYS_WAIT_H
307218885Sdim  struct sigaction Act, Old;
308218885Sdim
309218885Sdim  if (Data_ == 0) {
310218885Sdim    MakeErrMsg(ErrMsg, "Process not started!");
311218885Sdim    return -1;
312218885Sdim  }
313218885Sdim
314218885Sdim  // Install a timeout handler.  The handler itself does nothing, but the simple
315218885Sdim  // fact of having a handler at all causes the wait below to return with EINTR,
316218885Sdim  // unlike if we used SIG_IGN.
317218885Sdim  if (secondsToWait) {
318218885Sdim    memset(&Act, 0, sizeof(Act));
319218885Sdim    Act.sa_handler = TimeOutHandler;
320218885Sdim    sigemptyset(&Act.sa_mask);
321218885Sdim    sigaction(SIGALRM, &Act, &Old);
322218885Sdim    alarm(secondsToWait);
323218885Sdim  }
324218885Sdim
325218885Sdim  // Parent process: Wait for the child process to terminate.
326218885Sdim  int status;
327218885Sdim  uint64_t pid = reinterpret_cast<uint64_t>(Data_);
328218885Sdim  pid_t child = static_cast<pid_t>(pid);
329218885Sdim  while (waitpid(pid, &status, 0) != child)
330218885Sdim    if (secondsToWait && errno == EINTR) {
331218885Sdim      // Kill the child.
332218885Sdim      kill(child, SIGKILL);
333218885Sdim
334218885Sdim      // Turn off the alarm and restore the signal handler
335218885Sdim      alarm(0);
336218885Sdim      sigaction(SIGALRM, &Old, 0);
337218885Sdim
338218885Sdim      // Wait for child to die
339218885Sdim      if (wait(&status) != child)
340218885Sdim        MakeErrMsg(ErrMsg, "Child timed out but wouldn't die");
341218885Sdim      else
342218885Sdim        MakeErrMsg(ErrMsg, "Child timed out", 0);
343218885Sdim
344223017Sdim      return -2;   // Timeout detected
345218885Sdim    } else if (errno != EINTR) {
346218885Sdim      MakeErrMsg(ErrMsg, "Error waiting for child process");
347218885Sdim      return -1;
348218885Sdim    }
349218885Sdim
350218885Sdim  // We exited normally without timeout, so turn off the timer.
351218885Sdim  if (secondsToWait) {
352218885Sdim    alarm(0);
353218885Sdim    sigaction(SIGALRM, &Old, 0);
354218885Sdim  }
355218885Sdim
356218885Sdim  // Return the proper exit status. Detect error conditions
357218885Sdim  // so we can return -1 for them and set ErrMsg informatively.
358218885Sdim  int result = 0;
359218885Sdim  if (WIFEXITED(status)) {
360218885Sdim    result = WEXITSTATUS(status);
361218885Sdim#ifdef HAVE_POSIX_SPAWN
362218885Sdim    // The posix_spawn child process returns 127 on any kind of error.
363218885Sdim    // Following the POSIX convention for command-line tools (which posix_spawn
364218885Sdim    // itself apparently does not), check to see if the failure was due to some
365218885Sdim    // reason other than the file not existing, and return 126 in this case.
366218885Sdim    bool Exists;
367218885Sdim    if (result == 127 && !llvm::sys::fs::exists(path.str(), Exists) && Exists)
368218885Sdim      result = 126;
369218885Sdim#endif
370218885Sdim    if (result == 127) {
371218885Sdim      if (ErrMsg)
372218885Sdim        *ErrMsg = llvm::sys::StrError(ENOENT);
373218885Sdim      return -1;
374218885Sdim    }
375218885Sdim    if (result == 126) {
376218885Sdim      if (ErrMsg)
377218885Sdim        *ErrMsg = "Program could not be executed";
378218885Sdim      return -1;
379218885Sdim    }
380218885Sdim  } else if (WIFSIGNALED(status)) {
381218885Sdim    if (ErrMsg) {
382218885Sdim      *ErrMsg = strsignal(WTERMSIG(status));
383218885Sdim#ifdef WCOREDUMP
384218885Sdim      if (WCOREDUMP(status))
385218885Sdim        *ErrMsg += " (core dumped)";
386218885Sdim#endif
387218885Sdim    }
388223017Sdim    // Return a special value to indicate that the process received an unhandled
389223017Sdim    // signal during execution as opposed to failing to execute.
390223017Sdim    return -2;
391218885Sdim  }
392218885Sdim  return result;
393218885Sdim#else
394218885Sdim  if (ErrMsg)
395218885Sdim    *ErrMsg = "Program::Wait is not implemented on this platform yet!";
396218885Sdim  return -1;
397218885Sdim#endif
398218885Sdim}
399218885Sdim
400234353Sdimerror_code Program::ChangeStdinToBinary(){
401218885Sdim  // Do nothing, as Unix doesn't differentiate between text and binary.
402234353Sdim  return make_error_code(errc::success);
403218885Sdim}
404218885Sdim
405234353Sdimerror_code Program::ChangeStdoutToBinary(){
406218885Sdim  // Do nothing, as Unix doesn't differentiate between text and binary.
407234353Sdim  return make_error_code(errc::success);
408218885Sdim}
409218885Sdim
410234353Sdimerror_code Program::ChangeStderrToBinary(){
411218885Sdim  // Do nothing, as Unix doesn't differentiate between text and binary.
412234353Sdim  return make_error_code(errc::success);
413218885Sdim}
414218885Sdim
415251662Sdimbool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) {
416251662Sdim  static long ArgMax = sysconf(_SC_ARG_MAX);
417251662Sdim
418251662Sdim  // System says no practical limit.
419251662Sdim  if (ArgMax == -1)
420251662Sdim    return true;
421251662Sdim
422251662Sdim  // Conservatively account for space required by environment variables.
423251662Sdim  ArgMax /= 2;
424251662Sdim
425251662Sdim  size_t ArgLength = 0;
426251662Sdim  for (ArrayRef<const char*>::iterator I = Args.begin(), E = Args.end();
427251662Sdim       I != E; ++I) {
428251662Sdim    ArgLength += strlen(*I) + 1;
429251662Sdim    if (ArgLength > size_t(ArgMax)) {
430251662Sdim      return false;
431251662Sdim    }
432251662Sdim  }
433251662Sdim  return true;
434218885Sdim}
435251662Sdim
436251662Sdim}
437