| // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CROS_DISKS_DISK_MANAGER_H_ |
| #define CROS_DISKS_DISK_MANAGER_H_ |
| |
| #include <libudev.h> |
| |
| #include <map> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include <base/callback.h> |
| #include <base/macros.h> |
| #include <gtest/gtest_prod.h> |
| |
| #include "cros-disks/device_ejector.h" |
| #include "cros-disks/device_event.h" |
| #include "cros-disks/device_event_source_interface.h" |
| #include "cros-disks/mount_manager.h" |
| |
| namespace cros_disks { |
| |
| class DeviceEjector; |
| class Disk; |
| class Filesystem; |
| class Mounter; |
| class Platform; |
| |
| // The DiskManager is responsible for reading device state from udev. |
| // Said changes could be the result of a udev notification or a synchronous |
| // call to enumerate the relevant storage devices attached to the system. |
| // |
| // Sample Usage: |
| // |
| // Platform platform; |
| // DiskManager manager("/media/removable", &platform); |
| // manager.Initialize(); |
| // manager.EnumerateDisks(); |
| // select(manager.udev_monitor_fd())... |
| // |
| // This class is designed to run within a single-threaded GMainLoop application |
| // and should not be considered thread safe. |
| class DiskManager : public MountManager, |
| public DeviceEventSourceInterface { |
| public: |
| DiskManager(const std::string& mount_root, Platform* platform, |
| Metrics* metrics, DeviceEjector* device_ejector); |
| ~DiskManager() override; |
| |
| // Initializes the disk manager and registers default filesystems. |
| // Returns true on success. |
| bool Initialize() override; |
| |
| // Stops a session. Returns true on success. |
| bool StopSession() override; |
| |
| // Returns true if mounting |source_path| is supported. |
| bool CanMount(const std::string& source_path) const override; |
| |
| // Returns the type of mount sources supported by the manager. |
| MountSourceType GetMountSourceType() const override { |
| return MOUNT_SOURCE_REMOVABLE_DEVICE; |
| } |
| |
| // Unmounts all mounted paths. |
| bool UnmountAll() override; |
| |
| // Lists the current block devices attached to the system. |
| std::vector<Disk> EnumerateDisks() const; |
| |
| // Implements the DeviceEventSourceInterface interface to read the changes |
| // from udev and converts the changes into device events. Returns false on |
| // error or if not device event is available. Must be called to clear the fd. |
| bool GetDeviceEvents(DeviceEventList* events) override; |
| |
| // Gets a Disk object that corresponds to a given device file. |
| bool GetDiskByDevicePath(const std::string& device_path, Disk *disk) const; |
| |
| // Registers a set of default filesystems to the disk manager. |
| void RegisterDefaultFilesystems(); |
| |
| // Registers a filesystem to the disk manager. |
| // Subsequent registrations of the same filesystem type are ignored. |
| void RegisterFilesystem(const Filesystem& filesystem); |
| |
| // A file descriptor that can be select()ed or poll()ed for system changes. |
| int udev_monitor_fd() const { return udev_monitor_fd_; } |
| |
| protected: |
| // Mounts |source_path| to |mount_path| as |filesystem_type| with |options|. |
| MountErrorType DoMount(const std::string& source_path, |
| const std::string& filesystem_type, |
| const std::vector<std::string>& options, |
| const std::string& mount_path) override; |
| |
| // Unmounts |path| with |options|. |
| MountErrorType DoUnmount(const std::string& path, |
| const std::vector<std::string>& options) override; |
| |
| // Returns a suggested mount path for a source path. |
| std::string SuggestMountPath(const std::string& source_path) const override; |
| |
| // Returns true to reserve a mount path on errors due to unknown or |
| // unsupported filesystems. |
| bool ShouldReserveMountPathOnError(MountErrorType error_type) const override; |
| |
| private: |
| // Creates an appropriate mounter object for a given filesystem. |
| // The caller is responsible for deleting the mounter object. |
| Mounter* CreateMounter(const Disk& disk, const Filesystem& filesystem, |
| const std::string& target_path, |
| const std::vector<std::string>& options) const; |
| |
| // Returns a Filesystem object if a given filesystem type is supported. |
| // Otherwise, it returns NULL. |
| const Filesystem* GetFilesystem(const std::string& filesystem_type) const; |
| |
| // An EnumerateBlockDevices callback that emulates a block device event |
| // defined by |action| on |device|. Always returns true to continue |
| // enumeration in EnumerateBlockDevices. |
| bool EmulateBlockDeviceEvent(const char* action, udev_device* device); |
| |
| // Enumerates the block devices on the system and invokes |callback| for each |
| // device found during the enumeration. The ownership of |udev_device| is not |
| // transferred to |callback|. The enumeration stops if |callback| returns |
| // false. |
| void EnumerateBlockDevices( |
| const base::Callback<bool(udev_device* dev)>& callback) const; |
| |
| // Determines one or more device/disk events from a udev block device change. |
| void ProcessBlockDeviceEvents(udev_device* device, |
| const char *action, |
| DeviceEventList* events); |
| |
| // Determines one or more device/disk events from a udev MMC or SCSI device |
| // change. |
| void ProcessMmcOrScsiDeviceEvents(udev_device* device, |
| const char* action, |
| DeviceEventList* events); |
| |
| // If |disk| should be ejected on unmount, add |mount_path| and the device |
| // file of |disk| to |devices_to_eject_on_unmount_| and returns true. Returns |
| // false otherwise. |
| bool ScheduleEjectOnUnmount(const std::string& mount_path, const Disk& disk); |
| |
| // Ejects media from a device mounted at |mount_path|. Return true if the |
| // eject process has started, or false if the |mount_path| is not in |
| // |devices_to_eject_on_unmount_| or |eject_device_on_unmount_| is set to |
| // false. |
| bool EjectDeviceOfMountPath(const std::string& mount_path); |
| |
| // Device ejector for ejecting media from optical devices. |
| DeviceEjector* device_ejector_; |
| |
| // The root udev object. |
| mutable udev* udev_; |
| |
| // Provides access to udev changes as they occur. |
| udev_monitor* udev_monitor_; |
| |
| // A file descriptor that indicates changes to the system. |
| int udev_monitor_fd_; |
| |
| // Set to true if devices should be ejected upon unmount. |
| bool eject_device_on_unmount_; |
| |
| // A set of device sysfs paths detected by the udev monitor. |
| std::set<std::string> devices_detected_; |
| |
| // A mapping from a mount path to the corresponding device file that should |
| // be ejected on unmount. |
| std::map<std::string, std::string> devices_to_eject_on_unmount_; |
| |
| // A mapping from a sysfs path of a disk, detected by the udev monitor, |
| // to a set of sysfs paths of the immediate children of the disk. |
| std::map<std::string, std::set<std::string>> disks_detected_; |
| |
| // A set of supported filesystems indexed by filesystem type. |
| std::map<std::string, Filesystem> filesystems_; |
| |
| FRIEND_TEST(DiskManagerTest, CreateExFATMounter); |
| FRIEND_TEST(DiskManagerTest, CreateExternalMounter); |
| FRIEND_TEST(DiskManagerTest, CreateNTFSMounter); |
| FRIEND_TEST(DiskManagerTest, CreateSystemMounter); |
| FRIEND_TEST(DiskManagerTest, GetFilesystem); |
| FRIEND_TEST(DiskManagerTest, RegisterFilesystem); |
| FRIEND_TEST(DiskManagerTest, DoMountDiskWithNonexistentSourcePath); |
| FRIEND_TEST(DiskManagerTest, DoUnmountDiskWithInvalidUnmountOptions); |
| FRIEND_TEST(DiskManagerTest, ScheduleEjectOnUnmount); |
| FRIEND_TEST(DiskManagerTest, EjectDeviceOfMountPath); |
| FRIEND_TEST(DiskManagerTest, EjectDeviceOfMountPathWhenEjectFailed); |
| FRIEND_TEST(DiskManagerTest, EjectDeviceOfMountPathWhenExplicitlyDisabled); |
| FRIEND_TEST(DiskManagerTest, EjectDeviceOfMountPathWhenMountPathExcluded); |
| |
| DISALLOW_COPY_AND_ASSIGN(DiskManager); |
| }; |
| |
| } // namespace cros_disks |
| |
| #endif // CROS_DISKS_DISK_MANAGER_H_ |