pid_t initPid;
/// Namespaces to which we'll attach
- std::vector<Namespace> namespaces;
+ int namespaces;
/// User ID to set
uid_t uid;
AttachConfig(const std::vector<std::string>& argv,
const pid_t initPid,
- const std::vector<Namespace>& namespaces,
+ const int namespaces,
const uid_t uid,
const gid_t gid,
const std::vector<gid_t>& supplementaryGids,
CONFIG_REGISTER
(
- //TODO: Uncomment and fix cstring serialization
argv,
initPid,
namespaces,
* Namespace types used to create the container
*
* Set: setNamespaces()
- * Get: none
+ * Get: getNamespaces()
*/
int mNamespaces;
mConfig.mNamespaces = namespaces;
}
+
+int ContainerImpl::getNamespaces() const
+{
+ return mConfig.mNamespaces;
+}
+
void ContainerImpl::start()
{
// TODO: check config consistency and completeness somehow
console.execute();
}
-const std::vector<Namespace>& ContainerImpl::getNamespaces() const
-{
- return mNamespaces;
-}
-
void ContainerImpl::addInterfaceConfig(const std::string& hostif,
const std::string& zoneif,
InterfaceType type,
void setTerminalCount(const unsigned int count);
- const std::vector<Namespace>& getNamespaces() const;
void setNamespaces(const int namespaces);
+ int getNamespaces() const;
// Execution actions
void start();
private:
ContainerConfig mConfig;
-
- // TODO: convert to ContainerConfig struct
- std::vector<Namespace> mNamespaces;
};
} // namespace lxcpp
const std::string &arg = "") = 0;
virtual void setTerminalCount(const unsigned int count) = 0;
+
virtual void setNamespaces(const int namespaces) = 0;
+ virtual int getNamespaces() const = 0;
// Execution actions
virtual void start() = 0;
#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)
+std::string nsToString(const int ns)
{
switch(ns) {
- case Namespace::USER:
+ case CLONE_NEWUSER:
return "user";
- case Namespace::MNT:
+ case CLONE_NEWNS:
return "mnt";
- case Namespace::PID:
+ case CLONE_NEWPID:
return "pid";
- case Namespace::UTS:
+ case CLONE_NEWUTS:
return "uts";
- case Namespace::IPC:
+ case CLONE_NEWIPC:
return "ipc";
- case Namespace::NET:
+ case CLONE_NEWNET:
return "net";
default:
const std::string msg = "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)
+std::string getPath(const pid_t pid, const int ns)
{
- return getNsPath(pid) + "/" + toString(ns);
+ return getNsPath(pid) + "/" + nsToString(ns);
}
} // namespace lxcpp
#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 nsToString(const int 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);
+std::string getPath(const pid_t pid, const int ns);
} // namespace lxcpp
#include <sys/wait.h>
#include <fcntl.h>
+#include <array>
+
namespace lxcpp {
pid_t fork()
return pid;
}
-pid_t clone(int (*function)(void *),
- void *args,
- const std::vector<Namespace>& namespaces,
- const int additionalFlags)
-{
- return clone(function, args, toFlag(namespaces) | additionalFlags);
-}
-
-void setns(const pid_t pid, const std::vector<Namespace>& namespaces)
+void setns(const pid_t pid, int requestedNamespaces)
{
int dirFD = utils::open(getNsPath(pid), O_DIRECTORY | O_CLOEXEC);
+ static const std::array<int, 6> NAMESPACES {{
+ CLONE_NEWUSER, CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC, CLONE_NEWNET
+ }};
+
// 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(),
+ std::vector<int> fds;
+ for(const int ns: NAMESPACES) {
+ if (!(ns & requestedNamespaces)) {
+ // This namespace wasn't requested
+ continue;
+ }
+
+ int fd = ::openat(dirFD,
+ nsToString(ns).c_str(),
O_RDONLY | O_CLOEXEC);
- if(fds[i] < 0) {
+ if(fd < 0) {
const std::string msg = "openat() failed: " + utils::getSystemErrorMessage();
- for (size_t j = 0; j < i; ++j) {
- utils::close(fds[j]);
+ // Cleanup file descriptors
+ for (const int d: fds) {
+ utils::close(d);
}
utils::close(dirFD);
LOGE(msg);
throw ProcessSetupException(msg);
}
+
+ fds.push_back(fd);
}
- // Setns for every namespace
+ // Setns to every requested namespace
for(size_t i = 0; i < fds.size(); ++i) {
- if(-1 == ::setns(fds[i], toFlag(namespaces[i]))) {
+ if(-1 == ::setns(fds[i], 0 /* we're sure it's a fd of the right namespace*/)) {
const std::string msg = "setns() failed: " + utils::getSystemErrorMessage();
for (size_t j = i; j < fds.size(); ++j) {
throw ProcessSetupException(msg);
}
-void unshare(const Namespace ns)
+void unshare(const int ns)
{
- if(-1 == ::unshare(toFlag(ns))) {
+ if(-1 == ::unshare(ns)) {
const std::string msg = "unshare() failed: " + utils::getSystemErrorMessage();
LOGE(msg);
throw ProcessSetupException(msg);
void *args,
const int flags);
-pid_t clone(int (*function)(void *),
- void *args,
- const std::vector<Namespace>& namespaces,
- const int additionalFlags = 0);
-
-void setns(const pid_t pid,
- const std::vector<Namespace>& namespaces);
+void setns(const pid_t pid, const int namespaces);
int waitpid(const pid_t pid);
-void unshare(const Namespace ns);
+void unshare(const int ns);
void execve(const std::vector<std::string>& argv);
using namespace lxcpp;
-const std::array<Namespace, 6> NAMESPACES {{
- Namespace::USER,
- Namespace::MNT,
- Namespace::PID,
- Namespace::UTS,
- Namespace::IPC,
- Namespace::NET
+static const std::array<int, 6> NAMESPACES {{
+ CLONE_NEWUSER,
+ CLONE_NEWNS,
+ CLONE_NEWPID,
+ CLONE_NEWUTS,
+ CLONE_NEWIPC,
+ CLONE_NEWNET
}};
-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) {
BOOST_AUTO_TEST_CASE(ToString)
{
for(const auto ns: NAMESPACES) {
- toString(ns);
+ nsToString(ns);
}
}
~Fixture() {}
};
-int clonefn(void* /*args*/) {
+int clonefn(void*) {
return 0;
}
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(lxcpp::clone(clonefn, nullptr, NAMESPACES));
- BOOST_CHECK_NO_THROW(lxcpp::clone(clonefn, nullptr, {Namespace::MNT}));
+ BOOST_CHECK_NO_THROW(lxcpp::clone(clonefn,
+ nullptr,
+ CLONE_NEWUSER | CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWNET));
+ BOOST_CHECK_NO_THROW(lxcpp::clone(clonefn, nullptr, CLONE_NEWNS));
}
BOOST_AUTO_TEST_CASE(Setns)
pid_t pid = lxcpp::fork();
if (pid == 0) {
try {
- lxcpp::setns(::getpid(), {Namespace::MNT,
- Namespace::PID,
- Namespace::UTS,
- Namespace::IPC,
- Namespace::NET
- });
+ lxcpp::setns(::getpid(),
+ CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWNET);
::_exit(TEST_PASSED);
} catch(...) {
::_exit(ERROR);
pid_t pid = lxcpp::fork();
if (pid == 0) {
try {
- lxcpp::setns(::getpid(), {Namespace::USER});
+ lxcpp::setns(::getpid(), CLONE_NEWUSER);
::_exit(ERROR);
} catch(ProcessSetupException) {
::_exit(TEST_PASSED);