TYPE3
[iec.git] / src / type3_AndroidCloud / anbox-master / external / process-cpp-minimal / src / core / posix / fork.cpp
1 /*
2  * Copyright © 2013 Canonical Ltd.
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License version 3,
6  * as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Authored by: Thomas Voß <thomas.voss@canonical.com>
17  */
18
19 #include <core/posix/exit.h>
20 #include <core/posix/fork.h>
21
22 #ifndef ANDROID
23 #include "backtrace.h"
24 #endif
25
26 #include <iomanip>
27 #include <iostream>
28 #include <system_error>
29
30 #include <unistd.h>
31
32 namespace
33 {
34 void redirect_stream_to_fd(int fd, int stream)
35 {
36     auto rc = ::dup2(fd, stream);
37     if (rc == -1)
38         throw std::system_error(errno, std::system_category());
39 }
40
41 void print_backtrace(std::ostream& out, const std::string& line_prefix)
42 {
43 #ifndef ANDROID
44     core::posix::backtrace::visit_with_handler([&out, line_prefix](const core::posix::backtrace::Frame& frame)
45     {
46         out << line_prefix << std::dec << std::setw(2) << frame.depth() << "@" << std::hex << std::setw(14) << frame.frame_pointer() << ": "
47             << (frame.symbol().is_cxx() ? frame.symbol().demangled() : frame.symbol().raw()) << std::endl;
48         return true;
49     });
50 #endif
51 }
52 }
53
54 namespace core
55 {
56 namespace posix
57 {
58
59 bool is_child(pid_t pid) { return pid == 0; }
60
61 ChildProcess fork(const std::function<posix::exit::Status()>& main,
62                   const StandardStream& flags)
63 {
64     ChildProcess::Pipe stdin_pipe{ChildProcess::Pipe::invalid()};
65     ChildProcess::Pipe stdout_pipe{ChildProcess::Pipe::invalid()};
66     ChildProcess::Pipe stderr_pipe{ChildProcess::Pipe::invalid()};
67
68     if ((flags & StandardStream::stdin) != StandardStream::empty)
69         stdin_pipe = ChildProcess::Pipe();
70     if ((flags & StandardStream::stdout) != StandardStream::empty)
71         stdout_pipe = ChildProcess::Pipe();
72     if ((flags & StandardStream::stderr) != StandardStream::empty)
73         stderr_pipe = ChildProcess::Pipe();
74
75     pid_t pid = ::fork();
76
77     if (pid == -1)
78         throw std::system_error(errno, std::system_category());
79
80     if (is_child(pid))
81     {
82         posix::exit::Status result = posix::exit::Status::failure;
83
84         try
85         {
86             stdin_pipe.close_write_fd();
87             stdout_pipe.close_read_fd();
88             stderr_pipe.close_read_fd();
89             // We replace stdin and stdout of the child process first:
90             if ((flags & StandardStream::stdin) != StandardStream::empty)
91                 redirect_stream_to_fd(stdin_pipe.read_fd(), STDIN_FILENO);
92             if ((flags & StandardStream::stdout) != StandardStream::empty)
93                 redirect_stream_to_fd(stdout_pipe.write_fd(), STDOUT_FILENO);
94             if ((flags & StandardStream::stderr) != StandardStream::empty)
95                 redirect_stream_to_fd(stderr_pipe.write_fd(), STDERR_FILENO);
96
97             result = main();
98         } catch(const std::exception& e)
99         {
100             std::cerr << "core::posix::fork(): An unhandled std::exception occured in the child process:" << std::endl
101                       << "  what(): " << e.what() << std::endl;
102             print_backtrace(std::cerr, "  ");
103         } catch(...)
104         {
105             std::cerr << "core::posix::fork(): An unhandled exception occured in the child process." << std::endl;
106             print_backtrace(std::cerr, "  ");
107         }
108
109         // We have to ensure that we exit here. Otherwise, we run into
110         // all sorts of weird issues.
111         ::exit(static_cast<int>(result));
112     }
113
114     // We are in the parent process, and create a process object
115     // corresponding to the newly forked process.
116     stdin_pipe.close_read_fd();
117     stdout_pipe.close_write_fd();
118     stderr_pipe.close_write_fd();
119
120     return ChildProcess(pid,
121                         stdin_pipe,
122                         stdout_pipe,
123                         stderr_pipe);
124 }
125
126 ChildProcess vfork(const std::function<posix::exit::Status()>& main,
127                    const StandardStream& flags)
128 {
129     ChildProcess::Pipe stdin_pipe, stdout_pipe, stderr_pipe;
130
131     pid_t pid = ::vfork();
132
133     if (pid == -1)
134         throw std::system_error(errno, std::system_category());
135
136     if (is_child(pid))
137     {
138         posix::exit::Status result = posix::exit::Status::failure;
139
140         try
141         {
142             // We replace stdin and stdout of the child process first:
143             stdin_pipe.close_write_fd();
144             stdout_pipe.close_read_fd();
145             stderr_pipe.close_read_fd();
146             // We replace stdin and stdout of the child process first:
147             if ((flags & StandardStream::stdin) != StandardStream::empty)
148                 redirect_stream_to_fd(stdin_pipe.read_fd(), STDIN_FILENO);
149             if ((flags & StandardStream::stdout) != StandardStream::empty)
150                 redirect_stream_to_fd(stdout_pipe.write_fd(), STDOUT_FILENO);
151             if ((flags & StandardStream::stderr) != StandardStream::empty)
152                 redirect_stream_to_fd(stderr_pipe.write_fd(), STDERR_FILENO);
153
154             result = main();
155         } catch(const std::exception& e)
156         {
157             std::cerr << "core::posix::fork(): An unhandled std::exception occured in the child process:" << std::endl
158                       << "  what(): " << e.what() << std::endl;
159             print_backtrace(std::cerr, "  ");
160         } catch(...)
161         {
162             std::cerr << "core::posix::fork(): An unhandled exception occured in the child process." << std::endl;
163             print_backtrace(std::cerr, "  ");
164         }
165
166         // We have to ensure that we exit here. Otherwise, we run into
167         // all sorts of weird issues.
168         ::exit(static_cast<int>(result));
169     }
170
171     // We are in the parent process, and create a process object
172     // corresponding to the newly forked process.
173     // Close the parent's pipe end
174     stdin_pipe.close_read_fd();
175     stdout_pipe.close_write_fd();
176     stderr_pipe.close_write_fd();
177
178     return ChildProcess(pid,
179                         stdin_pipe,
180                         stdout_pipe,
181                         stderr_pipe);
182 }
183 }
184 }