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 extern "C" {
31 #include <fcntl.h>
32 #include <poll.h>
33 #include <signal.h>
34 #include <unistd.h>
35 }
36 
37 #include <cerrno>
38 #include <cstring>
39 
40 extern "C" {
41 #include "../atf-c/error.h"
42 }
43 
44 #include "../atf-c++/detail/auto_array.hpp"
45 #include "../atf-c++/detail/exceptions.hpp"
46 #include "../atf-c++/detail/sanity.hpp"
47 
48 #include "io.hpp"
49 
50 namespace impl = atf::atf_run;
51 #define IMPL_NAME "atf::atf_run"
52 
53 // ------------------------------------------------------------------------
54 // The "file_handle" class.
55 // ------------------------------------------------------------------------
56 
57 impl::file_handle::file_handle(void) :
58     m_handle(invalid_value())
59 {
60 }
61 
62 impl::file_handle::file_handle(handle_type h) :
63     m_handle(h)
64 {
65     PRE(m_handle != invalid_value());
66 }
67 
68 impl::file_handle::file_handle(const file_handle& fh) :
69     m_handle(fh.m_handle)
70 {
71     fh.m_handle = invalid_value();
72 }
73 
74 impl::file_handle::~file_handle(void)
75 {
76     if (is_valid())
77         close();
78 }
79 
80 impl::file_handle&
81 impl::file_handle::operator=(const file_handle& fh)
82 {
83     m_handle = fh.m_handle;
84     fh.m_handle = invalid_value();
85 
86     return *this;
87 }
88 
89 bool
90 impl::file_handle::is_valid(void)
91     const
92 {
93     return m_handle != invalid_value();
94 }
95 
96 void
97 impl::file_handle::close(void)
98 {
99     PRE(is_valid());
100 
101     ::close(m_handle);
102 
103     m_handle = invalid_value();
104 }
105 
106 impl::file_handle::handle_type
107 impl::file_handle::disown(void)
108 {
109     PRE(is_valid());
110 
111     handle_type h = m_handle;
112     m_handle = invalid_value();
113     return h;
114 }
115 
116 impl::file_handle::handle_type
117 impl::file_handle::get(void)
118     const
119 {
120     PRE(is_valid());
121 
122     return m_handle;
123 }
124 
125 void
126 impl::file_handle::posix_remap(handle_type h)
127 {
128     PRE(is_valid());
129 
130     if (m_handle == h)
131         return;
132 
133     if (::dup2(m_handle, h) == -1)
134         throw system_error(IMPL_NAME "::file_handle::posix_remap",
135                            "dup2(2) failed", errno);
136 
137     if (::close(m_handle) == -1) {
138         ::close(h);
139         throw system_error(IMPL_NAME "::file_handle::posix_remap",
140                            "close(2) failed", errno);
141     }
142 
143     m_handle = h;
144 }
145 
146 impl::file_handle::handle_type
147 impl::file_handle::invalid_value(void)
148 {
149     return -1;
150 }
151 
152 // ------------------------------------------------------------------------
153 // The "systembuf" class.
154 // ------------------------------------------------------------------------
155 
156 impl::systembuf::systembuf(handle_type h, std::size_t bufsize) :
157     m_handle(h),
158     m_bufsize(bufsize),
159     m_read_buf(NULL),
160     m_write_buf(NULL)
161 {
162     PRE(m_handle >= 0);
163     PRE(m_bufsize > 0);
164 
165     try {
166         m_read_buf = new char[bufsize];
167         m_write_buf = new char[bufsize];
168     } catch (...) {
169         if (m_read_buf != NULL)
170             delete [] m_read_buf;
171         if (m_write_buf != NULL)
172             delete [] m_write_buf;
173         throw;
174     }
175 
176     setp(m_write_buf, m_write_buf + m_bufsize);
177 }
178 
179 impl::systembuf::~systembuf(void)
180 {
181     delete [] m_read_buf;
182     delete [] m_write_buf;
183 }
184 
185 impl::systembuf::int_type
186 impl::systembuf::underflow(void)
187 {
188     PRE(gptr() >= egptr());
189 
190     bool ok;
191     ssize_t cnt = ::read(m_handle, m_read_buf, m_bufsize);
192     ok = (cnt != -1 && cnt != 0);
193 
194     if (!ok)
195         return traits_type::eof();
196     else {
197         setg(m_read_buf, m_read_buf, m_read_buf + cnt);
198         return traits_type::to_int_type(*gptr());
199     }
200 }
201 
202 impl::systembuf::int_type
203 impl::systembuf::overflow(int c)
204 {
205     PRE(pptr() >= epptr());
206     if (sync() == -1)
207         return traits_type::eof();
208     if (!traits_type::eq_int_type(c, traits_type::eof())) {
209         traits_type::assign(*pptr(), c);
210         pbump(1);
211     }
212     return traits_type::not_eof(c);
213 }
214 
215 int
216 impl::systembuf::sync(void)
217 {
218     ssize_t cnt = pptr() - pbase();
219 
220     bool ok;
221     ok = ::write(m_handle, pbase(), cnt) == cnt;
222 
223     if (ok)
224         pbump(-cnt);
225     return ok ? 0 : -1;
226 }
227 
228 // ------------------------------------------------------------------------
229 // The "pistream" class.
230 // ------------------------------------------------------------------------
231 
232 impl::pistream::pistream(const int fd) :
233     std::istream(NULL),
234     m_systembuf(fd)
235 {
236     rdbuf(&m_systembuf);
237 }
238 
239 // ------------------------------------------------------------------------
240 // The "muxer" class.
241 // ------------------------------------------------------------------------
242 
243 static int
244 safe_poll(struct pollfd fds[], nfds_t nfds, int timeout)
245 {
246     int ret = ::poll(fds, nfds, timeout);
247     if (ret == -1) {
248         if (errno == EINTR)
249             ret = 0;
250         else
251             throw atf::system_error(IMPL_NAME "::safe_poll", "poll(2) failed",
252                                     errno);
253     }
254     INV(ret >= 0);
255     return ret;
256 }
257 
258 static size_t
259 safe_read(const int fd, void* buffer, const size_t nbytes,
260           const bool report_errors)
261 {
262     int ret;
263     while ((ret = ::read(fd, buffer, nbytes)) == -1 && errno == EINTR) {}
264     if (ret == -1) {
265         INV(errno != EINTR);
266 
267         if (report_errors)
268             throw atf::system_error(IMPL_NAME "::safe_read", "read(2) failed",
269                                     errno);
270         else
271             ret = 0;
272     }
273     INV(ret >= 0);
274     return static_cast< size_t >(ret);
275 }
276 
277 impl::muxer::muxer(const int* fds, const size_t nfds, const size_t bufsize) :
278     m_fds(fds),
279     m_nfds(nfds),
280     m_bufsize(bufsize),
281     m_buffers(new std::string[nfds])
282 {
283 }
284 
285 impl::muxer::~muxer(void)
286 {
287 }
288 
289 size_t
290 impl::muxer::read_one(const size_t index, const int fd, std::string& accum,
291                       const bool report_errors)
292 {
293     atf::auto_array< char > buffer(new char[m_bufsize]);
294     const size_t nbytes = safe_read(fd, buffer.get(), m_bufsize - 1,
295                                     report_errors);
296     INV(nbytes < m_bufsize);
297     buffer[nbytes] = '\0';
298 
299     std::string line(accum);
300 
301     size_t line_start = 0;
302     for (size_t i = 0; i < nbytes; i++) {
303         if (buffer[i] == '\n') {
304             line_callback(index, line);
305             line.clear();
306             accum.clear();
307             line_start = i + 1;
308         } else if (buffer[i] == '\r') {
309             // Do nothing.
310         } else {
311             line.append(1, buffer[i]);
312         }
313     }
314     accum.append(&buffer[line_start]);
315 
316     return nbytes;
317 }
318 
319 void
320 impl::muxer::mux(volatile const bool& terminate)
321 {
322     atf::auto_array< struct pollfd > poll_fds(new struct pollfd[m_nfds]);
323     for (size_t i = 0; i < m_nfds; i++) {
324         poll_fds[i].fd = m_fds[i];
325         poll_fds[i].events = POLLIN;
326     }
327 
328     size_t nactive = m_nfds;
329     while (nactive > 0 && !terminate) {
330         int ret;
331         while (!terminate && (ret = safe_poll(poll_fds.get(), 2, 250)) == 0) {}
332 
333         for (size_t i = 0; !terminate && i < m_nfds; i++) {
334             if (poll_fds[i].events == 0)
335                 continue;
336 
337             if (poll_fds[i].revents & POLLHUP) {
338                 // Any data still available at this point will be processed by
339                 // a call to the flush method.
340                 poll_fds[i].events = 0;
341 
342                 INV(nactive >= 1);
343                 nactive--;
344             } else if (poll_fds[i].revents & (POLLIN | POLLRDNORM | POLLRDBAND |
345                                        POLLPRI)) {
346                 (void)read_one(i, poll_fds[i].fd, m_buffers[i], true);
347             }
348         }
349     }
350 }
351 
352 void
353 impl::muxer::flush(void)
354 {
355     for (size_t i = 0; i < m_nfds; i++) {
356         while (read_one(i, m_fds[i], m_buffers[i], false) > 0) {}
357 
358         if (!m_buffers[i].empty())
359             line_callback(i, m_buffers[i]);
360     }
361 }
362