1bdd1243dSDimitry Andric//===- llvm/Support/Unix/Program.inc ----------------------------*- C++ -*-===//
20b57cec5SDimitry Andric//
30b57cec5SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric// See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric//
70b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric//
90b57cec5SDimitry Andric// This file implements the Unix specific portion of the Program class.
100b57cec5SDimitry Andric//
110b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
14bdd1243dSDimitry Andric//=== WARNING: Implementation here must contain only generic UNIX
15bdd1243dSDimitry Andric//===          code that is guaranteed to work on *all* UNIX variants.
160b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
170b57cec5SDimitry Andric
185ffd83dbSDimitry Andric#include "llvm/Support/Program.h"
195ffd83dbSDimitry Andric
200b57cec5SDimitry Andric#include "Unix.h"
210b57cec5SDimitry Andric#include "llvm/ADT/StringExtras.h"
220b57cec5SDimitry Andric#include "llvm/Config/config.h"
235f757f3fSDimitry Andric#include "llvm/Support/AutoConvert.h"
240b57cec5SDimitry Andric#include "llvm/Support/Compiler.h"
250b57cec5SDimitry Andric#include "llvm/Support/Errc.h"
260b57cec5SDimitry Andric#include "llvm/Support/FileSystem.h"
270b57cec5SDimitry Andric#include "llvm/Support/Path.h"
280b57cec5SDimitry Andric#include "llvm/Support/StringSaver.h"
295f757f3fSDimitry Andric#include "llvm/Support/SystemZ/zOSSupport.h"
300b57cec5SDimitry Andric#include "llvm/Support/raw_ostream.h"
310b57cec5SDimitry Andric#if HAVE_SYS_STAT_H
320b57cec5SDimitry Andric#include <sys/stat.h>
330b57cec5SDimitry Andric#endif
340b57cec5SDimitry Andric#if HAVE_SYS_RESOURCE_H
350b57cec5SDimitry Andric#include <sys/resource.h>
360b57cec5SDimitry Andric#endif
370b57cec5SDimitry Andric#if HAVE_SIGNAL_H
380b57cec5SDimitry Andric#include <signal.h>
390b57cec5SDimitry Andric#endif
400b57cec5SDimitry Andric#if HAVE_FCNTL_H
410b57cec5SDimitry Andric#include <fcntl.h>
420b57cec5SDimitry Andric#endif
430b57cec5SDimitry Andric#if HAVE_UNISTD_H
440b57cec5SDimitry Andric#include <unistd.h>
450b57cec5SDimitry Andric#endif
460b57cec5SDimitry Andric#ifdef HAVE_POSIX_SPAWN
470b57cec5SDimitry Andric#include <spawn.h>
480b57cec5SDimitry Andric
490b57cec5SDimitry Andric#if defined(__APPLE__)
500b57cec5SDimitry Andric#include <TargetConditionals.h>
510b57cec5SDimitry Andric#endif
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric#if defined(__APPLE__) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
540b57cec5SDimitry Andric#define USE_NSGETENVIRON 1
550b57cec5SDimitry Andric#else
560b57cec5SDimitry Andric#define USE_NSGETENVIRON 0
570b57cec5SDimitry Andric#endif
580b57cec5SDimitry Andric
590b57cec5SDimitry Andric#if !USE_NSGETENVIRON
600b57cec5SDimitry Andricextern char **environ;
610b57cec5SDimitry Andric#else
620b57cec5SDimitry Andric#include <crt_externs.h> // _NSGetEnviron
630b57cec5SDimitry Andric#endif
640b57cec5SDimitry Andric#endif
650b57cec5SDimitry Andric
665ffd83dbSDimitry Andricusing namespace llvm;
670b57cec5SDimitry Andricusing namespace sys;
680b57cec5SDimitry Andric
690b57cec5SDimitry AndricProcessInfo::ProcessInfo() : Pid(0), ReturnCode(0) {}
700b57cec5SDimitry Andric
710b57cec5SDimitry AndricErrorOr<std::string> sys::findProgramByName(StringRef Name,
720b57cec5SDimitry Andric                                            ArrayRef<StringRef> Paths) {
730b57cec5SDimitry Andric  assert(!Name.empty() && "Must have a name!");
740b57cec5SDimitry Andric  // Use the given path verbatim if it contains any slashes; this matches
750b57cec5SDimitry Andric  // the behavior of sh(1) and friends.
76349cc55cSDimitry Andric  if (Name.contains('/'))
77349cc55cSDimitry Andric    return std::string(Name);
780b57cec5SDimitry Andric
790b57cec5SDimitry Andric  SmallVector<StringRef, 16> EnvironmentPaths;
800b57cec5SDimitry Andric  if (Paths.empty())
810b57cec5SDimitry Andric    if (const char *PathEnv = std::getenv("PATH")) {
820b57cec5SDimitry Andric      SplitString(PathEnv, EnvironmentPaths, ":");
830b57cec5SDimitry Andric      Paths = EnvironmentPaths;
840b57cec5SDimitry Andric    }
850b57cec5SDimitry Andric
860b57cec5SDimitry Andric  for (auto Path : Paths) {
870b57cec5SDimitry Andric    if (Path.empty())
880b57cec5SDimitry Andric      continue;
890b57cec5SDimitry Andric
900b57cec5SDimitry Andric    // Check to see if this first directory contains the executable...
910b57cec5SDimitry Andric    SmallString<128> FilePath(Path);
920b57cec5SDimitry Andric    sys::path::append(FilePath, Name);
930b57cec5SDimitry Andric    if (sys::fs::can_execute(FilePath.c_str()))
947a6dacacSDimitry Andric      return std::string(FilePath); // Found the executable!
950b57cec5SDimitry Andric  }
960b57cec5SDimitry Andric  return errc::no_such_file_or_directory;
970b57cec5SDimitry Andric}
980b57cec5SDimitry Andric
99bdd1243dSDimitry Andricstatic bool RedirectIO(std::optional<StringRef> Path, int FD, std::string *ErrMsg) {
1000b57cec5SDimitry Andric  if (!Path) // Noop
1010b57cec5SDimitry Andric    return false;
1020b57cec5SDimitry Andric  std::string File;
1030b57cec5SDimitry Andric  if (Path->empty())
1040b57cec5SDimitry Andric    // Redirect empty paths to /dev/null
1050b57cec5SDimitry Andric    File = "/dev/null";
1060b57cec5SDimitry Andric  else
1075ffd83dbSDimitry Andric    File = std::string(*Path);
1080b57cec5SDimitry Andric
1090b57cec5SDimitry Andric  // Open the file
1100b57cec5SDimitry Andric  int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY | O_CREAT, 0666);
1110b57cec5SDimitry Andric  if (InFD == -1) {
112bdd1243dSDimitry Andric    MakeErrMsg(ErrMsg, "Cannot open file '" + File + "' for " +
113bdd1243dSDimitry Andric                           (FD == 0 ? "input" : "output"));
1140b57cec5SDimitry Andric    return true;
1150b57cec5SDimitry Andric  }
1160b57cec5SDimitry Andric
1170b57cec5SDimitry Andric  // Install it as the requested FD
1180b57cec5SDimitry Andric  if (dup2(InFD, FD) == -1) {
1190b57cec5SDimitry Andric    MakeErrMsg(ErrMsg, "Cannot dup2");
1200b57cec5SDimitry Andric    close(InFD);
1210b57cec5SDimitry Andric    return true;
1220b57cec5SDimitry Andric  }
1230b57cec5SDimitry Andric  close(InFD); // Close the original FD
1240b57cec5SDimitry Andric  return false;
1250b57cec5SDimitry Andric}
1260b57cec5SDimitry Andric
1270b57cec5SDimitry Andric#ifdef HAVE_POSIX_SPAWN
1280b57cec5SDimitry Andricstatic bool RedirectIO_PS(const std::string *Path, int FD, std::string *ErrMsg,
1290b57cec5SDimitry Andric                          posix_spawn_file_actions_t *FileActions) {
1300b57cec5SDimitry Andric  if (!Path) // Noop
1310b57cec5SDimitry Andric    return false;
1320b57cec5SDimitry Andric  const char *File;
1330b57cec5SDimitry Andric  if (Path->empty())
1340b57cec5SDimitry Andric    // Redirect empty paths to /dev/null
1350b57cec5SDimitry Andric    File = "/dev/null";
1360b57cec5SDimitry Andric  else
1370b57cec5SDimitry Andric    File = Path->c_str();
1380b57cec5SDimitry Andric
1390b57cec5SDimitry Andric  if (int Err = posix_spawn_file_actions_addopen(
140bdd1243dSDimitry Andric          FileActions, FD, File, FD == 0 ? O_RDONLY : O_WRONLY | O_CREAT, 0666))
1418bcb0991SDimitry Andric    return MakeErrMsg(ErrMsg, "Cannot posix_spawn_file_actions_addopen", Err);
1420b57cec5SDimitry Andric  return false;
1430b57cec5SDimitry Andric}
1440b57cec5SDimitry Andric#endif
1450b57cec5SDimitry Andric
146bdd1243dSDimitry Andricstatic void TimeOutHandler(int Sig) {}
1470b57cec5SDimitry Andric
1480b57cec5SDimitry Andricstatic void SetMemoryLimits(unsigned size) {
1490b57cec5SDimitry Andric#if HAVE_SYS_RESOURCE_H && HAVE_GETRLIMIT && HAVE_SETRLIMIT
1500b57cec5SDimitry Andric  struct rlimit r;
1510b57cec5SDimitry Andric  __typeof__(r.rlim_cur) limit = (__typeof__(r.rlim_cur))(size)*1048576;
1520b57cec5SDimitry Andric
1530b57cec5SDimitry Andric  // Heap size
1540b57cec5SDimitry Andric  getrlimit(RLIMIT_DATA, &r);
1550b57cec5SDimitry Andric  r.rlim_cur = limit;
1560b57cec5SDimitry Andric  setrlimit(RLIMIT_DATA, &r);
1570b57cec5SDimitry Andric#ifdef RLIMIT_RSS
1580b57cec5SDimitry Andric  // Resident set size.
1590b57cec5SDimitry Andric  getrlimit(RLIMIT_RSS, &r);
1600b57cec5SDimitry Andric  r.rlim_cur = limit;
1610b57cec5SDimitry Andric  setrlimit(RLIMIT_RSS, &r);
1620b57cec5SDimitry Andric#endif
1630b57cec5SDimitry Andric#endif
1640b57cec5SDimitry Andric}
1650b57cec5SDimitry Andric
1660b57cec5SDimitry Andricstatic std::vector<const char *>
1670b57cec5SDimitry AndrictoNullTerminatedCStringArray(ArrayRef<StringRef> Strings, StringSaver &Saver) {
1680b57cec5SDimitry Andric  std::vector<const char *> Result;
1690b57cec5SDimitry Andric  for (StringRef S : Strings)
1700b57cec5SDimitry Andric    Result.push_back(Saver.save(S).data());
1710b57cec5SDimitry Andric  Result.push_back(nullptr);
1720b57cec5SDimitry Andric  return Result;
1730b57cec5SDimitry Andric}
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andricstatic bool Execute(ProcessInfo &PI, StringRef Program,
176bdd1243dSDimitry Andric                    ArrayRef<StringRef> Args, std::optional<ArrayRef<StringRef>> Env,
177bdd1243dSDimitry Andric                    ArrayRef<std::optional<StringRef>> Redirects,
178e8d8bef9SDimitry Andric                    unsigned MemoryLimit, std::string *ErrMsg,
179e8d8bef9SDimitry Andric                    BitVector *AffinityMask) {
1800b57cec5SDimitry Andric  if (!llvm::sys::fs::exists(Program)) {
1810b57cec5SDimitry Andric    if (ErrMsg)
1820b57cec5SDimitry Andric      *ErrMsg = std::string("Executable \"") + Program.str() +
1830b57cec5SDimitry Andric                std::string("\" doesn't exist!");
1840b57cec5SDimitry Andric    return false;
1850b57cec5SDimitry Andric  }
1860b57cec5SDimitry Andric
187e8d8bef9SDimitry Andric  assert(!AffinityMask && "Starting a process with an affinity mask is "
188e8d8bef9SDimitry Andric                          "currently not supported on Unix!");
189e8d8bef9SDimitry Andric
1900b57cec5SDimitry Andric  BumpPtrAllocator Allocator;
1910b57cec5SDimitry Andric  StringSaver Saver(Allocator);
1920b57cec5SDimitry Andric  std::vector<const char *> ArgVector, EnvVector;
1930b57cec5SDimitry Andric  const char **Argv = nullptr;
1940b57cec5SDimitry Andric  const char **Envp = nullptr;
1950b57cec5SDimitry Andric  ArgVector = toNullTerminatedCStringArray(Args, Saver);
1960b57cec5SDimitry Andric  Argv = ArgVector.data();
1970b57cec5SDimitry Andric  if (Env) {
1980b57cec5SDimitry Andric    EnvVector = toNullTerminatedCStringArray(*Env, Saver);
1990b57cec5SDimitry Andric    Envp = EnvVector.data();
2000b57cec5SDimitry Andric  }
2010b57cec5SDimitry Andric
2020b57cec5SDimitry Andric  // If this OS has posix_spawn and there is no memory limit being implied, use
2030b57cec5SDimitry Andric  // posix_spawn.  It is more efficient than fork/exec.
2040b57cec5SDimitry Andric#ifdef HAVE_POSIX_SPAWN
2050b57cec5SDimitry Andric  if (MemoryLimit == 0) {
2060b57cec5SDimitry Andric    posix_spawn_file_actions_t FileActionsStore;
2070b57cec5SDimitry Andric    posix_spawn_file_actions_t *FileActions = nullptr;
2080b57cec5SDimitry Andric
2090b57cec5SDimitry Andric    // If we call posix_spawn_file_actions_addopen we have to make sure the
2100b57cec5SDimitry Andric    // c strings we pass to it stay alive until the call to posix_spawn,
2110b57cec5SDimitry Andric    // so we copy any StringRefs into this variable.
2120b57cec5SDimitry Andric    std::string RedirectsStorage[3];
2130b57cec5SDimitry Andric
2140b57cec5SDimitry Andric    if (!Redirects.empty()) {
2150b57cec5SDimitry Andric      assert(Redirects.size() == 3);
2160b57cec5SDimitry Andric      std::string *RedirectsStr[3] = {nullptr, nullptr, nullptr};
2170b57cec5SDimitry Andric      for (int I = 0; I < 3; ++I) {
2180b57cec5SDimitry Andric        if (Redirects[I]) {
2195ffd83dbSDimitry Andric          RedirectsStorage[I] = std::string(*Redirects[I]);
2200b57cec5SDimitry Andric          RedirectsStr[I] = &RedirectsStorage[I];
2210b57cec5SDimitry Andric        }
2220b57cec5SDimitry Andric      }
2230b57cec5SDimitry Andric
2240b57cec5SDimitry Andric      FileActions = &FileActionsStore;
2250b57cec5SDimitry Andric      posix_spawn_file_actions_init(FileActions);
2260b57cec5SDimitry Andric
2270b57cec5SDimitry Andric      // Redirect stdin/stdout.
2280b57cec5SDimitry Andric      if (RedirectIO_PS(RedirectsStr[0], 0, ErrMsg, FileActions) ||
2290b57cec5SDimitry Andric          RedirectIO_PS(RedirectsStr[1], 1, ErrMsg, FileActions))
2300b57cec5SDimitry Andric        return false;
2310b57cec5SDimitry Andric      if (!Redirects[1] || !Redirects[2] || *Redirects[1] != *Redirects[2]) {
2320b57cec5SDimitry Andric        // Just redirect stderr
2330b57cec5SDimitry Andric        if (RedirectIO_PS(RedirectsStr[2], 2, ErrMsg, FileActions))
2340b57cec5SDimitry Andric          return false;
2350b57cec5SDimitry Andric      } else {
2360b57cec5SDimitry Andric        // If stdout and stderr should go to the same place, redirect stderr
2370b57cec5SDimitry Andric        // to the FD already open for stdout.
2380b57cec5SDimitry Andric        if (int Err = posix_spawn_file_actions_adddup2(FileActions, 1, 2))
2390b57cec5SDimitry Andric          return !MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout", Err);
2400b57cec5SDimitry Andric      }
2410b57cec5SDimitry Andric    }
2420b57cec5SDimitry Andric
2430b57cec5SDimitry Andric    if (!Envp)
2440b57cec5SDimitry Andric#if !USE_NSGETENVIRON
2450b57cec5SDimitry Andric      Envp = const_cast<const char **>(environ);
2460b57cec5SDimitry Andric#else
2470b57cec5SDimitry Andric      // environ is missing in dylibs.
2480b57cec5SDimitry Andric      Envp = const_cast<const char **>(*_NSGetEnviron());
2490b57cec5SDimitry Andric#endif
2500b57cec5SDimitry Andric
2510b57cec5SDimitry Andric    constexpr int maxRetries = 8;
2520b57cec5SDimitry Andric    int retries = 0;
2530b57cec5SDimitry Andric    pid_t PID;
2540b57cec5SDimitry Andric    int Err;
2550b57cec5SDimitry Andric    do {
2560b57cec5SDimitry Andric      PID = 0; // Make Valgrind happy.
2570b57cec5SDimitry Andric      Err = posix_spawn(&PID, Program.str().c_str(), FileActions,
2580b57cec5SDimitry Andric                        /*attrp*/ nullptr, const_cast<char **>(Argv),
2590b57cec5SDimitry Andric                        const_cast<char **>(Envp));
2600b57cec5SDimitry Andric    } while (Err == EINTR && ++retries < maxRetries);
2610b57cec5SDimitry Andric
2620b57cec5SDimitry Andric    if (FileActions)
2630b57cec5SDimitry Andric      posix_spawn_file_actions_destroy(FileActions);
2640b57cec5SDimitry Andric
2650b57cec5SDimitry Andric    if (Err)
2660b57cec5SDimitry Andric      return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err);
2670b57cec5SDimitry Andric
2680b57cec5SDimitry Andric    PI.Pid = PID;
2690b57cec5SDimitry Andric    PI.Process = PID;
2700b57cec5SDimitry Andric
2710b57cec5SDimitry Andric    return true;
2720b57cec5SDimitry Andric  }
2730b57cec5SDimitry Andric#endif
2740b57cec5SDimitry Andric
2750b57cec5SDimitry Andric  // Create a child process.
2760b57cec5SDimitry Andric  int child = fork();
2770b57cec5SDimitry Andric  switch (child) {
2780b57cec5SDimitry Andric  // An error occurred:  Return to the caller.
2790b57cec5SDimitry Andric  case -1:
2800b57cec5SDimitry Andric    MakeErrMsg(ErrMsg, "Couldn't fork");
2810b57cec5SDimitry Andric    return false;
2820b57cec5SDimitry Andric
2830b57cec5SDimitry Andric  // Child process: Execute the program.
2840b57cec5SDimitry Andric  case 0: {
2850b57cec5SDimitry Andric    // Redirect file descriptors...
2860b57cec5SDimitry Andric    if (!Redirects.empty()) {
2870b57cec5SDimitry Andric      // Redirect stdin
288bdd1243dSDimitry Andric      if (RedirectIO(Redirects[0], 0, ErrMsg)) {
289bdd1243dSDimitry Andric        return false;
290bdd1243dSDimitry Andric      }
2910b57cec5SDimitry Andric      // Redirect stdout
292bdd1243dSDimitry Andric      if (RedirectIO(Redirects[1], 1, ErrMsg)) {
293bdd1243dSDimitry Andric        return false;
294bdd1243dSDimitry Andric      }
2950b57cec5SDimitry Andric      if (Redirects[1] && Redirects[2] && *Redirects[1] == *Redirects[2]) {
2960b57cec5SDimitry Andric        // If stdout and stderr should go to the same place, redirect stderr
2970b57cec5SDimitry Andric        // to the FD already open for stdout.
2980b57cec5SDimitry Andric        if (-1 == dup2(1, 2)) {
2990b57cec5SDimitry Andric          MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout");
3000b57cec5SDimitry Andric          return false;
3010b57cec5SDimitry Andric        }
3020b57cec5SDimitry Andric      } else {
3030b57cec5SDimitry Andric        // Just redirect stderr
304bdd1243dSDimitry Andric        if (RedirectIO(Redirects[2], 2, ErrMsg)) {
305bdd1243dSDimitry Andric          return false;
306bdd1243dSDimitry Andric        }
3070b57cec5SDimitry Andric      }
3080b57cec5SDimitry Andric    }
3090b57cec5SDimitry Andric
3100b57cec5SDimitry Andric    // Set memory limits
3110b57cec5SDimitry Andric    if (MemoryLimit != 0) {
3120b57cec5SDimitry Andric      SetMemoryLimits(MemoryLimit);
3130b57cec5SDimitry Andric    }
3140b57cec5SDimitry Andric
3150b57cec5SDimitry Andric    // Execute!
3165ffd83dbSDimitry Andric    std::string PathStr = std::string(Program);
3170b57cec5SDimitry Andric    if (Envp != nullptr)
3180b57cec5SDimitry Andric      execve(PathStr.c_str(), const_cast<char **>(Argv),
3190b57cec5SDimitry Andric             const_cast<char **>(Envp));
3200b57cec5SDimitry Andric    else
3210b57cec5SDimitry Andric      execv(PathStr.c_str(), const_cast<char **>(Argv));
3220b57cec5SDimitry Andric    // If the execve() failed, we should exit. Follow Unix protocol and
3230b57cec5SDimitry Andric    // return 127 if the executable was not found, and 126 otherwise.
3240b57cec5SDimitry Andric    // Use _exit rather than exit so that atexit functions and static
3250b57cec5SDimitry Andric    // object destructors cloned from the parent process aren't
3260b57cec5SDimitry Andric    // redundantly run, and so that any data buffered in stdio buffers
3270b57cec5SDimitry Andric    // cloned from the parent aren't redundantly written out.
3280b57cec5SDimitry Andric    _exit(errno == ENOENT ? 127 : 126);
3290b57cec5SDimitry Andric  }
3300b57cec5SDimitry Andric
3310b57cec5SDimitry Andric  // Parent process: Break out of the switch to do our processing.
3320b57cec5SDimitry Andric  default:
3330b57cec5SDimitry Andric    break;
3340b57cec5SDimitry Andric  }
3350b57cec5SDimitry Andric
3360b57cec5SDimitry Andric  PI.Pid = child;
3370b57cec5SDimitry Andric  PI.Process = child;
3380b57cec5SDimitry Andric
3390b57cec5SDimitry Andric  return true;
3400b57cec5SDimitry Andric}
3410b57cec5SDimitry Andric
3420b57cec5SDimitry Andricnamespace llvm {
3435ffd83dbSDimitry Andricnamespace sys {
3440b57cec5SDimitry Andric
3455f757f3fSDimitry Andric#if defined(_AIX)
3465ffd83dbSDimitry Andricstatic pid_t(wait4)(pid_t pid, int *status, int options, struct rusage *usage);
3475f757f3fSDimitry Andric#elif !defined(__Fuchsia__)
3485f757f3fSDimitry Andricusing ::wait4;
3495ffd83dbSDimitry Andric#endif
3505ffd83dbSDimitry Andric
3515ffd83dbSDimitry Andric} // namespace sys
3525ffd83dbSDimitry Andric} // namespace llvm
3535ffd83dbSDimitry Andric
3545ffd83dbSDimitry Andric#ifdef _AIX
3555ffd83dbSDimitry Andric#ifndef _ALL_SOURCE
3565ffd83dbSDimitry Andricextern "C" pid_t(wait4)(pid_t pid, int *status, int options,
3575ffd83dbSDimitry Andric                        struct rusage *usage);
3585ffd83dbSDimitry Andric#endif
3595ffd83dbSDimitry Andricpid_t(llvm::sys::wait4)(pid_t pid, int *status, int options,
3605ffd83dbSDimitry Andric                        struct rusage *usage) {
3615ffd83dbSDimitry Andric  assert(pid > 0 && "Only expecting to handle actual PID values!");
3625ffd83dbSDimitry Andric  assert((options & ~WNOHANG) == 0 && "Expecting WNOHANG at most!");
3635ffd83dbSDimitry Andric  assert(usage && "Expecting usage collection!");
3645ffd83dbSDimitry Andric
3655ffd83dbSDimitry Andric  // AIX wait4 does not work well with WNOHANG.
3665ffd83dbSDimitry Andric  if (!(options & WNOHANG))
3675ffd83dbSDimitry Andric    return ::wait4(pid, status, options, usage);
3685ffd83dbSDimitry Andric
3695ffd83dbSDimitry Andric  // For WNOHANG, we use waitid (which supports WNOWAIT) until the child process
3705ffd83dbSDimitry Andric  // has terminated.
3715ffd83dbSDimitry Andric  siginfo_t WaitIdInfo;
3725ffd83dbSDimitry Andric  WaitIdInfo.si_pid = 0;
3735ffd83dbSDimitry Andric  int WaitIdRetVal =
3745ffd83dbSDimitry Andric      waitid(P_PID, pid, &WaitIdInfo, WNOWAIT | WEXITED | options);
3755ffd83dbSDimitry Andric
3765ffd83dbSDimitry Andric  if (WaitIdRetVal == -1 || WaitIdInfo.si_pid == 0)
3775ffd83dbSDimitry Andric    return WaitIdRetVal;
3785ffd83dbSDimitry Andric
3795ffd83dbSDimitry Andric  assert(WaitIdInfo.si_pid == pid);
3805ffd83dbSDimitry Andric
3815ffd83dbSDimitry Andric  // The child has already terminated, so a blocking wait on it is okay in the
3825ffd83dbSDimitry Andric  // absence of indiscriminate `wait` calls from the current process (which
3835ffd83dbSDimitry Andric  // would cause the call here to fail with ECHILD).
3845ffd83dbSDimitry Andric  return ::wait4(pid, status, options & ~WNOHANG, usage);
3855ffd83dbSDimitry Andric}
3865ffd83dbSDimitry Andric#endif
3875ffd83dbSDimitry Andric
388bdd1243dSDimitry AndricProcessInfo llvm::sys::Wait(const ProcessInfo &PI,
389bdd1243dSDimitry Andric                            std::optional<unsigned> SecondsToWait,
390bdd1243dSDimitry Andric                            std::string *ErrMsg,
391bdd1243dSDimitry Andric                            std::optional<ProcessStatistics> *ProcStat,
392bdd1243dSDimitry Andric                            bool Polling) {
3930b57cec5SDimitry Andric  struct sigaction Act, Old;
3940b57cec5SDimitry Andric  assert(PI.Pid && "invalid pid to wait on, process not started?");
3950b57cec5SDimitry Andric
3960b57cec5SDimitry Andric  int WaitPidOptions = 0;
3970b57cec5SDimitry Andric  pid_t ChildPid = PI.Pid;
398bdd1243dSDimitry Andric  bool WaitUntilTerminates = false;
399bdd1243dSDimitry Andric  if (!SecondsToWait) {
400bdd1243dSDimitry Andric    WaitUntilTerminates = true;
401bdd1243dSDimitry Andric  } else {
402bdd1243dSDimitry Andric    if (*SecondsToWait == 0)
403bdd1243dSDimitry Andric      WaitPidOptions = WNOHANG;
404bdd1243dSDimitry Andric
4050b57cec5SDimitry Andric    // Install a timeout handler.  The handler itself does nothing, but the
4060b57cec5SDimitry Andric    // simple fact of having a handler at all causes the wait below to return
4070b57cec5SDimitry Andric    // with EINTR, unlike if we used SIG_IGN.
4080b57cec5SDimitry Andric    memset(&Act, 0, sizeof(Act));
4090b57cec5SDimitry Andric    Act.sa_handler = TimeOutHandler;
4100b57cec5SDimitry Andric    sigemptyset(&Act.sa_mask);
4110b57cec5SDimitry Andric    sigaction(SIGALRM, &Act, &Old);
4125ffd83dbSDimitry Andric    // FIXME The alarm signal may be delivered to another thread.
413bdd1243dSDimitry Andric    alarm(*SecondsToWait);
414bdd1243dSDimitry Andric  }
4150b57cec5SDimitry Andric
4160b57cec5SDimitry Andric  // Parent process: Wait for the child process to terminate.
417bdd1243dSDimitry Andric  int status = 0;
4180b57cec5SDimitry Andric  ProcessInfo WaitResult;
4195f757f3fSDimitry Andric#ifndef __Fuchsia__
4205ffd83dbSDimitry Andric  rusage Info;
4215ffd83dbSDimitry Andric  if (ProcStat)
4225ffd83dbSDimitry Andric    ProcStat->reset();
4230b57cec5SDimitry Andric
4240b57cec5SDimitry Andric  do {
4255ffd83dbSDimitry Andric    WaitResult.Pid = sys::wait4(ChildPid, &status, WaitPidOptions, &Info);
4260b57cec5SDimitry Andric  } while (WaitUntilTerminates && WaitResult.Pid == -1 && errno == EINTR);
4275f757f3fSDimitry Andric#endif
4280b57cec5SDimitry Andric
4290b57cec5SDimitry Andric  if (WaitResult.Pid != PI.Pid) {
4300b57cec5SDimitry Andric    if (WaitResult.Pid == 0) {
4310b57cec5SDimitry Andric      // Non-blocking wait.
4320b57cec5SDimitry Andric      return WaitResult;
4330b57cec5SDimitry Andric    } else {
434bdd1243dSDimitry Andric      if (SecondsToWait && errno == EINTR && !Polling) {
4350b57cec5SDimitry Andric        // Kill the child.
4360b57cec5SDimitry Andric        kill(PI.Pid, SIGKILL);
4370b57cec5SDimitry Andric
4380b57cec5SDimitry Andric        // Turn off the alarm and restore the signal handler
4390b57cec5SDimitry Andric        alarm(0);
4400b57cec5SDimitry Andric        sigaction(SIGALRM, &Old, nullptr);
4410b57cec5SDimitry Andric
4420b57cec5SDimitry Andric        // Wait for child to die
4435ffd83dbSDimitry Andric        // FIXME This could grab some other child process out from another
4445ffd83dbSDimitry Andric        // waiting thread and then leave a zombie anyway.
4450b57cec5SDimitry Andric        if (wait(&status) != ChildPid)
4460b57cec5SDimitry Andric          MakeErrMsg(ErrMsg, "Child timed out but wouldn't die");
4470b57cec5SDimitry Andric        else
4480b57cec5SDimitry Andric          MakeErrMsg(ErrMsg, "Child timed out", 0);
4490b57cec5SDimitry Andric
4500b57cec5SDimitry Andric        WaitResult.ReturnCode = -2; // Timeout detected
4510b57cec5SDimitry Andric        return WaitResult;
4520b57cec5SDimitry Andric      } else if (errno != EINTR) {
4530b57cec5SDimitry Andric        MakeErrMsg(ErrMsg, "Error waiting for child process");
4540b57cec5SDimitry Andric        WaitResult.ReturnCode = -1;
4550b57cec5SDimitry Andric        return WaitResult;
4560b57cec5SDimitry Andric      }
4570b57cec5SDimitry Andric    }
4580b57cec5SDimitry Andric  }
4590b57cec5SDimitry Andric
4600b57cec5SDimitry Andric  // We exited normally without timeout, so turn off the timer.
4610b57cec5SDimitry Andric  if (SecondsToWait && !WaitUntilTerminates) {
4620b57cec5SDimitry Andric    alarm(0);
4630b57cec5SDimitry Andric    sigaction(SIGALRM, &Old, nullptr);
4640b57cec5SDimitry Andric  }
4650b57cec5SDimitry Andric
4665f757f3fSDimitry Andric#ifndef __Fuchsia__
4675ffd83dbSDimitry Andric  if (ProcStat) {
4685ffd83dbSDimitry Andric    std::chrono::microseconds UserT = toDuration(Info.ru_utime);
4695ffd83dbSDimitry Andric    std::chrono::microseconds KernelT = toDuration(Info.ru_stime);
470fe6060f1SDimitry Andric    uint64_t PeakMemory = 0;
4715f757f3fSDimitry Andric#if !defined(__HAIKU__) && !defined(__MVS__)
472fe6060f1SDimitry Andric    PeakMemory = static_cast<uint64_t>(Info.ru_maxrss);
473fe6060f1SDimitry Andric#endif
4745ffd83dbSDimitry Andric    *ProcStat = ProcessStatistics{UserT + KernelT, UserT, PeakMemory};
4755ffd83dbSDimitry Andric  }
4765f757f3fSDimitry Andric#endif
4775ffd83dbSDimitry Andric
4780b57cec5SDimitry Andric  // Return the proper exit status. Detect error conditions
4790b57cec5SDimitry Andric  // so we can return -1 for them and set ErrMsg informatively.
4800b57cec5SDimitry Andric  int result = 0;
4810b57cec5SDimitry Andric  if (WIFEXITED(status)) {
4820b57cec5SDimitry Andric    result = WEXITSTATUS(status);
4830b57cec5SDimitry Andric    WaitResult.ReturnCode = result;
4840b57cec5SDimitry Andric
4850b57cec5SDimitry Andric    if (result == 127) {
4860b57cec5SDimitry Andric      if (ErrMsg)
4870b57cec5SDimitry Andric        *ErrMsg = llvm::sys::StrError(ENOENT);
4880b57cec5SDimitry Andric      WaitResult.ReturnCode = -1;
4890b57cec5SDimitry Andric      return WaitResult;
4900b57cec5SDimitry Andric    }
4910b57cec5SDimitry Andric    if (result == 126) {
4920b57cec5SDimitry Andric      if (ErrMsg)
4930b57cec5SDimitry Andric        *ErrMsg = "Program could not be executed";
4940b57cec5SDimitry Andric      WaitResult.ReturnCode = -1;
4950b57cec5SDimitry Andric      return WaitResult;
4960b57cec5SDimitry Andric    }
4970b57cec5SDimitry Andric  } else if (WIFSIGNALED(status)) {
4980b57cec5SDimitry Andric    if (ErrMsg) {
4990b57cec5SDimitry Andric      *ErrMsg = strsignal(WTERMSIG(status));
5000b57cec5SDimitry Andric#ifdef WCOREDUMP
5010b57cec5SDimitry Andric      if (WCOREDUMP(status))
5020b57cec5SDimitry Andric        *ErrMsg += " (core dumped)";
5030b57cec5SDimitry Andric#endif
5040b57cec5SDimitry Andric    }
5050b57cec5SDimitry Andric    // Return a special value to indicate that the process received an unhandled
5060b57cec5SDimitry Andric    // signal during execution as opposed to failing to execute.
5070b57cec5SDimitry Andric    WaitResult.ReturnCode = -2;
5080b57cec5SDimitry Andric  }
5090b57cec5SDimitry Andric  return WaitResult;
5100b57cec5SDimitry Andric}
5110b57cec5SDimitry Andric
512fe6060f1SDimitry Andricstd::error_code llvm::sys::ChangeStdinMode(fs::OpenFlags Flags) {
513fe6060f1SDimitry Andric  if (!(Flags & fs::OF_Text))
514fe6060f1SDimitry Andric    return ChangeStdinToBinary();
515fe6060f1SDimitry Andric  return std::error_code();
516fe6060f1SDimitry Andric}
517fe6060f1SDimitry Andric
518fe6060f1SDimitry Andricstd::error_code llvm::sys::ChangeStdoutMode(fs::OpenFlags Flags) {
519fe6060f1SDimitry Andric  if (!(Flags & fs::OF_Text))
520fe6060f1SDimitry Andric    return ChangeStdoutToBinary();
521fe6060f1SDimitry Andric  return std::error_code();
522fe6060f1SDimitry Andric}
523fe6060f1SDimitry Andric
5245ffd83dbSDimitry Andricstd::error_code llvm::sys::ChangeStdinToBinary() {
5255f757f3fSDimitry Andric#ifdef __MVS__
5265f757f3fSDimitry Andric  return disableAutoConversion(STDIN_FILENO);
5275f757f3fSDimitry Andric#else
5280b57cec5SDimitry Andric  // Do nothing, as Unix doesn't differentiate between text and binary.
5290b57cec5SDimitry Andric  return std::error_code();
5305f757f3fSDimitry Andric#endif
5310b57cec5SDimitry Andric}
5320b57cec5SDimitry Andric
5335ffd83dbSDimitry Andricstd::error_code llvm::sys::ChangeStdoutToBinary() {
5340b57cec5SDimitry Andric  // Do nothing, as Unix doesn't differentiate between text and binary.
5350b57cec5SDimitry Andric  return std::error_code();
5360b57cec5SDimitry Andric}
5370b57cec5SDimitry Andric
5380b57cec5SDimitry Andricstd::error_code
5390b57cec5SDimitry Andricllvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents,
5400b57cec5SDimitry Andric                                 WindowsEncodingMethod Encoding /*unused*/) {
5410b57cec5SDimitry Andric  std::error_code EC;
542bdd1243dSDimitry Andric  llvm::raw_fd_ostream OS(FileName, EC,
543bdd1243dSDimitry Andric                          llvm::sys::fs::OpenFlags::OF_TextWithCRLF);
5440b57cec5SDimitry Andric
5450b57cec5SDimitry Andric  if (EC)
5460b57cec5SDimitry Andric    return EC;
5470b57cec5SDimitry Andric
5480b57cec5SDimitry Andric  OS << Contents;
5490b57cec5SDimitry Andric
5500b57cec5SDimitry Andric  if (OS.has_error())
5510b57cec5SDimitry Andric    return make_error_code(errc::io_error);
5520b57cec5SDimitry Andric
5530b57cec5SDimitry Andric  return EC;
5540b57cec5SDimitry Andric}
5550b57cec5SDimitry Andric
5560b57cec5SDimitry Andricbool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program,
5570b57cec5SDimitry Andric                                                  ArrayRef<StringRef> Args) {
5580b57cec5SDimitry Andric  static long ArgMax = sysconf(_SC_ARG_MAX);
5590b57cec5SDimitry Andric  // POSIX requires that _POSIX_ARG_MAX is 4096, which is the lowest possible
5600b57cec5SDimitry Andric  // value for ARG_MAX on a POSIX compliant system.
5610b57cec5SDimitry Andric  static long ArgMin = _POSIX_ARG_MAX;
5620b57cec5SDimitry Andric
5630b57cec5SDimitry Andric  // This the same baseline used by xargs.
5640b57cec5SDimitry Andric  long EffectiveArgMax = 128 * 1024;
5650b57cec5SDimitry Andric
5660b57cec5SDimitry Andric  if (EffectiveArgMax > ArgMax)
5670b57cec5SDimitry Andric    EffectiveArgMax = ArgMax;
5680b57cec5SDimitry Andric  else if (EffectiveArgMax < ArgMin)
5690b57cec5SDimitry Andric    EffectiveArgMax = ArgMin;
5700b57cec5SDimitry Andric
5710b57cec5SDimitry Andric  // System says no practical limit.
5720b57cec5SDimitry Andric  if (ArgMax == -1)
5730b57cec5SDimitry Andric    return true;
5740b57cec5SDimitry Andric
5750b57cec5SDimitry Andric  // Conservatively account for space required by environment variables.
5760b57cec5SDimitry Andric  long HalfArgMax = EffectiveArgMax / 2;
5770b57cec5SDimitry Andric
5780b57cec5SDimitry Andric  size_t ArgLength = Program.size() + 1;
5790b57cec5SDimitry Andric  for (StringRef Arg : Args) {
5800b57cec5SDimitry Andric    // Ensure that we do not exceed the MAX_ARG_STRLEN constant on Linux, which
5810b57cec5SDimitry Andric    // does not have a constant unlike what the man pages would have you
5820b57cec5SDimitry Andric    // believe. Since this limit is pretty high, perform the check
5830b57cec5SDimitry Andric    // unconditionally rather than trying to be aggressive and limiting it to
5840b57cec5SDimitry Andric    // Linux only.
5850b57cec5SDimitry Andric    if (Arg.size() >= (32 * 4096))
5860b57cec5SDimitry Andric      return false;
5870b57cec5SDimitry Andric
5880b57cec5SDimitry Andric    ArgLength += Arg.size() + 1;
5890b57cec5SDimitry Andric    if (ArgLength > size_t(HalfArgMax)) {
5900b57cec5SDimitry Andric      return false;
5910b57cec5SDimitry Andric    }
5920b57cec5SDimitry Andric  }
5930b57cec5SDimitry Andric
5940b57cec5SDimitry Andric  return true;
5950b57cec5SDimitry Andric}
596