Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 1 | // Copyright 2018 The Chromium OS Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "cros-disks/fuse_mount_manager.h" |
| 6 | |
Anand K Mistry | ad958eb | 2019-10-02 13:03:31 +1000 | [diff] [blame] | 7 | #include <sys/mount.h> |
| 8 | |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 9 | #include <utility> |
| 10 | |
Qijiang Fan | 713061e | 2021-03-08 15:45:12 +0900 | [diff] [blame] | 11 | #include <base/check.h> |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 12 | #include <base/files/file_path.h> |
| 13 | #include <base/logging.h> |
Simon Glass | 2b1da09 | 2020-05-21 12:24:16 -0600 | [diff] [blame] | 14 | #include <brillo/process/process_reaper.h> |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 15 | |
Sam McNally | c56ae31 | 2018-05-22 13:14:27 +1000 | [diff] [blame] | 16 | #include "cros-disks/drivefs_helper.h" |
Sergei Datsenko | bcd8e46 | 2018-04-20 15:44:56 +1000 | [diff] [blame] | 17 | #include "cros-disks/fuse_mounter.h" |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 18 | #include "cros-disks/platform.h" |
François Degros | 8b4e31e | 2019-07-29 11:39:19 +1000 | [diff] [blame] | 19 | #include "cros-disks/quote.h" |
Anand K Mistry | 110478e | 2019-10-29 15:24:11 +1100 | [diff] [blame] | 20 | #include "cros-disks/smbfs_helper.h" |
Sergei Datsenko | bcd8e46 | 2018-04-20 15:44:56 +1000 | [diff] [blame] | 21 | #include "cros-disks/sshfs_helper.h" |
| 22 | #include "cros-disks/uri.h" |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 23 | |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 24 | namespace cros_disks { |
| 25 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 26 | FUSEMountManager::FUSEMountManager(const std::string& mount_root, |
Sergei Datsenko | bcd8e46 | 2018-04-20 15:44:56 +1000 | [diff] [blame] | 27 | const std::string& working_dirs_root, |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 28 | Platform* platform, |
Sergei Datsenko | a910bba | 2019-06-18 13:31:59 +1000 | [diff] [blame] | 29 | Metrics* metrics, |
| 30 | brillo::ProcessReaper* process_reaper) |
| 31 | : MountManager(mount_root, platform, metrics, process_reaper), |
Sergei Datsenko | bcd8e46 | 2018-04-20 15:44:56 +1000 | [diff] [blame] | 32 | working_dirs_root_(working_dirs_root) {} |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 33 | |
Sam McNally | 8a71c5c | 2019-03-15 15:51:37 +1100 | [diff] [blame] | 34 | FUSEMountManager::~FUSEMountManager() { |
| 35 | UnmountAll(); |
| 36 | } |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 37 | |
| 38 | bool FUSEMountManager::Initialize() { |
| 39 | if (!MountManager::Initialize()) |
| 40 | return false; |
| 41 | |
Sergei Datsenko | bcd8e46 | 2018-04-20 15:44:56 +1000 | [diff] [blame] | 42 | if (!platform()->DirectoryExists(working_dirs_root_) && |
| 43 | !platform()->CreateDirectory(working_dirs_root_)) { |
| 44 | LOG(ERROR) << "Can't create writable FUSE directory"; |
| 45 | return false; |
| 46 | } |
| 47 | if (!platform()->SetOwnership(working_dirs_root_, getuid(), getgid()) || |
| 48 | !platform()->SetPermissions(working_dirs_root_, 0755)) { |
| 49 | LOG(ERROR) << "Can't set up writable FUSE directory"; |
| 50 | return false; |
| 51 | } |
| 52 | |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 53 | // Register specific FUSE mount helpers here. |
Sergei Datsenko | a910bba | 2019-06-18 13:31:59 +1000 | [diff] [blame] | 54 | RegisterHelper(std::make_unique<DrivefsHelper>(platform(), process_reaper())); |
Sergei Datsenko | 71ba50a | 2020-11-27 14:33:39 +1100 | [diff] [blame] | 55 | RegisterHelper(std::make_unique<SshfsHelper>( |
| 56 | platform(), process_reaper(), base::FilePath(working_dirs_root_))); |
Anand K Mistry | 110478e | 2019-10-29 15:24:11 +1100 | [diff] [blame] | 57 | RegisterHelper(std::make_unique<SmbfsHelper>(platform(), process_reaper())); |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 58 | |
| 59 | return true; |
| 60 | } |
| 61 | |
Anand K Mistry | d0a0523 | 2020-01-24 14:04:18 +1100 | [diff] [blame] | 62 | std::unique_ptr<MountPoint> FUSEMountManager::DoMount( |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 63 | const std::string& source, |
| 64 | const std::string& fuse_type, |
| 65 | const std::vector<std::string>& options, |
Anand K Mistry | 25a5f85 | 2020-01-14 17:08:39 +1100 | [diff] [blame] | 66 | const base::FilePath& mount_path, |
Anand K Mistry | 25a5f85 | 2020-01-14 17:08:39 +1100 | [diff] [blame] | 67 | MountErrorType* error) { |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 68 | CHECK(!mount_path.empty()) << "Invalid mount path argument"; |
| 69 | |
Sergei Datsenko | bcd8e46 | 2018-04-20 15:44:56 +1000 | [diff] [blame] | 70 | Uri uri = Uri::Parse(source); |
François Degros | 15a44a8 | 2019-11-19 14:01:08 +1100 | [diff] [blame] | 71 | CHECK(uri.valid()) << "Source " << quote(source) << " is not a URI"; |
| 72 | |
Sergei Datsenko | 25898b1 | 2020-11-26 08:07:15 +1100 | [diff] [blame] | 73 | base::FilePath dir_name; |
| 74 | const Mounter* selected_helper = nullptr; |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 75 | for (const auto& helper : helpers_) { |
Sergei Datsenko | 25898b1 | 2020-11-26 08:07:15 +1100 | [diff] [blame] | 76 | if (helper->CanMount(source, options, &dir_name)) { |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 77 | selected_helper = helper.get(); |
| 78 | break; |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | if (!selected_helper) { |
François Degros | ca45086 | 2021-01-14 14:40:02 +1100 | [diff] [blame] | 83 | LOG(ERROR) << "Cannot find FUSE module for " << redact(source) |
| 84 | << " of type " << quote(fuse_type); |
Anand K Mistry | 25a5f85 | 2020-01-14 17:08:39 +1100 | [diff] [blame] | 85 | *error = MOUNT_ERROR_UNKNOWN_FILESYSTEM; |
| 86 | return nullptr; |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 87 | } |
| 88 | |
Sergei Datsenko | f3ebcc3 | 2020-12-07 23:47:56 +1100 | [diff] [blame] | 89 | auto mountpoint = selected_helper->Mount(source, mount_path, options, error); |
Sergei Datsenko | 25898b1 | 2020-11-26 08:07:15 +1100 | [diff] [blame] | 90 | LOG_IF(ERROR, *error != MOUNT_ERROR_NONE) |
François Degros | ca45086 | 2021-01-14 14:40:02 +1100 | [diff] [blame] | 91 | << "Cannot mount " << redact(source) << " of type " << quote(fuse_type) |
| 92 | << ": " << *error; |
| 93 | |
Sergei Datsenko | 25898b1 | 2020-11-26 08:07:15 +1100 | [diff] [blame] | 94 | return mountpoint; |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 95 | } |
| 96 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 97 | bool FUSEMountManager::CanMount(const std::string& source) const { |
Sergei Datsenko | 25898b1 | 2020-11-26 08:07:15 +1100 | [diff] [blame] | 98 | base::FilePath dir; |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 99 | for (const auto& helper : helpers_) { |
Sergei Datsenko | 25898b1 | 2020-11-26 08:07:15 +1100 | [diff] [blame] | 100 | if (helper->CanMount(source, {}, &dir)) |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 101 | return true; |
| 102 | } |
| 103 | return false; |
| 104 | } |
| 105 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 106 | std::string FUSEMountManager::SuggestMountPath( |
| 107 | const std::string& source) const { |
François Degros | 15a44a8 | 2019-11-19 14:01:08 +1100 | [diff] [blame] | 108 | Uri uri = Uri::Parse(source); |
| 109 | if (!uri.valid()) { |
Sergei Datsenko | bcd8e46 | 2018-04-20 15:44:56 +1000 | [diff] [blame] | 110 | return ""; |
| 111 | } |
François Degros | 15a44a8 | 2019-11-19 14:01:08 +1100 | [diff] [blame] | 112 | |
Sergei Datsenko | 25898b1 | 2020-11-26 08:07:15 +1100 | [diff] [blame] | 113 | base::FilePath dir; |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 114 | for (const auto& helper : helpers_) { |
Sergei Datsenko | 25898b1 | 2020-11-26 08:07:15 +1100 | [diff] [blame] | 115 | if (helper->CanMount(source, {}, &dir)) |
| 116 | return mount_root().Append(dir).value(); |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 117 | } |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 118 | base::FilePath base_name = base::FilePath(source).BaseName(); |
Anand K Mistry | 30e32fa | 2020-02-04 10:07:57 +1100 | [diff] [blame] | 119 | return mount_root().Append(base_name).value(); |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 120 | } |
| 121 | |
Sergei Datsenko | 25898b1 | 2020-11-26 08:07:15 +1100 | [diff] [blame] | 122 | void FUSEMountManager::RegisterHelper(std::unique_ptr<Mounter> helper) { |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 123 | helpers_.push_back(std::move(helper)); |
| 124 | } |
| 125 | |
| 126 | } // namespace cros_disks |