/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* to complete, returning the exit status.
*
* A thread-safe [1] version of popen() (type="r", to read from the child):
- * Subprocess proc(cmd, Subprocess::pipeStdout());
+ * Subprocess proc(cmd, Subprocess::Options().pipeStdout());
* // read from proc.stdoutFd()
* proc.wait();
*
* A thread-safe [1] version of popen() (type="w", to write to the child):
- * Subprocess proc(cmd, Subprocess::pipeStdin());
+ * Subprocess proc(cmd, Subprocess::Options().pipeStdin());
* // write to proc.stdinFd()
* proc.wait();
*
#include <string>
#include <boost/container/flat_map.hpp>
-#include <boost/operators.hpp>
#include <folly/Exception.h>
#include <folly/File.h>
#include <folly/FileUtil.h>
#include <folly/Function.h>
-#include <folly/gen/String.h>
-#include <folly/io/IOBufQueue.h>
#include <folly/MapUtil.h>
+#include <folly/Optional.h>
#include <folly/Portability.h>
#include <folly/Range.h>
+#include <folly/gen/String.h>
+#include <folly/io/IOBufQueue.h>
+#include <folly/portability/SysResource.h>
namespace folly {
class CalledProcessError : public SubprocessError {
public:
explicit CalledProcessError(ProcessReturnCode rc);
- ~CalledProcessError() throw() = default;
+ ~CalledProcessError() throw() override = default;
const char* what() const throw() override { return what_.c_str(); }
ProcessReturnCode returnCode() const { return returnCode_; }
private:
class SubprocessSpawnError : public SubprocessError {
public:
SubprocessSpawnError(const char* executable, int errCode, int errnoValue);
- ~SubprocessSpawnError() throw() = default;
+ ~SubprocessSpawnError() throw() override = default;
const char* what() const throw() override { return what_.c_str(); }
int errnoValue() const { return errnoValue_; }
* the close-on-exec flag is set (fcntl FD_CLOEXEC) and inherited
* otherwise.
*/
- class Options : private boost::orable<Options> {
+ class Options {
friend class Subprocess;
public:
Options() {} // E.g. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58328
return *this;
}
+#if __linux__
/**
- * Helpful way to combine Options.
+ * This is an experimental feature, it is best you don't use it at this
+ * point of time.
+ * Although folly would support cloning with custom flags in some form, this
+ * API might change in the near future. So use the following assuming it is
+ * experimental. (Apr 11, 2017)
+ *
+ * This unlocks Subprocess to support clone flags, many of them need
+ * CAP_SYS_ADMIN permissions. It might also require you to go through the
+ * implementation to understand what happens before, between and after the
+ * fork-and-exec.
+ *
+ * `man 2 clone` would be a starting point for knowing about the available
+ * flags.
*/
- Options& operator|=(const Options& other);
+ using clone_flags_t = uint64_t;
+ Options& useCloneWithFlags(clone_flags_t cloneFlags) noexcept {
+ cloneFlags_ = cloneFlags;
+ return *this;
+ }
+#endif
private:
typedef boost::container::flat_map<int, int> FdMap;
bool processGroupLeader_{false};
DangerousPostForkPreExecCallback*
dangerousPostForkPreExecCallback_{nullptr};
+#if __linux__
+ // none means `vfork()` instead of a custom `clone()`
+ // Optional<> is used because value of '0' means do clone without any flags.
+ Optional<clone_flags_t> cloneFlags_;
+#endif
};
- static Options pipeStdin() { return Options().stdinFd(PIPE); }
- static Options pipeStdout() { return Options().stdoutFd(PIPE); }
- static Options pipeStderr() { return Options().stderrFd(PIPE); }
-
// Non-copiable, but movable
Subprocess(const Subprocess&) = delete;
Subprocess& operator=(const Subprocess&) = delete;
* e.g. if you wait for the underlying process without going through this
* Subprocess instance.
*/
- ProcessReturnCode poll();
+ ProcessReturnCode poll(struct rusage* ru = nullptr);
/**
* Poll the child's status. If the process is still running, return false.
std::vector<Pipe> pipes_;
};
-inline Subprocess::Options& Subprocess::Options::operator|=(
- const Subprocess::Options& other) {
- if (this == &other) return *this;
- // Replace
- for (auto& p : other.fdActions_) {
- fdActions_[p.first] = p.second;
- }
- closeOtherFds_ |= other.closeOtherFds_;
- usePath_ |= other.usePath_;
- processGroupLeader_ |= other.processGroupLeader_;
- return *this;
-}
-
} // namespace folly