aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Support/Unix/Process.inc
diff options
context:
space:
mode:
authorDavid Majnemer <david.majnemer@gmail.com>2014-10-06 23:16:18 +0000
committerDavid Majnemer <david.majnemer@gmail.com>2014-10-06 23:16:18 +0000
commit121a174f52805811bb673848ddd87f19665a4633 (patch)
treeeabb18387e7669bd6625a524b9f013659e18cfb9 /llvm/lib/Support/Unix/Process.inc
parenta9ae365b2d0fa3e545fc76b819c00c7915d20f02 (diff)
downloadllvm-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.inc59
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);
}