diff options
author | David Majnemer <david.majnemer@gmail.com> | 2014-10-06 23:16:18 +0000 |
---|---|---|
committer | David Majnemer <david.majnemer@gmail.com> | 2014-10-06 23:16:18 +0000 |
commit | 121a174f52805811bb673848ddd87f19665a4633 (patch) | |
tree | eabb18387e7669bd6625a524b9f013659e18cfb9 /llvm/lib/Support/Unix/Process.inc | |
parent | a9ae365b2d0fa3e545fc76b819c00c7915d20f02 (diff) | |
download | llvm-121a174f52805811bb673848ddd87f19665a4633.zip llvm-121a174f52805811bb673848ddd87f19665a4633.tar.gz llvm-121a174f52805811bb673848ddd87f19665a4633.tar.bz2 |
Support: Add a utility to remap std{in,out,err} to /dev/null if closed
It's possible to start a program with one (or all) of the standard file
descriptors closed. Subsequent open system calls will give the program
a low-numbered file descriptor.
This is problematic because we may believe we are writing to standard
out instead of a file.
Introduce Process::FixupStandardFileDescriptors, a helper function to
remap standard file descriptors to /dev/null if they were closed before
the program started.
llvm-svn: 219170
Diffstat (limited to 'llvm/lib/Support/Unix/Process.inc')
-rw-r--r-- | llvm/lib/Support/Unix/Process.inc | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/llvm/lib/Support/Unix/Process.inc b/llvm/lib/Support/Unix/Process.inc index 4d272fd..01c78cb 100644 --- a/llvm/lib/Support/Unix/Process.inc +++ b/llvm/lib/Support/Unix/Process.inc @@ -18,6 +18,9 @@ #include "llvm/Support/Mutex.h" #include "llvm/Support/MutexGuard.h" #include "llvm/Support/TimeValue.h" +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif @@ -199,6 +202,62 @@ Process::GetArgumentVector(SmallVectorImpl<const char *> &ArgsOut, return std::error_code(); } +namespace { +class FDCloser { +public: + FDCloser(int &FD) : FD(FD), KeepOpen(false) {} + void keepOpen() { KeepOpen = true; } + ~FDCloser() { + if (!KeepOpen && FD >= 0) + ::close(FD); + } + +private: + FDCloser(const FDCloser &) LLVM_DELETED_FUNCTION; + void operator=(const FDCloser &) LLVM_DELETED_FUNCTION; + + int &FD; + bool KeepOpen; +}; +} + +std::error_code Process::FixupStandardFileDescriptors() { + int NullFD = -1; + FDCloser FDC(NullFD); + const int StandardFDs[] = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}; + for (int StandardFD : StandardFDs) { + struct stat st; + errno = 0; + while (fstat(StandardFD, &st) < 0) { + assert(errno && "expected errno to be set if fstat failed!"); + // fstat should return EBADF if the file descriptor is closed. + if (errno == EBADF) + break; + // retry fstat if we got EINTR, otherwise bubble up the failure. + if (errno != EINTR) + return std::error_code(errno, std::generic_category()); + } + // if fstat succeeds, move on to the next FD. + if (!errno) + continue; + assert(errno == EBADF && "expected errno to have EBADF at this point!"); + + if (NullFD < 0) { + while ((NullFD = open("/dev/null", O_RDWR)) < 0) { + if (errno == EINTR) + continue; + return std::error_code(errno, std::generic_category()); + } + } + + if (NullFD == StandardFD) + FDC.keepOpen(); + else if (dup2(NullFD, StandardFD) < 0) + return std::error_code(errno, std::generic_category()); + } + return std::error_code(); +} + bool Process::StandardInIsUserInput() { return FileDescriptorIsDisplayed(STDIN_FILENO); } |