--- /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 Implementation of attaching to a container
+ */
+
+#include "lxcpp/attach-manager.hpp"
+#include "lxcpp/exception.hpp"
+#include "lxcpp/process.hpp"
+#include "lxcpp/filesystem.hpp"
+#include "lxcpp/namespace.hpp"
+#include "lxcpp/capability.hpp"
+
+#include "utils/exception.hpp"
+
+#include <unistd.h>
+#include <sys/mount.h>
+
+
+namespace lxcpp {
+
+namespace {
+
+void setupMountPoints()
+{
+ /* TODO: Uncomment when preparing the final attach() version
+
+ // TODO: This unshare should be optional only if we attach to PID/NET namespace, but not MNT.
+ // Otherwise container already has remounted /proc /sys
+ lxcpp::unshare(Namespace::MNT);
+
+ if (isMountPointShared("/")) {
+ // TODO: Handle case when the container rootfs or mount location is MS_SHARED, but not '/'
+ lxcpp::mount(nullptr, "/", nullptr, MS_SLAVE | MS_REC, nullptr);
+ }
+
+ if(isMountPoint("/proc")) {
+ lxcpp::umount("/proc", MNT_DETACH);
+ lxcpp::mount("none", "/proc", "proc", 0, nullptr);
+ }
+
+ if(isMountPoint("/sys")) {
+ lxcpp::umount("/sys", MNT_DETACH);
+ lxcpp::mount("none", "/sys", "sysfs", 0, nullptr);
+ }
+
+ */
+}
+
+} // namespace
+
+AttachManager::AttachManager(lxcpp::ContainerImpl& container)
+ : mContainer(container)
+{
+}
+
+AttachManager::~AttachManager()
+{
+}
+
+void AttachManager::attach(Container::AttachCall& call,
+ const std::string& wdInContainer)
+{
+ // Channels for setup synchronization
+ utils::Channel intermChannel;
+
+ const pid_t interPid = lxcpp::fork();
+ if (interPid > 0) {
+ intermChannel.setLeft();
+ parent(intermChannel, interPid);
+ intermChannel.shutdown();
+ } else {
+ intermChannel.setRight();
+ interm(intermChannel, wdInContainer, call);
+ intermChannel.shutdown();
+ ::_exit(0);
+ }
+}
+
+int AttachManager::child(void* data)
+{
+ try {
+ // TODO Pass mask and options via data
+ dropCapsFromBoundingExcept(0);
+ setupMountPoints();
+ return (*static_cast<Container::AttachCall*>(data))();
+ } catch(...) {
+ return -1; // Non-zero on failure
+ }
+ return 0; // Success
+}
+
+void AttachManager::parent(utils::Channel& intermChannel, const pid_t interPid)
+{
+ // TODO: Setup cgroups etc
+ const pid_t childPid = intermChannel.read<pid_t>();
+
+ // Wait for all processes
+ lxcpp::waitpid(interPid);
+ lxcpp::waitpid(childPid);
+}
+
+void AttachManager::interm(utils::Channel& intermChannel,
+ const std::string& wdInContainer,
+ Container::AttachCall& call)
+{
+ lxcpp::setns(mContainer.getInitPid(), mContainer.getNamespaces());
+
+ // Change the current work directory
+ // wdInContainer is a path relative to the container's root
+ lxcpp::chdir(wdInContainer);
+
+ // PID namespace won't affect the returned pid
+ // CLONE_PARENT: Child's PPID == Caller's PID
+ const pid_t childPid = lxcpp::clone(&AttachManager::child,
+ &call,
+ CLONE_PARENT);
+ intermChannel.write(childPid);
+
+}
+
+} // 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 Implementation of attaching to a container
+ */
+
+#ifndef LXCPP_ATTACH_MANAGER_HPP
+#define LXCPP_ATTACH_MANAGER_HPP
+
+#include "lxcpp/container-impl.hpp"
+#include "utils/channel.hpp"
+
+#include <string>
+
+namespace lxcpp {
+
+class AttachManager final {
+public:
+ AttachManager(lxcpp::ContainerImpl& container);
+ ~AttachManager();
+
+ /**
+ * Runs the call in the container's context
+ *
+ * @param call function to run inside container
+ * @param wdInContainer Current Work Directory. Path relative to container's root
+ */
+ void attach(Container::AttachCall& call,
+ const std::string& wdInContainer);
+
+private:
+ const lxcpp::ContainerImpl& mContainer;
+
+ // Methods for different stages of setting up the attachment
+ static int child(void* data);
+
+ void parent(utils::Channel& intermChannel,
+ const pid_t pid);
+
+ void interm(utils::Channel& intermChannel,
+ const std::string& wdInContainer,
+ Container::AttachCall& call);
+};
+
+} // namespace lxcpp
+
+#endif // LXCPP_ATTACH_MANAGER_HPP
\ No newline at end of file
#include "lxcpp/filesystem.hpp"
#include "lxcpp/namespace.hpp"
#include "lxcpp/capability.hpp"
+#include "lxcpp/attach-manager.hpp"
#include "utils/exception.hpp"
throw NotImplementedException();
}
-int ContainerImpl::getInitPid()
+pid_t ContainerImpl::getInitPid() const
{
- throw NotImplementedException();
+ return mInitPid;
}
void ContainerImpl::create()
throw NotImplementedException();
}
-namespace {
-void setupMountPoints()
+void ContainerImpl::attach(Container::AttachCall& call,
+ const std::string& cwdInContainer)
{
- /* TODO: Uncomment when preparing the final attach() version
-
- // TODO: This unshare should be optional only if we attach to PID/NET namespace, but not MNT.
- // Otherwise container already has remounted /proc /sys
- lxcpp::unshare(Namespace::MNT);
-
- if (isMountPointShared("/")) {
- // TODO: Handle case when the container rootfs or mount location is MS_SHARED, but not '/'
- lxcpp::mount(nullptr, "/", nullptr, MS_SLAVE | MS_REC, nullptr);
- }
-
- if(isMountPoint("/proc")) {
- lxcpp::umount("/proc", MNT_DETACH);
- lxcpp::mount("none", "/proc", "proc", 0, nullptr);
- }
-
- if(isMountPoint("/sys")) {
- lxcpp::umount("/sys", MNT_DETACH);
- lxcpp::mount("none", "/sys", "sysfs", 0, nullptr);
- }
-
- */
-}
-} // namespace
-
-int ContainerImpl::attachChild(void* data) {
- try {
- // TODO Pass mask and options via data
- dropCapsFromBoundingExcept(0);
- setupMountPoints();
- return (*static_cast<Container::AttachCall*>(data))();
- } catch(...) {
- return -1; // Non-zero on failure
- }
- return 0; // Success
+ AttachManager attachManager(*this);
+ attachManager.attach(call, cwdInContainer);
}
-void ContainerImpl::attachParent(utils::Channel& channel, const pid_t interPid)
+const std::vector<Namespace>& ContainerImpl::getNamespaces() const
{
- // TODO: Setup cgroups etc
- pid_t childPid = channel.read<pid_t>();
-
- // Wait for the Intermediate process
- lxcpp::waitpid(interPid);
-
- // Wait for the Child process
- lxcpp::waitpid(childPid);
-}
-
-void ContainerImpl::attachIntermediate(utils::Channel& channel, Container::AttachCall& call)
-{
- lxcpp::setns(mInitPid, mNamespaces);
-
- // PID namespace won't affect the returned pid
- // CLONE_PARENT: Child's PPID == Caller's PID
- const pid_t pid = lxcpp::clone(&ContainerImpl::attachChild,
- &call,
- CLONE_PARENT);
- channel.write(pid);
+ return mNamespaces;
}
-void ContainerImpl::attach(Container::AttachCall& call)
-{
- utils::Channel channel;
-
- const pid_t interPid = lxcpp::fork();
- if (interPid > 0) {
- channel.setLeft();
- attachParent(channel, interPid);
- channel.shutdown();
- } else {
- channel.setRight();
- attachIntermediate(channel, call);
- channel.shutdown();
- ::_exit(0);
- }
-}
void ContainerImpl::addInterfaceConfig(const std::string& hostif,
const std::string& zoneif,
void freeze();
void unfreeze();
void reboot();
- int getInitPid();
+ pid_t getInitPid() const;
+ const std::vector<Namespace>& getNamespaces() const;
//Filesystem actions
void create();
std::string getRootPath();
// Other
- void attach(Container::AttachCall& attachCall);
+ void attach(Container::AttachCall& attachCall,
+ const std::string& cwdInContainer);
// Network interfaces setup/config
void addInterfaceConfig(const std::string& hostif,
void delAddr(const std::string& ifname, const InetAddr& addr);
private:
-
- // Methods for different stages of setting up the attachment
- void attachParent(utils::Channel& channel, const pid_t pid);
- void attachIntermediate(utils::Channel& channel, Container::AttachCall& call);
- static int attachChild(void* data);
-
pid_t mInitPid;
std::vector<Namespace> mNamespaces;
std::vector<NetworkInterfaceConfig> mInterfaceConfig;
#define LXCPP_CONTAINER_HPP
#include "lxcpp/network-config.hpp"
+#include <sys/types.h>
#include <string>
#include <functional>
virtual void freeze() = 0;
virtual void unfreeze() = 0;
virtual void reboot() = 0;
- virtual int getInitPid() = 0;
+ virtual pid_t getInitPid() const = 0;
//Filesystem actions
virtual void create() = 0;
virtual std::string getRootPath() = 0;
// Other
- virtual void attach(AttachCall& attachCall) = 0;
+ virtual void attach(AttachCall& attachCall,
+ const std::string& cwdInContainer) = 0;
// Network interfaces setup/config
virtual void addInterfaceConfig(const std::string& hostif,
#include <iterator>
#include <sys/mount.h>
#include <sys/stat.h>
+#include <unistd.h>
namespace lxcpp {
return false;
}
+void fchdir(int fd)
+{
+ if(-1 == ::fchdir(fd)) {
+ const std::string msg = "fchdir() failed: " + utils::getSystemErrorMessage();
+ LOGE(msg);
+ throw FileSystemSetupException(msg);
+ }
+}
+
+void chdir(const std::string& path)
+{
+ if(-1 == ::chdir(path.c_str())) {
+ const std::string msg = "chdir() failed: " + utils::getSystemErrorMessage();
+ LOGE(msg);
+ throw FileSystemSetupException(msg);
+ }
+}
+
} // namespace lxcpp
\ No newline at end of file
*/
bool isMountPointShared(const std::string& path);
+void fchdir(int fd);
+
+void chdir(const std::string& path);
+
} // namespace lxcpp
#endif // LXCPP_FILESYSTEM_HPP
\ No newline at end of file
mType(type),
mMode(mode)
{
+ // TODO: Remove temporary usage
+ (void) mType;
+ (void) mMode;
}
+
void addNetAddr(const InetAddr&);
void delNetAddr(const InetAddr&);
NetworkInterface(Container& c, const std::string& ifname) :
mContainer(c),
mIfname(ifname)
- { }
+ {
+ // TODO: Remove temporary usage
+ (void) mContainer;
+ }
//Network actions on Container
void create(const std::string& hostif, InterfaceType type, MacVLanMode mode=MacVLanMode::PRIVATE);