summaryrefslogtreecommitdiffhomepage
path: root/test/util/multiprocess_util.h
diff options
context:
space:
mode:
Diffstat (limited to 'test/util/multiprocess_util.h')
-rw-r--r--test/util/multiprocess_util.h113
1 files changed, 113 insertions, 0 deletions
diff --git a/test/util/multiprocess_util.h b/test/util/multiprocess_util.h
new file mode 100644
index 000000000..c09d6167f
--- /dev/null
+++ b/test/util/multiprocess_util.h
@@ -0,0 +1,113 @@
+// Copyright 2018 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef GVISOR_TEST_UTIL_MULTIPROCESS_UTIL_H_
+#define GVISOR_TEST_UTIL_MULTIPROCESS_UTIL_H_
+
+#include <unistd.h>
+
+#include <algorithm>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "test/util/cleanup.h"
+#include "test/util/posix_error.h"
+
+namespace gvisor {
+namespace testing {
+
+// Immutable holder for a dynamically-sized array of pointers to mutable char,
+// terminated by a null pointer, as required for the argv and envp arguments to
+// execve(2).
+class ExecveArray {
+ public:
+ // Constructs an empty ExecveArray.
+ ExecveArray() = default;
+
+ // Constructs an ExecveArray by copying strings from the given range. T must
+ // be a range over ranges of char.
+ template <typename T>
+ explicit ExecveArray(T const& strs) : ExecveArray(strs.begin(), strs.end()) {}
+
+ // Constructs an ExecveArray by copying strings from [first, last). InputIt
+ // must be an input iterator over a range over char.
+ template <typename InputIt>
+ ExecveArray(InputIt first, InputIt last) {
+ std::vector<size_t> offsets;
+ auto output_it = std::back_inserter(str_);
+ for (InputIt it = first; it != last; ++it) {
+ offsets.push_back(str_.size());
+ auto const& s = *it;
+ std::copy(s.begin(), s.end(), output_it);
+ str_.push_back('\0');
+ }
+ ptrs_.reserve(offsets.size() + 1);
+ for (auto offset : offsets) {
+ ptrs_.push_back(str_.data() + offset);
+ }
+ ptrs_.push_back(nullptr);
+ }
+
+ // Constructs an ExecveArray by copying strings from list. This overload must
+ // exist independently of the single-argument template constructor because
+ // std::initializer_list does not participate in template argument deduction
+ // (i.e. cannot be type-inferred in an invocation of the templated
+ // constructor).
+ /* implicit */ ExecveArray(std::initializer_list<absl::string_view> list)
+ : ExecveArray(list.begin(), list.end()) {}
+
+ // Disable move construction and assignment since ptrs_ points into str_.
+ ExecveArray(ExecveArray&&) = delete;
+ ExecveArray& operator=(ExecveArray&&) = delete;
+
+ char* const* get() const { return ptrs_.data(); }
+
+ private:
+ std::vector<char> str_;
+ std::vector<char*> ptrs_;
+};
+
+// Simplified version of SubProcess. Returns OK and a cleanup function to kill
+// the child if it made it to execve.
+//
+// fn is run between fork and exec. If it needs to fail, it should exit the
+// process.
+//
+// The child pid is returned via child, if provided.
+// execve's error code is returned via execve_errno, if provided.
+PosixErrorOr<Cleanup> ForkAndExec(const std::string& filename,
+ const ExecveArray& argv,
+ const ExecveArray& envv,
+ const std::function<void()>& fn, pid_t* child,
+ int* execve_errno);
+
+inline PosixErrorOr<Cleanup> ForkAndExec(const std::string& filename,
+ const ExecveArray& argv,
+ const ExecveArray& envv, pid_t* child,
+ int* execve_errno) {
+ return ForkAndExec(filename, argv, envv, [] {}, child, execve_errno);
+}
+
+// Calls fn in a forked subprocess and returns the exit status of the
+// subprocess.
+//
+// fn must be async-signal-safe.
+PosixErrorOr<int> InForkedProcess(const std::function<void()>& fn);
+
+} // namespace testing
+} // namespace gvisor
+
+#endif // GVISOR_TEST_UTIL_MULTIPROCESS_UTIL_H_