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