1240116Smarcel// 2240116Smarcel// Automated Testing Framework (atf) 3240116Smarcel// 4240116Smarcel// Copyright (c) 2007 The NetBSD Foundation, Inc. 5240116Smarcel// All rights reserved. 6240116Smarcel// 7240116Smarcel// Redistribution and use in source and binary forms, with or without 8240116Smarcel// modification, are permitted provided that the following conditions 9240116Smarcel// are met: 10240116Smarcel// 1. Redistributions of source code must retain the above copyright 11240116Smarcel// notice, this list of conditions and the following disclaimer. 12240116Smarcel// 2. Redistributions in binary form must reproduce the above copyright 13240116Smarcel// notice, this list of conditions and the following disclaimer in the 14240116Smarcel// documentation and/or other materials provided with the distribution. 15240116Smarcel// 16240116Smarcel// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17240116Smarcel// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18240116Smarcel// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19240116Smarcel// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20240116Smarcel// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21240116Smarcel// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22240116Smarcel// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23240116Smarcel// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24240116Smarcel// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25240116Smarcel// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26240116Smarcel// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27240116Smarcel// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28240116Smarcel// 29240116Smarcel 30240116Smarcelextern "C" { 31240116Smarcel#include <fcntl.h> 32240116Smarcel#include <poll.h> 33240116Smarcel#include <signal.h> 34240116Smarcel#include <unistd.h> 35240116Smarcel} 36240116Smarcel 37240116Smarcel#include <cerrno> 38240116Smarcel#include <cstring> 39240116Smarcel 40240116Smarcelextern "C" { 41240116Smarcel#include "../atf-c/error.h" 42240116Smarcel} 43240116Smarcel 44240116Smarcel#include "../atf-c++/detail/exceptions.hpp" 45240116Smarcel#include "../atf-c++/detail/sanity.hpp" 46240116Smarcel#include "../atf-c++/utils.hpp" 47240116Smarcel 48240116Smarcel#include "io.hpp" 49240116Smarcel 50240116Smarcelnamespace impl = atf::atf_run; 51240116Smarcel#define IMPL_NAME "atf::atf_run" 52240116Smarcel 53240116Smarcel// ------------------------------------------------------------------------ 54240116Smarcel// The "file_handle" class. 55240116Smarcel// ------------------------------------------------------------------------ 56240116Smarcel 57240116Smarcelimpl::file_handle::file_handle(void) : 58240116Smarcel m_handle(invalid_value()) 59240116Smarcel{ 60240116Smarcel} 61240116Smarcel 62240116Smarcelimpl::file_handle::file_handle(handle_type h) : 63240116Smarcel m_handle(h) 64240116Smarcel{ 65240116Smarcel PRE(m_handle != invalid_value()); 66240116Smarcel} 67240116Smarcel 68240116Smarcelimpl::file_handle::file_handle(const file_handle& fh) : 69240116Smarcel m_handle(fh.m_handle) 70240116Smarcel{ 71240116Smarcel fh.m_handle = invalid_value(); 72240116Smarcel} 73240116Smarcel 74240116Smarcelimpl::file_handle::~file_handle(void) 75240116Smarcel{ 76240116Smarcel if (is_valid()) 77240116Smarcel close(); 78240116Smarcel} 79240116Smarcel 80240116Smarcelimpl::file_handle& 81240116Smarcelimpl::file_handle::operator=(const file_handle& fh) 82240116Smarcel{ 83240116Smarcel m_handle = fh.m_handle; 84240116Smarcel fh.m_handle = invalid_value(); 85240116Smarcel 86240116Smarcel return *this; 87240116Smarcel} 88240116Smarcel 89240116Smarcelbool 90240116Smarcelimpl::file_handle::is_valid(void) 91240116Smarcel const 92240116Smarcel{ 93240116Smarcel return m_handle != invalid_value(); 94240116Smarcel} 95240116Smarcel 96240116Smarcelvoid 97240116Smarcelimpl::file_handle::close(void) 98240116Smarcel{ 99240116Smarcel PRE(is_valid()); 100240116Smarcel 101240116Smarcel ::close(m_handle); 102240116Smarcel 103240116Smarcel m_handle = invalid_value(); 104240116Smarcel} 105240116Smarcel 106240116Smarcelimpl::file_handle::handle_type 107240116Smarcelimpl::file_handle::disown(void) 108240116Smarcel{ 109240116Smarcel PRE(is_valid()); 110240116Smarcel 111240116Smarcel handle_type h = m_handle; 112240116Smarcel m_handle = invalid_value(); 113240116Smarcel return h; 114240116Smarcel} 115240116Smarcel 116240116Smarcelimpl::file_handle::handle_type 117240116Smarcelimpl::file_handle::get(void) 118240116Smarcel const 119240116Smarcel{ 120240116Smarcel PRE(is_valid()); 121240116Smarcel 122240116Smarcel return m_handle; 123240116Smarcel} 124240116Smarcel 125240116Smarcelvoid 126240116Smarcelimpl::file_handle::posix_remap(handle_type h) 127240116Smarcel{ 128240116Smarcel PRE(is_valid()); 129240116Smarcel 130240116Smarcel if (m_handle == h) 131240116Smarcel return; 132240116Smarcel 133240116Smarcel if (::dup2(m_handle, h) == -1) 134240116Smarcel throw system_error(IMPL_NAME "::file_handle::posix_remap", 135240116Smarcel "dup2(2) failed", errno); 136240116Smarcel 137240116Smarcel if (::close(m_handle) == -1) { 138240116Smarcel ::close(h); 139240116Smarcel throw system_error(IMPL_NAME "::file_handle::posix_remap", 140240116Smarcel "close(2) failed", errno); 141240116Smarcel } 142240116Smarcel 143240116Smarcel m_handle = h; 144240116Smarcel} 145240116Smarcel 146240116Smarcelimpl::file_handle::handle_type 147240116Smarcelimpl::file_handle::invalid_value(void) 148240116Smarcel{ 149240116Smarcel return -1; 150240116Smarcel} 151240116Smarcel 152240116Smarcel// ------------------------------------------------------------------------ 153240116Smarcel// The "systembuf" class. 154240116Smarcel// ------------------------------------------------------------------------ 155240116Smarcel 156240116Smarcelimpl::systembuf::systembuf(handle_type h, std::size_t bufsize) : 157240116Smarcel m_handle(h), 158240116Smarcel m_bufsize(bufsize), 159240116Smarcel m_read_buf(NULL), 160240116Smarcel m_write_buf(NULL) 161240116Smarcel{ 162240116Smarcel PRE(m_handle >= 0); 163240116Smarcel PRE(m_bufsize > 0); 164240116Smarcel 165240116Smarcel try { 166240116Smarcel m_read_buf = new char[bufsize]; 167240116Smarcel m_write_buf = new char[bufsize]; 168240116Smarcel } catch (...) { 169240116Smarcel if (m_read_buf != NULL) 170240116Smarcel delete [] m_read_buf; 171240116Smarcel if (m_write_buf != NULL) 172240116Smarcel delete [] m_write_buf; 173240116Smarcel throw; 174240116Smarcel } 175240116Smarcel 176240116Smarcel setp(m_write_buf, m_write_buf + m_bufsize); 177240116Smarcel} 178240116Smarcel 179240116Smarcelimpl::systembuf::~systembuf(void) 180240116Smarcel{ 181240116Smarcel delete [] m_read_buf; 182240116Smarcel delete [] m_write_buf; 183240116Smarcel} 184240116Smarcel 185240116Smarcelimpl::systembuf::int_type 186240116Smarcelimpl::systembuf::underflow(void) 187240116Smarcel{ 188240116Smarcel PRE(gptr() >= egptr()); 189240116Smarcel 190240116Smarcel bool ok; 191240116Smarcel ssize_t cnt = ::read(m_handle, m_read_buf, m_bufsize); 192240116Smarcel ok = (cnt != -1 && cnt != 0); 193240116Smarcel 194240116Smarcel if (!ok) 195240116Smarcel return traits_type::eof(); 196240116Smarcel else { 197240116Smarcel setg(m_read_buf, m_read_buf, m_read_buf + cnt); 198240116Smarcel return traits_type::to_int_type(*gptr()); 199240116Smarcel } 200240116Smarcel} 201240116Smarcel 202240116Smarcelimpl::systembuf::int_type 203240116Smarcelimpl::systembuf::overflow(int c) 204240116Smarcel{ 205240116Smarcel PRE(pptr() >= epptr()); 206240116Smarcel if (sync() == -1) 207240116Smarcel return traits_type::eof(); 208240116Smarcel if (!traits_type::eq_int_type(c, traits_type::eof())) { 209240116Smarcel traits_type::assign(*pptr(), c); 210240116Smarcel pbump(1); 211240116Smarcel } 212240116Smarcel return traits_type::not_eof(c); 213240116Smarcel} 214240116Smarcel 215240116Smarcelint 216240116Smarcelimpl::systembuf::sync(void) 217240116Smarcel{ 218240116Smarcel ssize_t cnt = pptr() - pbase(); 219240116Smarcel 220240116Smarcel bool ok; 221240116Smarcel ok = ::write(m_handle, pbase(), cnt) == cnt; 222240116Smarcel 223240116Smarcel if (ok) 224240116Smarcel pbump(-cnt); 225240116Smarcel return ok ? 0 : -1; 226240116Smarcel} 227240116Smarcel 228240116Smarcel// ------------------------------------------------------------------------ 229240116Smarcel// The "pistream" class. 230240116Smarcel// ------------------------------------------------------------------------ 231240116Smarcel 232240116Smarcelimpl::pistream::pistream(const int fd) : 233240116Smarcel std::istream(NULL), 234240116Smarcel m_systembuf(fd) 235240116Smarcel{ 236240116Smarcel rdbuf(&m_systembuf); 237240116Smarcel} 238240116Smarcel 239240116Smarcel// ------------------------------------------------------------------------ 240240116Smarcel// The "muxer" class. 241240116Smarcel// ------------------------------------------------------------------------ 242240116Smarcel 243240116Smarcelstatic int 244240116Smarcelsafe_poll(struct pollfd fds[], nfds_t nfds, int timeout) 245240116Smarcel{ 246240116Smarcel int ret = ::poll(fds, nfds, timeout); 247240116Smarcel if (ret == -1) { 248240116Smarcel if (errno == EINTR) 249240116Smarcel ret = 0; 250240116Smarcel else 251240116Smarcel throw atf::system_error(IMPL_NAME "::safe_poll", "poll(2) failed", 252240116Smarcel errno); 253240116Smarcel } 254240116Smarcel INV(ret >= 0); 255240116Smarcel return ret; 256240116Smarcel} 257240116Smarcel 258240116Smarcelstatic size_t 259240116Smarcelsafe_read(const int fd, void* buffer, const size_t nbytes, 260240116Smarcel const bool report_errors) 261240116Smarcel{ 262240116Smarcel int ret; 263240116Smarcel while ((ret = ::read(fd, buffer, nbytes)) == -1 && errno == EINTR) {} 264240116Smarcel if (ret == -1) { 265240116Smarcel INV(errno != EINTR); 266240116Smarcel 267240116Smarcel if (report_errors) 268240116Smarcel throw atf::system_error(IMPL_NAME "::safe_read", "read(2) failed", 269240116Smarcel errno); 270240116Smarcel else 271240116Smarcel ret = 0; 272240116Smarcel } 273240116Smarcel INV(ret >= 0); 274240116Smarcel return static_cast< size_t >(ret); 275240116Smarcel} 276240116Smarcel 277240116Smarcelimpl::muxer::muxer(const int* fds, const size_t nfds, const size_t bufsize) : 278240116Smarcel m_fds(fds), 279240116Smarcel m_nfds(nfds), 280240116Smarcel m_bufsize(bufsize), 281240116Smarcel m_buffers(new std::string[nfds]) 282240116Smarcel{ 283240116Smarcel} 284240116Smarcel 285240116Smarcelimpl::muxer::~muxer(void) 286240116Smarcel{ 287240116Smarcel} 288240116Smarcel 289240116Smarcelsize_t 290240116Smarcelimpl::muxer::read_one(const size_t index, const int fd, std::string& accum, 291240116Smarcel const bool report_errors) 292240116Smarcel{ 293240116Smarcel atf::utils::auto_array< char > buffer(new char[m_bufsize]); 294240116Smarcel const size_t nbytes = safe_read(fd, buffer.get(), m_bufsize - 1, 295240116Smarcel report_errors); 296240116Smarcel INV(nbytes < m_bufsize); 297240116Smarcel buffer[nbytes] = '\0'; 298240116Smarcel 299240116Smarcel std::string line(accum); 300240116Smarcel 301240116Smarcel size_t line_start = 0; 302240116Smarcel for (size_t i = 0; i < nbytes; i++) { 303240116Smarcel if (buffer[i] == '\n') { 304240116Smarcel line_callback(index, line); 305240116Smarcel line.clear(); 306240116Smarcel accum.clear(); 307240116Smarcel line_start = i + 1; 308240116Smarcel } else if (buffer[i] == '\r') { 309240116Smarcel // Do nothing. 310240116Smarcel } else { 311240116Smarcel line.append(1, buffer[i]); 312240116Smarcel } 313240116Smarcel } 314240116Smarcel accum.append(&buffer[line_start]); 315240116Smarcel 316240116Smarcel return nbytes; 317240116Smarcel} 318240116Smarcel 319240116Smarcelvoid 320240116Smarcelimpl::muxer::mux(volatile const bool& terminate) 321240116Smarcel{ 322240116Smarcel atf::utils::auto_array< struct pollfd > poll_fds(new struct pollfd[m_nfds]); 323240116Smarcel for (size_t i = 0; i < m_nfds; i++) { 324240116Smarcel poll_fds[i].fd = m_fds[i]; 325240116Smarcel poll_fds[i].events = POLLIN; 326240116Smarcel } 327240116Smarcel 328240116Smarcel size_t nactive = m_nfds; 329240116Smarcel while (nactive > 0 && !terminate) { 330240116Smarcel int ret; 331240116Smarcel while (!terminate && (ret = safe_poll(poll_fds.get(), 2, 250)) == 0) {} 332240116Smarcel 333240116Smarcel for (size_t i = 0; !terminate && i < m_nfds; i++) { 334240116Smarcel if (poll_fds[i].events == 0) 335240116Smarcel continue; 336240116Smarcel 337240116Smarcel if (poll_fds[i].revents & POLLHUP) { 338240116Smarcel // Any data still available at this point will be processed by 339240116Smarcel // a call to the flush method. 340240116Smarcel poll_fds[i].events = 0; 341240116Smarcel 342240116Smarcel INV(nactive >= 1); 343240116Smarcel nactive--; 344240116Smarcel } else if (poll_fds[i].revents & (POLLIN | POLLRDNORM | POLLRDBAND | 345240116Smarcel POLLPRI)) { 346240116Smarcel (void)read_one(i, poll_fds[i].fd, m_buffers[i], true); 347240116Smarcel } 348240116Smarcel } 349240116Smarcel } 350240116Smarcel} 351240116Smarcel 352240116Smarcelvoid 353240116Smarcelimpl::muxer::flush(void) 354240116Smarcel{ 355240116Smarcel for (size_t i = 0; i < m_nfds; i++) { 356240116Smarcel while (read_one(i, m_fds[i], m_buffers[i], false) > 0) {} 357240116Smarcel 358240116Smarcel if (!m_buffers[i].empty()) 359240116Smarcel line_callback(i, m_buffers[i]); 360240116Smarcel } 361240116Smarcel} 362