Ben Chan | 1e5a0cb | 2012-03-22 00:41:52 -0700 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Ben Chan | d30e743 | 2011-11-28 13:43:17 -0800 | [diff] [blame] | 5 | // Defines cros-disks::MountManager, which is a base class for implementing |
| 6 | // the filesystem mounting service used by CrosDisksServer. It is further |
| 7 | // subclassed to provide the mounting service for particular types of |
| 8 | // filesystem. |
| 9 | |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 10 | #ifndef CROS_DISKS_MOUNT_MANAGER_H_ |
| 11 | #define CROS_DISKS_MOUNT_MANAGER_H_ |
| 12 | |
Anand K Mistry | e9a60fb | 2019-11-07 16:41:03 +1100 | [diff] [blame] | 13 | #include <memory> |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 14 | #include <string> |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 15 | #include <unordered_map> |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 16 | #include <vector> |
| 17 | |
Anand K Mistry | 09f2db1 | 2019-11-07 17:06:56 +1100 | [diff] [blame] | 18 | #include <base/files/file_path.h> |
Anand K Mistry | e9a60fb | 2019-11-07 16:41:03 +1100 | [diff] [blame] | 19 | #include <base/optional.h> |
Ben Chan | 6d0b272 | 2011-11-18 08:24:14 -0800 | [diff] [blame] | 20 | #include <chromeos/dbus/service_constants.h> |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 21 | #include <gtest/gtest_prod.h> |
| 22 | |
Ben Chan | 0214e30 | 2017-10-17 15:39:16 -0700 | [diff] [blame] | 23 | #include "cros-disks/mount_entry.h" |
Anand K Mistry | e9a60fb | 2019-11-07 16:41:03 +1100 | [diff] [blame] | 24 | #include "cros-disks/mount_point.h" |
Tatsuhisa Yamaguchi | 5a6a303 | 2016-08-19 20:03:54 +0900 | [diff] [blame] | 25 | |
Sergei Datsenko | a910bba | 2019-06-18 13:31:59 +1000 | [diff] [blame] | 26 | namespace brillo { |
| 27 | class ProcessReaper; |
| 28 | } // namespace brillo |
| 29 | |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 30 | namespace cros_disks { |
| 31 | |
Ben Chan | be2b4a7 | 2011-11-08 13:42:23 -0800 | [diff] [blame] | 32 | class Metrics; |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 33 | class Platform; |
| 34 | |
| 35 | // A base class for managing mounted filesystems of certain kinds. |
| 36 | // It provides template methods for mounting and unmounting filesystems. |
Anand K Mistry | 2481ce8 | 2020-01-24 14:46:53 +1100 | [diff] [blame] | 37 | // A derived class implements pure virtual methods CanMount, DoMount, and |
| 38 | // SuggestMountPath to provide specific operations for supporting certain kinds |
| 39 | // of filesystem. |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 40 | class MountManager { |
| 41 | public: |
Ben Chan | d30e743 | 2011-11-28 13:43:17 -0800 | [diff] [blame] | 42 | // Constructor that takes a mount root directory, an object for providing |
| 43 | // platform service, and an object for collecting UMA metrics. The mount |
| 44 | // root directory |mount_root| must be a non-empty path string, but it is |
| 45 | // OK if the directory does not exist. Both |platform| and |metrics| must |
| 46 | // be a valid object. An instance of this class does not take ownership |
| 47 | // of the |platform| and |metrics| object, and thus expects these objects |
| 48 | // to exist until its destruction. No actual operation is performed at |
| 49 | // construction. Initialization is performed when Initializes() is called. |
Ben Chan | de0e3f6 | 2017-09-26 06:28:39 -0700 | [diff] [blame] | 50 | MountManager(const std::string& mount_root, |
| 51 | Platform* platform, |
Sergei Datsenko | a910bba | 2019-06-18 13:31:59 +1000 | [diff] [blame] | 52 | Metrics* metrics, |
| 53 | brillo::ProcessReaper* process_reaper); |
Qijiang Fan | 6bc59e1 | 2020-11-11 02:51:06 +0900 | [diff] [blame] | 54 | MountManager(const MountManager&) = delete; |
| 55 | MountManager& operator=(const MountManager&) = delete; |
Ben Chan | d30e743 | 2011-11-28 13:43:17 -0800 | [diff] [blame] | 56 | |
| 57 | // Destructor that performs no specific operations and does not unmount |
| 58 | // any mounted or reserved mount paths. A derived class should override |
| 59 | // the destructor to perform appropriate cleanup, such as unmounting |
| 60 | // mounted filesystems. |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 61 | virtual ~MountManager(); |
| 62 | |
| 63 | // Initializes the mount manager. Returns true on success. |
Ben Chan | d30e743 | 2011-11-28 13:43:17 -0800 | [diff] [blame] | 64 | // It must be called only once before other methods are called. |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 65 | // This base class provides a default implementation that creates the |
| 66 | // mount root directory. A derived class can override this method to |
| 67 | // perform any necessary initialization. |
| 68 | virtual bool Initialize(); |
| 69 | |
Ben Chan | b3bf8d1 | 2013-04-23 13:57:55 -0700 | [diff] [blame] | 70 | // Starts a session. Returns true on success. |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 71 | // This base class provides a default implementation that does nothing. |
| 72 | // A derived class can override this method to perform any necessary |
Ben Chan | d30e743 | 2011-11-28 13:43:17 -0800 | [diff] [blame] | 73 | // operations when a session starts. This method is called in response |
| 74 | // to a SessionStateChanged event from the Chromium OS session manager. |
Ben Chan | b3bf8d1 | 2013-04-23 13:57:55 -0700 | [diff] [blame] | 75 | virtual bool StartSession(); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 76 | |
Ben Chan | b3bf8d1 | 2013-04-23 13:57:55 -0700 | [diff] [blame] | 77 | // Stops a session. Returns true on success. |
Ben Chan | 2d73356 | 2019-03-18 23:55:10 -0700 | [diff] [blame] | 78 | // This base class provides a default implementation that calls UnmountAll() |
| 79 | // to unmount all mounted paths managed by this mount manager. |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 80 | // A derived class can override this method to perform any necessary |
Ben Chan | d30e743 | 2011-11-28 13:43:17 -0800 | [diff] [blame] | 81 | // operations when a session stops. This method is called in response |
| 82 | // to a SessionStateChanged event from the Chromium OS session manager. |
Ben Chan | b3bf8d1 | 2013-04-23 13:57:55 -0700 | [diff] [blame] | 83 | virtual bool StopSession(); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 84 | |
| 85 | // Implemented by a derived class to return true if it supports mounting |
| 86 | // |source_path|. |
| 87 | virtual bool CanMount(const std::string& source_path) const = 0; |
| 88 | |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 89 | // Implemented by a derived class to return the type of mount sources |
| 90 | // it supports. |
| 91 | virtual MountSourceType GetMountSourceType() const = 0; |
| 92 | |
| 93 | // Mounts |source_path| to |mount_path| as |filesystem_type| with |options|. |
Tatsuhisa Yamaguchi | b670bd1 | 2016-09-28 23:06:44 +0900 | [diff] [blame] | 94 | // If "remount" option exists in |options|, attempts to remount |source_path| |
| 95 | // to the mount path which it's currently mounted to. Content of |mount_path| |
| 96 | // will be ignored and |mount_path| is set to the existing mount path. |
| 97 | // Otherwise, attempts to mount a new source. When mounting a new source, if |
| 98 | // |mount_path| is an empty string, SuggestMountPath() is called to obtain a |
| 99 | // suggested mount path. |mount_path| is set to actual mount path on success. |
| 100 | // If an error occurs and ShouldReserveMountPathOnError() returns true for |
| 101 | // that type of error, the mount path is reserved and |mount_path| is set to |
| 102 | // the reserved mount path. |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 103 | MountErrorType Mount(const std::string& source_path, |
| 104 | const std::string& filesystem_type, |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 105 | std::vector<std::string> options, |
Tatsuhisa Yamaguchi | b670bd1 | 2016-09-28 23:06:44 +0900 | [diff] [blame] | 106 | std::string* mount_path); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 107 | |
Anand K Mistry | 5a6d5fa | 2019-11-05 17:21:48 +1100 | [diff] [blame] | 108 | // Unmounts |path|, which can be a source path or a mount path. If the mount |
| 109 | // path is reserved during Mount(), this method releases the reserved mount |
| 110 | // path. |
| 111 | MountErrorType Unmount(const std::string& path); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 112 | |
| 113 | // Unmounts all mounted paths. |
Ben Chan | 1e5a0cb | 2012-03-22 00:41:52 -0700 | [diff] [blame] | 114 | virtual bool UnmountAll(); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 115 | |
Ben Chan | 7dfb810 | 2017-10-17 15:47:37 -0700 | [diff] [blame] | 116 | // Returns the mount entries managed by this mount manager. |
| 117 | std::vector<MountEntry> GetMountEntries() const; |
Ben Chan | 8fb742b | 2014-04-28 23:46:57 -0700 | [diff] [blame] | 118 | |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 119 | protected: |
Tatsuhisa Yamaguchi | 5a6a303 | 2016-08-19 20:03:54 +0900 | [diff] [blame] | 120 | // Type definition of a cache mapping a source path to its mount state of |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 121 | // filesystems mounted by the manager. |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 122 | using MountStateMap = |
| 123 | std::unordered_map<std::string, std::unique_ptr<MountPoint>>; |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 124 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 125 | MountPoint* FindMountBySource(const std::string& source); |
| 126 | MountPoint* FindMountByMountPath(const base::FilePath& path); |
| 127 | bool RemoveMount(MountPoint* mount_point); |
Sergei Datsenko | 0ba1203 | 2021-01-07 08:51:14 +1100 | [diff] [blame] | 128 | |
Ben Chan | 632c9f8 | 2011-10-11 12:22:16 -0700 | [diff] [blame] | 129 | // Type definition of a cache mapping a reserved mount path to the mount |
| 130 | // error that caused the mount path to be reserved. |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 131 | using ReservedMountPathMap = |
| 132 | std::unordered_map<base::FilePath, MountErrorType>; |
Ben Chan | 632c9f8 | 2011-10-11 12:22:16 -0700 | [diff] [blame] | 133 | |
Jorge Lucangeli Obes | 0a388a2 | 2020-04-06 11:43:21 -0400 | [diff] [blame] | 134 | // The base class calls Platform::GetRealPath(), derived classes can override |
| 135 | // it. |
| 136 | virtual bool ResolvePath(const std::string& path, std::string* real_path); |
| 137 | |
Tatsuhisa Yamaguchi | b670bd1 | 2016-09-28 23:06:44 +0900 | [diff] [blame] | 138 | // Mounts |source_path| to |mount_path| as |filesystem_type| with |options|. |
| 139 | MountErrorType MountNewSource(const std::string& source_path, |
| 140 | const std::string& filesystem_type, |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 141 | std::vector<std::string> options, |
Tatsuhisa Yamaguchi | b670bd1 | 2016-09-28 23:06:44 +0900 | [diff] [blame] | 142 | std::string* mount_path); |
| 143 | |
| 144 | // Remounts |source_path| on |mount_path| as |filesystem_type| with |options|. |
| 145 | MountErrorType Remount(const std::string& source_path, |
| 146 | const std::string& filesystem_type, |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 147 | std::vector<std::string> options, |
Tatsuhisa Yamaguchi | b670bd1 | 2016-09-28 23:06:44 +0900 | [diff] [blame] | 148 | std::string* mount_path); |
| 149 | |
Nigel Tao | ca7a4ef | 2021-05-14 11:44:25 +1000 | [diff] [blame] | 150 | // Implemented by a derived class to mount |source_path| to |mount_path| as |
| 151 | // |filesystem_type| with |options|. An implementation may append their own |
| 152 | // mount options to |options|. On success, an implementation MUST set |error| |
| 153 | // to MOUNT_ERROR_NONE and return a non-null MountPoint. On failure, |error| |
| 154 | // must be set to an appropriate error code and nullptr is returned. |
Anand K Mistry | d0a0523 | 2020-01-24 14:04:18 +1100 | [diff] [blame] | 155 | virtual std::unique_ptr<MountPoint> DoMount( |
Anand K Mistry | f41a696 | 2019-12-19 17:41:04 +1100 | [diff] [blame] | 156 | const std::string& source_path, |
| 157 | const std::string& filesystem_type, |
| 158 | const std::vector<std::string>& options, |
| 159 | const base::FilePath& mount_path, |
Anand K Mistry | d0a0523 | 2020-01-24 14:04:18 +1100 | [diff] [blame] | 160 | MountErrorType* error) = 0; |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 161 | |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 162 | // Returns a suggested mount path for |source_path|. |
| 163 | virtual std::string SuggestMountPath( |
| 164 | const std::string& source_path) const = 0; |
| 165 | |
Ben Chan | f869288 | 2011-08-21 10:15:30 -0700 | [diff] [blame] | 166 | // Returns true if the manager should reserve a mount path if the mount |
| 167 | // operation returns a particular type of error. The default implementation |
| 168 | // returns false on any error. A derived class should override this method |
| 169 | // if it needs to reserve mount paths on certain types of error. |
| 170 | virtual bool ShouldReserveMountPathOnError(MountErrorType error_type) const; |
| 171 | |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 172 | // Returns true if |path| is an immediate child of |parent|, i.e. |
| 173 | // |path| is an immediate file or directory under |parent|. |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 174 | static bool IsPathImmediateChildOfParent(const base::FilePath& path, |
| 175 | const base::FilePath& parent); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 176 | |
Ben Chan | adc5d00 | 2014-03-12 15:02:26 -0700 | [diff] [blame] | 177 | // Returns true if |mount_path| is a valid mount path, which should be an |
| 178 | // immediate child of the mount root specified by |mount_root_|. The check |
| 179 | // performed by this method takes the simplest approach and does not first try |
| 180 | // to canonicalize |mount_path|, resolve symlinks or determine the absolute |
| 181 | // path of |mount_path|, so a legitimate mount path may be deemed as invalid. |
| 182 | // But we don't consider these cases as part of the use cases of cros-disks. |
Anand K Mistry | 09f2db1 | 2019-11-07 17:06:56 +1100 | [diff] [blame] | 183 | bool IsValidMountPath(const base::FilePath& mount_path) const; |
Ben Chan | adc5d00 | 2014-03-12 15:02:26 -0700 | [diff] [blame] | 184 | |
Ben Chan | 9ed09e3 | 2011-11-22 16:24:06 -0800 | [diff] [blame] | 185 | // Returns the root directory under which mount directories are created. |
Anand K Mistry | 09f2db1 | 2019-11-07 17:06:56 +1100 | [diff] [blame] | 186 | const base::FilePath& mount_root() const { return mount_root_; } |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 187 | |
Ben Chan | 9ed09e3 | 2011-11-22 16:24:06 -0800 | [diff] [blame] | 188 | // Returns an object that provides platform service. |
Ben Chan | 930f18d | 2011-11-21 09:18:50 -0800 | [diff] [blame] | 189 | Platform* platform() const { return platform_; } |
| 190 | |
Ben Chan | 9ed09e3 | 2011-11-22 16:24:06 -0800 | [diff] [blame] | 191 | // Returns an object that collects UMA metrics. |
Ben Chan | 930f18d | 2011-11-21 09:18:50 -0800 | [diff] [blame] | 192 | Metrics* metrics() const { return metrics_; } |
| 193 | |
Sergei Datsenko | a910bba | 2019-06-18 13:31:59 +1000 | [diff] [blame] | 194 | // Returns an object that monitors children processes. |
| 195 | brillo::ProcessReaper* process_reaper() const { return process_reaper_; } |
| 196 | |
Ben Chan | 930f18d | 2011-11-21 09:18:50 -0800 | [diff] [blame] | 197 | private: |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 198 | // Prepares empty directory to mount into. If |mount_path| contains a path |
| 199 | // it may be used, but not necessarily. Returns the status of the operation |
| 200 | // and if successful - fills |mount_path|. |
| 201 | MountErrorType CreateMountPathForSource(const std::string& source, |
| 202 | const std::string& label, |
| 203 | base::FilePath* mount_path); |
| 204 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 205 | // Returns true if |mount_path| is reserved. |
| 206 | bool IsMountPathReserved(const base::FilePath& mount_path) const; |
| 207 | |
| 208 | // Returns the mount error that caused |mount_path| to be reserved, or |
| 209 | // kMountErrorNone if |mount_path| is not a reserved path. |
| 210 | MountErrorType GetMountErrorOfReservedMountPath( |
| 211 | const base::FilePath& mount_path) const; |
| 212 | |
| 213 | // Adds |mount_path| to the set of reserved mount paths. Also records |
| 214 | // |error_type| that caused the mount path to be reserved. If a |mount_path| |
| 215 | // has been reserved, subsequent calls to this method with the same |
| 216 | // |mount_path| but different |error_type| are ignored. |
| 217 | void ReserveMountPath(base::FilePath mount_path, MountErrorType error_type); |
| 218 | |
| 219 | // Removes |mount_path| from the set of reserved mount paths. |
| 220 | void UnreserveMountPath(const base::FilePath& mount_path); |
| 221 | |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 222 | // The root directory under which mount directories are created. |
Anand K Mistry | 09f2db1 | 2019-11-07 17:06:56 +1100 | [diff] [blame] | 223 | const base::FilePath mount_root_; |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 224 | |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 225 | // An object that provides platform service. |
Sergei Datsenko | a910bba | 2019-06-18 13:31:59 +1000 | [diff] [blame] | 226 | Platform* const platform_; |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 227 | |
Ben Chan | be2b4a7 | 2011-11-08 13:42:23 -0800 | [diff] [blame] | 228 | // An object that collects UMA metrics. |
Sergei Datsenko | a910bba | 2019-06-18 13:31:59 +1000 | [diff] [blame] | 229 | Metrics* const metrics_; |
| 230 | |
| 231 | // Object that monitors children processes. |
| 232 | brillo::ProcessReaper* const process_reaper_; |
Ben Chan | be2b4a7 | 2011-11-08 13:42:23 -0800 | [diff] [blame] | 233 | |
Tatsuhisa Yamaguchi | 5a6a303 | 2016-08-19 20:03:54 +0900 | [diff] [blame] | 234 | // A cache mapping a source path to its mount state of filesystems mounted |
Ben Chan | 930f18d | 2011-11-21 09:18:50 -0800 | [diff] [blame] | 235 | // by the manager. |
Tatsuhisa Yamaguchi | 5a6a303 | 2016-08-19 20:03:54 +0900 | [diff] [blame] | 236 | MountStateMap mount_states_; |
Ben Chan | 930f18d | 2011-11-21 09:18:50 -0800 | [diff] [blame] | 237 | |
| 238 | // A cache mapping a reserved mount path to the error that caused |
| 239 | // the path to reserved. |
| 240 | ReservedMountPathMap reserved_mount_paths_; |
| 241 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 242 | friend class MountManagerUnderTest; |
| 243 | |
Ben Chan | 09c90d0 | 2012-04-25 22:09:09 -0700 | [diff] [blame] | 244 | FRIEND_TEST(MountManagerTest, ExtractMountLabelFromOptions); |
| 245 | FRIEND_TEST(MountManagerTest, ExtractMountLabelFromOptionsWithNoMountLabel); |
| 246 | FRIEND_TEST(MountManagerTest, ExtractMountLabelFromOptionsWithTwoMountLabels); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 247 | FRIEND_TEST(MountManagerTest, IsPathImmediateChildOfParent); |
Ben Chan | adc5d00 | 2014-03-12 15:02:26 -0700 | [diff] [blame] | 248 | FRIEND_TEST(MountManagerTest, IsValidMountPath); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 249 | }; |
| 250 | |
| 251 | } // namespace cros_disks |
| 252 | |
| 253 | #endif // CROS_DISKS_MOUNT_MANAGER_H_ |