summaryrefslogtreecommitdiffstats
path: root/unit/atf-src/tools/io.hpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 18:37:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 18:37:14 +0000
commitea648e70a989cca190cd7403fe892fd2dcc290b4 (patch)
treee2b6b1c647da68b0d4d66082835e256eb30970e8 /unit/atf-src/tools/io.hpp
parentInitial commit. (diff)
downloadbind9-upstream.tar.xz
bind9-upstream.zip
Adding upstream version 1:9.11.5.P4+dfsg.upstream/1%9.11.5.P4+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'unit/atf-src/tools/io.hpp')
-rw-r--r--unit/atf-src/tools/io.hpp436
1 files changed, 436 insertions, 0 deletions
diff --git a/unit/atf-src/tools/io.hpp b/unit/atf-src/tools/io.hpp
new file mode 100644
index 0000000..3fb417b
--- /dev/null
+++ b/unit/atf-src/tools/io.hpp
@@ -0,0 +1,436 @@
+//
+// Automated Testing Framework (atf)
+//
+// Copyright (c) 2007 The NetBSD Foundation, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
+// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
+// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#if !defined(TOOLS_IO_HPP)
+#define TOOLS_IO_HPP
+
+#include <istream>
+#include <ostream>
+#include <streambuf>
+
+#include "auto_array.hpp"
+#include "fs.hpp"
+
+namespace tools {
+namespace io {
+
+// ------------------------------------------------------------------------
+// The "file_handle" class.
+// ------------------------------------------------------------------------
+
+//!
+//! \brief 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:
+ //!
+ //! \brief 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 in a POSIX system, \a NativeSystemHandle is
+ //! an integer type while it is a \a HANDLE in a Win32 system.
+ //!
+ typedef int handle_type;
+
+ //!
+ //! \brief 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 is_valid()
+ //!
+ file_handle(void);
+
+ //!
+ //! \brief 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 disown().
+ //!
+ //! \pre The native file handle must be valid; a close operation must
+ //! succeed on it.
+ //!
+ //! \see disown()
+ //!
+ file_handle(handle_type h);
+
+ //!
+ //! \brief 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 need 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);
+
+ //!
+ //! \brief Releases resources if the handle is valid.
+ //!
+ //! If the file handle is valid, the destructor closes it.
+ //!
+ //! \see is_valid()
+ //!
+ ~file_handle(void);
+
+ //!
+ //! \brief 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 need 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);
+
+ //!
+ //! \brief 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 applications can be
+ //! executed other than the destructor.
+ //!
+ //! \return True if the file handle is valid; false otherwise.
+ //!
+ bool is_valid(void) const;
+
+ //!
+ //! \brief 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(void);
+
+ //!
+ //! \brief 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 disown(void);
+
+ //!
+ //! \brief 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, disown() shall be used.
+ //!
+ //! \pre The file handle is valid.
+ //! \return The native file handle.
+ //!
+ handle_type get(void) const;
+
+ //!
+ //! \brief 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 matches the current value of the handle, this is a no-op.
+ //! This is done for simplicity, to avoid the caller having to check
+ //! this condition on its own.
+ //!
+ //! 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 system_error If the internal remapping operation fails.
+ //!
+ void posix_remap(handle_type h);
+
+private:
+ //!
+ //! \brief 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 m_handle;
+
+ //!
+ //! \brief 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
+ //! Win32 due to the value being of a complex type.
+ //!
+ static handle_type invalid_value(void);
+};
+
+// ------------------------------------------------------------------------
+// The "systembuf" class.
+// ------------------------------------------------------------------------
+
+//!
+//! \brief 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
+{
+ // Non-copyable.
+ systembuf(const systembuf&);
+ systembuf& operator=(const systembuf&);
+
+public:
+ typedef int handle_type;
+
+ //!
+ //! \brief 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.
+ //!
+ explicit systembuf(handle_type h, std::size_t bufsize = 8192);
+ ~systembuf(void);
+
+private:
+ //!
+ //! \brief Native file handle used by the systembuf object.
+ //!
+ handle_type m_handle;
+
+ //!
+ //! \brief Internal buffer size used during read and write operations.
+ //!
+ std::size_t m_bufsize;
+
+ //!
+ //! \brief Internal buffer used during read operations.
+ //!
+ char* m_read_buf;
+
+ //!
+ //! \brief Internal buffer used during write operations.
+ //!
+ char* m_write_buf;
+
+protected:
+ //!
+ //! \brief Reads new data from the native file handle.
+ //!
+ //! This operation is called by input methods when there are 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(void);
+
+ //!
+ //! \brief 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);
+
+ //!
+ //! \brief 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(void);
+};
+
+// ------------------------------------------------------------------------
+// The "pistream" class.
+// ------------------------------------------------------------------------
+
+//!
+//! \brief 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 <b>Blocking remarks</b>: 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
+{
+ // Non-copyable.
+ pistream(const pistream&);
+ pistream& operator=(const pistream&);
+
+ //!
+ //! \brief The systembuf object used to manage this stream's data.
+ //!
+ systembuf m_systembuf;
+
+public:
+ //!
+ //! \brief 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(const int);
+};
+
+// ------------------------------------------------------------------------
+// The "muxer" class.
+// ------------------------------------------------------------------------
+
+class muxer {
+ // Non-copyable.
+ muxer(const muxer&);
+ muxer& operator=(const muxer&);
+
+ const int* m_fds;
+ const size_t m_nfds;
+
+ const size_t m_bufsize;
+ tools::auto_array< std::string > m_buffers;
+
+protected:
+ virtual void line_callback(const size_t, const std::string&) = 0;
+
+ size_t read_one(const size_t, const int, std::string&, const bool);
+
+public:
+ muxer(const int*, const size_t, const size_t bufsize = 1024);
+ virtual ~muxer(void);
+
+ void mux(volatile const bool&);
+ void flush(void);
+};
+
+} // namespace io
+} // namespace tools
+
+#endif // !defined(TOOLS_IO_HPP)