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