lxcpp: AttachManager and chdir 74/46874/7
authorJan Olszak <j.olszak@samsung.com>
Wed, 26 Aug 2015 16:42:18 +0000 (18:42 +0200)
committerJan Olszak <j.olszak@samsung.com>
Thu, 27 Aug 2015 13:49:20 +0000 (15:49 +0200)
[Feature]       Added AttachManager for handling attaching
                It's possible to set cwd inside container.
[Cause]         N/A
[Solution]      N/A
[Verification]  Build, install, run tests

Change-Id: Ida77e56a7d4f42225554c8fe02b5794509b83ef2

libs/lxcpp/attach-manager.cpp [new file with mode: 0644]
libs/lxcpp/attach-manager.hpp [new file with mode: 0644]
libs/lxcpp/container-impl.cpp
libs/lxcpp/container-impl.hpp
libs/lxcpp/container.hpp
libs/lxcpp/filesystem.cpp
libs/lxcpp/filesystem.hpp
libs/lxcpp/network-config.hpp
libs/lxcpp/network.hpp

diff --git a/libs/lxcpp/attach-manager.cpp b/libs/lxcpp/attach-manager.cpp
new file mode 100644 (file)
index 0000000..3479673
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ *  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
diff --git a/libs/lxcpp/attach-manager.hpp b/libs/lxcpp/attach-manager.hpp
new file mode 100644 (file)
index 0000000..be37ade
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *  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
index cba0691..6de22dc 100644 (file)
@@ -27,6 +27,7 @@
 #include "lxcpp/filesystem.hpp"
 #include "lxcpp/namespace.hpp"
 #include "lxcpp/capability.hpp"
+#include "lxcpp/attach-manager.hpp"
 
 #include "utils/exception.hpp"
 
@@ -78,9 +79,9 @@ void ContainerImpl::reboot()
     throw NotImplementedException();
 }
 
-int ContainerImpl::getInitPid()
+pid_t ContainerImpl::getInitPid() const
 {
-    throw NotImplementedException();
+    return mInitPid;
 }
 
 void ContainerImpl::create()
@@ -103,86 +104,18 @@ std::string ContainerImpl::getRootPath()
     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,
index a57c340..c862473 100644 (file)
@@ -46,7 +46,8 @@ public:
     void freeze();
     void unfreeze();
     void reboot();
-    int getInitPid();
+    pid_t getInitPid() const;
+    const std::vector<Namespace>& getNamespaces() const;
 
     //Filesystem actions
     void create();
@@ -55,7 +56,8 @@ public:
     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,
@@ -78,12 +80,6 @@ public:
     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;
index 44a3567..d07bc27 100644 (file)
@@ -25,6 +25,7 @@
 #define LXCPP_CONTAINER_HPP
 
 #include "lxcpp/network-config.hpp"
+#include <sys/types.h>
 
 #include <string>
 #include <functional>
@@ -58,7 +59,7 @@ public:
     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;
@@ -67,7 +68,8 @@ public:
     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,
index c085861..4881449 100644 (file)
@@ -34,6 +34,7 @@
 #include <iterator>
 #include <sys/mount.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
 
 namespace lxcpp {
@@ -119,4 +120,22 @@ bool isMountPointShared(const std::string& path)
     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
index 6833ffc..63aacee 100644 (file)
@@ -47,6 +47,10 @@ bool isMountPoint(const std::string& path);
  */
 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
index b490aa0..b4e2fe0 100644 (file)
@@ -99,7 +99,11 @@ public:
         mType(type),
         mMode(mode)
     {
+        // TODO: Remove temporary usage
+        (void) mType;
+        (void) mMode;
     }
+
     void addNetAddr(const InetAddr&);
     void delNetAddr(const InetAddr&);
 
index 44ab268..8381611 100644 (file)
@@ -44,7 +44,10 @@ public:
     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);