588 lines · plain
1//===- llvm/Support/Unix/Program.inc ----------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the Unix specific portion of the Program class.10//11//===----------------------------------------------------------------------===//12 13//===----------------------------------------------------------------------===//14//=== WARNING: Implementation here must contain only generic UNIX15//=== code that is guaranteed to work on *all* UNIX variants.16//===----------------------------------------------------------------------===//17 18#include "llvm/Support/Program.h"19 20#include "Unix.h"21#include "llvm/ADT/StringExtras.h"22#include "llvm/Config/config.h"23#include "llvm/Support/AutoConvert.h"24#include "llvm/Support/Compiler.h"25#include "llvm/Support/Errc.h"26#include "llvm/Support/FileSystem.h"27#include "llvm/Support/Path.h"28#include "llvm/Support/StringSaver.h"29#include "llvm/Support/raw_ostream.h"30#include <fcntl.h>31#include <signal.h>32#include <sys/resource.h>33#include <sys/stat.h>34#if HAVE_UNISTD_H35#include <unistd.h>36#endif37#ifdef HAVE_POSIX_SPAWN38#include <spawn.h>39 40#if defined(__APPLE__)41#include <TargetConditionals.h>42#endif43 44#if defined(__APPLE__) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)45#define USE_NSGETENVIRON 146#else47#define USE_NSGETENVIRON 048#endif49 50#if !USE_NSGETENVIRON51extern char **environ;52#else53#include <crt_externs.h> // _NSGetEnviron54#endif55#endif56 57using namespace llvm;58using namespace sys;59 60ProcessInfo::ProcessInfo() : Pid(0), ReturnCode(0) {}61 62ErrorOr<std::string> sys::findProgramByName(StringRef Name,63 ArrayRef<StringRef> Paths) {64 assert(!Name.empty() && "Must have a name!");65 // Use the given path verbatim if it contains any slashes; this matches66 // the behavior of sh(1) and friends.67 if (Name.contains('/'))68 return std::string(Name);69 70 SmallVector<StringRef, 16> EnvironmentPaths;71 if (Paths.empty())72 if (const char *PathEnv = std::getenv("PATH")) {73 SplitString(PathEnv, EnvironmentPaths, ":");74 Paths = EnvironmentPaths;75 }76 77 for (auto Path : Paths) {78 if (Path.empty())79 continue;80 81 // Check to see if this first directory contains the executable...82 SmallString<128> FilePath(Path);83 sys::path::append(FilePath, Name);84 if (sys::fs::can_execute(FilePath.c_str()))85 return std::string(FilePath); // Found the executable!86 }87 return errc::no_such_file_or_directory;88}89 90static bool RedirectIO(std::optional<StringRef> Path, int FD, std::string *ErrMsg) {91 if (!Path) // Noop92 return false;93 std::string File;94 if (Path->empty())95 // Redirect empty paths to /dev/null96 File = "/dev/null";97 else98 File = std::string(*Path);99 100 // Open the file101 int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY | O_CREAT, 0666);102 if (InFD == -1) {103 MakeErrMsg(ErrMsg, "Cannot open file '" + File + "' for " +104 (FD == 0 ? "input" : "output"));105 return true;106 }107 108 // Install it as the requested FD109 if (dup2(InFD, FD) == -1) {110 MakeErrMsg(ErrMsg, "Cannot dup2");111 close(InFD);112 return true;113 }114 close(InFD); // Close the original FD115 return false;116}117 118#ifdef HAVE_POSIX_SPAWN119static bool RedirectIO_PS(const std::string *Path, int FD, std::string *ErrMsg,120 posix_spawn_file_actions_t *FileActions) {121 if (!Path) // Noop122 return false;123 const char *File;124 if (Path->empty())125 // Redirect empty paths to /dev/null126 File = "/dev/null";127 else128 File = Path->c_str();129 130 if (int Err = posix_spawn_file_actions_addopen(131 FileActions, FD, File, FD == 0 ? O_RDONLY : O_WRONLY | O_CREAT, 0666))132 return MakeErrMsg(ErrMsg, "Cannot posix_spawn_file_actions_addopen", Err);133 return false;134}135#endif136 137static void TimeOutHandler(int Sig) {}138 139static void SetMemoryLimits(unsigned size) {140 struct rlimit r;141 __typeof__(r.rlim_cur) limit = (__typeof__(r.rlim_cur))(size)*1048576;142 143 // Heap size144 getrlimit(RLIMIT_DATA, &r);145 r.rlim_cur = limit;146 setrlimit(RLIMIT_DATA, &r);147#ifdef RLIMIT_RSS148 // Resident set size.149 getrlimit(RLIMIT_RSS, &r);150 r.rlim_cur = limit;151 setrlimit(RLIMIT_RSS, &r);152#endif153}154 155static std::vector<const char *>156toNullTerminatedCStringArray(ArrayRef<StringRef> Strings, StringSaver &Saver) {157 std::vector<const char *> Result;158 for (StringRef S : Strings)159 Result.push_back(Saver.save(S).data());160 Result.push_back(nullptr);161 return Result;162}163 164static bool Execute(ProcessInfo &PI, StringRef Program,165 ArrayRef<StringRef> Args,166 std::optional<ArrayRef<StringRef>> Env,167 ArrayRef<std::optional<StringRef>> Redirects,168 unsigned MemoryLimit, std::string *ErrMsg,169 BitVector *AffinityMask, bool DetachProcess) {170 assert(!AffinityMask && "Starting a process with an affinity mask is "171 "currently not supported on Unix!");172 173 BumpPtrAllocator Allocator;174 StringSaver Saver(Allocator);175 std::vector<const char *> ArgVector, EnvVector;176 const char **Argv = nullptr;177 const char **Envp = nullptr;178 ArgVector = toNullTerminatedCStringArray(Args, Saver);179 Argv = ArgVector.data();180 if (Env) {181 EnvVector = toNullTerminatedCStringArray(*Env, Saver);182 Envp = EnvVector.data();183 }184 185 // If this OS has posix_spawn and there is no memory limit being implied, use186 // posix_spawn. It is more efficient than fork/exec.187#ifdef HAVE_POSIX_SPAWN188 // Cannot use posix_spawn if you would like to detach the process189 if (MemoryLimit == 0 && !DetachProcess) {190 posix_spawn_file_actions_t FileActionsStore;191 posix_spawn_file_actions_t *FileActions = nullptr;192 193 // If we call posix_spawn_file_actions_addopen we have to make sure the194 // c strings we pass to it stay alive until the call to posix_spawn,195 // so we copy any StringRefs into this variable.196 std::string RedirectsStorage[3];197 198 if (!Redirects.empty()) {199 assert(Redirects.size() == 3);200 std::string *RedirectsStr[3] = {nullptr, nullptr, nullptr};201 for (int I = 0; I < 3; ++I) {202 if (Redirects[I]) {203 RedirectsStorage[I] = std::string(*Redirects[I]);204 RedirectsStr[I] = &RedirectsStorage[I];205 }206 }207 208 FileActions = &FileActionsStore;209 posix_spawn_file_actions_init(FileActions);210 211 // Redirect stdin/stdout.212 if (RedirectIO_PS(RedirectsStr[0], 0, ErrMsg, FileActions) ||213 RedirectIO_PS(RedirectsStr[1], 1, ErrMsg, FileActions))214 return false;215 if (!Redirects[1] || !Redirects[2] || *Redirects[1] != *Redirects[2]) {216 // Just redirect stderr217 if (RedirectIO_PS(RedirectsStr[2], 2, ErrMsg, FileActions))218 return false;219 } else {220 // If stdout and stderr should go to the same place, redirect stderr221 // to the FD already open for stdout.222 if (int Err = posix_spawn_file_actions_adddup2(FileActions, 1, 2))223 return !MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout", Err);224 }225 }226 227 if (!Envp)228#if !USE_NSGETENVIRON229 Envp = const_cast<const char **>(environ);230#else231 // environ is missing in dylibs.232 Envp = const_cast<const char **>(*_NSGetEnviron());233#endif234 235 constexpr int maxRetries = 8;236 int retries = 0;237 pid_t PID;238 int Err;239 do {240 PID = 0; // Make Valgrind happy.241 Err = posix_spawn(&PID, Program.str().c_str(), FileActions,242 /*attrp*/ nullptr, const_cast<char **>(Argv),243 const_cast<char **>(Envp));244 } while (Err == EINTR && ++retries < maxRetries);245 246 if (FileActions)247 posix_spawn_file_actions_destroy(FileActions);248 249 if (Err)250 return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err);251 252 PI.Pid = PID;253 PI.Process = PID;254 255 return true;256 }257#endif // HAVE_POSIX_SPAWN258 259 // Create a child process.260 int child = fork();261 switch (child) {262 // An error occurred: Return to the caller.263 case -1:264 MakeErrMsg(ErrMsg, "Couldn't fork");265 return false;266 267 // Child process: Execute the program.268 case 0: {269 // Redirect file descriptors...270 if (!Redirects.empty()) {271 // Redirect stdin272 if (RedirectIO(Redirects[0], 0, ErrMsg)) {273 return false;274 }275 // Redirect stdout276 if (RedirectIO(Redirects[1], 1, ErrMsg)) {277 return false;278 }279 if (Redirects[1] && Redirects[2] && *Redirects[1] == *Redirects[2]) {280 // If stdout and stderr should go to the same place, redirect stderr281 // to the FD already open for stdout.282 if (-1 == dup2(1, 2)) {283 MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout");284 return false;285 }286 } else {287 // Just redirect stderr288 if (RedirectIO(Redirects[2], 2, ErrMsg)) {289 return false;290 }291 }292 }293 294 if (DetachProcess) {295 // Detach from controlling terminal296 if (::setsid() == -1) {297 MakeErrMsg(ErrMsg, "Could not detach process, ::setsid failed");298 return false;299 }300 }301 302 // Set memory limits303 if (MemoryLimit != 0) {304 SetMemoryLimits(MemoryLimit);305 }306 307 // Execute!308 std::string PathStr = std::string(Program);309 if (Envp != nullptr)310 execve(PathStr.c_str(), const_cast<char **>(Argv),311 const_cast<char **>(Envp));312 else313 execv(PathStr.c_str(), const_cast<char **>(Argv));314 // If the execve() failed, we should exit. Follow Unix protocol and315 // return 127 if the executable was not found, and 126 otherwise.316 // Use _exit rather than exit so that atexit functions and static317 // object destructors cloned from the parent process aren't318 // redundantly run, and so that any data buffered in stdio buffers319 // cloned from the parent aren't redundantly written out.320 _exit(errno == ENOENT ? 127 : 126);321 }322 323 // Parent process: Break out of the switch to do our processing.324 default:325 break;326 }327 328 PI.Pid = child;329 PI.Process = child;330 331 return true;332}333 334namespace llvm {335namespace sys {336 337#if defined(_AIX)338static pid_t(wait4)(pid_t pid, int *status, int options, struct rusage *usage);339#elif !defined(__Fuchsia__)340using ::wait4;341#endif342 343} // namespace sys344} // namespace llvm345 346#ifdef _AIX347#ifndef _ALL_SOURCE348extern "C" pid_t(wait4)(pid_t pid, int *status, int options,349 struct rusage *usage);350#endif351pid_t(llvm::sys::wait4)(pid_t pid, int *status, int options,352 struct rusage *usage) {353 assert(pid > 0 && "Only expecting to handle actual PID values!");354 assert((options & ~WNOHANG) == 0 && "Expecting WNOHANG at most!");355 assert(usage && "Expecting usage collection!");356 357 // AIX wait4 does not work well with WNOHANG.358 if (!(options & WNOHANG))359 return ::wait4(pid, status, options, usage);360 361 // For WNOHANG, we use waitid (which supports WNOWAIT) until the child process362 // has terminated.363 siginfo_t WaitIdInfo;364 WaitIdInfo.si_pid = 0;365 int WaitIdRetVal =366 waitid(P_PID, pid, &WaitIdInfo, WNOWAIT | WEXITED | options);367 368 if (WaitIdRetVal == -1 || WaitIdInfo.si_pid == 0)369 return WaitIdRetVal;370 371 assert(WaitIdInfo.si_pid == pid);372 373 // The child has already terminated, so a blocking wait on it is okay in the374 // absence of indiscriminate `wait` calls from the current process (which375 // would cause the call here to fail with ECHILD).376 return ::wait4(pid, status, options & ~WNOHANG, usage);377}378#endif379 380ProcessInfo llvm::sys::Wait(const ProcessInfo &PI,381 std::optional<unsigned> SecondsToWait,382 std::string *ErrMsg,383 std::optional<ProcessStatistics> *ProcStat,384 bool Polling) {385 struct sigaction Act, Old;386 assert(PI.Pid && "invalid pid to wait on, process not started?");387 388 int WaitPidOptions = 0;389 pid_t ChildPid = PI.Pid;390 bool WaitUntilTerminates = false;391 if (!SecondsToWait) {392 WaitUntilTerminates = true;393 } else {394 if (*SecondsToWait == 0)395 WaitPidOptions = WNOHANG;396 397 // Install a timeout handler. The handler itself does nothing, but the398 // simple fact of having a handler at all causes the wait below to return399 // with EINTR, unlike if we used SIG_IGN.400 memset(&Act, 0, sizeof(Act));401 Act.sa_handler = TimeOutHandler;402 sigemptyset(&Act.sa_mask);403 sigaction(SIGALRM, &Act, &Old);404 // FIXME The alarm signal may be delivered to another thread.405 alarm(*SecondsToWait);406 }407 408 // Parent process: Wait for the child process to terminate.409 int status = 0;410 ProcessInfo WaitResult;411#ifndef __Fuchsia__412 rusage Info;413 if (ProcStat)414 ProcStat->reset();415 416 do {417 WaitResult.Pid = sys::wait4(ChildPid, &status, WaitPidOptions, &Info);418 } while (WaitUntilTerminates && WaitResult.Pid == -1 && errno == EINTR);419#endif420 421 if (WaitResult.Pid != PI.Pid) {422 if (WaitResult.Pid == 0) {423 // Non-blocking wait.424 return WaitResult;425 } else {426 if (SecondsToWait && errno == EINTR && !Polling) {427 // Kill the child.428 kill(PI.Pid, SIGKILL);429 430 // Turn off the alarm and restore the signal handler431 alarm(0);432 sigaction(SIGALRM, &Old, nullptr);433 434 // Wait for child to die435 // FIXME This could grab some other child process out from another436 // waiting thread and then leave a zombie anyway.437 if (wait(&status) != ChildPid)438 MakeErrMsg(ErrMsg, "Child timed out but wouldn't die");439 else440 MakeErrMsg(ErrMsg, "Child timed out", 0);441 442 WaitResult.ReturnCode = -2; // Timeout detected443 return WaitResult;444 } else if (errno != EINTR) {445 MakeErrMsg(ErrMsg, "Error waiting for child process");446 WaitResult.ReturnCode = -1;447 return WaitResult;448 }449 }450 }451 452 // We exited normally without timeout, so turn off the timer.453 if (SecondsToWait && !WaitUntilTerminates) {454 alarm(0);455 sigaction(SIGALRM, &Old, nullptr);456 }457 458#ifndef __Fuchsia__459 if (ProcStat) {460 std::chrono::microseconds UserT = toDuration(Info.ru_utime);461 std::chrono::microseconds KernelT = toDuration(Info.ru_stime);462 uint64_t PeakMemory = 0;463#if !defined(__HAIKU__) && !defined(__MVS__)464 PeakMemory = static_cast<uint64_t>(Info.ru_maxrss);465#endif466 *ProcStat = ProcessStatistics{UserT + KernelT, UserT, PeakMemory};467 }468#endif469 470 // Return the proper exit status. Detect error conditions471 // so we can return -1 for them and set ErrMsg informatively.472 int result = 0;473 if (WIFEXITED(status)) {474 result = WEXITSTATUS(status);475 WaitResult.ReturnCode = result;476 477 if (result == 127) {478 if (ErrMsg)479 *ErrMsg = llvm::sys::StrError(ENOENT);480 WaitResult.ReturnCode = -1;481 return WaitResult;482 }483 if (result == 126) {484 if (ErrMsg)485 *ErrMsg = "Program could not be executed";486 WaitResult.ReturnCode = -1;487 return WaitResult;488 }489 } else if (WIFSIGNALED(status)) {490 if (ErrMsg) {491 *ErrMsg = strsignal(WTERMSIG(status));492#ifdef WCOREDUMP493 if (WCOREDUMP(status))494 *ErrMsg += " (core dumped)";495#endif496 }497 // Return a special value to indicate that the process received an unhandled498 // signal during execution as opposed to failing to execute.499 WaitResult.ReturnCode = -2;500 }501 return WaitResult;502}503 504std::error_code llvm::sys::ChangeStdinMode(fs::OpenFlags Flags) {505 if (!(Flags & fs::OF_Text))506 return ChangeStdinToBinary();507 return std::error_code();508}509 510std::error_code llvm::sys::ChangeStdoutMode(fs::OpenFlags Flags) {511 if (!(Flags & fs::OF_Text))512 return ChangeStdoutToBinary();513 return std::error_code();514}515 516std::error_code llvm::sys::ChangeStdinToBinary() {517#ifdef __MVS__518 return disableAutoConversion(STDIN_FILENO);519#else520 // Do nothing, as Unix doesn't differentiate between text and binary.521 return std::error_code();522#endif523}524 525std::error_code llvm::sys::ChangeStdoutToBinary() {526 // Do nothing, as Unix doesn't differentiate between text and binary.527 return std::error_code();528}529 530std::error_code531llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents,532 WindowsEncodingMethod Encoding /*unused*/) {533 std::error_code EC;534 llvm::raw_fd_ostream OS(FileName, EC,535 llvm::sys::fs::OpenFlags::OF_TextWithCRLF);536 537 if (EC)538 return EC;539 540 OS << Contents;541 542 if (OS.has_error())543 return make_error_code(errc::io_error);544 545 return EC;546}547 548bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program,549 ArrayRef<StringRef> Args) {550 static long ArgMax = sysconf(_SC_ARG_MAX);551 // POSIX requires that _POSIX_ARG_MAX is 4096, which is the lowest possible552 // value for ARG_MAX on a POSIX compliant system.553 static long ArgMin = _POSIX_ARG_MAX;554 555 // This the same baseline used by xargs.556 long EffectiveArgMax = 128 * 1024;557 558 if (EffectiveArgMax > ArgMax)559 EffectiveArgMax = ArgMax;560 else if (EffectiveArgMax < ArgMin)561 EffectiveArgMax = ArgMin;562 563 // System says no practical limit.564 if (ArgMax == -1)565 return true;566 567 // Conservatively account for space required by environment variables.568 long HalfArgMax = EffectiveArgMax / 2;569 570 size_t ArgLength = Program.size() + 1;571 for (StringRef Arg : Args) {572 // Ensure that we do not exceed the MAX_ARG_STRLEN constant on Linux, which573 // does not have a constant unlike what the man pages would have you574 // believe. Since this limit is pretty high, perform the check575 // unconditionally rather than trying to be aggressive and limiting it to576 // Linux only.577 if (Arg.size() >= (32 * 4096))578 return false;579 580 ArgLength += Arg.size() + 1;581 if (ArgLength > size_t(HalfArgMax)) {582 return false;583 }584 }585 586 return true;587}588