lxcpp: Remounting /proc and /sys on attach 41/46641/5
authorJan Olszak <j.olszak@samsung.com>
Mon, 24 Aug 2015 09:13:05 +0000 (11:13 +0200)
committerJan Olszak <j.olszak@samsung.com>
Tue, 25 Aug 2015 08:56:41 +0000 (10:56 +0200)
[Feature]       Remounting /proc /sys
                Filesystem handling functions
[Cause]         N/A
[Solution]      N/A
[Verification]  Build, install, run tests

Change-Id: I8015b7a66c1fabab9133ad360e9e7a45c069082c

libs/lxcpp/container-impl.cpp
libs/lxcpp/exception.hpp
libs/lxcpp/filesystem.cpp [new file with mode: 0644]
libs/lxcpp/filesystem.hpp [new file with mode: 0644]
libs/lxcpp/process.cpp
libs/lxcpp/process.hpp

index 6fd9775..2ac232f 100644 (file)
 #include "lxcpp/container-impl.hpp"
 #include "lxcpp/exception.hpp"
 #include "lxcpp/process.hpp"
+#include "lxcpp/filesystem.hpp"
+#include "lxcpp/namespace.hpp"
 
 #include "utils/exception.hpp"
 
 #include <unistd.h>
+#include <sys/mount.h>
+
 
 namespace lxcpp {
 
@@ -99,9 +103,37 @@ std::string ContainerImpl::getRootPath()
     throw NotImplementedException();
 }
 
+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
 
 int ContainerImpl::attachChild(void* data) {
     try {
+        setupMountPoints();
         return (*static_cast<Container::AttachCall*>(data))();
     } catch(...) {
         return -1; // Non-zero on failure
index 12ae299..bdb56f7 100644 (file)
@@ -46,6 +46,11 @@ struct ProcessSetupException: public Exception {
         : Exception(message) {}
 };
 
+struct FileSystemSetupException: public Exception {
+    FileSystemSetupException(const std::string& message = "Error during a file system operation")
+        : Exception(message) {}
+};
+
 struct BadArgument: public Exception {
     BadArgument(const std::string& message = "Bad argument passed")
         : Exception(message) {}
diff --git a/libs/lxcpp/filesystem.cpp b/libs/lxcpp/filesystem.cpp
new file mode 100644 (file)
index 0000000..c085861
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ *  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   file system handling routines
+ */
+
+#include "lxcpp/filesystem.hpp"
+#include "lxcpp/exception.hpp"
+#include "lxcpp/process.hpp"
+
+#include "utils/paths.hpp"
+#include "utils/exception.hpp"
+#include "logger/logger.hpp"
+
+#include <sstream>
+#include <fstream>
+#include <iterator>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+
+namespace lxcpp {
+
+void mount(const std::string& source,
+           const std::string& target,
+           const std::string& filesystemtype,
+           unsigned long mountflags,
+           const std::string& data)
+{
+    if (-1 == ::mount(source.c_str(),
+                      target.c_str(),
+                      filesystemtype.c_str(),
+                      mountflags,
+                      data.c_str())) {
+        const std::string msg = "mount() failed: src:" + source
+                                + ", tgt: " + target
+                                + ", filesystemtype: " + filesystemtype
+                                + ", mountflags: " + std::to_string(mountflags)
+                                + ", data: " + data
+                                + ", msg: " + utils::getSystemErrorMessage();
+        LOGE(msg);
+        throw FileSystemSetupException(msg);
+    }
+}
+
+void umount(const std::string& path, const int flags)
+{
+    if (-1 == ::umount2(path.c_str(), flags)) {
+        const std::string msg = "umount() failed: '" + path + "': " + utils::getSystemErrorMessage();
+        LOGD(msg);
+        throw FileSystemSetupException(msg);
+    }
+}
+
+bool isMountPoint(const std::string& path)
+{
+    std::string parentPath = utils::dirName(path);
+
+    struct stat s1, s2;
+    if (-1 == ::stat(path.c_str(), &s1)) {
+        const std::string msg = "stat() failed: " + path + ": " + utils::getSystemErrorMessage();
+        LOGE(msg);
+        throw FileSystemSetupException(msg);
+    }
+
+    if (-1 == ::stat(parentPath.c_str(), &s2)) {
+        const std::string msg = "stat() failed: " + parentPath + ": " + utils::getSystemErrorMessage();
+        LOGE(msg);
+        throw FileSystemSetupException(msg);
+    }
+
+    return s1.st_dev != s2.st_dev;
+}
+
+bool isMountPointShared(const std::string& path)
+{
+    std::ifstream fileStream("/proc/self/mountinfo");
+    if (!fileStream.good()) {
+        const std::string msg = "Failed to open /proc/self/mountinfo";
+        LOGE(msg);
+        throw FileSystemSetupException(msg);
+    }
+
+    // Find the line corresponding to the path
+    std::string line;
+    while (std::getline(fileStream, line).good()) {
+        std::istringstream iss(line);
+        auto it = std::istream_iterator<std::string>(iss);
+        std::advance(it, 4);
+
+        if (it->compare(path)) {
+            // Wrong line, different path
+            continue;
+        }
+
+        // Right line, check if mount point shared
+        std::advance(it, 2);
+        return it->find("shared:") != std::string::npos;
+    }
+
+    // Path not found
+    return false;
+}
+
+} // namespace lxcpp
\ No newline at end of file
diff --git a/libs/lxcpp/filesystem.hpp b/libs/lxcpp/filesystem.hpp
new file mode 100644 (file)
index 0000000..6833ffc
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  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   file system handling routines
+ */
+
+#ifndef LXCPP_FILESYSTEM_HPP
+#define LXCPP_FILESYSTEM_HPP
+
+#include <string>
+
+namespace lxcpp {
+
+void mount(const std::string& source,
+           const std::string& target,
+           const std::string& filesystemtype,
+           unsigned long mountflags,
+           const std::string& data);
+
+void umount(const std::string& path, const int flags);
+
+bool isMountPoint(const std::string& path);
+
+/**
+ * Detect whether path is mounted as MS_SHARED.
+ * Parses /proc/self/mountinfo
+ *
+ * @param path mount point
+ * @return is the mount point shared
+ */
+bool isMountPointShared(const std::string& path);
+
+} // namespace lxcpp
+
+#endif // LXCPP_FILESYSTEM_HPP
\ No newline at end of file
index b707353..96475d5 100644 (file)
@@ -154,4 +154,12 @@ int waitpid(const pid_t pid)
     throw ProcessSetupException(msg);
 }
 
+void unshare(const Namespace ns)
+{
+    if(-1 == ::unshare(toFlag(ns))) {
+        const std::string msg = "unshare() failed: " + utils::getSystemErrorMessage();
+        LOGE(msg);
+        throw ProcessSetupException(msg);
+    }
+}
 } // namespace lxcpp
\ No newline at end of file
index a640e1a..869e3d6 100644 (file)
@@ -47,6 +47,8 @@ void setns(const pid_t pid,
 
 int waitpid(const pid_t pid);
 
+void unshare(const Namespace ns);
+
 } // namespace lxcpp
 
 #endif // LXCPP_PROCESS_HPP
\ No newline at end of file