1//
2// Automated Testing Framework (atf)
3//
4// Copyright (c) 2007 The NetBSD Foundation, Inc.
5// All rights reserved.
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions
9// are met:
10// 1. Redistributions of source code must retain the above copyright
11//    notice, this list of conditions and the following disclaimer.
12// 2. Redistributions in binary form must reproduce the above copyright
13//    notice, this list of conditions and the following disclaimer in the
14//    documentation and/or other materials provided with the distribution.
15//
16// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29
30#if !defined(_ATF_RUN_IO_HPP_)
31#define _ATF_RUN_IO_HPP_
32
33#include <istream>
34#include <ostream>
35#include <streambuf>
36
37#include "fs.hpp"
38
39#include "../atf-c++/utils.hpp"
40
41namespace atf {
42namespace atf_run {
43
44// ------------------------------------------------------------------------
45// The "file_handle" class.
46// ------------------------------------------------------------------------
47
48//!
49//! \brief Simple RAII model for system file handles.
50//!
51//! The \a file_handle class is a simple RAII model for native system file
52//! handles.  This class wraps one of such handles grabbing its ownership,
53//! and automaticaly closes it upon destruction.  It is basically used
54//! inside the library to avoid leaking open file handles, shall an
55//! unexpected execution trace occur.
56//!
57//! A \a file_handle object can be copied but doing so invalidates the
58//! source object.  There can only be a single valid \a file_handle object
59//! for a given system file handle.  This is similar to std::auto_ptr\<\>'s
60//! semantics.
61//!
62//! This class also provides some convenience methods to issue special file
63//! operations under their respective platforms.
64//!
65class file_handle
66{
67public:
68    //!
69    //! \brief Opaque name for the native handle type.
70    //!
71    //! Each operating system identifies file handles using a specific type.
72    //! The \a handle_type type is used to transparently refer to file
73    //! handles regarless of the operating system in which this class is
74    //! used.
75    //!
76    //! If this class is used in a POSIX system, \a NativeSystemHandle is
77    //! an integer type while it is a \a HANDLE in a Win32 system.
78    //!
79    typedef int handle_type;
80
81    //!
82    //! \brief Constructs an invalid file handle.
83    //!
84    //! This constructor creates a new \a file_handle object that represents
85    //! an invalid file handle.  An invalid file handle can be copied but
86    //! cannot be manipulated in any way (except checking for its validity).
87    //!
88    //! \see is_valid()
89    //!
90    file_handle(void);
91
92    //!
93    //! \brief Constructs a new file handle from a native file handle.
94    //!
95    //! This constructor creates a new \a file_handle object that takes
96    //! ownership of the given \a h native file handle.  The user must not
97    //! close \a h on his own during the lifetime of the new object.
98    //! Ownership can be reclaimed using disown().
99    //!
100    //! \pre The native file handle must be valid; a close operation must
101    //!      succeed on it.
102    //!
103    //! \see disown()
104    //!
105    file_handle(handle_type h);
106
107    //!
108    //! \brief Copy constructor; invalidates the source handle.
109    //!
110    //! This copy constructor creates a new file handle from a given one.
111    //! Ownership of the native file handle is transferred to the new
112    //! object, effectively invalidating the source file handle.  This
113    //! avoids having two live \a file_handle objects referring to the
114    //! same native file handle.  The source file handle need not be
115    //! valid in the name of simplicity.
116    //!
117    //! \post The source file handle is invalid.
118    //! \post The new file handle owns the source's native file handle.
119    //!
120    file_handle(const file_handle& fh);
121
122    //!
123    //! \brief Releases resources if the handle is valid.
124    //!
125    //! If the file handle is valid, the destructor closes it.
126    //!
127    //! \see is_valid()
128    //!
129    ~file_handle(void);
130
131    //!
132    //! \brief Assignment operator; invalidates the source handle.
133    //!
134    //! This assignment operator transfers ownership of the RHS file
135    //! handle to the LHS one, effectively invalidating the source file
136    //! handle.  This avoids having two live \a file_handle objects
137    //! referring to the same native file handle.  The source file
138    //! handle need not be valid in the name of simplicity.
139    //!
140    //! \post The RHS file handle is invalid.
141    //! \post The LHS file handle owns RHS' native file handle.
142    //! \return A reference to the LHS file handle.
143    //!
144    file_handle& operator=(const file_handle& fh);
145
146    //!
147    //! \brief Checks whether the file handle is valid or not.
148    //!
149    //! Returns a boolean indicating whether the file handle is valid or
150    //! not.  If the file handle is invalid, no other applications can be
151    //! executed other than the destructor.
152    //!
153    //! \return True if the file handle is valid; false otherwise.
154    //!
155    bool is_valid(void) const;
156
157    //!
158    //! \brief Closes the file handle.
159    //!
160    //! Explicitly closes the file handle, which must be valid.  Upon
161    //! exit, the handle is not valid any more.
162    //!
163    //! \pre The file handle is valid.
164    //! \post The file handle is invalid.
165    //! \post The native file handle is closed.
166    //!
167    void close(void);
168
169    //!
170    //! \brief Reclaims ownership of the native file handle.
171    //!
172    //! Explicitly reclaims ownership of the native file handle contained
173    //! in the \a file_handle object, returning the native file handle.
174    //! The caller is responsible of closing it later on.
175    //!
176    //! \pre The file handle is valid.
177    //! \post The file handle is invalid.
178    //! \return The native file handle.
179    //!
180    handle_type disown(void);
181
182    //!
183    //! \brief Gets the native file handle.
184    //!
185    //! Returns the native file handle for the \a file_handle object.
186    //! The caller can issue any operation on it except closing it.
187    //! If closing is required, disown() shall be used.
188    //!
189    //! \pre The file handle is valid.
190    //! \return The native file handle.
191    //!
192    handle_type get(void) const;
193
194    //!
195    //! \brief Changes the native file handle to the given one.
196    //!
197    //! Given a new native file handle \a h, this operation assigns this
198    //! handle to the current object, closing its old native file handle.
199    //! In other words, it first calls dup2() to remap the old handle to
200    //! the new one and then closes the old handle.
201    //!
202    //! If \a h matches the current value of the handle, this is a no-op.
203    //! This is done for simplicity, to avoid the caller having to check
204    //! this condition on its own.
205    //!
206    //! If \a h is open, it is automatically closed by dup2().
207    //!
208    //! This operation is only available in POSIX systems.
209    //!
210    //! \pre The file handle is valid.
211    //! \pre The native file handle \a h is valid; i.e., it must be
212    //!      closeable.
213    //! \post The file handle's native file handle is \a h.
214    //! \throw system_error If the internal remapping operation fails.
215    //!
216    void posix_remap(handle_type h);
217
218private:
219    //!
220    //! \brief Internal handle value.
221    //!
222    //! This variable holds the native handle value for the file handle
223    //! hold by this object.  It is interesting to note that this needs
224    //! to be mutable because the copy constructor and the assignment
225    //! operator invalidate the source object.
226    //!
227    mutable handle_type m_handle;
228
229    //!
230    //! \brief Constant function representing an invalid handle value.
231    //!
232    //! Returns the platform-specific handle value that represents an
233    //! invalid handle.  This is a constant function rather than a regular
234    //! constant because, in the latter case, we cannot define it under
235    //! Win32 due to the value being of a complex type.
236    //!
237    static handle_type invalid_value(void);
238};
239
240// ------------------------------------------------------------------------
241// The "systembuf" class.
242// ------------------------------------------------------------------------
243
244//!
245//! \brief std::streambuf implementation for system file handles.
246//!
247//! systembuf provides a std::streambuf implementation for system file
248//! handles.  Contrarywise to file_handle, this class does \b not take
249//! ownership of the native file handle; this should be taken care of
250//! somewhere else.
251//!
252//! This class follows the expected semantics of a std::streambuf object.
253//! However, it is not copyable to avoid introducing inconsistences with
254//! the on-disk file and the in-memory buffers.
255//!
256class systembuf :
257    public std::streambuf, atf::utils::noncopyable
258{
259public:
260    typedef int handle_type;
261
262    //!
263    //! \brief Constructs a new systembuf for the given file handle.
264    //!
265    //! This constructor creates a new systembuf object that reads or
266    //! writes data from/to the \a h native file handle.  This handle
267    //! is \b not owned by the created systembuf object; the code
268    //! should take care of it externally.
269    //!
270    //! This class buffers input and output; the buffer size may be
271    //! tuned through the \a bufsize parameter, which defaults to 8192
272    //! bytes.
273    //!
274    //! \see pistream.
275    //!
276    explicit systembuf(handle_type h, std::size_t bufsize = 8192);
277    ~systembuf(void);
278
279private:
280    //!
281    //! \brief Native file handle used by the systembuf object.
282    //!
283    handle_type m_handle;
284
285    //!
286    //! \brief Internal buffer size used during read and write operations.
287    //!
288    std::size_t m_bufsize;
289
290    //!
291    //! \brief Internal buffer used during read operations.
292    //!
293    char* m_read_buf;
294
295    //!
296    //! \brief Internal buffer used during write operations.
297    //!
298    char* m_write_buf;
299
300protected:
301    //!
302    //! \brief Reads new data from the native file handle.
303    //!
304    //! This operation is called by input methods when there are no more
305    //! data in the input buffer.  The function fills the buffer with new
306    //! data, if available.
307    //!
308    //! \pre All input positions are exhausted (gptr() >= egptr()).
309    //! \post The input buffer has new data, if available.
310    //! \returns traits_type::eof() if a read error occurrs or there are
311    //!          no more data to be read.  Otherwise returns
312    //!          traits_type::to_int_type(*gptr()).
313    //!
314    virtual int_type underflow(void);
315
316    //!
317    //! \brief Makes room in the write buffer for additional data.
318    //!
319    //! This operation is called by output methods when there is no more
320    //! space in the output buffer to hold a new element.  The function
321    //! first flushes the buffer's contents to disk and then clears it to
322    //! leave room for more characters.  The given \a c character is
323    //! stored at the beginning of the new space.
324    //!
325    //! \pre All output positions are exhausted (pptr() >= epptr()).
326    //! \post The output buffer has more space if no errors occurred
327    //!       during the write to disk.
328    //! \post *(pptr() - 1) is \a c.
329    //! \returns traits_type::eof() if a write error occurrs.  Otherwise
330    //!          returns traits_type::not_eof(c).
331    //!
332    virtual int_type overflow(int c);
333
334    //!
335    //! \brief Flushes the output buffer to disk.
336    //!
337    //! Synchronizes the systembuf buffers with the contents of the file
338    //! associated to this object through the native file handle.  The
339    //! output buffer is flushed to disk and cleared to leave new room
340    //! for more data.
341    //!
342    //! \returns 0 on success, -1 if an error occurred.
343    //!
344    virtual int sync(void);
345};
346
347// ------------------------------------------------------------------------
348// The "pistream" class.
349// ------------------------------------------------------------------------
350
351//!
352//! \brief Child process' output stream.
353//!
354//! The pistream class represents an output communication channel with the
355//! child process.  The child process writes data to this stream and the
356//! parent process can read it through the pistream object.  In other
357//! words, from the child's point of view, the communication channel is an
358//! output one, but from the parent's point of view it is an input one;
359//! hence the confusing pistream name.
360//!
361//! pistream objects cannot be copied because they own the file handle
362//! they use to communicate with the child and because they buffer data
363//! that flows through the communication channel.
364//!
365//! A pistream object behaves as a std::istream stream in all senses.
366//! The class is only provided because it must provide a method to let
367//! the caller explicitly close the communication channel.
368//!
369//! \remark <b>Blocking remarks</b>: Functions that read data from this
370//! stream can block if the associated file handle blocks during the read.
371//! As this class is used to communicate with child processes through
372//! anonymous pipes, the most typical blocking condition happens when the
373//! child has no more data to send to the pipe's system buffer.  When
374//! this happens, the buffer eventually empties and the system blocks
375//! until the writer generates some data.
376//!
377class pistream :
378    public std::istream, utils::noncopyable
379{
380    //!
381    //! \brief The systembuf object used to manage this stream's data.
382    //!
383    systembuf m_systembuf;
384
385public:
386    //!
387    //! \brief Creates a new process' output stream.
388    //!
389    //! Given a file handle, this constructor creates a new pistream
390    //! object that owns the given file handle \a fh.  Ownership of
391    //! \a fh is transferred to the created pistream object.
392    //!
393    //! \pre \a fh is valid.
394    //! \post \a fh is invalid.
395    //! \post The new pistream object owns \a fh.
396    //!
397    explicit pistream(const int);
398};
399
400// ------------------------------------------------------------------------
401// The "muxer" class.
402// ------------------------------------------------------------------------
403
404class muxer : utils::noncopyable {
405    const int* m_fds;
406    const size_t m_nfds;
407
408    const size_t m_bufsize;
409    atf::utils::auto_array< std::string > m_buffers;
410
411protected:
412    virtual void line_callback(const size_t, const std::string&) = 0;
413
414    size_t read_one(const size_t, const int, std::string&, const bool);
415
416public:
417    muxer(const int*, const size_t, const size_t bufsize = 1024);
418    virtual ~muxer(void);
419
420    void mux(volatile const bool&);
421    void flush(void);
422};
423
424} // namespace atf_run
425} // namespace atf
426
427#endif // !defined(_ATF_RUN_IO_HPP_)
428