提交 ca59f27c 编写于 作者: S Simon Fels 提交者: GitHub

Merge pull request #354 from morphis/f/squashfuse-mount-support

Add support for rootfs mounts via squashfuse
......@@ -23,6 +23,7 @@
#include "anbox/config.h"
#include "core/posix/signal.h"
#include "core/posix/exec.h"
#include <sys/mount.h>
#include <linux/loop.h>
......@@ -121,29 +122,66 @@ bool anbox::cmds::ContainerManager::setup_mounts() {
if (!fs::exists(android_rootfs_dir))
fs::create_directory(android_rootfs_dir);
std::shared_ptr<common::LoopDevice> loop_device;
// We prefer using the kernel for mounting the squashfs image but
// for some cases (unprivileged containers) where no loop support
// is available we do the mount instead via squashfuse which will
// work entirely in userspace.
if (fs::exists("/dev/loop-control")) {
std::shared_ptr<common::LoopDevice> loop_device;
try {
loop_device = common::LoopDeviceAllocator::new_device();
} catch (const std::exception& e) {
ERROR("Could not create loopback device: %s", e.what());
return false;
} catch (...) {
ERROR("Could not create loopback device");
return false;
}
try {
loop_device = common::LoopDeviceAllocator::new_device();
} catch (const std::exception& e) {
ERROR("Could not create loopback device: %s", e.what());
return false;
} catch (...) {
ERROR("Could not create loopback device");
return false;
}
if (!loop_device->attach_file(android_img_path)) {
ERROR("Failed to attach Android rootfs image to loopback device");
return false;
}
if (!loop_device->attach_file(android_img_path)) {
ERROR("Failed to attach Android rootfs image to loopback device");
return false;
}
auto m = common::MountEntry::create(loop_device, android_rootfs_dir, "squashfs", MS_MGC_VAL | MS_RDONLY | MS_PRIVATE);
if (!m) {
ERROR("Failed to mount Android rootfs");
auto m = common::MountEntry::create(loop_device, android_rootfs_dir, "squashfs", MS_MGC_VAL | MS_RDONLY | MS_PRIVATE);
if (!m) {
ERROR("Failed to mount Android rootfs");
return false;
}
mounts_.push_back(m);
} else if (fs::exists("/dev/fuse") && !utils::find_program_on_path("squashfuse").empty()) {
std::vector<std::string> args = {
"-t", "fuse.squashfuse",
// Allow other users than root to access the rootfs
"-o", "allow_other",
android_img_path.string(),
android_rootfs_dir,
};
// Easiest is here to go with the standard mount program as that
// will handle everything for us which is relevant to get the
// squashfs via squashfuse properly mount without having to
// reimplement all the details. Once the mount call comes back
// without an error we can expect the image to be mounted.
auto child = core::posix::exec("/bin/mount", args, {}, core::posix::StandardStream::empty, []() {});
const auto result = child.wait_for(core::posix::wait::Flags::untraced);
if (result.status != core::posix::wait::Result::Status::exited ||
result.detail.if_exited.status != core::posix::exit::Status::success) {
ERROR("Failed to mount squashfs Android image");
return false;
}
auto m = common::MountEntry::create(android_rootfs_dir);
if (!m) {
ERROR("Failed to create mount entry for Android rootfs");
return false;
}
mounts_.push_back(m);
} else {
ERROR("No loop device or FUSE support found. Can't setup Android rootfs!");
return false;
}
mounts_.push_back(m);
for (const auto &dir_name : std::vector<std::string>{"cache", "data"}) {
auto target_dir_path = fs::path(android_rootfs_dir) / dir_name;
......
......@@ -17,18 +17,23 @@
#include "anbox/common/mount_entry.h"
#include "anbox/common/loop_device.h"
#include "anbox/logger.h"
#include <sys/mount.h>
namespace anbox {
namespace common {
std::shared_ptr<MountEntry> MountEntry::create(const boost::filesystem::path &src, const boost::filesystem::path &target,
const std::string &fs_type, unsigned long flags) {
const std::string &fs_type, unsigned long flags, const std::string &data) {
auto entry = std::shared_ptr<MountEntry>(new MountEntry(target));
if (!entry)
return nullptr;
if (::mount(src.c_str(), target.c_str(), !fs_type.empty() ? fs_type.c_str() : nullptr, flags, nullptr) != 0)
const void *mount_data = nullptr;
if (!data.empty())
mount_data = reinterpret_cast<const void*>(data.c_str());
if (::mount(src.c_str(), target.c_str(), !fs_type.empty() ? fs_type.c_str() : nullptr, flags, mount_data) != 0)
return nullptr;
entry->active_ = true;
......@@ -37,8 +42,8 @@ std::shared_ptr<MountEntry> MountEntry::create(const boost::filesystem::path &sr
}
std::shared_ptr<MountEntry> MountEntry::create(const std::shared_ptr<LoopDevice> &loop, const boost::filesystem::path &target,
const std::string &fs_type, unsigned long flags) {
auto entry = create(loop->path(), target, fs_type, flags);
const std::string &fs_type, unsigned long flags, const std::string &data) {
auto entry = create(loop->path(), target, fs_type, flags, data);
if (!entry)
return nullptr;
......@@ -46,6 +51,16 @@ std::shared_ptr<MountEntry> MountEntry::create(const std::shared_ptr<LoopDevice>
return entry;
}
std::shared_ptr<MountEntry> MountEntry::create(const boost::filesystem::path &target) {
auto entry = std::shared_ptr<MountEntry>(new MountEntry(target));
if (!entry)
return nullptr;
entry->active_ = true;
return entry;
}
MountEntry::MountEntry(const boost::filesystem::path &target) :
active_{false}, target_{target} {}
......
......@@ -26,10 +26,12 @@ class LoopDevice;
class MountEntry {
public:
static std::shared_ptr<MountEntry> create(const boost::filesystem::path &src, const boost::filesystem::path &target,
const std::string &fs_type = "", unsigned long flags = 0);
const std::string &fs_type = "", unsigned long flags = 0, const std::string &data = "");
static std::shared_ptr<MountEntry> create(const std::shared_ptr<LoopDevice> &loop, const boost::filesystem::path &target,
const std::string &fs_type = "", unsigned long flags = 0);
const std::string &fs_type = "", unsigned long flags = 0, const std::string &data = "");
static std::shared_ptr<MountEntry> create(const boost::filesystem::path &target);
~MountEntry();
......
......@@ -27,6 +27,8 @@
#include <fcntl.h>
#include <mntent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "anbox/utils.h"
......@@ -34,7 +36,6 @@ namespace fs = boost::filesystem;
namespace anbox {
namespace utils {
std::vector<std::string> collect_arguments(int argc, char **argv) {
std::vector<std::string> result;
for (int i = 1; i < argc; i++) result.push_back(argv[i]);
......@@ -193,5 +194,17 @@ bool is_mounted(const std::string &path) {
}
std::string find_program_on_path(const std::string &name) {
struct stat sb;
std::string path = std::string(getenv("PATH"));
size_t start_pos = 0, end_pos = 0;
while ((end_pos = path.find(':', start_pos)) != std::string::npos) {
const auto current_path = path.substr(start_pos, end_pos - start_pos) + "/" + name;
if ((::stat(current_path.c_str(), &sb) == 0) && (sb.st_mode & S_IXOTH))
return current_path;
start_pos = end_pos + 1;
}
return "";
}
} // namespace utils
} // namespace anbox
......@@ -56,6 +56,8 @@ std::string process_get_exe_path(const pid_t &pid);
bool is_mounted(const std::string &path);
std::string find_program_on_path(const std::string &name);
template <typename... Types>
static std::string string_format(const std::string &fmt_str, Types &&... args);
} // namespace utils
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册