1// Copyright 2010 Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9//   notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above copyright
11//   notice, this list of conditions and the following disclaimer in the
12//   documentation and/or other materials provided with the distribution.
13// * Neither the name of Google Inc. nor the names of its contributors
14//   may be used to endorse or promote products derived from this software
15//   without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29#include "utils/process/child.ipp"
30
31extern "C" {
32#include <sys/stat.h>
33#include <sys/wait.h>
34
35#include <fcntl.h>
36#include <signal.h>
37#include <unistd.h>
38}
39
40#include <cassert>
41#include <cerrno>
42#include <cstdlib>
43#include <cstring>
44#include <iostream>
45#include <memory>
46
47#include "utils/defs.hpp"
48#include "utils/format/macros.hpp"
49#include "utils/logging/macros.hpp"
50#include "utils/process/exceptions.hpp"
51#include "utils/process/fdstream.hpp"
52#include "utils/process/system.hpp"
53#include "utils/process/status.hpp"
54#include "utils/sanity.hpp"
55#include "utils/signals/interrupts.hpp"
56
57
58namespace utils {
59namespace process {
60
61
62/// Private implementation fields for child objects.
63struct child::impl {
64    /// The process identifier.
65    pid_t _pid;
66
67    /// The input stream for the process' stdout and stderr.  May be NULL.
68    std::unique_ptr< process::ifdstream > _output;
69
70    /// Initializes private implementation data.
71    ///
72    /// \param pid The process identifier.
73    /// \param output The input stream.  Grabs ownership of the pointer.
74    impl(const pid_t pid, process::ifdstream* output) :
75        _pid(pid), _output(output) {}
76};
77
78
79}  // namespace process
80}  // namespace utils
81
82
83namespace fs = utils::fs;
84namespace process = utils::process;
85namespace signals = utils::signals;
86
87
88namespace {
89
90
91/// Exception-based version of dup(2).
92///
93/// \param old_fd The file descriptor to duplicate.
94/// \param new_fd The file descriptor to use as the duplicate.  This is
95///     closed if it was open before the copy happens.
96///
97/// \throw process::system_error If the call to dup2(2) fails.
98static void
99safe_dup(const int old_fd, const int new_fd)
100{
101    if (process::detail::syscall_dup2(old_fd, new_fd) == -1) {
102        const int original_errno = errno;
103        throw process::system_error(F("dup2(%s, %s) failed") % old_fd % new_fd,
104                                    original_errno);
105    }
106}
107
108
109/// Exception-based version of open(2) to open (or create) a file for append.
110///
111/// \param filename The file to open in append mode.
112///
113/// \return The file descriptor for the opened or created file.
114///
115/// \throw process::system_error If the call to open(2) fails.
116static int
117open_for_append(const fs::path& filename)
118{
119    const int fd = process::detail::syscall_open(
120        filename.c_str(), O_CREAT | O_WRONLY | O_APPEND,
121        S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
122    if (fd == -1) {
123        const int original_errno = errno;
124        throw process::system_error(F("Failed to create %s because open(2) "
125                                      "failed") % filename, original_errno);
126    }
127    return fd;
128}
129
130
131/// Exception-based, type-improved version of wait(2).
132///
133/// Because we are waiting for the termination of a process, and because this is
134/// the canonical way to call wait(2) for this module, we ensure from here that
135/// any subprocess of the process we are killing is terminated.
136///
137/// \param pid The identifier of the process to wait for.
138///
139/// \return The termination status of the process.
140///
141/// \throw process::system_error If the call to waitpid(2) fails.
142static process::status
143safe_wait(const pid_t pid)
144{
145    LD(F("Waiting for pid=%s") % pid);
146    int stat_loc;
147    if (process::detail::syscall_waitpid(pid, &stat_loc, 0) == -1) {
148        const int original_errno = errno;
149        throw process::system_error(F("Failed to wait for PID %s") % pid,
150                                    original_errno);
151    }
152    return process::status(pid, stat_loc);
153}
154
155
156/// Logs the execution of another program.
157///
158/// \param program The binary to execute.
159/// \param args The arguments to pass to the binary, without the program name.
160static void
161log_exec(const fs::path& program, const process::args_vector& args)
162{
163    std::string plain_command = program.str();
164    for (process::args_vector::const_iterator iter = args.begin();
165         iter != args.end(); ++iter)
166        plain_command += F(" %s") % *iter;
167    LD(F("Executing %s") % plain_command);
168}
169
170
171/// Maximum number of arguments supported by cxx_exec.
172///
173/// We need this limit to avoid having to allocate dynamic memory in the child
174/// process to construct the arguments list, which would have side-effects in
175/// the parent's memory if we use vfork().
176#define MAX_ARGS 128
177
178
179static void cxx_exec(const fs::path& program, const process::args_vector& args)
180    throw() UTILS_NORETURN;
181
182
183/// Executes an external binary and replaces the current process.
184///
185/// This function must not use any of the logging features, so that the output
186/// of the subprocess is not "polluted" by our own messages.
187///
188/// This function must also not affect the global state of the current process
189/// as otherwise we would not be able to use vfork().  Only state stored in the
190/// stack can be touched.
191///
192/// \param program The binary to execute.
193/// \param args The arguments to pass to the binary, without the program name.
194static void
195cxx_exec(const fs::path& program, const process::args_vector& args) throw()
196{
197    assert(args.size() < MAX_ARGS);
198    try {
199        const char* argv[MAX_ARGS + 1];
200
201        argv[0] = program.c_str();
202        for (process::args_vector::size_type i = 0; i < args.size(); i++)
203            argv[1 + i] = args[i].c_str();
204        argv[1 + args.size()] = NULL;
205
206        const int ret = ::execv(program.c_str(),
207                                (char* const*)(unsigned long)(const void*)argv);
208        const int original_errno = errno;
209        assert(ret == -1);
210
211        std::cerr << "Failed to execute " << program << ": "
212                  << std::strerror(original_errno) << "\n";
213        std::abort();
214    } catch (const std::runtime_error& error) {
215        std::cerr << "Failed to execute " << program << ": "
216                  << error.what() << "\n";
217        std::abort();
218    } catch (...) {
219        std::cerr << "Failed to execute " << program << "; got unexpected "
220            "exception during exec\n";
221        std::abort();
222    }
223}
224
225
226}  // anonymous namespace
227
228
229/// Creates a new child.
230///
231/// \param implptr A dynamically-allocated impl object with the contents of the
232///     new child.
233process::child::child(impl *implptr) :
234    _pimpl(implptr)
235{
236}
237
238
239/// Destructor for child.
240process::child::~child(void)
241{
242}
243
244
245/// Helper function for fork().
246///
247/// Please note: if you update this function to change the return type or to
248/// raise different errors, do not forget to update fork() accordingly.
249///
250/// \return In the case of the parent, a new child object returned as a
251/// dynamically-allocated object because children classes are unique and thus
252/// noncopyable.  In the case of the child, a NULL pointer.
253///
254/// \throw process::system_error If the calls to pipe(2) or fork(2) fail.
255std::unique_ptr< process::child >
256process::child::fork_capture_aux(void)
257{
258    std::cout.flush();
259    std::cerr.flush();
260
261    int fds[2];
262    if (detail::syscall_pipe(fds) == -1)
263        throw process::system_error("pipe(2) failed", errno);
264
265    std::unique_ptr< signals::interrupts_inhibiter > inhibiter(
266        new signals::interrupts_inhibiter);
267    pid_t pid = detail::syscall_fork();
268    if (pid == -1) {
269        inhibiter.reset(NULL);  // Unblock signals.
270        ::close(fds[0]);
271        ::close(fds[1]);
272        throw process::system_error("fork(2) failed", errno);
273    } else if (pid == 0) {
274        inhibiter.reset(NULL);  // Unblock signals.
275        ::setpgid(::getpid(), ::getpid());
276
277        try {
278            ::close(fds[0]);
279            safe_dup(fds[1], STDOUT_FILENO);
280            safe_dup(fds[1], STDERR_FILENO);
281            ::close(fds[1]);
282        } catch (const system_error& e) {
283            std::cerr << F("Failed to set up subprocess: %s\n") % e.what();
284            std::abort();
285        }
286        return std::unique_ptr< process::child >();
287    } else {
288        ::close(fds[1]);
289        LD(F("Spawned process %s: stdout and stderr inherited") % pid);
290        signals::add_pid_to_kill(pid);
291        inhibiter.reset(NULL);  // Unblock signals.
292        return std::unique_ptr< process::child >(
293            new process::child(new impl(pid, new process::ifdstream(fds[0]))));
294    }
295}
296
297
298/// Helper function for fork().
299///
300/// Please note: if you update this function to change the return type or to
301/// raise different errors, do not forget to update fork() accordingly.
302///
303/// \param stdout_file The name of the file in which to store the stdout.
304///     If this has the magic value /dev/stdout, then the parent's stdout is
305///     reused without applying any redirection.
306/// \param stderr_file The name of the file in which to store the stderr.
307///     If this has the magic value /dev/stderr, then the parent's stderr is
308///     reused without applying any redirection.
309///
310/// \return In the case of the parent, a new child object returned as a
311/// dynamically-allocated object because children classes are unique and thus
312/// noncopyable.  In the case of the child, a NULL pointer.
313///
314/// \throw process::system_error If the call to fork(2) fails.
315std::unique_ptr< process::child >
316process::child::fork_files_aux(const fs::path& stdout_file,
317                               const fs::path& stderr_file)
318{
319    std::cout.flush();
320    std::cerr.flush();
321
322    std::unique_ptr< signals::interrupts_inhibiter > inhibiter(
323        new signals::interrupts_inhibiter);
324    pid_t pid = detail::syscall_fork();
325    if (pid == -1) {
326        inhibiter.reset(NULL);  // Unblock signals.
327        throw process::system_error("fork(2) failed", errno);
328    } else if (pid == 0) {
329        inhibiter.reset(NULL);  // Unblock signals.
330        ::setpgid(::getpid(), ::getpid());
331
332        try {
333            if (stdout_file != fs::path("/dev/stdout")) {
334                const int stdout_fd = open_for_append(stdout_file);
335                safe_dup(stdout_fd, STDOUT_FILENO);
336                ::close(stdout_fd);
337            }
338            if (stderr_file != fs::path("/dev/stderr")) {
339                const int stderr_fd = open_for_append(stderr_file);
340                safe_dup(stderr_fd, STDERR_FILENO);
341                ::close(stderr_fd);
342            }
343        } catch (const system_error& e) {
344            std::cerr << F("Failed to set up subprocess: %s\n") % e.what();
345            std::abort();
346        }
347        return std::unique_ptr< process::child >();
348    } else {
349        LD(F("Spawned process %s: stdout=%s, stderr=%s") % pid % stdout_file %
350           stderr_file);
351        signals::add_pid_to_kill(pid);
352        inhibiter.reset(NULL);  // Unblock signals.
353        return std::unique_ptr< process::child >(
354            new process::child(new impl(pid, NULL)));
355    }
356}
357
358
359/// Spawns a new binary and multiplexes and captures its stdout and stderr.
360///
361/// If the subprocess cannot be completely set up for any reason, it attempts to
362/// dump an error message to its stderr channel and it then calls std::abort().
363///
364/// \param program The binary to execute.
365/// \param args The arguments to pass to the binary, without the program name.
366///
367/// \return A new child object, returned as a dynamically-allocated object
368/// because children classes are unique and thus noncopyable.
369///
370/// \throw process::system_error If the process cannot be spawned due to a
371///     system call error.
372std::unique_ptr< process::child >
373process::child::spawn_capture(const fs::path& program, const args_vector& args)
374{
375    std::unique_ptr< child > child = fork_capture_aux();
376    if (child.get() == NULL)
377        cxx_exec(program, args);
378    log_exec(program, args);
379    return child;
380}
381
382
383/// Spawns a new binary and redirects its stdout and stderr to files.
384///
385/// If the subprocess cannot be completely set up for any reason, it attempts to
386/// dump an error message to its stderr channel and it then calls std::abort().
387///
388/// \param program The binary to execute.
389/// \param args The arguments to pass to the binary, without the program name.
390/// \param stdout_file The name of the file in which to store the stdout.
391/// \param stderr_file The name of the file in which to store the stderr.
392///
393/// \return A new child object, returned as a dynamically-allocated object
394/// because children classes are unique and thus noncopyable.
395///
396/// \throw process::system_error If the process cannot be spawned due to a
397///     system call error.
398std::unique_ptr< process::child >
399process::child::spawn_files(const fs::path& program,
400                            const args_vector& args,
401                            const fs::path& stdout_file,
402                            const fs::path& stderr_file)
403{
404    std::unique_ptr< child > child = fork_files_aux(stdout_file, stderr_file);
405    if (child.get() == NULL)
406        cxx_exec(program, args);
407    log_exec(program, args);
408    return child;
409}
410
411
412/// Returns the process identifier of this child.
413///
414/// \return A process identifier.
415int
416process::child::pid(void) const
417{
418    return _pimpl->_pid;
419}
420
421
422/// Gets the input stream corresponding to the stdout and stderr of the child.
423///
424/// \pre The child must have been started by fork_capture().
425///
426/// \return A reference to the input stream connected to the output of the test
427/// case.
428std::istream&
429process::child::output(void)
430{
431    PRE(_pimpl->_output.get() != NULL);
432    return *_pimpl->_output;
433}
434
435
436/// Blocks to wait for completion.
437///
438/// \return The termination status of the child process.
439///
440/// \throw process::system_error If the call to waitpid(2) fails.
441process::status
442process::child::wait(void)
443{
444    const process::status status = safe_wait(_pimpl->_pid);
445    {
446        signals::interrupts_inhibiter inhibiter;
447        signals::remove_pid_to_kill(_pimpl->_pid);
448    }
449    return status;
450}
451