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