10b57cec5SDimitry Andric //===-- Program.cpp - Implement OS Program Concept --------------*- 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 operating system Program concept.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "llvm/Support/Program.h"
140b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
150b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h"
165ffd83dbSDimitry Andric #include "llvm/Support/raw_ostream.h"
170b57cec5SDimitry Andric using namespace llvm;
180b57cec5SDimitry Andric using namespace sys;
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
210b57cec5SDimitry Andric //=== WARNING: Implementation here must contain only TRULY operating system
220b57cec5SDimitry Andric //=== independent code.
230b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
240b57cec5SDimitry Andric
250b57cec5SDimitry Andric static bool Execute(ProcessInfo &PI, StringRef Program,
26bdd1243dSDimitry Andric ArrayRef<StringRef> Args,
27bdd1243dSDimitry Andric std::optional<ArrayRef<StringRef>> Env,
28bdd1243dSDimitry Andric ArrayRef<std::optional<StringRef>> Redirects,
29e8d8bef9SDimitry Andric unsigned MemoryLimit, std::string *ErrMsg,
30*0fca6ea1SDimitry Andric BitVector *AffinityMask, bool DetachProcess);
310b57cec5SDimitry Andric
ExecuteAndWait(StringRef Program,ArrayRef<StringRef> Args,std::optional<ArrayRef<StringRef>> Env,ArrayRef<std::optional<StringRef>> Redirects,unsigned SecondsToWait,unsigned MemoryLimit,std::string * ErrMsg,bool * ExecutionFailed,std::optional<ProcessStatistics> * ProcStat,BitVector * AffinityMask)320b57cec5SDimitry Andric int sys::ExecuteAndWait(StringRef Program, ArrayRef<StringRef> Args,
33bdd1243dSDimitry Andric std::optional<ArrayRef<StringRef>> Env,
34bdd1243dSDimitry Andric ArrayRef<std::optional<StringRef>> Redirects,
350b57cec5SDimitry Andric unsigned SecondsToWait, unsigned MemoryLimit,
365ffd83dbSDimitry Andric std::string *ErrMsg, bool *ExecutionFailed,
37bdd1243dSDimitry Andric std::optional<ProcessStatistics> *ProcStat,
38e8d8bef9SDimitry Andric BitVector *AffinityMask) {
390b57cec5SDimitry Andric assert(Redirects.empty() || Redirects.size() == 3);
400b57cec5SDimitry Andric ProcessInfo PI;
41e8d8bef9SDimitry Andric if (Execute(PI, Program, Args, Env, Redirects, MemoryLimit, ErrMsg,
42*0fca6ea1SDimitry Andric AffinityMask, /*DetachProcess=*/false)) {
430b57cec5SDimitry Andric if (ExecutionFailed)
440b57cec5SDimitry Andric *ExecutionFailed = false;
45bdd1243dSDimitry Andric ProcessInfo Result = Wait(
46bdd1243dSDimitry Andric PI, SecondsToWait == 0 ? std::nullopt : std::optional(SecondsToWait),
475ffd83dbSDimitry Andric ErrMsg, ProcStat);
480b57cec5SDimitry Andric return Result.ReturnCode;
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric if (ExecutionFailed)
520b57cec5SDimitry Andric *ExecutionFailed = true;
530b57cec5SDimitry Andric
540b57cec5SDimitry Andric return -1;
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric
ExecuteNoWait(StringRef Program,ArrayRef<StringRef> Args,std::optional<ArrayRef<StringRef>> Env,ArrayRef<std::optional<StringRef>> Redirects,unsigned MemoryLimit,std::string * ErrMsg,bool * ExecutionFailed,BitVector * AffinityMask,bool DetachProcess)570b57cec5SDimitry Andric ProcessInfo sys::ExecuteNoWait(StringRef Program, ArrayRef<StringRef> Args,
58bdd1243dSDimitry Andric std::optional<ArrayRef<StringRef>> Env,
59bdd1243dSDimitry Andric ArrayRef<std::optional<StringRef>> Redirects,
600b57cec5SDimitry Andric unsigned MemoryLimit, std::string *ErrMsg,
61*0fca6ea1SDimitry Andric bool *ExecutionFailed, BitVector *AffinityMask,
62*0fca6ea1SDimitry Andric bool DetachProcess) {
630b57cec5SDimitry Andric assert(Redirects.empty() || Redirects.size() == 3);
640b57cec5SDimitry Andric ProcessInfo PI;
650b57cec5SDimitry Andric if (ExecutionFailed)
660b57cec5SDimitry Andric *ExecutionFailed = false;
67e8d8bef9SDimitry Andric if (!Execute(PI, Program, Args, Env, Redirects, MemoryLimit, ErrMsg,
68*0fca6ea1SDimitry Andric AffinityMask, DetachProcess))
690b57cec5SDimitry Andric if (ExecutionFailed)
700b57cec5SDimitry Andric *ExecutionFailed = true;
710b57cec5SDimitry Andric
720b57cec5SDimitry Andric return PI;
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric
commandLineFitsWithinSystemLimits(StringRef Program,ArrayRef<const char * > Args)750b57cec5SDimitry Andric bool sys::commandLineFitsWithinSystemLimits(StringRef Program,
760b57cec5SDimitry Andric ArrayRef<const char *> Args) {
770b57cec5SDimitry Andric SmallVector<StringRef, 8> StringRefArgs;
780b57cec5SDimitry Andric StringRefArgs.reserve(Args.size());
790b57cec5SDimitry Andric for (const char *A : Args)
800b57cec5SDimitry Andric StringRefArgs.emplace_back(A);
810b57cec5SDimitry Andric return commandLineFitsWithinSystemLimits(Program, StringRefArgs);
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric
printArg(raw_ostream & OS,StringRef Arg,bool Quote)845ffd83dbSDimitry Andric void sys::printArg(raw_ostream &OS, StringRef Arg, bool Quote) {
855ffd83dbSDimitry Andric const bool Escape = Arg.find_first_of(" \"\\$") != StringRef::npos;
865ffd83dbSDimitry Andric
875ffd83dbSDimitry Andric if (!Quote && !Escape) {
885ffd83dbSDimitry Andric OS << Arg;
895ffd83dbSDimitry Andric return;
905ffd83dbSDimitry Andric }
915ffd83dbSDimitry Andric
925ffd83dbSDimitry Andric // Quote and escape. This isn't really complete, but good enough.
935ffd83dbSDimitry Andric OS << '"';
945ffd83dbSDimitry Andric for (const auto c : Arg) {
955ffd83dbSDimitry Andric if (c == '"' || c == '\\' || c == '$')
965ffd83dbSDimitry Andric OS << '\\';
975ffd83dbSDimitry Andric OS << c;
985ffd83dbSDimitry Andric }
995ffd83dbSDimitry Andric OS << '"';
1005ffd83dbSDimitry Andric }
1015ffd83dbSDimitry Andric
1020b57cec5SDimitry Andric // Include the platform-specific parts of this class.
1030b57cec5SDimitry Andric #ifdef LLVM_ON_UNIX
1040b57cec5SDimitry Andric #include "Unix/Program.inc"
1050b57cec5SDimitry Andric #endif
1060b57cec5SDimitry Andric #ifdef _WIN32
1070b57cec5SDimitry Andric #include "Windows/Program.inc"
1080b57cec5SDimitry Andric #endif
109