diff options
Diffstat (limited to 'utils/process/executor.ipp')
-rw-r--r-- | utils/process/executor.ipp | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/utils/process/executor.ipp b/utils/process/executor.ipp new file mode 100644 index 000000000000..e91f994673d7 --- /dev/null +++ b/utils/process/executor.ipp @@ -0,0 +1,182 @@ +// Copyright 2015 The Kyua Authors. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#if !defined(UTILS_PROCESS_EXECUTOR_IPP) +#define UTILS_PROCESS_EXECUTOR_IPP + +#include "utils/process/executor.hpp" + +#include "utils/fs/path.hpp" +#include "utils/optional.ipp" +#include "utils/passwd.hpp" +#include "utils/process/child.ipp" + +namespace utils { +namespace process { + + +namespace executor { +namespace detail { + +/// Functor to execute a hook in a child process. +/// +/// The hook is executed after the process has been isolated per the logic in +/// utils::process::isolation based on the input parameters at construction +/// time. +template< class Hook > +class run_child { + /// Function or functor to invoke in the child. + Hook _hook; + + /// Directory where the hook may place control files. + const fs::path& _control_directory; + + /// Directory to enter when running the subprocess. + /// + /// This is a subdirectory of _control_directory but is separate so that + /// subprocess operations do not inadvertently affect our files. + const fs::path& _work_directory; + + /// User to switch to when running the subprocess. + /// + /// If not none, the subprocess will be executed as the provided user and + /// the control and work directories will be writable by this user. + const optional< passwd::user > _unprivileged_user; + +public: + /// Constructor. + /// + /// \param hook Function or functor to invoke in the child. + /// \param control_directory Directory where control files can be placed. + /// \param work_directory Directory to enter when running the subprocess. + /// \param unprivileged_user If set, user to switch to before execution. + run_child(Hook hook, + const fs::path& control_directory, + const fs::path& work_directory, + const optional< passwd::user > unprivileged_user) : + _hook(hook), + _control_directory(control_directory), + _work_directory(work_directory), + _unprivileged_user(unprivileged_user) + { + } + + /// Body of the subprocess. + void + operator()(void) + { + executor::detail::setup_child(_unprivileged_user, + _control_directory, _work_directory); + _hook(_control_directory); + } +}; + +} // namespace detail +} // namespace executor + + +/// Forks and executes a subprocess asynchronously. +/// +/// \tparam Hook Type of the hook. +/// \param hook Function or functor to run in the subprocess. +/// \param timeout Maximum amount of time the subprocess can run for. +/// \param unprivileged_user If not none, user to switch to before execution. +/// \param stdout_target If not none, file to which to write the stdout of the +/// test case. +/// \param stderr_target If not none, file to which to write the stderr of the +/// test case. +/// +/// \return A handle for the background operation. Used to match the result of +/// the execution returned by wait_any() with this invocation. +template< class Hook > +executor::exec_handle +executor::executor_handle::spawn( + Hook hook, + const datetime::delta& timeout, + const optional< passwd::user > unprivileged_user, + const optional< fs::path > stdout_target, + const optional< fs::path > stderr_target) +{ + const fs::path unique_work_directory = spawn_pre(); + + const fs::path stdout_path = stdout_target ? + stdout_target.get() : (unique_work_directory / detail::stdout_name); + const fs::path stderr_path = stderr_target ? + stderr_target.get() : (unique_work_directory / detail::stderr_name); + + std::auto_ptr< process::child > child = process::child::fork_files( + detail::run_child< Hook >(hook, + unique_work_directory, + unique_work_directory / detail::work_subdir, + unprivileged_user), + stdout_path, stderr_path); + + return spawn_post(unique_work_directory, stdout_path, stderr_path, + timeout, unprivileged_user, child); +} + + +/// Forks and executes a subprocess asynchronously in the context of another. +/// +/// By context we understand the on-disk state of a previously-executed process, +/// thus the new subprocess spawned by this function will run with the same +/// control and work directories as another process. +/// +/// \tparam Hook Type of the hook. +/// \param hook Function or functor to run in the subprocess. +/// \param base Context of the subprocess in which to run this one. The +/// exit_handle provided here must remain alive throughout the existence of +/// this other object because the original exit_handle is the one that owns +/// the on-disk state. +/// \param timeout Maximum amount of time the subprocess can run for. +/// +/// \return A handle for the background operation. Used to match the result of +/// the execution returned by wait_any() with this invocation. +template< class Hook > +executor::exec_handle +executor::executor_handle::spawn_followup(Hook hook, + const exit_handle& base, + const datetime::delta& timeout) +{ + spawn_followup_pre(); + + std::auto_ptr< process::child > child = process::child::fork_files( + detail::run_child< Hook >(hook, + base.control_directory(), + base.work_directory(), + base.unprivileged_user()), + base.stdout_file(), base.stderr_file()); + + return spawn_followup_post(base, timeout, child); +} + + +} // namespace process +} // namespace utils + +#endif // !defined(UTILS_PROCESS_EXECUTOR_IPP) |