1 //===-- Program.cpp - Implement OS Program Concept --------------*- 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the operating system Program concept. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/Support/Program.h" 14 #include "llvm/ADT/StringRef.h" 15 #include "llvm/Config/llvm-config.h" 16 #include "llvm/Support/raw_ostream.h" 17 using namespace llvm; 18 using namespace sys; 19 20 //===----------------------------------------------------------------------===// 21 //=== WARNING: Implementation here must contain only TRULY operating system 22 //=== independent code. 23 //===----------------------------------------------------------------------===// 24 25 static bool Execute(ProcessInfo &PI, StringRef Program, 26 ArrayRef<StringRef> Args, 27 std::optional<ArrayRef<StringRef>> Env, 28 ArrayRef<std::optional<StringRef>> Redirects, 29 unsigned MemoryLimit, std::string *ErrMsg, 30 BitVector *AffinityMask, bool DetachProcess); 31 32 int sys::ExecuteAndWait(StringRef Program, ArrayRef<StringRef> Args, 33 std::optional<ArrayRef<StringRef>> Env, 34 ArrayRef<std::optional<StringRef>> Redirects, 35 unsigned SecondsToWait, unsigned MemoryLimit, 36 std::string *ErrMsg, bool *ExecutionFailed, 37 std::optional<ProcessStatistics> *ProcStat, 38 BitVector *AffinityMask) { 39 assert(Redirects.empty() || Redirects.size() == 3); 40 ProcessInfo PI; 41 if (Execute(PI, Program, Args, Env, Redirects, MemoryLimit, ErrMsg, 42 AffinityMask, /*DetachProcess=*/false)) { 43 if (ExecutionFailed) 44 *ExecutionFailed = false; 45 ProcessInfo Result = Wait( 46 PI, SecondsToWait == 0 ? std::nullopt : std::optional(SecondsToWait), 47 ErrMsg, ProcStat); 48 return Result.ReturnCode; 49 } 50 51 if (ExecutionFailed) 52 *ExecutionFailed = true; 53 54 return -1; 55 } 56 57 ProcessInfo sys::ExecuteNoWait(StringRef Program, ArrayRef<StringRef> Args, 58 std::optional<ArrayRef<StringRef>> Env, 59 ArrayRef<std::optional<StringRef>> Redirects, 60 unsigned MemoryLimit, std::string *ErrMsg, 61 bool *ExecutionFailed, BitVector *AffinityMask, 62 bool DetachProcess) { 63 assert(Redirects.empty() || Redirects.size() == 3); 64 ProcessInfo PI; 65 if (ExecutionFailed) 66 *ExecutionFailed = false; 67 if (!Execute(PI, Program, Args, Env, Redirects, MemoryLimit, ErrMsg, 68 AffinityMask, DetachProcess)) 69 if (ExecutionFailed) 70 *ExecutionFailed = true; 71 72 return PI; 73 } 74 75 bool sys::commandLineFitsWithinSystemLimits(StringRef Program, 76 ArrayRef<const char *> Args) { 77 SmallVector<StringRef, 8> StringRefArgs(Args); 78 return commandLineFitsWithinSystemLimits(Program, StringRefArgs); 79 } 80 81 void sys::printArg(raw_ostream &OS, StringRef Arg, bool Quote) { 82 const bool Escape = Arg.find_first_of(" \"\\$") != StringRef::npos; 83 84 if (!Quote && !Escape) { 85 OS << Arg; 86 return; 87 } 88 89 // Quote and escape. This isn't really complete, but good enough. 90 OS << '"'; 91 for (const auto c : Arg) { 92 if (c == '"' || c == '\\' || c == '$') 93 OS << '\\'; 94 OS << c; 95 } 96 OS << '"'; 97 } 98 99 // Include the platform-specific parts of this class. 100 #ifdef LLVM_ON_UNIX 101 #include "Unix/Program.inc" 102 #endif 103 #ifdef _WIN32 104 #include "Windows/Program.inc" 105 #endif 106