Skip to content

Commit c452e63

Browse files
yfeldblumfacebook-github-bot
authored andcommitted
Subprocess fd-action to keep open
Summary: A way to ask `Subprocess` to keep a specific fd open in child process, even if it might be marked cloexec in the parent. Two options: * The value is the new constant `NO_CLOEXEC`. * The value is equal to the fd key. As if doing a `dup2` of the key, which is a no-op, but with the added behavior of removing cloexec. Reviewed By: dmm-fb Differential Revision: D70514691 fbshipit-source-id: 8065c2de654a9f52e5fe47b94369647bdcba880a
1 parent 7fd9dd6 commit c452e63

File tree

3 files changed

+35
-1
lines changed

3 files changed

+35
-1
lines changed

folly/Subprocess.cpp

+11-1
Original file line numberDiff line numberDiff line change
@@ -790,10 +790,20 @@ int Subprocess::prepareChild(SpawnRawArgs const& args) {
790790
return errno;
791791
}
792792
detail::subprocess_libc::close(devNull);
793-
} else if (p.second != p.first) {
793+
} else if (p.second != p.first && p.second != NO_CLOEXEC) {
794794
if (detail::subprocess_libc::dup2(p.second, p.first) == -1) {
795795
return errno;
796796
}
797+
} else if (p.second == p.first || p.second == NO_CLOEXEC) {
798+
int flags = detail::subprocess_libc::fcntl(p.first, F_GETFD);
799+
if (flags == -1) {
800+
return errno;
801+
}
802+
if (int newflags = flags & ~FD_CLOEXEC; newflags != flags) {
803+
if (detail::subprocess_libc::fcntl(p.first, F_SETFD, newflags) == -1) {
804+
return errno;
805+
}
806+
}
797807
}
798808
}
799809

folly/Subprocess.h

+1
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ class Subprocess {
299299
static const int PIPE_IN = -3;
300300
static const int PIPE_OUT = -4;
301301
static const int DEV_NULL = -5;
302+
static const int NO_CLOEXEC = -6;
302303

303304
/**
304305
* See Subprocess::Options::dangerousPostForkPreExecCallback() for usage.

folly/test/SubprocessTest.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -897,3 +897,26 @@ TEST(CloseOtherDescriptorsSubprocessTest, ClosesFileDescriptors) {
897897
EXPECT_EQ("0\n1\n2\n3\n", p.first);
898898
proc.wait();
899899
}
900+
901+
TEST(KeepFileOpenSubprocessTest, KeepsFileOpen) {
902+
auto f0 = folly::File{"/dev/null"};
903+
auto f1 = f0.dup();
904+
auto f2 = f0.dup();
905+
auto f3 = f0.dup();
906+
907+
f0.close(); // make space for fd 3, for ls to open /proc/self/fd
908+
909+
auto options =
910+
Subprocess::Options()
911+
.closeOtherFds()
912+
.pipeStdout()
913+
.fd(f1.fd(), Subprocess::NO_CLOEXEC)
914+
.fd(f2.fd(), f2.fd());
915+
Subprocess proc(
916+
std::vector<std::string>{"/bin/ls", "/proc/self/fd"}, options);
917+
auto p = proc.communicate();
918+
proc.wait();
919+
int fds[] = {0, 1, 2, 3, f1.fd(), f2.fd()};
920+
std::sort(std::begin(fds), std::end(fds));
921+
EXPECT_EQ(fmt::format("{}\n", fmt::join(fds, "\n")), p.first);
922+
}

0 commit comments

Comments
 (0)