2 * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License version 2.1 as published by the Free Software Foundation.
8 * This library 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 GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * @author Jan Olszak (j.olszak@samsung.com)
21 * @brief process handling routines
24 #include "lxcpp/process.hpp"
25 #include "lxcpp/exception.hpp"
27 #include "logger/logger.hpp"
28 #include "utils/fd-utils.hpp"
29 #include "utils/exception.hpp"
45 const std::string msg = "fork() failed: " +
46 utils::getSystemErrorMessage();
48 throw ProcessSetupException(msg);
53 pid_t clone(int (*function)(void *),
57 // Won't fail, well known resource name
58 size_t stackSize = ::sysconf(_SC_PAGESIZE);
60 // PAGESIZE is enough, it'll exec after this
61 char *stack = static_cast<char*>(::alloca(stackSize));
63 pid_t pid = ::clone(function, stack + stackSize, flags | SIGCHLD, args);
65 const std::string msg = "clone() failed: " +
66 utils::getSystemErrorMessage();
68 throw ProcessSetupException(msg);
74 void setns(const pid_t pid, int requestedNamespaces)
76 int dirFD = utils::open(getNsPath(pid), O_DIRECTORY | O_CLOEXEC);
78 static const std::array<int, 6> NAMESPACES {{
79 CLONE_NEWUSER, CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC, CLONE_NEWNET
82 // Open FDs connected with the requested namespaces
84 for(const int ns: NAMESPACES) {
85 if (!(ns & requestedNamespaces)) {
86 // This namespace wasn't requested
90 int fd = ::openat(dirFD,
91 nsToString(ns).c_str(),
92 O_RDONLY | O_CLOEXEC);
94 const std::string msg = "openat() failed: " + utils::getSystemErrorMessage();
96 // Cleanup file descriptors
97 for (const int d: fds) {
103 throw ProcessSetupException(msg);
109 // Setns to every requested namespace
110 for(size_t i = 0; i < fds.size(); ++i) {
111 if(-1 == ::setns(fds[i], 0 /* we're sure it's a fd of the right namespace*/)) {
112 const std::string msg = "setns() failed: " + utils::getSystemErrorMessage();
114 for (size_t j = i; j < fds.size(); ++j) {
115 utils::close(fds[j]);
120 throw ProcessSetupException(msg);
122 utils::close(fds[i]);
128 int waitpid(const pid_t pid)
131 while (-1 == ::waitpid(pid, &status, 0)) {
132 if (errno == EINTR) {
133 LOGT("waitpid() interrupted, retrying");
136 const std::string msg = "waitpid() failed: " + utils::getSystemErrorMessage();
138 throw ProcessSetupException(msg);
141 // Return child's return status if everything is OK
142 if (WIFEXITED(status)) {
143 return WEXITSTATUS(status);
146 // Something went wrong in the child
148 if (WIFSIGNALED(status)) {
149 msg = "Child killed by signal " + std::to_string(WTERMSIG(status));
151 msg = "Unknown eror in child process";
154 throw ProcessSetupException(msg);
157 void unshare(const int ns)
159 if(-1 == ::unshare(ns)) {
160 const std::string msg = "unshare() failed: " + utils::getSystemErrorMessage();
162 throw ProcessSetupException(msg);
166 void execve(const std::vector<std::string>& argv)
168 // Prepare the arguments
169 std::vector<char const *> tmpArgv;
170 tmpArgv.reserve(argv.size() + 1);
172 for (auto const &str : argv) {
173 tmpArgv.push_back(str.c_str());
175 tmpArgv.push_back(nullptr);
178 ::execve(tmpArgv[0], const_cast<char *const*>(tmpArgv.data()), nullptr);