xref: /netbsd-src/external/bsd/atf/dist/tools/process.cpp (revision d780102efefa02003390cc43ea410dbd0ebb4a85)
1 //
2 // Automated Testing Framework (atf)
3 //
4 // Copyright (c) 2008 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 <sys/types.h>
32 #include <sys/wait.h>
33 
34 #include <fcntl.h>
35 #include <signal.h>
36 }
37 
38 #include <cassert>
39 #include <cstdarg>
40 #include <cerrno>
41 #include <cstring>
42 #include <iostream>
43 
44 #include "defs.hpp"
45 #include "exceptions.hpp"
46 #include "text.hpp"
47 #include "process.hpp"
48 
49 namespace detail = tools::process::detail;
50 namespace impl = tools::process;
51 #define IMPL_NAME "tools::process"
52 
53 // ------------------------------------------------------------------------
54 // Auxiliary functions.
55 // ------------------------------------------------------------------------
56 
57 template< class C >
58 tools::auto_array< const char* >
59 collection_to_argv(const C& c)
60 {
61     tools::auto_array< const char* > argv(new const char*[c.size() + 1]);
62 
63     std::size_t pos = 0;
64     for (typename C::const_iterator iter = c.begin(); iter != c.end();
65          iter++) {
66         argv[pos] = (*iter).c_str();
67         pos++;
68     }
69     assert(pos == c.size());
70     argv[pos] = NULL;
71 
72     return argv;
73 }
74 
75 template< class C >
76 C
77 argv_to_collection(const char* const* argv)
78 {
79     C c;
80 
81     for (const char* const* iter = argv; *iter != NULL; iter++)
82         c.push_back(std::string(*iter));
83 
84     return c;
85 }
86 
87 static
88 void
89 safe_dup(const int oldfd, const int newfd)
90 {
91     if (oldfd != newfd) {
92         if (dup2(oldfd, newfd) == -1) {
93             throw tools::system_error(IMPL_NAME "::safe_dup",
94                                       "Could not allocate file descriptor",
95                                       errno);
96         } else {
97             ::close(oldfd);
98         }
99     }
100 }
101 
102 static
103 int
104 const_execvp(const char *file, const char *const *argv)
105 {
106 #define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
107     return ::execvp(file, (char* const*)(UNCONST(argv)));
108 #undef UNCONST
109 }
110 
111 void
112 detail::do_exec(void *v)
113 {
114     struct exec_args *ea = reinterpret_cast<struct exec_args *>(v);
115 
116     if (ea->m_prehook != NULL)
117         ea->m_prehook();
118 
119     const int ret = const_execvp(ea->m_prog.c_str(), ea->m_argv.exec_argv());
120     const int errnocopy = errno;
121     assert(ret == -1);
122     std::cerr << "exec(" << ea->m_prog.str() << ") failed: "
123               << std::strerror(errnocopy) << "\n";
124     std::exit(EXIT_FAILURE);
125 }
126 
127 // ------------------------------------------------------------------------
128 // The "argv_array" type.
129 // ------------------------------------------------------------------------
130 
131 impl::argv_array::argv_array(void) :
132     m_exec_argv(collection_to_argv(m_args))
133 {
134 }
135 
136 impl::argv_array::argv_array(const char* arg1, ...)
137 {
138     m_args.push_back(arg1);
139 
140     {
141         va_list ap;
142         const char* nextarg;
143 
144         va_start(ap, arg1);
145         while ((nextarg = va_arg(ap, const char*)) != NULL)
146             m_args.push_back(nextarg);
147         va_end(ap);
148     }
149 
150     ctor_init_exec_argv();
151 }
152 
153 impl::argv_array::argv_array(const char* const* ca) :
154     m_args(argv_to_collection< args_vector >(ca)),
155     m_exec_argv(collection_to_argv(m_args))
156 {
157 }
158 
159 impl::argv_array::argv_array(const argv_array& a) :
160     m_args(a.m_args),
161     m_exec_argv(collection_to_argv(m_args))
162 {
163 }
164 
165 void
166 impl::argv_array::ctor_init_exec_argv(void)
167 {
168     m_exec_argv = collection_to_argv(m_args);
169 }
170 
171 const char* const*
172 impl::argv_array::exec_argv(void)
173     const
174 {
175     return m_exec_argv.get();
176 }
177 
178 impl::argv_array::size_type
179 impl::argv_array::size(void)
180     const
181 {
182     return m_args.size();
183 }
184 
185 const char*
186 impl::argv_array::operator[](int idx)
187     const
188 {
189     return m_args[idx].c_str();
190 }
191 
192 impl::argv_array::const_iterator
193 impl::argv_array::begin(void)
194     const
195 {
196     return m_args.begin();
197 }
198 
199 impl::argv_array::const_iterator
200 impl::argv_array::end(void)
201     const
202 {
203     return m_args.end();
204 }
205 
206 impl::argv_array&
207 impl::argv_array::operator=(const argv_array& a)
208 {
209     if (this != &a) {
210         m_args = a.m_args;
211         m_exec_argv = collection_to_argv(m_args);
212     }
213     return *this;
214 }
215 
216 // ------------------------------------------------------------------------
217 // The "stream" types.
218 // ------------------------------------------------------------------------
219 
220 impl::stream_capture::stream_capture(void)
221 {
222     for (int i = 0; i < 2; i++)
223         m_pipefds[i] = -1;
224 }
225 
226 impl::stream_capture::~stream_capture(void)
227 {
228     for (int i = 0; i < 2; i++)
229         if (m_pipefds[i] != -1)
230             ::close(m_pipefds[i]);
231 }
232 
233 void
234 impl::stream_capture::prepare(void)
235 {
236     if (pipe(m_pipefds) == -1)
237         throw system_error(IMPL_NAME "::stream_capture::prepare",
238                            "Failed to create pipe", errno);
239 }
240 
241 int
242 impl::stream_capture::connect_parent(void)
243 {
244     ::close(m_pipefds[1]); m_pipefds[1] = -1;
245     const int fd = m_pipefds[0];
246     m_pipefds[0] = -1;
247     return fd;
248 }
249 
250 void
251 impl::stream_capture::connect_child(const int fd)
252 {
253     ::close(m_pipefds[0]); m_pipefds[0] = -1;
254     if (m_pipefds[1] != fd) {
255         safe_dup(m_pipefds[1], fd);
256     }
257     m_pipefds[1] = -1;
258 }
259 
260 impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd) :
261     m_src_fd(src_fd), m_tgt_fd(tgt_fd)
262 {
263 }
264 
265 void
266 impl::stream_connect::prepare(void)
267 {
268 }
269 
270 int
271 impl::stream_connect::connect_parent(void)
272 {
273     return -1;
274 }
275 
276 void
277 impl::stream_connect::connect_child(const int fd ATF_DEFS_ATTRIBUTE_UNUSED)
278 {
279     safe_dup(m_tgt_fd, m_src_fd);
280 }
281 
282 impl::stream_inherit::stream_inherit(void)
283 {
284 }
285 
286 void
287 impl::stream_inherit::prepare(void)
288 {
289 }
290 
291 int
292 impl::stream_inherit::connect_parent(void)
293 {
294     return -1;
295 }
296 
297 void
298 impl::stream_inherit::connect_child(const int fd ATF_DEFS_ATTRIBUTE_UNUSED)
299 {
300 }
301 
302 impl::stream_redirect_fd::stream_redirect_fd(const int fd) :
303     m_fd(fd)
304 {
305 }
306 
307 void
308 impl::stream_redirect_fd::prepare(void)
309 {
310 }
311 
312 int
313 impl::stream_redirect_fd::connect_parent(void)
314 {
315     return -1;
316 }
317 
318 void
319 impl::stream_redirect_fd::connect_child(const int fd)
320 {
321     safe_dup(m_fd, fd);
322 }
323 
324 impl::stream_redirect_path::stream_redirect_path(const tools::fs::path& p) :
325     m_path(p)
326 {
327 }
328 
329 void
330 impl::stream_redirect_path::prepare(void)
331 {
332 }
333 
334 int
335 impl::stream_redirect_path::connect_parent(void)
336 {
337     return -1;
338 }
339 
340 void
341 impl::stream_redirect_path::connect_child(const int fd)
342 {
343     const int aux = ::open(m_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
344     if (aux == -1)
345         throw system_error(IMPL_NAME "::stream_redirect_path::connect_child",
346                            "Could not create " + m_path.str(), errno);
347     else
348         safe_dup(aux, fd);
349 }
350 
351 // ------------------------------------------------------------------------
352 // The "status" type.
353 // ------------------------------------------------------------------------
354 
355 impl::status::status(int s) :
356     m_status(s)
357 {
358 }
359 
360 impl::status::~status(void)
361 {
362 }
363 
364 bool
365 impl::status::exited(void)
366     const
367 {
368     int mutable_status = m_status;
369     return WIFEXITED(mutable_status);
370 }
371 
372 int
373 impl::status::exitstatus(void)
374     const
375 {
376     assert(exited());
377     int mutable_status = m_status;
378     return WEXITSTATUS(mutable_status);
379 }
380 
381 bool
382 impl::status::signaled(void)
383     const
384 {
385     int mutable_status = m_status;
386     return WIFSIGNALED(mutable_status);
387 }
388 
389 int
390 impl::status::termsig(void)
391     const
392 {
393     assert(signaled());
394     int mutable_status = m_status;
395     return WTERMSIG(mutable_status);
396 }
397 
398 bool
399 impl::status::coredump(void)
400     const
401 {
402     assert(signaled());
403 #if defined(WCOREDUMP)
404     int mutable_status = m_status;
405     return WCOREDUMP(mutable_status);
406 #else
407     return false;
408 #endif
409 }
410 
411 // ------------------------------------------------------------------------
412 // The "child" type.
413 // ------------------------------------------------------------------------
414 
415 impl::child::child(const pid_t pid_arg, const int stdout_fd_arg,
416                    const int stderr_fd_arg) :
417     m_pid(pid_arg),
418     m_stdout(stdout_fd_arg),
419     m_stderr(stderr_fd_arg),
420     m_waited(false)
421 {
422 }
423 
424 impl::child::~child(void)
425 {
426     if (!m_waited) {
427         ::kill(m_pid, SIGTERM);
428         (void)wait();
429 
430         if (m_stdout != -1)
431             ::close(m_stdout);
432         if (m_stderr != -1)
433             ::close(m_stderr);
434     }
435 }
436 
437 impl::status
438 impl::child::wait(void)
439 {
440     int s;
441 
442     if (::waitpid(m_pid, &s, 0) == -1)
443         throw system_error(IMPL_NAME "::child::wait", "Failed waiting for "
444                            "process " + text::to_string(m_pid), errno);
445 
446     if (m_stdout != -1)
447         ::close(m_stdout); m_stdout = -1;
448     if (m_stderr != -1)
449         ::close(m_stderr); m_stderr = -1;
450 
451     m_waited = true;
452     return status(s);
453 }
454 
455 pid_t
456 impl::child::pid(void)
457     const
458 {
459     return m_pid;
460 }
461 
462 int
463 impl::child::stdout_fd(void)
464 {
465     return m_stdout;
466 }
467 
468 int
469 impl::child::stderr_fd(void)
470 {
471     return m_stderr;
472 }
473 
474 // ------------------------------------------------------------------------
475 // Free functions.
476 // ------------------------------------------------------------------------
477 
478 void
479 detail::flush_streams(void)
480 {
481     // This is a weird hack to ensure that the output of the parent process
482     // is flushed before executing a child which prevents, for example, the
483     // output of the atf-run hooks to appear before the output of atf-run
484     // itself.
485     //
486     // TODO: This should only be executed when inheriting the stdout or
487     // stderr file descriptors.  However, the flushing is specific to the
488     // iostreams, so we cannot do it from the C library where all the process
489     // logic is performed.  Come up with a better design.
490     std::cout.flush();
491     std::cerr.flush();
492 }
493