X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FSubprocess.cpp;h=1e294ba767b985b91d083877f9eab3984cfe324d;hb=788ab800753936d3e2aae211b9fcb5bc6109421d;hp=04866e1dde2ec52079d29b70aa3296a741fa8826;hpb=0e7cb3feec43284e953bb3c555802a076df78085;p=folly.git diff --git a/folly/Subprocess.cpp b/folly/Subprocess.cpp index 04866e1d..1e294ba7 100644 --- a/folly/Subprocess.cpp +++ b/folly/Subprocess.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2015 Facebook, Inc. + * Copyright 2016 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,9 +24,6 @@ #include #endif #include -#include - -#include #include #include @@ -42,8 +39,9 @@ #include #include #include - -extern char** environ; +#include +#include +#include constexpr int kExecFailure = 127; constexpr int kChildFailure = 126; @@ -163,13 +161,13 @@ Subprocess::Options& Subprocess::Options::fd(int fd, int action) { return *this; } +Subprocess::Subprocess() {} + Subprocess::Subprocess( const std::vector& argv, const Options& options, const char* executable, - const std::vector* env) - : pid_(-1), - returnCode_(RV_NOT_STARTED) { + const std::vector* env) { if (argv.empty()) { throw std::invalid_argument("argv must not be empty"); } @@ -180,9 +178,7 @@ Subprocess::Subprocess( Subprocess::Subprocess( const std::string& cmd, const Options& options, - const std::vector* env) - : pid_(-1), - returnCode_(RV_NOT_STARTED) { + const std::vector* env) { if (options.usePath_) { throw std::invalid_argument("usePath() not allowed when running in shell"); } @@ -211,8 +207,7 @@ struct ChildErrorInfo { int errnoValue; }; -FOLLY_NORETURN void childError(int errFd, int errCode, int errnoValue); -void childError(int errFd, int errCode, int errnoValue) { +[[noreturn]] void childError(int errFd, int errCode, int errnoValue) { ChildErrorInfo info = {errCode, errnoValue}; // Write the error information over the pipe to our parent process. // We can't really do anything else if this write call fails. @@ -481,7 +476,9 @@ int Subprocess::prepareChild(const Options& options, #if __linux__ // Opt to receive signal on parent death, if requested if (options.parentDeathSignal_ != 0) { - if (prctl(PR_SET_PDEATHSIG, options.parentDeathSignal_, 0, 0, 0) == -1) { + const auto parentDeathSignal = + static_cast(options.parentDeathSignal_); + if (prctl(PR_SET_PDEATHSIG, parentDeathSignal, 0, 0, 0) == -1) { return errno; } } @@ -493,6 +490,13 @@ int Subprocess::prepareChild(const Options& options, } } + // The user callback comes last, so that the child is otherwise all set up. + if (options.dangerousPostForkPreExecCallback_) { + if (int error = (*options.dangerousPostForkPreExecCallback_)()) { + return error; + } + } + return 0; } @@ -542,7 +546,10 @@ ProcessReturnCode Subprocess::poll() { DCHECK_GT(pid_, 0); int status; pid_t found = ::waitpid(pid_, &status, WNOHANG); - checkUnixError(found, "waitpid"); + // The spec guarantees that EINTR does not occur with WNOHANG, so the only + // two remaining errors are ECHILD (other code reaped the child?), or + // EINVAL (cosmic rays?), both of which merit an abort: + PCHECK(found != -1) << "waitpid(" << pid_ << ", &status, WNOHANG)"; if (found != 0) { // Though the child process had quit, this call does not close the pipes // since its descendants may still be using them. @@ -568,7 +575,9 @@ ProcessReturnCode Subprocess::wait() { do { found = ::waitpid(pid_, &status, 0); } while (found == -1 && errno == EINTR); - checkUnixError(found, "waitpid"); + // The only two remaining errors are ECHILD (other code reaped the + // child?), or EINVAL (cosmic rays?), and both merit an abort: + PCHECK(found != -1) << "waitpid(" << pid_ << ", &status, WNOHANG)"; // Though the child process had quit, this call does not close the pipes // since its descendants may still be using them. DCHECK_EQ(found, pid_); @@ -594,21 +603,23 @@ pid_t Subprocess::pid() const { namespace { -std::pair queueFront(const IOBufQueue& queue) { +ByteRange queueFront(const IOBufQueue& queue) { auto* p = queue.front(); - if (!p) return std::make_pair(nullptr, 0); - return io::Cursor(p).peek(); + if (!p) { + return ByteRange{}; + } + return io::Cursor(p).peekBytes(); } // fd write bool handleWrite(int fd, IOBufQueue& queue) { for (;;) { - auto p = queueFront(queue); - if (p.second == 0) { + auto b = queueFront(queue); + if (b.empty()) { return true; // EOF } - ssize_t n = writeNoInt(fd, p.first, p.second); + ssize_t n = writeNoInt(fd, b.data(), b.size()); if (n == -1 && errno == EAGAIN) { return false; } @@ -819,7 +830,7 @@ void Subprocess::closeParentFd(int childFd) { std::vector Subprocess::takeOwnershipOfPipes() { std::vector pipes; for (auto& p : pipes_) { - pipes.emplace_back(ChildPipe{p.childFd, std::move(p.pipe)}); + pipes.emplace_back(p.childFd, std::move(p.pipe)); } pipes_.clear(); return pipes;