Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / unit / atf-src / atf-run / io.cpp
blobc99ee34ef211245704bd2128dd6994857374408a
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.
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.
30 extern "C" {
31 #include <fcntl.h>
32 #include <poll.h>
33 #include <signal.h>
34 #include <unistd.h>
37 #include <cerrno>
38 #include <cstring>
40 extern "C" {
41 #include "../atf-c/error.h"
44 #include "../atf-c++/detail/auto_array.hpp"
45 #include "../atf-c++/detail/exceptions.hpp"
46 #include "../atf-c++/detail/sanity.hpp"
48 #include "io.hpp"
50 namespace impl = atf::atf_run;
51 #define IMPL_NAME "atf::atf_run"
53 // ------------------------------------------------------------------------
54 // The "file_handle" class.
55 // ------------------------------------------------------------------------
57 impl::file_handle::file_handle(void) :
58 m_handle(invalid_value())
62 impl::file_handle::file_handle(handle_type h) :
63 m_handle(h)
65 PRE(m_handle != invalid_value());
68 impl::file_handle::file_handle(const file_handle& fh) :
69 m_handle(fh.m_handle)
71 fh.m_handle = invalid_value();
74 impl::file_handle::~file_handle(void)
76 if (is_valid())
77 close();
80 impl::file_handle&
81 impl::file_handle::operator=(const file_handle& fh)
83 m_handle = fh.m_handle;
84 fh.m_handle = invalid_value();
86 return *this;
89 bool
90 impl::file_handle::is_valid(void)
91 const
93 return m_handle != invalid_value();
96 void
97 impl::file_handle::close(void)
99 PRE(is_valid());
101 ::close(m_handle);
103 m_handle = invalid_value();
106 impl::file_handle::handle_type
107 impl::file_handle::disown(void)
109 PRE(is_valid());
111 handle_type h = m_handle;
112 m_handle = invalid_value();
113 return h;
116 impl::file_handle::handle_type
117 impl::file_handle::get(void)
118 const
120 PRE(is_valid());
122 return m_handle;
125 void
126 impl::file_handle::posix_remap(handle_type h)
128 PRE(is_valid());
130 if (m_handle == h)
131 return;
133 if (::dup2(m_handle, h) == -1)
134 throw system_error(IMPL_NAME "::file_handle::posix_remap",
135 "dup2(2) failed", errno);
137 if (::close(m_handle) == -1) {
138 ::close(h);
139 throw system_error(IMPL_NAME "::file_handle::posix_remap",
140 "close(2) failed", errno);
143 m_handle = h;
146 impl::file_handle::handle_type
147 impl::file_handle::invalid_value(void)
149 return -1;
152 // ------------------------------------------------------------------------
153 // The "systembuf" class.
154 // ------------------------------------------------------------------------
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)
162 PRE(m_handle >= 0);
163 PRE(m_bufsize > 0);
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;
176 setp(m_write_buf, m_write_buf + m_bufsize);
179 impl::systembuf::~systembuf(void)
181 delete [] m_read_buf;
182 delete [] m_write_buf;
185 impl::systembuf::int_type
186 impl::systembuf::underflow(void)
188 PRE(gptr() >= egptr());
190 bool ok;
191 ssize_t cnt = ::read(m_handle, m_read_buf, m_bufsize);
192 ok = (cnt != -1 && cnt != 0);
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());
202 impl::systembuf::int_type
203 impl::systembuf::overflow(int c)
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);
212 return traits_type::not_eof(c);
216 impl::systembuf::sync(void)
218 ssize_t cnt = pptr() - pbase();
220 bool ok;
221 ok = ::write(m_handle, pbase(), cnt) == cnt;
223 if (ok)
224 pbump(-cnt);
225 return ok ? 0 : -1;
228 // ------------------------------------------------------------------------
229 // The "pistream" class.
230 // ------------------------------------------------------------------------
232 impl::pistream::pistream(const int fd) :
233 std::istream(NULL),
234 m_systembuf(fd)
236 rdbuf(&m_systembuf);
239 // ------------------------------------------------------------------------
240 // The "muxer" class.
241 // ------------------------------------------------------------------------
243 static int
244 safe_poll(struct pollfd fds[], nfds_t nfds, int timeout)
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);
254 INV(ret >= 0);
255 return ret;
258 static size_t
259 safe_read(const int fd, void* buffer, const size_t nbytes,
260 const bool report_errors)
262 int ret;
263 while ((ret = ::read(fd, buffer, nbytes)) == -1 && errno == EINTR) {}
264 if (ret == -1) {
265 INV(errno != EINTR);
267 if (report_errors)
268 throw atf::system_error(IMPL_NAME "::safe_read", "read(2) failed",
269 errno);
270 else
271 ret = 0;
273 INV(ret >= 0);
274 return static_cast< size_t >(ret);
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])
285 impl::muxer::~muxer(void)
289 size_t
290 impl::muxer::read_one(const size_t index, const int fd, std::string& accum,
291 const bool report_errors)
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';
299 std::string line(accum);
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]);
314 accum.append(&buffer[line_start]);
316 return nbytes;
319 void
320 impl::muxer::mux(volatile const bool& terminate)
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;
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) {}
333 for (size_t i = 0; !terminate && i < m_nfds; i++) {
334 if (poll_fds[i].events == 0)
335 continue;
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;
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);
352 void
353 impl::muxer::flush(void)
355 for (size_t i = 0; i < m_nfds; i++) {
356 while (read_one(i, m_fds[i], m_buffers[i], false) > 0) {}
358 if (!m_buffers[i].empty())
359 line_callback(i, m_buffers[i]);