114 lines
4.0 KiB
C
114 lines
4.0 KiB
C
|
// 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_
|