{
while (waitpid(pid, &status, 0) == -1) {
if (errno != EINTR) {
+ LOGE("waitpid() failed: " << getSystemErrorMessage());
return false;
}
}
## Link libraries ##############################################################
INCLUDE_DIRECTORIES(${LIBS_FOLDER})
+INCLUDE_DIRECTORIES(${COMMON_FOLDER})
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} Logger)
## Generate the pc file ########################################################
ProcessSetupException(const std::string& message = "Error during setting up a process")
: Exception(message) {}
};
+
+struct BadArgument: public Exception {
+ BadArgument(const std::string& message = "Bad argument passed")
+ : Exception(message) {}
+};
+
} // namespace lxcpp
#endif // LXCPP_EXCEPTION_HPP
--- /dev/null
+/*
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief lxcpp container factory definition
+ */
+
+#include "lxcpp/namespace.hpp"
+#include "lxcpp/exception.hpp"
+#include "logger/logger.hpp"
+
+#include <numeric>
+#include <functional>
+
+namespace lxcpp {
+
+Namespace operator|(const Namespace a, const Namespace b)
+{
+ return static_cast<Namespace>(static_cast<std::underlying_type<Namespace>::type>(a) |
+ static_cast<std::underlying_type<Namespace>::type>(b));
+}
+
+std::string toString(const Namespace ns)
+{
+ switch(ns) {
+ case Namespace::USER:
+ return "user";
+ case Namespace::MNT:
+ return "mnt";
+ case Namespace::PID:
+ return "pid";
+ case Namespace::UTS:
+ return "uts";
+ case Namespace::IPC:
+ return "ipc";
+ case Namespace::NET:
+ return "net";
+ default:
+ LOGE("Bad namespace passed to the function");
+ throw BadArgument("Bad namespace passed to the function");
+ }
+}
+
+int toFlag(const std::vector<Namespace>& namespaces)
+{
+ Namespace flag = std::accumulate(namespaces.begin(),
+ namespaces.end(),
+ static_cast<Namespace>(0),
+ std::bit_or<Namespace>());
+ return static_cast<int>(flag);
+}
+
+int toFlag(const Namespace ns)
+{
+ return static_cast<int>(ns);
+}
+
+std::string getNsPath(const pid_t pid)
+{
+ return "/proc/" + std::to_string(pid) + "/ns";
+}
+
+std::string getPath(const pid_t pid, const Namespace ns)
+{
+ return getNsPath(pid) + "/" + toString(ns);
+}
+
+} // namespace lxcpp
--- /dev/null
+/*
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief process handling routines
+ */
+
+#ifndef LXCPP_NAMESPACE_HPP
+#define LXCPP_NAMESPACE_HPP
+
+#include <sched.h>
+#include <string>
+#include <vector>
+
+namespace lxcpp {
+
+enum class Namespace : int {
+ USER = CLONE_NEWUSER,
+ MNT = CLONE_NEWNS,
+ PID = CLONE_NEWPID,
+ UTS = CLONE_NEWUTS,
+ IPC = CLONE_NEWIPC,
+ NET = CLONE_NEWNET
+};
+
+Namespace operator |(const Namespace a, const Namespace b);
+
+std::string toString(const Namespace ns);
+
+std::string getNsPath(const pid_t pid);
+
+std::string getPath(const pid_t pid, const Namespace ns);
+
+int toFlag(const Namespace ns);
+
+int toFlag(const std::vector<Namespace>& namespaces);
+
+} // namespace lxcpp
+
+#endif // LXCPP_NAMESPACE_HPP
\ No newline at end of file
#include "lxcpp/process.hpp"
#include "lxcpp/exception.hpp"
+
#include "logger/logger.hpp"
+#include "utils/fd-utils.hpp"
+#include "utils/exception.hpp"
#include <alloca.h>
#include <sched.h>
#include <unistd.h>
#include <sys/wait.h>
+#include <fcntl.h>
namespace lxcpp {
-pid_t clone(int (*function)(void *), int flags, void *args) {
+pid_t clone(int (*function)(void *),
+ void *args,
+ const std::vector<Namespace>& namespaces,
+ const int additionalFlags)
+{
// Won't fail, well known resource name
size_t stackSize = ::sysconf(_SC_PAGESIZE);
// PAGESIZE is enough, it'll exec after this
char *stack = static_cast<char*>(::alloca(stackSize));
- pid_t ret;
- ret = ::clone(function, stack + stackSize, flags | SIGCHLD, args);
- if (ret < 0) {
- LOGE("clone() failed");
- throw ProcessSetupException("clone() failed");
+ pid_t pid = ::clone(function, stack + stackSize, toFlag(namespaces) | additionalFlags | SIGCHLD, args);
+ if (pid < 0) {
+ const std::string msg = utils::getSystemErrorMessage();
+ LOGE("clone() failed: " << msg);
+ throw ProcessSetupException("clone() failed " + msg);
+ }
+
+ return pid;
+}
+
+void setns(const std::vector<Namespace>& namespaces)
+{
+ pid_t pid = ::getpid();
+
+ int dirFD = ::open(getNsPath(pid).c_str(), O_DIRECTORY | O_CLOEXEC);
+ if(dirFD < 0) {
+ const std::string msg = utils::getSystemErrorMessage();
+ LOGE("open() failed: " << msg);
+ throw ProcessSetupException("open() failed: " + msg);
+ }
+
+ // Open FDs connected with the requested namespaces
+ std::vector<int> fds(namespaces.size(), -1);
+ for(size_t i = 0; i < namespaces.size(); ++i) {
+ fds[i] = ::openat(dirFD, toString(namespaces[i]).c_str(), O_RDONLY | O_CLOEXEC);
+ if(fds[i] < 0) {
+ const std::string msg = utils::getSystemErrorMessage();
+
+ for (size_t j = 0; j < i; ++j) {
+ utils::close(fds[j]);
+ }
+ utils::close(dirFD);
+
+ LOGE("openat() failed: " << msg);
+ throw ProcessSetupException("openat() failed: " + msg);
+ }
+ }
+
+ // Setns for every namespace
+ for(size_t i = 0; i < fds.size(); ++i) {
+ if(-1 == ::setns(fds[i], toFlag(namespaces[i]))) {
+ const std::string msg = utils::getSystemErrorMessage();
+
+ for (size_t j = i; j < fds.size(); ++j) {
+ utils::close(fds[j]);
+ }
+ utils::close(dirFD);
+
+ LOGE("setns() failed: " << msg);
+ throw ProcessSetupException("setns() failed: " + msg);
+ }
+ utils::close(fds[i]);
}
- return ret;
+ utils::close(dirFD);
}
} // namespace lxcpp
\ No newline at end of file
#ifndef LXCPP_PROCESS_HPP
#define LXCPP_PROCESS_HPP
+#include "lxcpp/namespace.hpp"
+
#include <sys/types.h>
+#include <vector>
namespace lxcpp {
-pid_t clone(int (*function)(void *), int flags, void *args);
+pid_t clone(int (*function)(void *),
+ void *args,
+ const std::vector<Namespace>& namespaces,
+ const int additionalFlags = 0);
+
+void setns(const std::vector<Namespace>& namespaces);
} // namespace lxcpp
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
*
- * Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
+ * Contact: Jan Olszak(j.olszak@samsung.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "lxcpp/lxcpp.hpp"
#include "lxcpp/exception.hpp"
-#include <memory>
-
namespace {
struct Fixture {
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Jan Olszak(j.olszak@samsung.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+
+/**
+ * @file
+ * @author Jan Olszak(j.olszak@samsung.com)
+ * @brief Unit tests of lxcpp namespace helpers
+ */
+
+#include "config.hpp"
+#include "ut.hpp"
+
+#include "lxcpp/namespace.hpp"
+#include <iostream>
+#include <sched.h>
+
+namespace {
+
+struct Fixture {
+ Fixture() {}
+ ~Fixture() {}
+};
+
+} // namespace
+
+BOOST_FIXTURE_TEST_SUITE(LxcppNamespaceSuite, Fixture)
+
+using namespace lxcpp;
+
+const std::array<Namespace, 6> NAMESPACES {{
+ Namespace::USER,
+ Namespace::MNT,
+ Namespace::PID,
+ Namespace::UTS,
+ Namespace::IPC,
+ Namespace::NET
+ }};
+
+BOOST_AUTO_TEST_CASE(OR)
+{
+ Namespace a = Namespace::USER;
+ Namespace b = Namespace::MNT;
+ BOOST_CHECK_EQUAL(CLONE_NEWUSER | CLONE_NEWNS, static_cast<int>(a | b));
+}
+
+BOOST_AUTO_TEST_CASE(GetPath)
+{
+ for(const auto ns: NAMESPACES) {
+ getPath(0, ns);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(ToString)
+{
+ for(const auto ns: NAMESPACES) {
+ toString(ns);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Jan Olszak(j.olszak@samsung.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+
+/**
+ * @file
+ * @author Jan Olszak(j.olszak@samsung.com)
+ * @brief Unit tests of lxcpp process helpers
+ */
+
+#include "config.hpp"
+#include "ut.hpp"
+
+#include "lxcpp/process.hpp"
+#include "lxcpp/exception.hpp"
+#include "utils/exception.hpp"
+#include "utils/execute.hpp"
+
+#include <iostream>
+#include <sched.h>
+#include <sys/wait.h>
+
+namespace {
+
+struct Fixture {
+ Fixture() {}
+ ~Fixture() {}
+};
+
+int clonefn(void* /*args*/) {
+ return 0;
+}
+
+} // namespace
+
+BOOST_FIXTURE_TEST_SUITE(LxcppProcessSuite, Fixture)
+
+using namespace lxcpp;
+
+const std::vector<Namespace> NAMESPACES {{
+ Namespace::USER,
+ Namespace::MNT,
+ Namespace::PID,
+ Namespace::UTS,
+ Namespace::IPC,
+ Namespace::NET
+ }};
+
+BOOST_AUTO_TEST_CASE(Clone)
+{
+ BOOST_CHECK_NO_THROW(clone(clonefn, nullptr, NAMESPACES));
+ BOOST_CHECK_NO_THROW(clone(clonefn, nullptr, {Namespace::MNT}));
+}
+
+BOOST_AUTO_TEST_CASE(Setns)
+{
+ const int TEST_PASSED = 0;
+ const int ERROR = 1;
+
+ pid_t pid = fork();
+ if (pid==-1) {
+ BOOST_REQUIRE(false);
+ } else if(pid ==0) {
+ try {
+ setns({Namespace::MNT,
+ Namespace::PID,
+ Namespace::UTS,
+ Namespace::IPC,
+ Namespace::NET
+ });
+ exit(TEST_PASSED);
+ } catch(...) {
+ exit(ERROR);
+ }
+ } else if(pid>0) {
+ int status = -1;
+ BOOST_REQUIRE(utils::waitPid(pid, status));
+ BOOST_REQUIRE(status == TEST_PASSED);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(SetnsUserNamespace)
+{
+ const int TEST_PASSED = 0;
+ const int ERROR = -1;
+
+ pid_t pid = fork();
+ if (pid==-1) {
+ BOOST_REQUIRE(false);
+ } else if(pid ==0) {
+ try {
+ setns({Namespace::USER});
+ exit(ERROR);
+ } catch(ProcessSetupException) {
+ exit(TEST_PASSED);
+ } catch(...) {
+ exit(ERROR);
+ }
+ } else if(pid>0) {
+ int status;
+ BOOST_REQUIRE(utils::waitPid(pid, status));
+ BOOST_REQUIRE(status == TEST_PASSED);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()