etc/services - sync with NetBSD-8
[minix.git] / external / bsd / atf / dist / tools / io.cpp
blob4cf8f6a4bfaa4e608da3b69a0846a2a5852ce281
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 <cassert>
38 #include <cerrno>
39 #include <cstring>
41 #include "auto_array.hpp"
42 #include "exceptions.hpp"
43 #include "io.hpp"
45 namespace impl = tools::io;
46 #define IMPL_NAME "tools::io"
48 // ------------------------------------------------------------------------
49 // The "file_handle" class.
50 // ------------------------------------------------------------------------
52 impl::file_handle::file_handle(void) :
53 m_handle(invalid_value())
57 impl::file_handle::file_handle(handle_type h) :
58 m_handle(h)
60 assert(m_handle != invalid_value());
63 impl::file_handle::file_handle(const file_handle& fh) :
64 m_handle(fh.m_handle)
66 fh.m_handle = invalid_value();
69 impl::file_handle::~file_handle(void)
71 if (is_valid())
72 close();
75 impl::file_handle&
76 impl::file_handle::operator=(const file_handle& fh)
78 m_handle = fh.m_handle;
79 fh.m_handle = invalid_value();
81 return *this;
84 bool
85 impl::file_handle::is_valid(void)
86 const
88 return m_handle != invalid_value();
91 void
92 impl::file_handle::close(void)
94 assert(is_valid());
96 ::close(m_handle);
98 m_handle = invalid_value();
101 impl::file_handle::handle_type
102 impl::file_handle::disown(void)
104 assert(is_valid());
106 handle_type h = m_handle;
107 m_handle = invalid_value();
108 return h;
111 impl::file_handle::handle_type
112 impl::file_handle::get(void)
113 const
115 assert(is_valid());
117 return m_handle;
120 void
121 impl::file_handle::posix_remap(handle_type h)
123 assert(is_valid());
125 if (m_handle == h)
126 return;
128 if (::dup2(m_handle, h) == -1)
129 throw tools::system_error(IMPL_NAME "::file_handle::posix_remap",
130 "dup2(2) failed", errno);
132 if (::close(m_handle) == -1) {
133 ::close(h);
134 throw tools::system_error(IMPL_NAME "::file_handle::posix_remap",
135 "close(2) failed", errno);
138 m_handle = h;
141 impl::file_handle::handle_type
142 impl::file_handle::invalid_value(void)
144 return -1;
147 // ------------------------------------------------------------------------
148 // The "systembuf" class.
149 // ------------------------------------------------------------------------
151 impl::systembuf::systembuf(handle_type h, std::size_t bufsize) :
152 m_handle(h),
153 m_bufsize(bufsize),
154 m_read_buf(NULL),
155 m_write_buf(NULL)
157 assert(m_handle >= 0);
158 assert(m_bufsize > 0);
160 try {
161 m_read_buf = new char[bufsize];
162 m_write_buf = new char[bufsize];
163 } catch (...) {
164 if (m_read_buf != NULL)
165 delete [] m_read_buf;
166 if (m_write_buf != NULL)
167 delete [] m_write_buf;
168 throw;
171 setp(m_write_buf, m_write_buf + m_bufsize);
174 impl::systembuf::~systembuf(void)
176 delete [] m_read_buf;
177 delete [] m_write_buf;
180 impl::systembuf::int_type
181 impl::systembuf::underflow(void)
183 assert(gptr() >= egptr());
185 bool ok;
186 ssize_t cnt = ::read(m_handle, m_read_buf, m_bufsize);
187 ok = (cnt != -1 && cnt != 0);
189 if (!ok)
190 return traits_type::eof();
191 else {
192 setg(m_read_buf, m_read_buf, m_read_buf + cnt);
193 return traits_type::to_int_type(*gptr());
197 impl::systembuf::int_type
198 impl::systembuf::overflow(int c)
200 assert(pptr() >= epptr());
201 if (sync() == -1)
202 return traits_type::eof();
203 if (!traits_type::eq_int_type(c, traits_type::eof())) {
204 traits_type::assign(*pptr(), c);
205 pbump(1);
207 return traits_type::not_eof(c);
211 impl::systembuf::sync(void)
213 ssize_t cnt = pptr() - pbase();
215 bool ok;
216 ok = ::write(m_handle, pbase(), cnt) == cnt;
218 if (ok)
219 pbump(-cnt);
220 return ok ? 0 : -1;
223 // ------------------------------------------------------------------------
224 // The "pistream" class.
225 // ------------------------------------------------------------------------
227 impl::pistream::pistream(const int fd) :
228 std::istream(NULL),
229 m_systembuf(fd)
231 rdbuf(&m_systembuf);
234 // ------------------------------------------------------------------------
235 // The "muxer" class.
236 // ------------------------------------------------------------------------
238 static int
239 safe_poll(struct pollfd fds[], nfds_t nfds, int timeout)
241 int ret = ::poll(fds, nfds, timeout);
242 if (ret == -1) {
243 if (errno == EINTR)
244 ret = 0;
245 else
246 throw tools::system_error(IMPL_NAME "::safe_poll", "poll(2) failed",
247 errno);
249 assert(ret >= 0);
250 return ret;
253 static size_t
254 safe_read(const int fd, void* buffer, const size_t nbytes,
255 const bool report_errors)
257 int ret;
258 while ((ret = ::read(fd, buffer, nbytes)) == -1 && errno == EINTR) {}
259 if (ret == -1) {
260 assert(errno != EINTR);
262 if (report_errors)
263 throw tools::system_error(IMPL_NAME "::safe_read", "read(2) failed",
264 errno);
265 else
266 ret = 0;
268 assert(ret >= 0);
269 return static_cast< size_t >(ret);
272 impl::muxer::muxer(const int* fds, const size_t nfds, const size_t bufsize) :
273 m_fds(fds),
274 m_nfds(nfds),
275 m_bufsize(bufsize),
276 m_buffers(new std::string[nfds])
280 impl::muxer::~muxer(void)
284 size_t
285 impl::muxer::read_one(const size_t index, const int fd, std::string& accum,
286 const bool report_errors)
288 tools::auto_array< char > buffer(new char[m_bufsize]);
289 const size_t nbytes = safe_read(fd, buffer.get(), m_bufsize - 1,
290 report_errors);
291 assert(nbytes < m_bufsize);
292 buffer[nbytes] = '\0';
294 std::string line(accum);
296 size_t line_start = 0;
297 for (size_t i = 0; i < nbytes; i++) {
298 if (buffer[i] == '\n') {
299 line_callback(index, line);
300 line.clear();
301 accum.clear();
302 line_start = i + 1;
303 } else if (buffer[i] == '\r') {
304 // Do nothing.
305 } else {
306 line.append(1, buffer[i]);
309 accum.append(&buffer[line_start]);
311 return nbytes;
314 void
315 impl::muxer::mux(volatile const bool& terminate)
317 tools::auto_array< struct pollfd > poll_fds(new struct pollfd[m_nfds]);
318 for (size_t i = 0; i < m_nfds; i++) {
319 poll_fds[i].fd = m_fds[i];
320 poll_fds[i].events = POLLIN;
323 size_t nactive = m_nfds;
324 while (nactive > 0 && !terminate) {
325 int ret;
326 while (!terminate && (ret = safe_poll(poll_fds.get(), 2, 250)) == 0) {}
328 for (size_t i = 0; !terminate && i < m_nfds; i++) {
329 if (poll_fds[i].events == 0)
330 continue;
332 if (poll_fds[i].revents & POLLHUP) {
333 // Any data still available at this point will be processed by
334 // a call to the flush method.
335 poll_fds[i].events = 0;
337 assert(nactive >= 1);
338 nactive--;
339 } else if (poll_fds[i].revents & (POLLIN | POLLRDNORM | POLLRDBAND |
340 POLLPRI)) {
341 (void)read_one(i, poll_fds[i].fd, m_buffers[i], true);
347 void
348 impl::muxer::flush(void)
350 for (size_t i = 0; i < m_nfds; i++) {
351 while (read_one(i, m_fds[i], m_buffers[i], false) > 0) {}
353 if (!m_buffers[i].empty())
354 line_callback(i, m_buffers[i]);