diff --git a/src/boost/boost/process.hpp b/src/boost/boost/process.hpp new file mode 100644 index 000000000..791d7da93 --- /dev/null +++ b/src/boost/boost/process.hpp @@ -0,0 +1,50 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process.hpp + * + * Convenience header that includes all other Boost.Process public header + * files. It is important to note that those headers that are specific to + * a given platform are only included if the library is being used in that + * same platform. + */ + +#ifndef BOOST_PROCESS_HPP +#define BOOST_PROCESS_HPP + +#include + +#if defined(BOOST_POSIX_API) +# include +# include +# include +# include +#elif defined(BOOST_WINDOWS_API) +# include +# include +# include +#else +# error "Unsupported platform." +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/src/boost/boost/process/child.hpp b/src/boost/boost/process/child.hpp new file mode 100644 index 000000000..fdb56a696 --- /dev/null +++ b/src/boost/boost/process/child.hpp @@ -0,0 +1,200 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/child.hpp + * + * Includes the declaration of the child class. + */ + +#ifndef BOOST_PROCESS_CHILD_HPP +#define BOOST_PROCESS_CHILD_HPP + +#include + +#if defined(BOOST_POSIX_API) +# include +# include +# include +#elif defined(BOOST_WINDOWS_API) +# include +#else +# error "Unsupported platform." +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace process { + +/** + * Generic implementation of the Child concept. + * + * The child class implements the Child concept in an operating system + * agnostic way. + */ +class child : public process +{ +public: + /** + * Gets a reference to the child's standard input stream. + * + * Returns a reference to a postream object that represents the + * standard input communication channel with the child process. + */ + postream &get_stdin() const + { + BOOST_ASSERT(stdin_); + + return *stdin_; + } + + /** + * Gets a reference to the child's standard output stream. + * + * Returns a reference to a pistream object that represents the + * standard output communication channel with the child process. + */ + pistream &get_stdout() const + { + BOOST_ASSERT(stdout_); + + return *stdout_; + } + + /** + * Gets a reference to the child's standard error stream. + * + * Returns a reference to a pistream object that represents the + * standard error communication channel with the child process. + */ + pistream &get_stderr() const + { + BOOST_ASSERT(stderr_); + + return *stderr_; + } + + /** + * Blocks and waits for the child process to terminate. + * + * Returns a status object that represents the child process' + * finalization condition. The child process object ceases to be + * valid after this call. + * + * \remark Blocking remarks: This call blocks if the child + * process has not finalized execution and waits until + * it terminates. + */ + status wait() + { +#if defined(BOOST_POSIX_API) + int s; + if (::waitpid(get_id(), &s, 0) == -1) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::child::wait: waitpid(2) failed")); + return status(s); +#elif defined(BOOST_WINDOWS_API) + ::WaitForSingleObject(process_handle_.get(), INFINITE); + DWORD code; + if (!::GetExitCodeProcess(process_handle_.get(), &code)) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::child::wait: GetExitCodeProcess failed")); + return status(code); +#endif + } + + /** + * Creates a new child object that represents the just spawned child + * process \a id. + * + * The \a fhstdin, \a fhstdout and \a fhstderr file handles represent + * the parent's handles used to communicate with the corresponding + * data streams. They needn't be valid but their availability must + * match the redirections configured by the launcher that spawned this + * process. + * + * The \a fhprocess handle represents a handle to the child process. + * It is only used on Windows as the implementation of wait() needs a + * process handle. + */ + child(id_type id, detail::file_handle fhstdin, detail::file_handle fhstdout, detail::file_handle fhstderr, detail::file_handle fhprocess = detail::file_handle()) + : process(id) +#if defined(BOOST_WINDOWS_API) + , process_handle_(fhprocess.release(), ::CloseHandle) +#endif + { + if (fhstdin.valid()) + stdin_.reset(new postream(fhstdin)); + if (fhstdout.valid()) + stdout_.reset(new pistream(fhstdout)); + if (fhstderr.valid()) + stderr_.reset(new pistream(fhstderr)); + } + +private: + /** + * The standard input stream attached to the child process. + * + * This postream object holds the communication channel with the + * child's process standard input. It is stored in a pointer because + * this field is only valid when the user requested to redirect this + * data stream. + */ + boost::shared_ptr stdin_; + + /** + * The standard output stream attached to the child process. + * + * This postream object holds the communication channel with the + * child's process standard output. It is stored in a pointer because + * this field is only valid when the user requested to redirect this + * data stream. + */ + boost::shared_ptr stdout_; + + /** + * The standard error stream attached to the child process. + * + * This postream object holds the communication channel with the + * child's process standard error. It is stored in a pointer because + * this field is only valid when the user requested to redirect this + * data stream. + */ + boost::shared_ptr stderr_; + +#if defined(BOOST_WINDOWS_API) + /** + * Process handle owned by RAII object. + */ + boost::shared_ptr process_handle_; +#endif +}; + +/** + * Collection of child objects. + * + * This convenience type represents a collection of child objects backed + * by a vector. + */ +typedef std::vector children; + +} +} + +#endif diff --git a/src/boost/boost/process/config.hpp b/src/boost/boost/process/config.hpp new file mode 100644 index 000000000..1f8da162a --- /dev/null +++ b/src/boost/boost/process/config.hpp @@ -0,0 +1,41 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/config.hpp + * + * Defines macros that are used by the library's code to determine the + * operating system it is running under and the features it supports. + */ + +#ifndef BOOST_PROCESS_CONFIG_HPP +#define BOOST_PROCESS_CONFIG_HPP + +#include +#include + +#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) +# if !defined(BOOST_PROCESS_POSIX_PATH_MAX) +/** + * The macro BOOST_PROCESS_POSIX_PATH_MAX is set to a positive integer + * value which specifies the system's maximal supported path length. + * By default it is set to 259. You should set the macro to PATH_MAX + * which should be defined in limits.h provided by your operating system + * if you experience problems when instantiating a context. The + * constructor of basic_work_directory_context tries to find out + * dynamically the maximal supported path length but uses + * BOOST_PROCESS_POSIX_PATH_MAX if it fails. + */ +# define BOOST_PROCESS_POSIX_PATH_MAX 259 +# endif +#endif + +#endif diff --git a/src/boost/boost/process/context.hpp b/src/boost/boost/process/context.hpp new file mode 100644 index 000000000..7b6cb9a55 --- /dev/null +++ b/src/boost/boost/process/context.hpp @@ -0,0 +1,209 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/context.hpp + * + * Includes the declaration of the context class and several accessory + * base classes. + */ + +#ifndef BOOST_PROCESS_CONTEXT_HPP +#define BOOST_PROCESS_CONTEXT_HPP + +#include + +#if defined(BOOST_POSIX_API) +# include +# include +# include +#elif defined(BOOST_WINDOWS_API) +# include +#else +# error "Unsupported platform." +#endif + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace process { + +/** + * Base context class that defines the child's work directory. + * + * Base context class that defines the necessary fields to configure a + * child's work directory. This class is useless on its own because no + * function in the library will accept it as a valid Context + * implementation. + */ +template +class basic_work_directory_context +{ +public: + /** + * Constructs a new work directory context. + * + * Constructs a new work directory context making the work directory + * described by the new object point to the caller's current working + * directory. + */ + basic_work_directory_context() + { +#if defined(BOOST_POSIX_API) + errno = 0; + long size = ::pathconf(".", _PC_PATH_MAX); + if (size == -1 && errno) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::basic_work_directory_context::basic_work_directory_context: pathconf(2) failed")); + else if (size == -1) + size = BOOST_PROCESS_POSIX_PATH_MAX; + boost::scoped_array cwd(new char[size]); + if (!::getcwd(cwd.get(), size)) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::basic_work_directory_context::basic_work_directory_context: getcwd(2) failed")); + work_directory = cwd.get(); +#elif defined(BOOST_WINDOWS_API) + char cwd[MAX_PATH]; + if (!::GetCurrentDirectoryA(sizeof(cwd), cwd)) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::basic_work_directory_context::basic_work_directory_context: GetCurrentDirectory failed")); + work_directory = cwd; +#endif + BOOST_ASSERT(!work_directory.empty()); + } + + /** + * The process' initial work directory. + * + * The work directory is the directory in which the process starts + * execution. + */ + Path work_directory; +}; + +/** + * Base context class that defines the child's environment. + * + * Base context class that defines the necessary fields to configure a + * child's environment variables. This class is useless on its own + * because no function in the library will accept it as a valid Context + * implementation. + */ +class environment_context +{ +public: + /** + * The process' environment. + * + * Contains the list of environment variables, alongside with their + * values, that will be passed to the spawned child process. + */ + boost::process::environment environment; +}; + +/** + * Process startup execution context. + * + * The context class groups all the parameters needed to configure a + * process' environment during its creation. + */ +template +class basic_context : public basic_work_directory_context, public environment_context +{ +public: + /** + * Child's stdin behavior. + */ + stream_behavior stdin_behavior; + + /** + * Child's stdout behavior. + */ + stream_behavior stdout_behavior; + + /** + * Child's stderr behavior. + */ + stream_behavior stderr_behavior; +}; + +typedef basic_context context; + +/** + * Represents a child process in a pipeline. + * + * This convenience class is a triplet that holds all the data required + * to spawn a new child process in a pipeline. + */ +template +class basic_pipeline_entry +{ +public: + /** + * The executable to launch. + */ + Executable executable; + + /** + * The set of arguments to pass to the executable. + */ + Arguments arguments; + + /** + * The child's execution context. + */ + Context context; + + /** + * The type of the Executable concept used in this template + * instantiation. + */ + typedef Executable executable_type; + + /** + * The type of the Arguments concept used in this template + * instantiation. + */ + typedef Arguments arguments_type; + + /** + * The type of the Context concept used in this template + * instantiation. + */ + typedef Context context_type; + + /** + * Constructs a new pipeline_entry object. + * + * Given the executable, set of arguments and execution triplet, + * constructs a new pipeline_entry object that holds the three + * values. + */ + basic_pipeline_entry(const Executable &exe, const Arguments &args, const Context &ctx) + : executable(exe), + arguments(args), + context(ctx) + { + } +}; + +/** + * Default instantiation of basic_pipeline_entry. + */ +typedef basic_pipeline_entry, context> pipeline_entry; + +} +} + +#endif diff --git a/src/boost/boost/process/detail/file_handle.hpp b/src/boost/boost/process/detail/file_handle.hpp new file mode 100644 index 000000000..f76326dcb --- /dev/null +++ b/src/boost/boost/process/detail/file_handle.hpp @@ -0,0 +1,406 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/detail/file_handle.hpp + * + * Includes the declaration of the file_handle class. This file is for + * internal usage only and must not be included by the library user. + */ + +#ifndef BOOST_PROCESS_DETAIL_FILE_HANDLE_HPP +#define BOOST_PROCESS_DETAIL_FILE_HANDLE_HPP + +#include + +#if defined(BOOST_POSIX_API) +# include +# include +#elif defined(BOOST_WINDOWS_API) +# include +#else +# error "Unsupported platform." +#endif + +#include +#include +#include + +namespace boost { +namespace process { +namespace detail { + +/** + * Simple RAII model for system file handles. + * + * The \a file_handle class is a simple RAII model for native system file + * handles. This class wraps one of such handles grabbing its ownership, + * and automaticaly closes it upon destruction. It is basically used + * inside the library to avoid leaking open file handles, shall an + * unexpected execution trace occur. + * + * A \a file_handle object can be copied but doing so invalidates the + * source object. There can only be a single valid \a file_handle object + * for a given system file handle. This is similar to std::auto_ptr's + * semantics. + * + * This class also provides some convenience methods to issue special file + * operations under their respective platforms. + */ +class file_handle +{ +public: +#if defined(BOOST_PROCESS_DOXYGEN) + /** + * Opaque name for the native handle type. + * + * Each operating system identifies file handles using a specific type. + * The \a handle_type type is used to transparently refer to file + * handles regarless of the operating system in which this class is + * used. + * + * If this class is used on a POSIX system, \a NativeSystemHandle is + * an integer type while it is a \a HANDLE on a Windows system. + */ + typedef NativeSystemHandle handle_type; +#elif defined(BOOST_POSIX_API) + typedef int handle_type; +#elif defined(BOOST_WINDOWS_API) + typedef HANDLE handle_type; +#endif + + /** + * Constructs an invalid file handle. + * + * This constructor creates a new \a file_handle object that represents + * an invalid file handle. An invalid file handle can be copied but + * cannot be manipulated in any way (except checking for its validity). + * + * \see valid() + */ + file_handle() + : handle_(invalid_value()) + { + } + + /** + * Constructs a new file handle from a native file handle. + * + * This constructor creates a new \a file_handle object that takes + * ownership of the given \a h native file handle. The user must not + * close \a h on his own during the lifetime of the new object. + * Ownership can be reclaimed using release(). + * + * \pre The native file handle must be valid; a close operation must + * succeed on it. + * \see release() + */ + file_handle(handle_type h) + : handle_(h) + { + BOOST_ASSERT(handle_ != invalid_value()); + } + + /** + * Copy constructor; invalidates the source handle. + * + * This copy constructor creates a new file handle from a given one. + * Ownership of the native file handle is transferred to the new + * object, effectively invalidating the source file handle. This + * avoids having two live \a file_handle objects referring to the + * same native file handle. The source file handle needs not be + * valid in the name of simplicity. + * + * \post The source file handle is invalid. + * \post The new file handle owns the source's native file handle. + */ + file_handle(const file_handle &fh) + : handle_(fh.handle_) + { + fh.handle_ = invalid_value(); + } + + /** + * Releases resources if the handle is valid. + * + * If the file handle is valid, the destructor closes it. + * + * \see valid() + */ + ~file_handle() + { + if (valid()) + close(); + } + + /** + * Assignment operator; invalidates the source handle. + * + * This assignment operator transfers ownership of the RHS file + * handle to the LHS one, effectively invalidating the source file + * handle. This avoids having two live \a file_handle objects + * referring to the same native file handle. The source file + * handle needs not be valid in the name of simplicity. + * + * \post The RHS file handle is invalid. + * \post The LHS file handle owns RHS' native file handle. + * \return A reference to the LHS file handle. + */ + file_handle &operator=(const file_handle &fh) + { + handle_ = fh.handle_; + fh.handle_ = invalid_value(); + return *this; + } + + /** + * Checks whether the file handle is valid or not. + * + * Returns a boolean indicating whether the file handle is valid or + * not. If the file handle is invalid, no other methods can be + * executed other than the destructor. + * + * \return true if the file handle is valid; false otherwise. + */ + bool valid() const + { + return handle_ != invalid_value(); + } + + /** + * Closes the file handle. + * + * Explicitly closes the file handle, which must be valid. Upon + * exit, the handle is not valid any more. + * + * \pre The file handle is valid. + * \post The file handle is invalid. + * \post The native file handle is closed. + */ + void close() + { + BOOST_ASSERT(valid()); + +#if defined(BOOST_POSIX_API) + ::close(handle_); +#elif defined(BOOST_WINDOWS_API) + ::CloseHandle(handle_); +#endif + + handle_ = invalid_value(); + } + + /** + * Reclaims ownership of the native file handle. + * + * Explicitly reclaims ownership of the native file handle contained + * in the \a file_handle object, returning the native file handle. + * The caller is responsible of closing it later on. + * + * \pre The file handle is valid. + * \post The file handle is invalid. + * \return The native file handle. + */ + handle_type release() + { + BOOST_ASSERT(valid()); + + handle_type h = handle_; + handle_ = invalid_value(); + return h; + } + + /** + * Gets the native file handle. + * + * Returns the native file handle for the \a file_handle object. + * The caller can issue any operation on it except closing it. + * If closing is required, release() shall be used. + * + * \pre The file handle is valid. + * \post The file handle is valid. + * \return The native file handle. + */ + handle_type get() const + { + BOOST_ASSERT(valid()); + + return handle_; + } + +#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) + /** + * Changes the native file handle to the given one. + * + * Given a new native file handle \a h, this operation assigns this + * handle to the current object, closing its old native file handle. + * In other words, it first calls dup2() to remap the old handle to + * the new one and then closes the old handle. + * + * If \a h is open, it is automatically closed by dup2(). + * + * This operation is only available in POSIX systems. + * + * \pre The file handle is valid. + * \pre The native file handle \a h is valid; i.e., it must be + * closeable. + * \post The file handle's native file handle is \a h. + * \throw boost::system::system_error If the internal remapping + * operation fails. + */ + void posix_remap(handle_type h) + { + BOOST_ASSERT(valid()); + + if (::dup2(handle_, h) == -1) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_remap: dup2(2) failed")); + + if (::close(handle_) == -1) + { + ::close(h); + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_remap: close(2) failed")); + } + + handle_ = h; + } + + /** + * Duplicates an open native file handle. + * + * Given a native file handle \a h1, this routine duplicates it so + * that it ends up being identified by the native file handle \a h2 + * and returns a new \a file_handle owning \a h2. + * + * This operation is only available in POSIX systems. + * + * \pre The native file handle \a h1 is open. + * \pre The native file handle \a h2 is valid (non-negative). + * \post The native file handle \a h1 is closed. + * \post The native file handle \a h2 is the same as the old \a h1 + * from the operating system's point of view. + * \return A new \a file_handle object that owns \a h2. + * \throw boost::system::system_error If dup2() fails. + */ + static file_handle posix_dup(int h1, int h2) + { + if (::dup2(h1, h2) == -1) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_dup: dup2(2) failed")); + + return file_handle(h2); + } +#endif + +#if defined(BOOST_WINDOWS_API) || defined(BOOST_PROCESS_DOXYGEN) + /** + * Duplicates the \a h native file handle. + * + * Given a native file handle \a h, this routine constructs a new + * \a file_handle object that owns a new duplicate of \a h. The + * duplicate's inheritable flag is set to the value of \a inheritable. + * + * This operation is only available in Windows systems. + * + * \pre The native file handle \a h is valid. + * \return A file handle owning a duplicate of \a h. + * \throw boost::system::system_error If DuplicateHandle() fails. + */ + static file_handle win32_dup(HANDLE h, bool inheritable) + { + HANDLE h2; + if (!::DuplicateHandle(::GetCurrentProcess(), h, ::GetCurrentProcess(), &h2, 0, inheritable ? TRUE : FALSE, DUPLICATE_SAME_ACCESS)) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_dup: DuplicateHandle failed")); + + return file_handle(h2); + } + + /** + * Creates a new duplicate of a standard file handle. + * + * Constructs a new \a file_handle object that owns a duplicate of a + * standard file handle. The \a d parameter specifies which standard + * file handle to duplicate and can be one of \a STD_INPUT_HANDLE, + * \a STD_OUTPUT_HANDLE or \a STD_ERROR_HANDLE. The duplicate's + * inheritable flag is set to the value of \a inheritable. + * + * This operation is only available in Windows systems. + * + * \pre \a d refers to one of the standard handles as described above. + * \return A file handle owning a duplicate of the standard handle + * referred to by \a d. + * \throw boost::system::system_error If GetStdHandle() or + * DuplicateHandle() fails. + */ + static file_handle win32_std(DWORD d, bool inheritable) + { + BOOST_ASSERT(d == STD_INPUT_HANDLE || d == STD_OUTPUT_HANDLE || d == STD_ERROR_HANDLE); + + HANDLE h = ::GetStdHandle(d); + if (h == INVALID_HANDLE_VALUE) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_std: GetStdHandle failed")); + + return win32_dup(h, inheritable); + } + + /** + * Changes the file handle's inheritable flag. + * + * Changes the file handle's inheritable flag to \a i. It is not + * necessary for the file handle's flag to be different than \a i. + * + * This operation is only available in Windows systems. + * + * \pre The file handle is valid. + * \post The native file handle's inheritable flag is set to \a i. + * \throw boost::system::system_error If the property change fails. + */ + void win32_set_inheritable(bool i) + { + BOOST_ASSERT(valid()); + + if (!::SetHandleInformation(handle_, HANDLE_FLAG_INHERIT, i ? HANDLE_FLAG_INHERIT : 0)) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_set_inheritable: SetHandleInformation failed")); + } +#endif + +private: + /** + * Internal handle value. + * + * This variable holds the native handle value for the file handle + * hold by this object. It is interesting to note that this needs + * to be mutable because the copy constructor and the assignment + * operator invalidate the source object. + */ + mutable handle_type handle_; + + /** + * Constant function representing an invalid handle value. + * + * Returns the platform-specific handle value that represents an + * invalid handle. This is a constant function rather than a regular + * constant because, in the latter case, we cannot define it under + * Windows due to the value being of a complex type. + */ + static const handle_type invalid_value() + { +#if defined(BOOST_POSIX_API) + return -1; +#elif defined(BOOST_WINDOWS_API) + return INVALID_HANDLE_VALUE; +#endif + } +}; + +} +} +} + +#endif diff --git a/src/boost/boost/process/detail/pipe.hpp b/src/boost/boost/process/detail/pipe.hpp new file mode 100644 index 000000000..dcd198bbf --- /dev/null +++ b/src/boost/boost/process/detail/pipe.hpp @@ -0,0 +1,187 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/detail/pipe.hpp + * + * Includes the declaration of the pipe class. This file is for + * internal usage only and must not be included by the library user. + */ + +#ifndef BOOST_PROCESS_DETAIL_PIPE_HPP +#define BOOST_PROCESS_DETAIL_PIPE_HPP + +#include + +#if defined(BOOST_POSIX_API) +# include +# include +#elif defined(BOOST_WINDOWS_API) +# if defined(BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE) +# include +# include +# endif +# include +#else +# error "Unsupported platform." +#endif + +#include +#include +#include + +namespace boost { +namespace process { +namespace detail { + +/** + * Simple RAII model for anonymous pipes. + * + * The pipe class is a simple RAII model for anonymous pipes. It + * provides a portable constructor that allocates a new %pipe and creates + * a pipe object that owns the two file handles associated to it: the + * read end and the write end. + * + * These handles can be retrieved for modification according to + * file_handle semantics. Optionally, their ownership can be transferred + * to external \a file_handle objects which comes handy when the two + * ends need to be used in different places (i.e. after a POSIX fork() + * system call). + * + * Pipes can be copied following the same semantics as file handles. + * In other words, copying a %pipe object invalidates the source one. + * + * \see file_handle + */ +class pipe +{ +public: + /** + * Creates a new %pipe. + * + * The default pipe constructor allocates a new anonymous %pipe + * and assigns its ownership to the created pipe object. On Windows + * when the macro BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE is defined + * a named pipe is created. This is required if asynchronous I/O + * should be used as asynchronous I/O is only supported by named + * pipes on Windows. + * + * \throw boost::system::system_error If the anonymous %pipe + * creation fails. + */ + pipe() + { + file_handle::handle_type hs[2]; + +#if defined(BOOST_POSIX_API) + if (::pipe(hs) == -1) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::pipe::pipe: pipe(2) failed")); +#elif defined(BOOST_WINDOWS_API) + SECURITY_ATTRIBUTES sa; + ZeroMemory(&sa, sizeof(sa)); + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = FALSE; + +# if defined(BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE) + static unsigned int nextid = 0; + std::string pipe = "\\\\.\\pipe\\boost_process_" + boost::lexical_cast(::GetCurrentProcessId()) + "_" + boost::lexical_cast(nextid++); + hs[0] = ::CreateNamedPipeA(pipe.c_str(), PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, 0, 1, 8192, 8192, 0, &sa); + if (hs[0] == INVALID_HANDLE_VALUE) + boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreateNamedPipe failed")); + hs[1] = ::CreateFileA(pipe.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + if (hs[1] == INVALID_HANDLE_VALUE) + boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreateFile failed")); + + OVERLAPPED overlapped; + ZeroMemory(&overlapped, sizeof(overlapped)); + overlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); + if (!overlapped.hEvent) + boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreateEvent failed")); + BOOL b = ::ConnectNamedPipe(hs[0], &overlapped); + if (!b) + { + if (::GetLastError() == ERROR_IO_PENDING) + { + if (::WaitForSingleObject(overlapped.hEvent, INFINITE) == WAIT_FAILED) + { + ::CloseHandle(overlapped.hEvent); + boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: WaitForSingleObject failed")); + } + } + else if (::GetLastError() != ERROR_PIPE_CONNECTED) + { + ::CloseHandle(overlapped.hEvent); + boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: ConnectNamedPipe failed")); + } + } + ::CloseHandle(overlapped.hEvent); +# else + if (!::CreatePipe(&hs[0], &hs[1], &sa, 0)) + boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreatePipe failed")); +# endif +#endif + + read_end_ = file_handle(hs[0]); + write_end_ = file_handle(hs[1]); + } + + /** + * Returns the %pipe's read end file handle. + * + * Obtains a reference to the %pipe's read end file handle. Care + * should be taken to not duplicate the returned object if ownership + * shall remain to the %pipe. + * + * Duplicating the returned object invalidates its corresponding file + * handle in the %pipe. + * + * \return A reference to the %pipe's read end file handle. + */ + file_handle &rend() + { + return read_end_; + } + + /** + * Returns the %pipe's write end file handle. + * + * Obtains a reference to the %pipe's write end file handle. Care + * should be taken to not duplicate the returned object if ownership + * shall remain to the %pipe. + * + * Duplicating the returned object invalidates its corresponding file + * handle in the %pipe. + * + * \return A reference to the %pipe's write end file handle. + */ + file_handle &wend() + { + return write_end_; + } + +private: + /** + * The %pipe's read end file handle. + */ + file_handle read_end_; + + /** + * The %pipe's write end file handle. + */ + file_handle write_end_; +}; + +} +} +} + +#endif diff --git a/src/boost/boost/process/detail/posix_ops.hpp b/src/boost/boost/process/detail/posix_ops.hpp new file mode 100644 index 000000000..a3276058f --- /dev/null +++ b/src/boost/boost/process/detail/posix_ops.hpp @@ -0,0 +1,495 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/detail/posix_ops.hpp + * + * Provides some convenience functions to start processes under POSIX + * operating systems. + */ + +#ifndef BOOST_PROCESS_DETAIL_POSIX_OPS_HPP +#define BOOST_PROCESS_DETAIL_POSIX_OPS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace process { +namespace detail { + +/** + * Converts the command line to an array of C strings. + * + * Converts the command line's list of arguments to the format expected + * by the \a argv parameter in the POSIX execve() system call. + * + * This operation is only available on POSIX systems. + * + * \return The first argument of the pair is an integer that indicates + * how many strings are stored in the second argument. The + * second argument is a NULL-terminated, dynamically allocated + * array of dynamically allocated strings holding the arguments + * to the executable. The caller is responsible of freeing them. + */ +template +inline std::pair collection_to_posix_argv(const Arguments &args) +{ + std::size_t nargs = args.size(); + BOOST_ASSERT(nargs > 0); + + char **argv = new char*[nargs + 1]; + typename Arguments::size_type i = 0; + for (typename Arguments::const_iterator it = args.begin(); it != args.end(); ++it) + { + argv[i] = new char[it->size() + 1]; + std::strncpy(argv[i], it->c_str(), it->size() + 1); + ++i; + } + argv[nargs] = 0; + + return std::pair(nargs, argv); +} + +/** + * Converts an environment to a char** table as used by execve(). + * + * Converts the environment's contents to the format used by the + * execve() system call. The returned char** array is allocated + * in dynamic memory; the caller must free it when not used any + * more. Each entry is also allocated in dynamic memory and is a + * NULL-terminated string of the form var=value; these must also be + * released by the caller. + * + * \return A dynamically allocated char** array that represents + * the environment's content. Each array entry is a + * NULL-terminated string of the form var=value. + */ +inline char **environment_to_envp(const environment &env) +{ + char **envp = new char*[env.size() + 1]; + + environment::size_type i = 0; + for (environment::const_iterator it = env.begin(); it != env.end(); ++it) + { + std::string s = it->first + "=" + it->second; + envp[i] = new char[s.size() + 1]; + std::strncpy(envp[i], s.c_str(), s.size() + 1); + ++i; + } + envp[i] = 0; + + return envp; +} + +/** + * Holds a mapping between native file descriptors and their corresponding + * pipes to set up communication between the parent and the %child process. + */ +typedef std::map info_map; + +/** + * Helper class to configure a POSIX %child. + * + * This helper class is used to hold all the attributes that configure a + * new POSIX %child process and to centralize all the actions needed to + * make them effective. + * + * All its fields are public for simplicity. It is only intended for + * internal use and it is heavily coupled with the Context + * implementations. + */ +struct posix_setup +{ + /** + * The work directory. + * + * This string specifies the directory in which the %child process + * starts execution. It cannot be empty. + */ + std::string work_directory; + + /** + * The chroot directory, if any. + * + * Specifies the directory in which the %child process is chrooted + * before execution. Empty if this feature is not desired. + */ + std::string chroot; + + /** + * The user credentials. + * + * UID that specifies the user credentials to use to run the %child + * process. Defaults to the current UID. + */ + uid_t uid; + + /** + * The effective user credentials. + * + * EUID that specifies the effective user credentials to use to run + * the %child process. Defaults to the current EUID. + */ + uid_t euid; + + /** + * The group credentials. + * + * GID that specifies the group credentials to use to run the %child + * process. Defaults to the current GID. + */ + gid_t gid; + + /** + * The effective group credentials. + * + * EGID that specifies the effective group credentials to use to run + * the %child process. Defaults to the current EGID. + */ + gid_t egid; + + /** + * Creates a new properties set. + * + * Creates a new object that has sensible default values for all the + * properties. + */ + posix_setup() + : uid(::getuid()), + euid(::geteuid()), + gid(::getgid()), + egid(::getegid()) + { + } + + /** + * Sets up the execution environment. + * + * Modifies the current execution environment (that of the %child) so + * that the properties become effective. + * + * \throw boost::system::system_error If any error ocurred during + * environment configuration. The child process should abort + * execution if this happens because its start conditions + * cannot be met. + */ + void operator()() const + { + if (!chroot.empty() && ::chroot(chroot.c_str()) == -1) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: chroot(2) failed")); + + if (gid != ::getgid() && ::setgid(gid) == -1) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setgid(2) failed")); + + if (egid != ::getegid() && ::setegid(egid) == -1) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setegid(2) failed")); + + if (uid != ::getuid() && ::setuid(uid) == -1) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setuid(2) failed")); + + if (euid != ::geteuid() && ::seteuid(euid) == -1) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: seteuid(2) failed")); + + BOOST_ASSERT(!work_directory.empty()); + if (::chdir(work_directory.c_str()) == -1) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: chdir(2) failed")); + } +}; + +/** + * Configures child process' input streams. + * + * Sets up the current process' input streams to behave according to the + * information in the \a info map. \a closeflags is modified to reflect + * those descriptors that should not be closed because they where modified + * by the function. + * + * Modifies the current execution environment, so this should only be run + * on the child process after the fork(2) has happened. + * + * \throw boost::system::system_error If any error occurs during the + * configuration. + */ +inline void setup_input(info_map &info, bool *closeflags, int maxdescs) +{ + for (info_map::iterator it = info.begin(); it != info.end(); ++it) + { + int d = it->first; + stream_info &si = it->second; + + BOOST_ASSERT(d < maxdescs); + closeflags[d] = false; + + switch (si.type_) + { + case stream_info::use_file: + { + int fd = ::open(si.file_.c_str(), O_RDONLY); + if (fd == -1) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::setup_input: open(2) of " + si.file_ + " failed")); + if (fd != d) + { + file_handle h(fd); + h.posix_remap(d); + h.release(); + } + break; + } + case stream_info::use_handle: + { + if (si.handle_.get() != d) + si.handle_.posix_remap(d); + break; + } + case stream_info::use_pipe: + { + si.pipe_->wend().close(); + if (d != si.pipe_->rend().get()) + si.pipe_->rend().posix_remap(d); + break; + } + default: + { + BOOST_ASSERT(si.type_ == stream_info::inherit); + break; + } + } + } +} + +/** + * Configures child process' output streams. + * + * Sets up the current process' output streams to behave according to the + * information in the \a info map. \a closeflags is modified to reflect + * those descriptors that should not be closed because they where + * modified by the function. + * + * Modifies the current execution environment, so this should only be run + * on the child process after the fork(2) has happened. + * + * \throw boost::system::system_error If any error occurs during the + * configuration. + */ +inline void setup_output(info_map &info, bool *closeflags, int maxdescs) +{ + for (info_map::iterator it = info.begin(); it != info.end(); ++it) + { + int d = it->first; + stream_info &si = it->second; + + BOOST_ASSERT(d < maxdescs); + closeflags[d] = false; + + switch (si.type_) + { + case stream_info::redirect: + { + break; + } + case stream_info::use_file: + { + int fd = ::open(si.file_.c_str(), O_WRONLY); + if (fd == -1) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::setup_output: open(2) of " + si.file_ + " failed")); + if (fd != d) + { + file_handle h(fd); + h.posix_remap(d); + h.release(); + } + break; + } + case stream_info::use_handle: + { + if (si.handle_.get() != d) + si.handle_.posix_remap(d); + break; + } + case stream_info::use_pipe: + { + si.pipe_->rend().close(); + if (d != si.pipe_->wend().get()) + si.pipe_->wend().posix_remap(d); + break; + } + default: + { + BOOST_ASSERT(si.type_ == stream_info::inherit); + break; + } + } + } + + for (info_map::const_iterator it = info.begin(); it != info.end(); ++it) + { + int d = it->first; + const stream_info &si = it->second; + + if (si.type_ == stream_info::redirect) + file_handle::posix_dup(si.desc_to_, d).release(); + } +} + +/** + * Starts a new child process in a POSIX operating system. + * + * This helper functions is provided to simplify the Context's task when + * it comes to starting up a new process in a POSIX operating system. + * The function hides all the details of the fork/exec pair of calls as + * well as all the setup of communication pipes and execution environment. + * + * \param exe The executable to spawn the child process. + * \param args The arguments for the executable. + * \param env The environment variables that the new child process + * receives. + * \param infoin A map describing all input file descriptors to be + * redirected. + * \param infoout A map describing all output file descriptors to be + * redirected. + * \param setup A helper object used to configure the child's execution + * environment. + * \return The new process' PID. The caller is responsible of creating + * an appropriate Child representation for it. + */ +template +inline pid_t posix_start(const Executable &exe, const Arguments &args, const environment &env, info_map &infoin, info_map &infoout, const posix_setup &setup) +{ + pid_t pid = ::fork(); + if (pid == -1) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_start: fork(2) failed")); + else if (pid == 0) + { +#if defined(F_MAXFD) + int maxdescs = ::fcntl(-1, F_MAXFD, 0); + if (maxdescs == -1) + maxdescs = ::sysconf(_SC_OPEN_MAX); +#else + int maxdescs = ::sysconf(_SC_OPEN_MAX); +#endif + if (maxdescs == -1) + maxdescs = 1024; + try + { + boost::scoped_array closeflags(new bool[maxdescs]); + for (int i = 0; i < maxdescs; ++i) + closeflags[i] = true; + + setup_input(infoin, closeflags.get(), maxdescs); + setup_output(infoout, closeflags.get(), maxdescs); + + for (int i = 0; i < maxdescs; ++i) + { + if (closeflags[i]) + ::close(i); + } + + setup(); + } + catch (const boost::system::system_error &e) + { + ::write(STDERR_FILENO, e.what(), std::strlen(e.what())); + ::write(STDERR_FILENO, "\n", 1); + std::exit(EXIT_FAILURE); + } + + std::pair argcv = collection_to_posix_argv(args); + char **envp = environment_to_envp(env); + + ::execve(exe.c_str(), argcv.second, envp); + boost::system::system_error e(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_start: execve(2) failed"); + + for (std::size_t i = 0; i < argcv.first; ++i) + delete[] argcv.second[i]; + delete[] argcv.second; + + for (std::size_t i = 0; i < env.size(); ++i) + delete[] envp[i]; + delete[] envp; + + ::write(STDERR_FILENO, e.what(), std::strlen(e.what())); + ::write(STDERR_FILENO, "\n", 1); + std::exit(EXIT_FAILURE); + } + + BOOST_ASSERT(pid > 0); + + for (info_map::iterator it = infoin.begin(); it != infoin.end(); ++it) + { + stream_info &si = it->second; + if (si.type_ == stream_info::use_pipe) + si.pipe_->rend().close(); + } + + for (info_map::iterator it = infoout.begin(); it != infoout.end(); ++it) + { + stream_info &si = it->second; + if (si.type_ == stream_info::use_pipe) + si.pipe_->wend().close(); + } + + return pid; +} + +/** + * Locates a communication pipe and returns one of its endpoints. + * + * Given a \a info map, and a file descriptor \a desc, searches for its + * communicataion pipe in the map and returns one of its endpoints as + * indicated by the \a out flag. This is intended to be used by a + * parent process after a fork(2) call. + * + * \pre If the info map contains the given descriptor, it is configured + * to use a pipe. + * \post The info map does not contain the given descriptor. + * \return If the file descriptor is found in the map, returns the pipe's + * read end if out is true; otherwise its write end. If the + * descriptor is not found returns an invalid file handle. + */ +inline file_handle posix_info_locate_pipe(info_map &info, int desc, bool out) +{ + file_handle fh; + + info_map::iterator it = info.find(desc); + if (it != info.end()) + { + stream_info &si = it->second; + if (si.type_ == stream_info::use_pipe) + { + fh = out ? si.pipe_->rend().release() : si.pipe_->wend().release(); + BOOST_ASSERT(fh.valid()); + } + info.erase(it); + } + + return fh; +} + +} +} +} + +#endif diff --git a/src/boost/boost/process/detail/stream_info.hpp b/src/boost/boost/process/detail/stream_info.hpp new file mode 100644 index 000000000..7c29fd40f --- /dev/null +++ b/src/boost/boost/process/detail/stream_info.hpp @@ -0,0 +1,176 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/detail/stream_info.hpp + * + * Provides the definition of the stream_info structure. + */ + +#ifndef BOOST_PROCESS_DETAIL_STREAM_INFO_HPP +#define BOOST_PROCESS_DETAIL_STREAM_INFO_HPP + +#include + +#if defined(BOOST_POSIX_API) +# include +#elif defined(BOOST_WINDOWS_API) +#else +# error "Unsupported platform." +#endif + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace process { +namespace detail { + +/** + * Configuration data for a file descriptor. + * + * This convenience structure provides a compact way to pass information + * around on how to configure a file descriptor. It is a lower-level + * representation of stream_behavior, as it can hold the same information + * but in a way that can be used by the underlying operating system. + */ +struct stream_info +{ + /** + * Supported stream types. + */ + enum type + { + /** + * Matches stream_behavior::close. + */ + close, + + /** + * Matches stream_behavior::inherit. + */ + inherit, + + /** + * Matches stream_behavior::redirect_to_stdout and + * stream_behavior::posix_redirect. + */ + redirect, + + /** + * Matches stream_behavior::silence. + */ + use_file, + + /** + * TODO: Matches nothing yet ... + */ + use_handle, + + /** + * Matches stream_behavior::capture. + */ + use_pipe + }; + + /** + * Stream type. + */ + type type_; + + /** + * Descriptor to use when stream type is set to \a redirect. + */ + int desc_to_; + + /** + * File to use when stream type is set to \a use_file. + */ + std::string file_; + + /** + * Handle to use when stream type is set to \a use_handle. + */ + file_handle handle_; + + /** + * Pipe to use when stream type is set to \a use_pipe. + */ + boost::optional pipe_; + + /** + * Constructs a new stream_info object. + */ + stream_info(const stream_behavior &sb, bool out) + { + switch (sb.type_) + { + case stream_behavior::close: + { + type_ = close; + break; + } + case stream_behavior::inherit: + { + type_ = inherit; + break; + } + case stream_behavior::redirect_to_stdout: + { + type_ = redirect; +#if defined(BOOST_POSIX_API) + desc_to_ = STDOUT_FILENO; +#elif defined(BOOST_WINDOWS_API) + desc_to_ = 1; +#endif + break; + } +#if defined(BOOST_POSIX_API) + case stream_behavior::posix_redirect: + { + type_ = redirect; + desc_to_ = sb.desc_to_; + break; + } +#endif + case stream_behavior::silence: + { + type_ = use_file; +#if defined(BOOST_POSIX_API) + file_ = out ? "/dev/null" : "/dev/zero"; +#elif defined(BOOST_WINDOWS_API) + file_ = "NUL"; +#endif + break; + } + case stream_behavior::capture: + { + type_ = use_pipe; + pipe_ = pipe(); + break; + } + default: + { + BOOST_ASSERT(false); + } + } + } +}; + +} +} +} + +#endif diff --git a/src/boost/boost/process/detail/systembuf.hpp b/src/boost/boost/process/detail/systembuf.hpp new file mode 100644 index 000000000..bb57083c5 --- /dev/null +++ b/src/boost/boost/process/detail/systembuf.hpp @@ -0,0 +1,231 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/detail/systembuf.hpp + * + * Includes the declaration of the systembuf class. This file is for + * internal usage only and must not be included by the library user. + */ + +#ifndef BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP +#define BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP + +#include + +#if defined(BOOST_POSIX_API) +# include +# include +#elif defined(BOOST_WINDOWS_API) +# include +#else +# error "Unsupported platform." +#endif + +#include +#include +#include +#include +#include + +namespace boost { +namespace process { + +class postream; + +namespace detail { + +/** + * std::streambuf implementation for system file handles. + * + * systembuf provides a std::streambuf implementation for system file + * handles. Contrarywise to file_handle, this class does \b not take + * ownership of the native file handle; this should be taken care of + * somewhere else. + * + * This class follows the expected semantics of a std::streambuf object. + * However, it is not copyable to avoid introducing inconsistences with + * the on-disk file and the in-memory buffers. + */ +class systembuf : public std::streambuf, public boost::noncopyable +{ + friend class ::boost::process::postream; + +public: +#if defined(BOOST_PROCESS_DOXYGEN) + /** + * Opaque name for the native handle type. + */ + typedef NativeHandleType handle_type; +#elif defined(BOOST_POSIX_API) + typedef int handle_type; +#elif defined(BOOST_WINDOWS_API) + typedef HANDLE handle_type; +#endif + + /** + * Constructs a new systembuf for the given file handle. + * + * This constructor creates a new systembuf object that reads or + * writes data from/to the \a h native file handle. This handle + * is \b not owned by the created systembuf object; the code + * should take care of it externally. + * + * This class buffers input and output; the buffer size may be + * tuned through the \a bufsize parameter, which defaults to 8192 + * bytes. + * + * \see pistream and postream + */ + explicit systembuf(handle_type h, std::size_t bufsize = 8192) + : handle_(h), + bufsize_(bufsize), + read_buf_(new char[bufsize]), + write_buf_(new char[bufsize]) + { +#if defined(BOOST_POSIX_API) + BOOST_ASSERT(handle_ >= 0); +#elif defined(BOOST_WINDOWS_API) + BOOST_ASSERT(handle_ != INVALID_HANDLE_VALUE); +#endif + BOOST_ASSERT(bufsize_ > 0); + + setp(write_buf_.get(), write_buf_.get() + bufsize_); + } + +protected: + /** + * Reads new data from the native file handle. + * + * This operation is called by input methods when there is no more + * data in the input buffer. The function fills the buffer with new + * data, if available. + * + * \pre All input positions are exhausted (gptr() >= egptr()). + * \post The input buffer has new data, if available. + * \returns traits_type::eof() if a read error occurrs or there are + * no more data to be read. Otherwise returns + * traits_type::to_int_type(*gptr()). + */ + virtual int_type underflow() + { + BOOST_ASSERT(gptr() >= egptr()); + + bool ok; +#if defined(BOOST_POSIX_API) + ssize_t cnt = ::read(handle_, read_buf_.get(), bufsize_); + ok = (cnt != -1 && cnt != 0); +#elif defined(BOOST_WINDOWS_API) + DWORD cnt; + BOOL res = ::ReadFile(handle_, read_buf_.get(), bufsize_, &cnt, NULL); + ok = (res && cnt > 0); +#endif + + if (!ok) + return traits_type::eof(); + else + { + setg(read_buf_.get(), read_buf_.get(), read_buf_.get() + cnt); + return traits_type::to_int_type(*gptr()); + } + } + + /** + * Makes room in the write buffer for additional data. + * + * This operation is called by output methods when there is no more + * space in the output buffer to hold a new element. The function + * first flushes the buffer's contents to disk and then clears it to + * leave room for more characters. The given \a c character is + * stored at the beginning of the new space. + * + * \pre All output positions are exhausted (pptr() >= epptr()). + * \post The output buffer has more space if no errors occurred + * during the write to disk. + * \post *(pptr() - 1) is \a c. + * \returns traits_type::eof() if a write error occurrs. Otherwise + * returns traits_type::not_eof(c). + */ + virtual int_type overflow(int c) + { + BOOST_ASSERT(pptr() >= epptr()); + + if (sync() == -1) + return traits_type::eof(); + + if (!traits_type::eq_int_type(c, traits_type::eof())) + { + traits_type::assign(*pptr(), c); + pbump(1); + } + + return traits_type::not_eof(c); + } + + /** + * Flushes the output buffer to disk. + * + * Synchronizes the systembuf buffers with the contents of the file + * associated to this object through the native file handle. The + * output buffer is flushed to disk and cleared to leave new room + * for more data. + * + * \returns 0 on success, -1 if an error occurred. + */ + virtual int sync() + { +#if defined(BOOST_POSIX_API) + ssize_t cnt = pptr() - pbase(); +#elif defined(BOOST_WINDOWS_API) + long cnt = pptr() - pbase(); +#endif + + bool ok; +#if defined(BOOST_POSIX_API) + ok = ::write(handle_, pbase(), cnt) == cnt; +#elif defined(BOOST_WINDOWS_API) + DWORD rcnt; + BOOL res = ::WriteFile(handle_, pbase(), cnt, &rcnt, NULL); + ok = (res && static_cast(rcnt) == cnt); +#endif + + if (ok) + pbump(-cnt); + return ok ? 0 : -1; + } + +private: + /** + * Native file handle used by the systembuf object. + */ + handle_type handle_; + + /** + * Internal buffer size used during read and write operations. + */ + std::size_t bufsize_; + + /** + * Internal buffer used during read operations. + */ + boost::scoped_array read_buf_; + + /** + * Internal buffer used during write operations. + */ + boost::scoped_array write_buf_; +}; + +} +} +} + +#endif diff --git a/src/boost/boost/process/detail/win32_ops.hpp b/src/boost/boost/process/detail/win32_ops.hpp new file mode 100644 index 000000000..80663dd72 --- /dev/null +++ b/src/boost/boost/process/detail/win32_ops.hpp @@ -0,0 +1,355 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/detail/win32_ops.hpp + * + * Provides some convenience functions to start processes under + * Windows-compatible operating systems. + */ + +#ifndef BOOST_PROCESS_DETAIL_WIN32_OPS_HPP +#define BOOST_PROCESS_DETAIL_WIN32_OPS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace process { +namespace detail { + +/** + * Converts the command line to a plain string. Converts the command line's + * list of arguments to the format expected by the \a lpCommandLine parameter + * in the CreateProcess() system call. + * + * This operation is only available on Windows systems. + * + * \return A dynamically allocated string holding the command line + * to be passed to the executable. It is returned in a + * shared_array object to ensure its release at some point. + */ +template +inline boost::shared_array collection_to_win32_cmdline(const Arguments &args) +{ + typedef std::vector arguments_t; + arguments_t args2; + typename Arguments::size_type i = 0; + std::size_t size = 0; + for (typename Arguments::const_iterator it = args.begin(); it != args.end(); ++it) + { + std::string arg = *it; + + std::string::size_type pos = 0; + while ( (pos = arg.find('"', pos)) != std::string::npos) + { + arg.replace(pos, 1, "\\\""); + pos += 2; + } + + if (arg.find(' ') != std::string::npos) + arg = '\"' + arg + '\"'; + + if (i++ != args.size() - 1) + arg += ' '; + + args2.push_back(arg); + size += arg.size() + 1; + } + + boost::shared_array cmdline(new char[size]); + cmdline.get()[0] = '\0'; + for (arguments_t::size_type i = 0; i < args.size(); ++i) +#if defined(__CYGWIN__) + ::strncat(cmdline.get(), args2[i].c_str(), args2[i].size()); +#else + ::strcat_s(cmdline.get(), size, args2[i].c_str()); +#endif + + return cmdline; +} + +/** + * Converts an environment to a string used by CreateProcess(). + * + * Converts the environment's contents to the format used by the + * CreateProcess() system call. The returned char* string is + * allocated in dynamic memory; the caller must free it when not + * used any more. This is enforced by the use of a shared pointer. + * + * \return A dynamically allocated char* string that represents + * the environment's content. This string is of the form + * var1=value1\\0var2=value2\\0\\0. + */ +inline boost::shared_array environment_to_win32_strings(const environment &env) +{ + boost::shared_array envp; + + if (env.empty()) + { + envp.reset(new char[2]); + ::ZeroMemory(envp.get(), 2); + } + else + { + std::string s; + for (environment::const_iterator it = env.begin(); it != env.end(); ++it) + { + s += it->first + "=" + it->second; + s.push_back(0); + } + + envp.reset(new char[s.size() + 1]); +#if defined(__CYGWIN__) + ::memcpy(envp.get(), s.c_str(), s.size() + 1); +#else + ::memcpy_s(envp.get(), s.size() + 1, s.c_str(), s.size() + 1); +#endif + } + + return envp; +} + +/** + * Helper class to configure a Win32 %child. + * + * This helper class is used to hold all the attributes that configure a + * new Win32 %child process. + * + * All its fields are public for simplicity. It is only intended for + * internal use and it is heavily coupled with the Context + * implementations. + */ +struct win32_setup +{ + /** + * The work directory. + * + * This string specifies the directory in which the %child process + * starts execution. It cannot be empty. + */ + std::string work_directory; + + /** + * The process startup properties. + * + * This Win32-specific object holds a list of properties that describe + * how the new process should be started. The \a STARTF_USESTDHANDLES + * flag should not be set in it because it is automatically configured + * by win32_start(). + */ + STARTUPINFOA *startupinfo; +}; + +/** + * Starts a new child process in a Win32 operating system. + * + * This helper functions is provided to simplify the Context's task when + * it comes to starting up a new process in a Win32 operating system. + * + * \param exe The executable to spawn the child process. + * \param args The arguments for the executable. + * \param env The environment variables that the new child process + * receives. + * \param infoin Information that describes stdin's behavior. + * \param infoout Information that describes stdout's behavior. + * \param infoerr Information that describes stderr's behavior. + * \param setup A helper object holding extra child information. + * \return The new process' information as returned by the CreateProcess() + * system call. The caller is responsible of creating an + * appropriate Child representation for it. + * \pre \a setup.startupinfo_ cannot have the \a STARTF_USESTDHANDLES set + * in the \a dwFlags field. + */ +template +inline PROCESS_INFORMATION win32_start(const Executable &exe, const Arguments &args, const environment &env, stream_info &infoin, stream_info &infoout, stream_info &infoerr, const win32_setup &setup) +{ + file_handle chin, chout, cherr; + + BOOST_ASSERT(setup.startupinfo->cb >= sizeof(STARTUPINFOA)); + BOOST_ASSERT(!(setup.startupinfo->dwFlags & STARTF_USESTDHANDLES)); + + boost::scoped_ptr si(new STARTUPINFOA); + ::CopyMemory(si.get(), setup.startupinfo, sizeof(*setup.startupinfo)); + si->dwFlags |= STARTF_USESTDHANDLES; + + switch (infoin.type_) + { + case stream_info::close: + { + break; + } + case stream_info::inherit: + { + chin = file_handle::win32_std(STD_INPUT_HANDLE, true); + break; + } + case stream_info::use_file: + { + HANDLE h = ::CreateFileA(infoin.file_.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed")); + chin = file_handle(h); + break; + } + case stream_info::use_handle: + { + chin = infoin.handle_; + chin.win32_set_inheritable(true); + break; + } + case stream_info::use_pipe: + { + infoin.pipe_->rend().win32_set_inheritable(true); + chin = infoin.pipe_->rend(); + break; + } + default: + { + BOOST_ASSERT(false); + break; + } + } + + si->hStdInput = chin.valid() ? chin.get() : INVALID_HANDLE_VALUE; + + switch (infoout.type_) + { + case stream_info::close: + { + break; + } + case stream_info::inherit: + { + chout = file_handle::win32_std(STD_OUTPUT_HANDLE, true); + break; + } + case stream_info::use_file: + { + HANDLE h = ::CreateFileA(infoout.file_.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed")); + chout = file_handle(h); + break; + } + case stream_info::use_handle: + { + chout = infoout.handle_; + chout.win32_set_inheritable(true); + break; + } + case stream_info::use_pipe: + { + infoout.pipe_->wend().win32_set_inheritable(true); + chout = infoout.pipe_->wend(); + break; + } + default: + { + BOOST_ASSERT(false); + break; + } + } + + si->hStdOutput = chout.valid() ? chout.get() : INVALID_HANDLE_VALUE; + + switch (infoerr.type_) + { + case stream_info::close: + { + break; + } + case stream_info::inherit: + { + cherr = file_handle::win32_std(STD_ERROR_HANDLE, true); + break; + } + case stream_info::redirect: + { + BOOST_ASSERT(infoerr.desc_to_ == 1); + BOOST_ASSERT(chout.valid()); + cherr = file_handle::win32_dup(chout.get(), true); + break; + } + case stream_info::use_file: + { + HANDLE h = ::CreateFileA(infoerr.file_.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed")); + cherr = file_handle(h); + break; + } + case stream_info::use_handle: + { + cherr = infoerr.handle_; + cherr.win32_set_inheritable(true); + break; + } + case stream_info::use_pipe: + { + infoerr.pipe_->wend().win32_set_inheritable(true); + cherr = infoerr.pipe_->wend(); + break; + } + default: + { + BOOST_ASSERT(false); + break; + } + } + + si->hStdError = cherr.valid() ? cherr.get() : INVALID_HANDLE_VALUE; + + PROCESS_INFORMATION pi; + ::ZeroMemory(&pi, sizeof(pi)); + + boost::shared_array cmdline = collection_to_win32_cmdline(args); + + boost::scoped_array executable(new char[exe.size() + 1]); +#if defined(__CYGWIN__) + ::strcpy(executable.get(), exe.c_str()); +#else + ::strcpy_s(executable.get(), exe.size() + 1, exe.c_str()); +#endif + + boost::scoped_array workdir(new char[setup.work_directory.size() + 1]); +#if defined(__CYGWIN__) + ::strcpy(workdir.get(), setup.work_directory.c_str()); +#else + ::strcpy_s(workdir.get(), setup.work_directory.size() + 1, setup.work_directory.c_str()); +#endif + + boost::shared_array envstrs = environment_to_win32_strings(env); + + if (!::CreateProcessA(executable.get(), cmdline.get(), NULL, NULL, TRUE, 0, envstrs.get(), workdir.get(), si.get(), &pi)) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateProcess failed")); + + return pi; +} + +} +} +} + +#endif diff --git a/src/boost/boost/process/environment.hpp b/src/boost/boost/process/environment.hpp new file mode 100644 index 000000000..6b474b919 --- /dev/null +++ b/src/boost/boost/process/environment.hpp @@ -0,0 +1,50 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/environment.hpp + * + * Includes the declaration of the environment class. + */ + +#ifndef BOOST_PROCESS_ENVIRONMENT_HPP +#define BOOST_PROCESS_ENVIRONMENT_HPP + +#include +#include + +namespace boost { +namespace process { + +/** + * Representation of a process' environment variables. + * + * The environment is a map that stablishes an unidirectional + * association between variable names and their values and is + * represented by a string to string map. + * + * Variables may be defined to the empty string. Be aware that doing so + * is not portable: POSIX systems will treat such variables as being + * defined to the empty value, but Windows systems are not able to + * distinguish them from undefined variables. + * + * Neither POSIX nor Windows systems support a variable with no name. + * + * It is worthy to note that the environment is sorted alphabetically. + * This is provided for-free by the map container used to implement this + * type, and this behavior is required by Windows systems. + */ +typedef std::map environment; + +} +} + +#endif diff --git a/src/boost/boost/process/operations.hpp b/src/boost/boost/process/operations.hpp new file mode 100644 index 000000000..4850d0328 --- /dev/null +++ b/src/boost/boost/process/operations.hpp @@ -0,0 +1,587 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/operations.hpp + * + * Provides miscellaneous free functions. + */ + +#ifndef BOOST_PROCESS_OPERATIONS_HPP +#define BOOST_PROCESS_OPERATIONS_HPP + +#include + +#if defined(BOOST_POSIX_API) +# include +# include +# include +# if defined(__CYGWIN__) +# include +# include +# endif +#elif defined(BOOST_WINDOWS_API) +# include +# include +# include +#else +# error "Unsupported platform." +#endif + +#include +#include +#include +#include +#include +#include + +// fix file system error +//#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace process { + +/** + * Locates the executable program \a file in all the directory components + * specified in \a path. If \a path is empty, the value of the PATH + * environment variable is used. + * + * The path variable is interpreted following the same conventions used + * to parse the PATH environment variable in the underlying platform. + * + * \throw boost::filesystem::filesystem_error If the file cannot be found + * in the path. + */ +inline std::string find_executable_in_path(const std::string &file, std::string path = "") +{ +#if defined(BOOST_POSIX_API) + BOOST_ASSERT(file.find('/') == std::string::npos); +#elif defined(BOOST_WINDOWS_API) + BOOST_ASSERT(file.find_first_of("\\/") == std::string::npos); +#endif + + std::string result; + +#if defined(BOOST_POSIX_API) + if (path.empty()) + { + const char *envpath = ::getenv("PATH"); + if (!envpath) + boost::throw_exception(boost::filesystem::filesystem_error("boost::process::find_executable_in_path: retrieving PATH failed", file, boost::system::errc::make_error_code(boost::system::errc::no_such_file_or_directory))); + + path = envpath; + } + BOOST_ASSERT(!path.empty()); + +#if defined(__CYGWIN__) + if (!::cygwin_posix_path_list_p(path.c_str())) + { + int size = ::cygwin_win32_to_posix_path_list_buf_size(path.c_str()); + boost::scoped_array cygpath(new char[size]); + ::cygwin_win32_to_posix_path_list(path.c_str(), cygpath.get()); + path = cygpath.get(); + } +#endif + + std::string::size_type pos1 = 0, pos2; + do + { + pos2 = path.find(':', pos1); + std::string dir = (pos2 != std::string::npos) ? path.substr(pos1, pos2 - pos1) : path.substr(pos1); + std::string f = dir + (boost::algorithm::ends_with(dir, "/") ? "" : "/") + file; + if (!::access(f.c_str(), X_OK)) + result = f; + pos1 = pos2 + 1; + } while (pos2 != std::string::npos && result.empty()); +#elif defined(BOOST_WINDOWS_API) + const char *exts[] = { "", ".exe", ".com", ".bat", NULL }; + const char **ext = exts; + while (*ext) + { + char buf[MAX_PATH]; + char *dummy; + DWORD size = ::SearchPathA(path.empty() ? NULL : path.c_str(), file.c_str(), *ext, MAX_PATH, buf, &dummy); + BOOST_ASSERT(size < MAX_PATH); + if (size > 0) + { + result = buf; + break; + } + ++ext; + } +#endif + + if (result.empty()) + boost::throw_exception(boost::filesystem::filesystem_error("boost::process::find_executable_in_path: file not found", file, boost::system::errc::make_error_code(boost::system::errc::no_such_file_or_directory))); + + return result; +} + +/** + * Extracts the program name from a given executable. + * + * \return The program name. On Windows the program name + * is returned without a file extension. + */ +inline std::string executable_to_progname(const std::string &exe) +{ + std::string::size_type begin = 0; + std::string::size_type end = std::string::npos; + +#if defined(BOOST_POSIX_API) + std::string::size_type slash = exe.rfind('/'); +#elif defined(BOOST_WINDOWS_API) + std::string::size_type slash = exe.find_last_of("/\\"); +#endif + if (slash != std::string::npos) + begin = slash + 1; + +#if defined(BOOST_WINDOWS_API) + if (exe.size() > 4 && + (boost::algorithm::iends_with(exe, ".exe") || boost::algorithm::iends_with(exe, ".com") || boost::algorithm::iends_with(exe, ".bat"))) + end = exe.size() - 4; +#endif + + return exe.substr(begin, end - begin); +} + +/** + * Starts a new child process. + * + * Launches a new process based on the binary image specified by the + * executable, the set of arguments to be passed to it and several + * parameters that describe the execution context. + * + * \remark Blocking remarks: This function may block if the device + * holding the executable blocks when loading the image. This might + * happen if, e.g., the binary is being loaded from a network share. + * + * \return A handle to the new child process. + */ +template +inline child launch(const Executable &exe, const Arguments &args, const Context &ctx) +{ + detail::file_handle fhstdin, fhstdout, fhstderr; + + BOOST_ASSERT(!args.empty()); + BOOST_ASSERT(!ctx.work_directory.empty()); + +#if defined(BOOST_POSIX_API) + detail::info_map infoin, infoout; + + if (ctx.stdin_behavior.get_type() != stream_behavior::close) + { + detail::stream_info si = detail::stream_info(ctx.stdin_behavior, false); + infoin.insert(detail::info_map::value_type(STDIN_FILENO, si)); + } + + if (ctx.stdout_behavior.get_type() != stream_behavior::close) + { + detail::stream_info si = detail::stream_info(ctx.stdout_behavior, true); + infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si)); + } + + if (ctx.stderr_behavior.get_type() != stream_behavior::close) + { + detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true); + infoout.insert(detail::info_map::value_type(STDERR_FILENO, si)); + } + + detail::posix_setup s; + s.work_directory = ctx.work_directory; + + child::id_type pid = detail::posix_start(exe, args, ctx.environment, infoin, infoout, s); + + if (ctx.stdin_behavior.get_type() == stream_behavior::capture) + { + fhstdin = detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false); + BOOST_ASSERT(fhstdin.valid()); + } + + if (ctx.stdout_behavior.get_type() == stream_behavior::capture) + { + fhstdout = detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true); + BOOST_ASSERT(fhstdout.valid()); + } + + if (ctx.stderr_behavior.get_type() == stream_behavior::capture) + { + fhstderr = detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true); + BOOST_ASSERT(fhstderr.valid()); + } + + return child(pid, fhstdin, fhstdout, fhstderr); +#elif defined(BOOST_WINDOWS_API) + detail::stream_info behin = detail::stream_info(ctx.stdin_behavior, false); + if (behin.type_ == detail::stream_info::use_pipe) + fhstdin = behin.pipe_->wend(); + detail::stream_info behout = detail::stream_info(ctx.stdout_behavior, true); + if (behout.type_ == detail::stream_info::use_pipe) + fhstdout = behout.pipe_->rend(); + detail::stream_info beherr = detail::stream_info(ctx.stderr_behavior, true); + if (beherr.type_ == detail::stream_info::use_pipe) + fhstderr = beherr.pipe_->rend(); + + STARTUPINFOA si; + ::ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + + detail::win32_setup s; + s.work_directory = ctx.work_directory; + s.startupinfo = &si; + + PROCESS_INFORMATION pi = detail::win32_start(exe, args, ctx.environment, behin, behout, beherr, s); + + if (!::CloseHandle(pi.hThread)) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch: CloseHandle failed")); + + return child(pi.dwProcessId, fhstdin, fhstdout, fhstderr, detail::file_handle(pi.hProcess)); +#endif +} + +/** + * Launches a shell-based command. + * + * Executes the given command through the default system shell. The + * command is subject to pattern expansion, redirection and pipelining. + * The shell is launched as described by the parameters in the execution + * context. + * + * This function behaves similarly to the system(3) system call. In a + * POSIX system, the command is fed to /bin/sh whereas under a Windows + * system, it is fed to cmd.exe. It is difficult to write portable + * commands as the first parameter, but this function comes in handy in + * multiple situations. + */ +template +inline child launch_shell(const std::string &command, const Context &ctx) +{ + std::string exe; + std::vector args; + +#if defined(BOOST_POSIX_API) + exe = "/bin/sh"; + args.push_back("sh"); + args.push_back("-c"); + args.push_back(command); +#elif defined(BOOST_WINDOWS_API) + char sysdir[MAX_PATH]; + UINT size = ::GetSystemDirectoryA(sysdir, sizeof(sysdir)); + if (!size) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_shell: GetWindowsDirectory failed")); + BOOST_ASSERT(size < MAX_PATH); + + exe = std::string(sysdir) + (sysdir[size - 1] != '\\' ? "\\cmd.exe" : "cmd.exe"); + args.push_back("cmd"); + args.push_back("/c"); + args.push_back(command); +#endif + + return launch(exe, args, ctx); +} + +/** + * Launches a pipelined set of child processes. + * + * Given a collection of pipeline_entry objects describing how to launch + * a set of child processes, spawns them all and connects their inputs and + * outputs in a way that permits pipelined communication. + * + * \pre Let 1..N be the processes in the collection: the input behavior of + * the 2..N processes must be set to close_stream(). + * \pre Let 1..N be the processes in the collection: the output behavior of + * the 1..N-1 processes must be set to close_stream(). + * \remark Blocking remarks: This function may block if the device holding + * the executable of one of the entries blocks when loading the + * image. This might happen if, e.g., the binary is being loaded + * from a network share. + * \return A set of Child objects that represent all the processes spawned + * by this call. You should use wait_children() to wait for their + * termination. + */ +template +inline children launch_pipeline(const Entries &entries) +{ + BOOST_ASSERT(entries.size() >= 2); + + children cs; + detail::file_handle fhinvalid; + + boost::scoped_array pipes(new detail::pipe[entries.size() - 1]); + +#if defined(BOOST_POSIX_API) + { + typename Entries::size_type i = 0; + const typename Entries::value_type::context_type &ctx = entries[i].context; + + detail::info_map infoin, infoout; + + if (ctx.stdin_behavior.get_type() != stream_behavior::close) + { + detail::stream_info si = detail::stream_info(ctx.stdin_behavior, false); + infoin.insert(detail::info_map::value_type(STDIN_FILENO, si)); + } + + BOOST_ASSERT(ctx.stdout_behavior.get_type() == stream_behavior::close); + detail::stream_info si2(close_stream(), true); + si2.type_ = detail::stream_info::use_handle; + si2.handle_ = pipes[i].wend().release(); + infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si2)); + + if (ctx.stderr_behavior.get_type() != stream_behavior::close) + { + detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true); + infoout.insert(detail::info_map::value_type(STDERR_FILENO, si)); + } + + detail::posix_setup s; + s.work_directory = ctx.work_directory; + + pid_t pid = detail::posix_start(entries[i].executable, entries[i].arguments, ctx.environment, infoin, infoout, s); + + detail::file_handle fhstdin; + + if (ctx.stdin_behavior.get_type() == stream_behavior::capture) + { + fhstdin = detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false); + BOOST_ASSERT(fhstdin.valid()); + } + + cs.push_back(child(pid, fhstdin, fhinvalid, fhinvalid)); + } + + for (typename Entries::size_type i = 1; i < entries.size() - 1; ++i) + { + const typename Entries::value_type::context_type &ctx = entries[i].context; + detail::info_map infoin, infoout; + + BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close); + detail::stream_info si1(close_stream(), false); + si1.type_ = detail::stream_info::use_handle; + si1.handle_ = pipes[i - 1].rend().release(); + infoin.insert(detail::info_map::value_type(STDIN_FILENO, si1)); + + BOOST_ASSERT(ctx.stdout_behavior.get_type() == stream_behavior::close); + detail::stream_info si2(close_stream(), true); + si2.type_ = detail::stream_info::use_handle; + si2.handle_ = pipes[i].wend().release(); + infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si2)); + + if (ctx.stderr_behavior.get_type() != stream_behavior::close) + { + detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true); + infoout.insert(detail::info_map::value_type(STDERR_FILENO, si)); + } + + detail::posix_setup s; + s.work_directory = ctx.work_directory; + + pid_t pid = detail::posix_start(entries[i].executable, entries[i].arguments, ctx.environment, infoin, infoout, s); + + cs.push_back(child(pid, fhinvalid, fhinvalid, fhinvalid)); + } + + { + typename Entries::size_type i = entries.size() - 1; + const typename Entries::value_type::context_type &ctx = entries[i].context; + + detail::info_map infoin, infoout; + + BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close); + detail::stream_info si1(close_stream(), false); + si1.type_ = detail::stream_info::use_handle; + si1.handle_ = pipes[i - 1].rend().release(); + infoin.insert(detail::info_map::value_type(STDIN_FILENO, si1)); + + if (ctx.stdout_behavior.get_type() != stream_behavior::close) + { + detail::stream_info si = detail::stream_info(ctx.stdout_behavior, true); + infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si)); + } + + if (ctx.stderr_behavior.get_type() != stream_behavior::close) + { + detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true); + infoout.insert(detail::info_map::value_type(STDERR_FILENO, si)); + } + + detail::posix_setup s; + s.work_directory = ctx.work_directory; + + pid_t pid = detail::posix_start(entries[i].executable, entries[i].arguments, ctx.environment, infoin, infoout, s); + + detail::file_handle fhstdout, fhstderr; + + if (ctx.stdout_behavior.get_type() == stream_behavior::capture) + { + fhstdout = detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true); + BOOST_ASSERT(fhstdout.valid()); + } + + if (ctx.stderr_behavior.get_type() == stream_behavior::capture) + { + fhstderr = detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true); + BOOST_ASSERT(fhstderr.valid()); + } + + cs.push_back(child(pid, fhinvalid, fhstdout, fhstderr)); + } +#elif defined(BOOST_WINDOWS_API) + STARTUPINFOA si; + detail::win32_setup s; + s.startupinfo = &si; + + { + typename Entries::size_type i = 0; + const typename Entries::value_type::context_type &ctx = entries[i].context; + + detail::stream_info sii = detail::stream_info(ctx.stdin_behavior, false); + detail::file_handle fhstdin; + if (sii.type_ == detail::stream_info::use_pipe) + fhstdin = sii.pipe_->wend(); + + BOOST_ASSERT(ctx.stdout_behavior.get_type() == stream_behavior::close); + detail::stream_info sio(close_stream(), true); + sio.type_ = detail::stream_info::use_handle; + sio.handle_ = pipes[i].wend().release(); + + detail::stream_info sie(ctx.stderr_behavior, true); + + s.work_directory = ctx.work_directory; + + ::ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + PROCESS_INFORMATION pi = detail::win32_start(entries[i].executable, entries[i].arguments, ctx.environment, sii, sio, sie, s); + + if (!::CloseHandle(pi.hThread)) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_pipeline: CloseHandle failed")); + + cs.push_back(child(pi.dwProcessId, fhstdin, fhinvalid, fhinvalid, detail::file_handle(pi.hProcess))); + } + + for (typename Entries::size_type i = 1; i < entries.size() - 1; ++i) + { + const typename Entries::value_type::context_type &ctx = entries[i].context; + + BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close); + detail::stream_info sii(close_stream(), false); + sii.type_ = detail::stream_info::use_handle; + sii.handle_ = pipes[i - 1].rend().release(); + + detail::stream_info sio(close_stream(), true); + sio.type_ = detail::stream_info::use_handle; + sio.handle_ = pipes[i].wend().release(); + + detail::stream_info sie(ctx.stderr_behavior, true); + + s.work_directory = ctx.work_directory; + + ::ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + PROCESS_INFORMATION pi = detail::win32_start(entries[i].executable, entries[i].arguments, ctx.environment, sii, sio, sie, s); + + if (!::CloseHandle(pi.hThread)) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_pipeline: CloseHandle failed")); + + cs.push_back(child(pi.dwProcessId, fhinvalid, fhinvalid, fhinvalid, detail::file_handle(pi.hProcess))); + } + + { + typename Entries::size_type i = entries.size() - 1; + const typename Entries::value_type::context_type &ctx = entries[i].context; + + BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close); + detail::stream_info sii(close_stream(), false); + sii.type_ = detail::stream_info::use_handle; + sii.handle_ = pipes[i - 1].rend().release(); + + detail::file_handle fhstdout, fhstderr; + + detail::stream_info sio(ctx.stdout_behavior, true); + if (sio.type_ == detail::stream_info::use_pipe) + fhstdout = sio.pipe_->rend(); + detail::stream_info sie(ctx.stderr_behavior, true); + if (sie.type_ == detail::stream_info::use_pipe) + fhstderr = sie.pipe_->rend(); + + s.work_directory = ctx.work_directory; + + ::ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + PROCESS_INFORMATION pi = detail::win32_start(entries[i].executable, entries[i].arguments, ctx.environment, sii, sio, sie, s); + + if (!::CloseHandle(pi.hThread)) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_pipeline: CloseHandle failed")); + + cs.push_back(child(pi.dwProcessId, fhinvalid, fhstdout, fhstderr, detail::file_handle(pi.hProcess))); + } +#endif + + return cs; +} + +/** + * Waits for a collection of children to terminate. + * + * Given a collection of Child objects (such as std::vector or + * the convenience children type), waits for the termination of all of + * them. + * + * \remark Blocking remarks: This call blocks if any of the children + * processes in the collection has not finalized execution and + * waits until it terminates. + * + * \return The exit status of the first process that returns an error + * code or, if all of them executed correctly, the exit status + * of the last process in the collection. + */ +template +inline status wait_children(Children &cs) +{ + BOOST_ASSERT(cs.size() >= 2); + + typename Children::iterator it = cs.begin(); + while (it != cs.end()) + { + const status s = it->wait(); + ++it; + if (it == cs.end()) + return s; + else if (!s.exited() || s.exit_status() != EXIT_SUCCESS) + { + while (it != cs.end()) + { + it->wait(); + ++it; + } + return s; + } + } + + BOOST_ASSERT(false); + return cs.begin()->wait(); +} + +} +} + +#endif diff --git a/src/boost/boost/process/pistream.hpp b/src/boost/boost/process/pistream.hpp new file mode 100644 index 000000000..73c86cc04 --- /dev/null +++ b/src/boost/boost/process/pistream.hpp @@ -0,0 +1,116 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/pistream.hpp + * + * Includes the declaration of the pistream class. + */ + +#ifndef BOOST_PROCESS_PISTREAM_HPP +#define BOOST_PROCESS_PISTREAM_HPP + +#include +#include +#include +#include + +namespace boost { +namespace process { + +/** + * Child process' output stream. + * + * The pistream class represents an output communication channel with the + * child process. The child process writes data to this stream and the + * parent process can read it through the pistream object. In other + * words, from the child's point of view, the communication channel is an + * output one, but from the parent's point of view it is an input one; + * hence the confusing pistream name. + * + * pistream objects cannot be copied because they own the file handle + * they use to communicate with the child and because they buffer data + * that flows through the communication channel. + * + * A pistream object behaves as a std::istream stream in all senses. + * The class is only provided because it must provide a method to let + * the caller explicitly close the communication channel. + * + * \remark Blocking remarks: Functions that read data from this + * stream can block if the associated file handle blocks during + * the read. As this class is used to communicate with child + * processes through anonymous pipes, the most typical blocking + * condition happens when the child has no more data to send to + * the pipe's system buffer. When this happens, the buffer + * eventually empties and the system blocks until the writer + * generates some data. + */ +class pistream : public std::istream, public boost::noncopyable +{ +public: + /** + * Creates a new process' output stream. + * + * Given a file handle, this constructor creates a new pistream + * object that owns the given file handle \a fh. Ownership of + * \a fh is transferred to the created pistream object. + * + * \pre \a fh is valid. + * \post \a fh is invalid. + * \post The new pistream object owns \a fh. + */ + explicit pistream(detail::file_handle &fh) + : std::istream(0), + handle_(fh), + systembuf_(handle_.get()) + { + rdbuf(&systembuf_); + } + + /** + * Returns the file handle managed by this stream. + * + * The file handle must not be copied. Copying invalidates + * the source file handle making the pistream unusable. + */ + detail::file_handle &handle() + { + return handle_; + } + + /** + * Closes the file handle managed by this stream. + * + * Explicitly closes the file handle managed by this stream. This + * function can be used by the user to tell the child process it's + * not willing to receive more data. + */ + void close() + { + handle_.close(); + } + +private: + /** + * The file handle managed by this stream. + */ + detail::file_handle handle_; + + /** + * The systembuf object used to manage this stream's data. + */ + detail::systembuf systembuf_; +}; + +} +} + +#endif diff --git a/src/boost/boost/process/posix_child.hpp b/src/boost/boost/process/posix_child.hpp new file mode 100644 index 000000000..ab449b3d9 --- /dev/null +++ b/src/boost/boost/process/posix_child.hpp @@ -0,0 +1,178 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/posix_child.hpp + * + * Includes the declaration of the posix_child class. + */ + +#ifndef BOOST_PROCESS_POSIX_CHILD_HPP +#define BOOST_PROCESS_POSIX_CHILD_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace process { + +/** + * POSIX implementation of the Child concept. + * + * The posix_child class implements the Child concept in a POSIX + * operating system. + * + * A POSIX child differs from a regular child (represented by a + * child object) in that it supports more than three communication + * channels with its parent. These channels are identified by regular + * file descriptors (integers). + * + * This class is built on top of the generic child so as to allow its + * trivial adoption. When a program is changed to use the POSIX-specific + * context (posix_context), it will most certainly need to migrate its + * use of the child class to posix_child. Doing so is only a matter of + * redefining the appropriate object and later using the required extra + * features: there should be no need to modify the existing code (e.g. + * method calls) in any other way. + */ +class posix_child : public child +{ +public: + /** + * Gets a reference to the child's input stream \a desc. + * + * Returns a reference to a postream object that represents one of + * the multiple input communication channels with the child process. + * The channel is identified by \a desc as seen from the child's + * point of view. The parent can use the returned stream to send + * data to the child. + * + * Giving this function the STDIN_FILENO constant (defined in + * unistd.h) is a synonym for the get_stdin() call inherited from + * child. + */ + postream &get_input(int desc) const + { + if (desc == STDIN_FILENO) + return posix_child::get_stdin(); + else + { + input_map_t::const_iterator it = input_map_.find(desc); + BOOST_ASSERT(it != input_map_.end()); + return *it->second; + } + } + + /** + * Gets a reference to the child's output stream \a desc. + * + * Returns a reference to a pistream object that represents one of + * the multiple output communication channels with the child process. + * The channel is identified by \a desc as seen from the child's + * point of view. The parent can use the returned stream to retrieve + * data from the child. + * + * Giving this function the STDOUT_FILENO or STDERR_FILENO constants + * (both defined in unistd.h) are synonyms for the get_stdout() and + * get_stderr() calls inherited from child, respectively. + */ + pistream &get_output(int desc) const + { + if (desc == STDOUT_FILENO) + return posix_child::get_stdout(); + else if (desc == STDERR_FILENO) + return posix_child::get_stderr(); + else + { + output_map_t::const_iterator it = output_map_.find(desc); + BOOST_ASSERT(it != output_map_.end()); + return *it->second; + } + } + + /** + * Constructs a new POSIX child object representing a just + * spawned child process. + * + * Creates a new child object that represents the just spawned process + * \a id. + * + * The \a infoin and \a infoout maps contain the pipes used to handle + * the redirections of the child process; at the moment, no other + * stream_info types are supported. If the launcher was asked to + * redirect any of the three standard flows, their pipes must be + * present in these maps. + */ + posix_child(id_type id, detail::info_map &infoin, detail::info_map &infoout) + : child(id, + detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false), + detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true), + detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true)) + { + for (detail::info_map::iterator it = infoin.begin(); it != infoin.end(); ++it) + { + detail::stream_info &si = it->second; + if (si.type_ == detail::stream_info::use_pipe) + { + BOOST_ASSERT(si.pipe_->wend().valid()); + boost::shared_ptr st(new postream(si.pipe_->wend())); + input_map_.insert(input_map_t::value_type(it->first, st)); + } + } + + for (detail::info_map::iterator it = infoout.begin(); it != infoout.end(); ++it) + { + detail::stream_info &si = it->second; + if (si.type_ == detail::stream_info::use_pipe) + { + BOOST_ASSERT(si.pipe_->rend().valid()); + boost::shared_ptr st(new pistream(si.pipe_->rend())); + output_map_.insert(output_map_t::value_type(it->first, st)); + } + } + } + +private: + /** + * Maps child's file descriptors to postream objects. + */ + typedef std::map > input_map_t; + + /** + * Contains all relationships between child's input file + * descriptors and their corresponding postream objects. + */ + input_map_t input_map_; + + /** + * Maps child's file descriptors to pistream objects. + */ + typedef std::map > output_map_t; + + /** + * Contains all relationships between child's output file + * descriptors and their corresponding pistream objects. + */ + output_map_t output_map_; +}; + +} +} + +#endif diff --git a/src/boost/boost/process/posix_context.hpp b/src/boost/boost/process/posix_context.hpp new file mode 100644 index 000000000..a75fbecfb --- /dev/null +++ b/src/boost/boost/process/posix_context.hpp @@ -0,0 +1,118 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/posix_context.hpp + * + * Includes the declaration of the posix_context class. + */ + +#ifndef BOOST_PROCESS_POSIX_CONTEXT_HPP +#define BOOST_PROCESS_POSIX_CONTEXT_HPP + +#include +#include +#include +#include +#include + +namespace boost { +namespace process { + +/** + * Holds a mapping between native file descriptors and their corresponding + * pipes to set up communication between the parent and the %child process. + */ +typedef std::map behavior_map; + +template +class posix_basic_context : public basic_work_directory_context, public environment_context +{ +public: + /** + * Constructs a new POSIX-specific context. + * + * Constructs a new context. It is configured as follows: + * * All communcation channels with the child process are closed. + * * There are no channel mergings. + * * The initial work directory of the child processes is set to the + * current working directory. + * * The environment variables table is empty. + * * The credentials are the same as those of the current process. + */ + posix_basic_context() + : uid(::getuid()), + euid(::geteuid()), + gid(::getgid()), + egid(::getegid()) + { + } + + /** + * List of input streams that will be redirected. + */ + behavior_map input_behavior; + + /** + * List of output streams that will be redirected. + */ + behavior_map output_behavior; + + /** + * The user credentials. + * + * UID that specifies the user credentials to use to run the %child + * process. Defaults to the current UID. + */ + uid_t uid; + + /** + * The effective user credentials. + * + * EUID that specifies the effective user credentials to use to run + * the %child process. Defaults to the current EUID. + */ + uid_t euid; + + /** + * The group credentials. + * + * GID that specifies the group credentials to use to run the %child + * process. Defaults to the current GID. + */ + gid_t gid; + + /** + * The effective group credentials. + * + * EGID that specifies the effective group credentials to use to run + * the %child process. Defaults to the current EGID. + */ + gid_t egid; + + /** + * The chroot directory, if any. + * + * Specifies the directory in which the %child process is chrooted + * before execution. Empty if this feature is not desired. + */ + Path chroot; +}; + +/** + * Default instantiation of posix_basic_context. + */ +typedef posix_basic_context posix_context; + +} +} + +#endif diff --git a/src/boost/boost/process/posix_operations.hpp b/src/boost/boost/process/posix_operations.hpp new file mode 100644 index 000000000..31cfabe2a --- /dev/null +++ b/src/boost/boost/process/posix_operations.hpp @@ -0,0 +1,81 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/posix_operations.hpp + * + * Provides miscellaneous free functions specific to POSIX operating + * systems. + */ + +#ifndef BOOST_PROCESS_POSIX_OPERATIONS_HPP +#define BOOST_PROCESS_POSIX_OPERATIONS_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace process { + +/** + * Starts a new child process. + * + * Given an executable and the set of arguments passed to it, starts + * a new process with all the parameters configured in the context. + * The context can be reused afterwards to launch other different + * processes. + * + * \return A handle to the new child process. + */ +template +inline posix_child posix_launch(const Executable &exe, const Arguments &args, const Posix_Context &ctx) +{ + detail::info_map input_info; + for (behavior_map::const_iterator it = ctx.input_behavior.begin(); it != ctx.input_behavior.end(); ++it) + { + if (it->second.get_type() != stream_behavior::close) + { + detail::stream_info si = detail::stream_info(it->second, false); + input_info.insert(detail::info_map::value_type(it->first, si)); + } + } + + detail::info_map output_info; + for (behavior_map::const_iterator it = ctx.output_behavior.begin(); it != ctx.output_behavior.end(); ++it) + { + if (it->second.get_type() != stream_behavior::close) + { + detail::stream_info si = detail::stream_info(it->second, true); + output_info.insert(detail::info_map::value_type(it->first, si)); + } + } + + detail::posix_setup s; + s.work_directory = ctx.work_directory; + s.uid = ctx.uid; + s.euid = ctx.euid; + s.gid = ctx.gid; + s.egid = ctx.egid; + s.chroot = ctx.chroot; + + pid_t pid = detail::posix_start(exe, args, ctx.environment, input_info, output_info, s); + + return posix_child(pid, input_info, output_info); +} + +} +} + +#endif diff --git a/src/boost/boost/process/posix_status.hpp b/src/boost/boost/process/posix_status.hpp new file mode 100644 index 000000000..30c0b93d9 --- /dev/null +++ b/src/boost/boost/process/posix_status.hpp @@ -0,0 +1,128 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/posix_status.hpp + * + * Includes the declaration of the posix_status class. + */ + +#ifndef BOOST_PROCESS_POSIX_STATUS_HPP +#define BOOST_PROCESS_POSIX_STATUS_HPP + +#include + +#if defined(BOOST_POSIX_API) +# include +#elif defined(BOOST_WINDOWS_API) +#else +# error "Unsupported platform." +#endif + +#include +#include + +namespace boost { +namespace process { + +/** + * Status returned by a finalized %child process on a POSIX system. + * + * This class represents the %status returned by a child process after it + * has terminated. It contains some methods not available in the status + * class that provide information only available in POSIX systems. + */ +class posix_status : public status +{ +public: + /** + * Creates a posix_status object from an existing status object. + * + * Creates a new status object representing the exit status of a + * child process. The construction is done based on an existing + * status object which already contains all the available + * information: this class only provides controlled access to it. + */ + posix_status(const status &s) + : status(s) + { + } + + /** + * Returns whether the process exited due to an external + * signal. + */ + bool signaled() const + { + return WIFSIGNALED(flags_); + } + + /** + * If signaled, returns the terminating signal code. + * + * If the process was signaled, returns the terminating signal code. + * + * \pre signaled() is true. + */ + int term_signal() const + { + BOOST_ASSERT(signaled()); + + return WTERMSIG(flags_); + } + + /** + * If signaled, returns whether the process dumped core. + * + * If the process was signaled, returns whether the process + * produced a core dump. + * + * \pre signaled() is true. + */ + bool dumped_core() const + { + BOOST_ASSERT(signaled()); + +#ifdef WCOREDUMP + return WCOREDUMP(flags_); +#else + return false; +#endif + } + + /** + * Returns whether the process was stopped by an external + * signal. + */ + bool stopped() const + { + return WIFSTOPPED(flags_); + } + + /** + * If stopped, returns the stop signal code. + * + * If the process was stopped, returns the stop signal code. + * + * \pre stopped() is true. + */ + int stop_signal() const + { + BOOST_ASSERT(stopped()); + + return WSTOPSIG(flags_); + } +}; + +} +} + +#endif diff --git a/src/boost/boost/process/postream.hpp b/src/boost/boost/process/postream.hpp new file mode 100644 index 000000000..b3b79b0f9 --- /dev/null +++ b/src/boost/boost/process/postream.hpp @@ -0,0 +1,117 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/postream.hpp + * + * Includes the declaration of the postream class. + */ + +#ifndef BOOST_PROCESS_POSTREAM_HPP +#define BOOST_PROCESS_POSTREAM_HPP + +#include +#include +#include +#include + +namespace boost { +namespace process { + +/** + * Child process' input stream. + * + * The postream class represents an input communication channel with the + * child process. The child process reads data from this stream and the + * parent process can write to it through the postream object. In other + * words, from the child's point of view, the communication channel is an + * input one, but from the parent's point of view it is an output one; + * hence the confusing postream name. + * + * postream objects cannot be copied because they own the file handle + * they use to communicate with the child and because they buffer data + * that flows through the communication channel. + * + * A postream object behaves as a std::ostream stream in all senses. + * The class is only provided because it must provide a method to let + * the caller explicitly close the communication channel. + * + * \remark Blocking remarks: Functions that write data to this + * stream can block if the associated file handle blocks during + * the write. As this class is used to communicate with child + * processes through anonymous pipes, the most typical blocking + * condition happens when the child is not processing the data + * in the pipe's system buffer. When this happens, the buffer + * eventually fills up and the system blocks until the reader + * consumes some data, leaving some new room. + */ +class postream : public std::ostream, public boost::noncopyable +{ +public: + /** + * Creates a new process' input stream. + * + * Given a file handle, this constructor creates a new postream + * object that owns the given file handle \a fh. Ownership of + * \a fh is transferred to the created postream object. + * + * \pre \a fh is valid. + * \post \a fh is invalid. + * \post The new postream object owns \a fh. + */ + explicit postream(detail::file_handle &fh) + : std::ostream(0), + handle_(fh), + systembuf_(handle_.get()) + { + rdbuf(&systembuf_); + } + + /** + * Returns the file handle managed by this stream. + * + * The file handle must not be copied. Copying invalidates + * the source file handle making the postream unusable. + */ + detail::file_handle &handle() + { + return handle_; + } + + /** + * Closes the file handle managed by this stream. + * + * Explicitly closes the file handle managed by this stream. This + * function can be used by the user to tell the child process there + * is no more data to send. + */ + void close() + { + systembuf_.sync(); + handle_.close(); + } + +private: + /** + * The file handle managed by this stream. + */ + detail::file_handle handle_; + + /** + * The systembuf object used to manage this stream's data. + */ + detail::systembuf systembuf_; +}; + +} +} + +#endif diff --git a/src/boost/boost/process/process.hpp b/src/boost/boost/process/process.hpp new file mode 100644 index 000000000..06f16481d --- /dev/null +++ b/src/boost/boost/process/process.hpp @@ -0,0 +1,130 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/process.hpp + * + * Includes the declaration of the process class. + */ + +#ifndef BOOST_PROCESS_PROCESS_HPP +#define BOOST_PROCESS_PROCESS_HPP + +#include + +#if defined(BOOST_POSIX_API) +# include +# include +#elif defined(BOOST_WINDOWS_API) +# include +# include +#else +# error "Unsupported platform." +#endif + +#include +#include + +namespace boost { +namespace process { + +/** + * Generic implementation of the Process concept. + * + * The process class implements the Process concept in an operating system + * agnostic way. + */ +class process +{ +public: +#if defined(BOOST_PROCESS_DOXYGEN) + /** + * Opaque name for the native process' identifier type. + * + * Each operating system identifies processes using a specific type. + * The \a id_type type is used to transparently refer to a process + * regardless of the operating system in which this class is used. + * + * This type is guaranteed to be an integral type on all supported + * platforms. + */ + typedef NativeProcessId id_type; +#elif defined(BOOST_POSIX_API) + typedef pid_t id_type; +#elif defined(BOOST_WINDOWS_API) + typedef DWORD id_type; +#endif + + /** + * Constructs a new process object. + * + * Creates a new process object that represents a running process + * within the system. + */ + process(id_type id) + : id_(id) + { + } + + /** + * Returns the process' identifier. + */ + id_type get_id() const + { + return id_; + } + + /** + * Terminates the process execution. + * + * Forces the termination of the process execution. Some platforms + * allow processes to ignore some external termination notifications + * or to capture them for a proper exit cleanup. You can set the + * \a force flag to true in them to force their termination regardless + * of any exit handler. + * + * After this call, accessing this object can be dangerous because the + * process identifier may have been reused by a different process. It + * might still be valid, though, if the process has refused to die. + * + * \throw boost::system::system_error If the system call used to + * terminate the process fails. + */ + void terminate(bool force = false) const + { +#if defined(BOOST_POSIX_API) + if (::kill(id_, force ? SIGKILL : SIGTERM) == -1) + boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::process::terminate: kill(2) failed")); +#elif defined(BOOST_WINDOWS_API) + HANDLE h = ::OpenProcess(PROCESS_TERMINATE, FALSE, id_); + if (h == NULL) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::process::terminate: OpenProcess failed")); + if (!::TerminateProcess(h, EXIT_FAILURE)) + { + ::CloseHandle(h); + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::process::terminate: TerminateProcess failed")); + } + if (!::CloseHandle(h)) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::process::terminate: CloseHandle failed")); +#endif + } + +private: + /** + * The process' identifier. + */ + id_type id_; +}; + +} +} + +#endif diff --git a/src/boost/boost/process/self.hpp b/src/boost/boost/process/self.hpp new file mode 100644 index 000000000..79828ca17 --- /dev/null +++ b/src/boost/boost/process/self.hpp @@ -0,0 +1,134 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/self.hpp + * + * Includes the declaration of the self class. + */ + +#ifndef BOOST_PROCESS_SELF_HPP +#define BOOST_PROCESS_SELF_HPP + +#include + +#if defined(BOOST_POSIX_API) +# include +#elif defined(BOOST_WINDOWS_API) +# include +#else +# error "Unsupported platform." +#endif + +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_POSIX_API) +extern "C" +{ + extern char **environ; +} +#endif + +namespace boost { +namespace process { + +/** + * Generic implementation of the Process concept. + * + * The self singleton provides access to the current process. + */ +class self : public process, boost::noncopyable +{ +public: + /** + * Returns the self instance representing the caller's process. + */ + static self &get_instance() + { + static self *instance = 0; + if (!instance) + instance = new self; + return *instance; + } + + /** + * Returns the current environment. + * + * Returns the current process' environment variables. Modifying the + * returned object has no effect on the current environment. + */ + static environment get_environment() + { + environment e; + +#if defined(BOOST_POSIX_API) + char **env = ::environ; + while (*env) + { + std::string s = *env; + std::string::size_type pos = s.find('='); + e.insert(boost::process::environment::value_type(s.substr(0, pos), s.substr(pos + 1))); + ++env; + } +#elif defined(BOOST_WINDOWS_API) +#ifdef GetEnvironmentStrings +#undef GetEnvironmentStrings +#endif + char *environ = ::GetEnvironmentStrings(); + if (!environ) + boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::self::get_environment: GetEnvironmentStrings failed")); + try + { + char *env = environ; + while (*env) + { + std::string s = env; + std::string::size_type pos = s.find('='); + e.insert(boost::process::environment::value_type(s.substr(0, pos), s.substr(pos + 1))); + env += s.size() + 1; + } + } + catch (...) + { + ::FreeEnvironmentStringsA(environ); + throw; + } + ::FreeEnvironmentStringsA(environ); +#endif + + return e; + } + +private: + /** + * Constructs a new self object. + * + * Creates a new self object that represents the current process. + */ + self() : +#if defined(BOOST_POSIX_API) + process(::getpid()) +#elif defined(BOOST_WINDOWS_API) + process(::GetCurrentProcessId()) +#endif + { + } +}; + +} +} + +#endif diff --git a/src/boost/boost/process/status.hpp b/src/boost/boost/process/status.hpp new file mode 100644 index 000000000..ef64d3705 --- /dev/null +++ b/src/boost/boost/process/status.hpp @@ -0,0 +1,105 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/status.hpp + * + * Includes the declaration of the status class. + */ + +#ifndef BOOST_PROCESS_STATUS_HPP +#define BOOST_PROCESS_STATUS_HPP + +#include + +#if defined(BOOST_POSIX_API) +# include +#elif defined(BOOST_WINDOWS_API) +#else +# error "Unsupported platform." +#endif + +#include + +namespace boost { +namespace process { + +class child; + +/** + * Status returned by a finalized %child process. + * + * This class represents the %status returned by a child process after it + * has terminated. It only provides that information available under all + * supported platforms. + * + * \see posix_status + */ +class status +{ + friend class child; + +public: + /** + * Returns whether the process exited gracefully or not. + */ + bool exited() const + { +#if defined(BOOST_POSIX_API) + return WIFEXITED(flags_); +#elif defined(BOOST_WINDOWS_API) + return true; +#endif + } + + /** + * If exited, returns the exit code. + * + * If the process exited, returns the exit code it returned. + * + * \pre exited() is true. + */ + int exit_status() const + { + BOOST_ASSERT(exited()); +#if defined(BOOST_POSIX_API) + return WEXITSTATUS(flags_); +#elif defined(BOOST_WINDOWS_API) + return flags_; +#endif + } + +protected: + /** + * Creates a status object based on exit information. + * + * Creates a new status object representing the exit status of a + * child process. + * + * \param flags In a POSIX system this parameter contains the + * flags returned by the ::waitpid() call. In a + * Windows system it contains the exit code only. + */ + status(int flags) + : flags_(flags) + { + } + + /** + * OS-specific codification of exit status. + */ + int flags_; +}; + +} +} + +#endif diff --git a/src/boost/boost/process/stream_behavior.hpp b/src/boost/boost/process/stream_behavior.hpp new file mode 100644 index 000000000..a61e42794 --- /dev/null +++ b/src/boost/boost/process/stream_behavior.hpp @@ -0,0 +1,234 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/stream_behavior.hpp + * + * Includes the declaration of the stream_behavior class and associated + * free functions. + */ + +#ifndef BOOST_PROCESS_STREAM_BEHAVIOR_HPP +#define BOOST_PROCESS_STREAM_BEHAVIOR_HPP + +#include + +namespace boost { +namespace process { + +namespace detail { + struct stream_info; +} + +/** + * Describes the possible states for a communication stream. + */ +class stream_behavior +{ +public: + friend struct detail::stream_info; + friend stream_behavior capture_stream(); + friend stream_behavior close_stream(); + friend stream_behavior inherit_stream(); + friend stream_behavior redirect_stream_to_stdout(); + friend stream_behavior silence_stream(); +#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) + friend stream_behavior posix_redirect_stream(int to); +#endif + + /** + * Describes the possible states for a communication stream. + */ + enum type + { + /** + * The child's stream is connected to the parent by using an + * anonymous pipe so that they can send and receive data to/from + * each other. + */ + capture, + + /** + * The child's stream is closed upon startup so that it will not + * have any access to it. + */ + close, + + /** + * The child's stream is connected to the same stream used by the + * parent. In other words, the corresponding parent's stream is + * inherited. + */ + inherit, + + /** + * The child's stream is connected to child's standard output. + * This is typically used when configuring the standard error + * stream. + */ + redirect_to_stdout, + + /** + * The child's stream is redirected to a null device so that its + * input is always zero or its output is lost, depending on + * whether the stream is an input or an output one. It is + * important to notice that this is different from close because + * the child is still able to write data. If we closed, e.g. + * stdout, the child might not work at all! + */ + silence, + +#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) + /** + * The child redirects the stream's output to the provided file + * descriptor. This is a generalization of the portable + * redirect_to_stdout behavior. + */ + posix_redirect +#endif + }; + + /** + * Constructs a new stream behavior of type close. + * + * The public constructor creates a new stream behavior that defaults + * to the close behavior. In general, you will want to use the + * available free functions to construct a stream behavior (including + * the close one). + */ + stream_behavior() + : type_(stream_behavior::close) + { + } + + /** + * Returns this stream's behavior type. + */ + type get_type() const + { + return type_; + } + +private: + /** + * Constructs a new stream behavior of type \a t. + * + * Constructs a new stream behavior of type \a t. It is the + * responsibility of the caller to fill in any other attributes + * required by the specified type, if any. + */ + stream_behavior(type t) + : type_(t) + { + } + + /** + * This stream's behavior type. + */ + type type_; + +#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) + /** + * File descriptor the stream is redirected to. + */ + int desc_to_; +#endif +}; + +/** + * Creates a new stream_behavior of type stream_behavior::capture. + * + * Creates a new stream_behavior of type stream_behavior::capture, + * meaning that the child's stream is connected to the parent by using an + * anonymous pipe so that they can send and receive data to/from each + * other. + */ +inline stream_behavior capture_stream() +{ + return stream_behavior(stream_behavior::capture); +} + +/** + * Creates a new stream_behavior of type stream_behavior::close. + * + * Creates a new stream_behavior of type stream_behavior::close, + * meaning that the child's stream is closed upon startup so that it + * will not have any access to it. + */ +inline stream_behavior close_stream() +{ + return stream_behavior(stream_behavior::close); +} + +/** + * Creates a new stream_behavior of type stream_behavior::inherit. + * + * Creates a new stream_behavior of type stream_behavior::inherit, + * meaning that the child's stream is connected to the same stream used + * by the parent. In other words, the corresponding parent's stream is + * inherited. + */ +inline stream_behavior inherit_stream() +{ + return stream_behavior(stream_behavior::inherit); +} + +/** + * Creates a new stream_behavior of type + * stream_behavior::redirect_to_stdout. + * + * Creates a new stream_behavior of type + * stream_behavior::redirect_to_stdout, meaning that the child's stream is + * connected to child's standard output. This is typically used when + * configuring the standard error stream. + */ +inline stream_behavior redirect_stream_to_stdout() +{ + return stream_behavior(stream_behavior::redirect_to_stdout); +} + +/** + * Creates a new stream_behavior of type stream_behavior::silence. + * + * Creates a new stream_behavior of type stream_behavior::silence, + * meaning that the child's stream is redirected to a null device so that + * its input is always zero or its output is lost, depending on whether + * the stream is an input or an output one. It is important to notice + * that this is different from close because the child is still able to + * write data. If we closed, e.g. stdout, the child might not work at + * all! + */ +inline stream_behavior silence_stream() +{ + return stream_behavior(stream_behavior::silence); +} + +#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) +/** + * Creates a new stream_behavior of type stream_behavior::posix_redirect. + * + * Creates a new stream_behavior of type stream_behavior::posix_redirect, + * meaning that the child's stream is redirected to the \a to child's + * file descriptor. This is a generalization of the portable + * redirect_stream_to_stdout() behavior. + */ +inline stream_behavior posix_redirect_stream(int to) +{ + stream_behavior sb(stream_behavior::posix_redirect); + sb.desc_to_ = to; + return sb; +} +#endif + +} +} + +#endif diff --git a/src/boost/boost/process/win32_child.hpp b/src/boost/boost/process/win32_child.hpp new file mode 100644 index 000000000..49b0fdb0c --- /dev/null +++ b/src/boost/boost/process/win32_child.hpp @@ -0,0 +1,128 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/win32_child.hpp + * + * Includes the declaration of the win32_child class. + */ + +#ifndef BOOST_PROCESS_WIN32_CHILD_HPP +#define BOOST_PROCESS_WIN32_CHILD_HPP + +#include +#include +#include + +namespace boost { +namespace process { + +/** + * Windows implementation of the Child concept. + * + * The win32_child class implements the Child concept in a Windows + * operating system. + * + * A Windows child differs from a regular %child (represented by a + * child object) in that it holds additional information about a process. + * Aside from the standard handle, it also includes a handle to the + * process' main thread, together with identifiers to both entities. + * + * This class is built on top of the generic child so as to allow its + * trivial adoption. When a program is changed to use the + * Windows-specific context (win32_context), it will most certainly need + * to migrate its use of the child class to win32_child. Doing so is only + * a matter of redefining the appropriate object and later using the + * required extra features: there should be no need to modify the existing + * code (e.g. method calls) in any other way. + */ +class win32_child : public child +{ +public: + /** + * Constructs a new Windows child object representing a just + * spawned %child process. + * + * Creates a new %child object that represents the process described by + * the \a pi structure. + * + * The \a fhstdin, \a fhstdout and \a fhstderr parameters hold the + * communication streams used to interact with the %child process if + * the launcher configured redirections. See the parent class' + * constructor for more details on these. + * + * \see child + */ + win32_child(const PROCESS_INFORMATION &pi, detail::file_handle fhstdin, detail::file_handle fhstdout, detail::file_handle fhstderr) + : child(pi.dwProcessId, fhstdin, fhstdout, fhstderr, pi.hProcess), + process_information_(pi), + thread_handle_(process_information_.hThread) + { + } + + /** + * Returns the process handle. + * + * Returns a process-specific handle that can be used to access the + * process. This is the value of the \a hProcess field in the + * PROCESS_INFORMATION structure returned by CreateProcess(). + * + * \see get_id() + */ + HANDLE get_handle() const + { + return process_information_.hProcess; + } + + /** + * Returns the primary thread's handle. + * + * Returns a handle to the primary thread of the new process. This is + * the value of the \a hThread field in the PROCESS_INFORMATION + * structure returned by CreateProcess(). + * + * \see get_primary_thread_id() + */ + HANDLE get_primary_thread_handle() const + { + return process_information_.hThread; + } + + /** + * Returns the primary thread's identifier. + * + * Returns a system-wide value that identifies the process's primary + * thread. This is the value of the \a dwThreadId field in the + * PROCESS_INFORMATION structure returned by CreateProcess(). + * + * \see get_primary_thread_handle() + */ + DWORD get_primary_thread_id() const + { + return process_information_.dwThreadId; + } + +private: + /** + * Windows-specific process information. + */ + PROCESS_INFORMATION process_information_; + + /** + * Thread handle owned by RAII object. + */ + detail::file_handle thread_handle_; +}; + +} +} + +#endif diff --git a/src/boost/boost/process/win32_context.hpp b/src/boost/boost/process/win32_context.hpp new file mode 100644 index 000000000..c1cb6b6a6 --- /dev/null +++ b/src/boost/boost/process/win32_context.hpp @@ -0,0 +1,61 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/win_32context.hpp + * + * Includes the declaration of the win32_context class. + */ + +#ifndef BOOST_PROCESS_WIN32_CONTEXT_HPP +#define BOOST_PROCESS_WIN32_CONTEXT_HPP + +#include +#include +#include + +namespace boost { +namespace process { + +/** + * Generic implementation of the Context concept. + * + * The context class implements the Context concept in an operating + * system agnostic way; it allows spawning new child processes using + * a single and common interface across different systems. + */ +template +class win32_basic_context : public basic_context +{ +public: + /** + * Initializes the Win32-specific process startup information with NULL. + */ + win32_basic_context() + : startupinfo(NULL) + { + } + + /** + * Win32-specific process startup information. + */ + STARTUPINFOA *startupinfo; +}; + +/** + * Default instantiation of win32_basic_context. + */ +typedef win32_basic_context win32_context; + +} +} + +#endif diff --git a/src/boost/boost/process/win32_operations.hpp b/src/boost/boost/process/win32_operations.hpp new file mode 100644 index 000000000..04e55c8a5 --- /dev/null +++ b/src/boost/boost/process/win32_operations.hpp @@ -0,0 +1,77 @@ +// +// Boost.Process +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008, 2009 Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * \file boost/process/win32_operations.hpp + * + * Provides miscellaneous free functions specific to Windows operating + * systems. + */ + +#ifndef BOOST_PROCESS_WIN32_OPERATIONS_HPP +#define BOOST_PROCESS_WIN32_OPERATIONS_HPP + +#include +#include +#include +#include +#include + +namespace boost { +namespace process { + +/** + * Starts a new child process. + * + * Given an executable and the set of arguments passed to it, starts + * a new process with all the parameters configured in the context. + * The context can be reused afterwards to launch other different + * processes. + * + * \return A handle to the new child process. + */ +template +inline win32_child win32_launch(const Executable &exe, const Arguments &args, const Win32_Context &ctx) +{ + detail::file_handle fhstdin, fhstdout, fhstderr; + + detail::stream_info behin = detail::stream_info(ctx.stdin_behavior, false); + if (behin.type_ == detail::stream_info::use_pipe) + fhstdin = behin.pipe_->wend(); + detail::stream_info behout = detail::stream_info(ctx.stdout_behavior, true); + if (behout.type_ == detail::stream_info::use_pipe) + fhstdout = behout.pipe_->rend(); + detail::stream_info beherr = detail::stream_info(ctx.stderr_behavior, true); + if (beherr.type_ == detail::stream_info::use_pipe) + fhstderr = beherr.pipe_->rend(); + + detail::win32_setup s; + s.work_directory = ctx.work_directory; + + STARTUPINFOA si; + if (!ctx.startupinfo) + { + ::ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + s.startupinfo = &si; + } + else + s.startupinfo = ctx.startupinfo; + + PROCESS_INFORMATION pi = detail::win32_start(exe, args, ctx.environment, behin, behout, beherr, s); + + return win32_child(pi, fhstdin, fhstdout, fhstderr); +} + +} +} + +#endif