blob: b846918276cf01fdf2ce4e1edbe44ab7887d6509 [file] [log] [blame]
// 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.
// Defines cros-disks::MountManager, which is a base class for implementing
// the filesystem mounting service used by CrosDisksServer. It is further
// subclassed to provide the mounting service for particular types of
// filesystem.
#ifndef CROS_DISKS_MOUNT_MANAGER_H_
#define CROS_DISKS_MOUNT_MANAGER_H_
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <sys/wait.h>
#include <base/callback.h>
#include <base/files/file_path.h>
#include <chromeos/dbus/service_constants.h>
#include <gtest/gtest_prod.h>
#include "cros-disks/mount_entry.h"
#include "cros-disks/mount_point.h"
namespace brillo {
class ProcessReaper;
} // namespace brillo
namespace cros_disks {
class Metrics;
class Platform;
// A base class for managing mounted filesystems of certain kinds.
// It provides template methods for mounting and unmounting filesystems.
// A derived class implements pure virtual methods CanMount, DoMount, and
// SuggestMountPath to provide specific operations for supporting certain kinds
// of filesystem.
class MountManager {
public:
// Constructor that takes a mount root directory, an object for providing
// platform service, and an object for collecting UMA metrics. The mount
// root directory |mount_root| must be a non-empty path string, but it is
// OK if the directory does not exist. Both |platform| and |metrics| must
// be a valid object. An instance of this class does not take ownership
// of the |platform| and |metrics| object, and thus expects these objects
// to exist until its destruction. No actual operation is performed at
// construction. Initialization is performed when Initializes() is called.
MountManager(const std::string& mount_root,
Platform* platform,
Metrics* metrics,
brillo::ProcessReaper* process_reaper);
MountManager(const MountManager&) = delete;
MountManager& operator=(const MountManager&) = delete;
// Destructor that performs no specific operations and does not unmount
// any mounted or reserved mount paths. A derived class should override
// the destructor to perform appropriate cleanup, such as unmounting
// mounted filesystems.
virtual ~MountManager();
// Initializes the mount manager. Returns true on success.
// It must be called only once before other methods are called.
// This base class provides a default implementation that creates the
// mount root directory. A derived class can override this method to
// perform any necessary initialization.
virtual bool Initialize();
// Starts a session. This method is called in response to a
// SessionStateChanged event from the Chromium OS session manager.
void StartSession();
// Stops a session. This method is called in response to a SessionStateChanged
// event from the Chromium OS session manager.
void StopSession();
// Implemented by a derived class to return true if it supports mounting
// |source|.
virtual bool CanMount(const std::string& source) const = 0;
// Implemented by a derived class to return the type of mount sources
// it supports.
virtual MountSourceType GetMountSourceType() const = 0;
// Callback called when the mount operation succeeds or fails.
using MountCallback = base::OnceCallback<void(const std::string& mount_path,
MountErrorType error)>;
// Mounts |source| as |filesystem_type| with |options|. If "remount"
// option exists in |options|, attempts to remount |source| to the mount
// path which it's currently mounted to. Otherwise, attempts to mount a new
// source. When mounting a new source, |SuggestMountPath()| is called to
// obtain a suggested mount path. If an error occurs and
// |ShouldReserveMountPathOnError()| returns true for that type of error, the
// mount path is reserved and |mount_path| is set to the reserved mount path.
// On completion or on error, |callback| is called.
void Mount(const std::string& source,
const std::string& filesystem_type,
std::vector<std::string> options,
MountCallback callback);
// Unmounts |path|, which can be a source path or a mount path. If the mount
// path is reserved during Mount(), this method releases the reserved mount
// path.
MountErrorType Unmount(const std::string& path);
// Unmounts all mounted paths.
virtual void UnmountAll();
// Returns the mount entries managed by this mount manager.
std::vector<MountEntry> GetMountEntries() const;
protected:
MountPoint* FindMountBySource(const std::string& source) const;
MountPoint* FindMountByMountPath(const base::FilePath& path) const;
bool RemoveMount(const MountPoint* mount_point);
// The base class calls Platform::GetRealPath(), derived classes can override
// it.
virtual bool ResolvePath(const std::string& path, std::string* real_path);
// Mounts |source| as |filesystem_type| with |options|.
void MountNewSource(const std::string& source,
const std::string& filesystem_type,
std::vector<std::string> options,
MountCallback callback);
// Remounts |source| on |mount_path| as |filesystem_type| with |options|.
MountErrorType Remount(const std::string& source,
const std::string& filesystem_type,
std::vector<std::string> options,
std::string* mount_path);
// Implemented by a derived class to mount |source| to |mount_path| as
// |filesystem_type| with |options|. An implementation may append their own
// mount options to |options|. On success, an implementation MUST set |error|
// to MOUNT_ERROR_NONE and return a non-null MountPoint. On failure, |error|
// must be set to an appropriate error code and nullptr is returned.
virtual std::unique_ptr<MountPoint> DoMount(
const std::string& source,
const std::string& filesystem_type,
const std::vector<std::string>& options,
const base::FilePath& mount_path,
MountErrorType* error) = 0;
// Returns a suggested mount path for |source|.
virtual std::string SuggestMountPath(const std::string& source) const = 0;
// Returns true if the manager should reserve a mount path if the mount
// operation returns a particular type of error. The default implementation
// returns false on any error. A derived class should override this method
// if it needs to reserve mount paths on certain types of error.
virtual bool ShouldReserveMountPathOnError(MountErrorType error_type) const;
// Returns true if |path| is an immediate child of |parent|, i.e.
// |path| is an immediate file or directory under |parent|.
static bool IsPathImmediateChildOfParent(const base::FilePath& path,
const base::FilePath& parent);
// Returns true if |mount_path| is a valid mount path, which should be an
// immediate child of the mount root specified by |mount_root_|. The check
// performed by this method takes the simplest approach and does not first try
// to canonicalize |mount_path|, resolve symlinks or determine the absolute
// path of |mount_path|, so a legitimate mount path may be deemed as invalid.
// But we don't consider these cases as part of the use cases of cros-disks.
bool IsValidMountPath(const base::FilePath& mount_path) const;
// Returns the root directory under which mount directories are created.
const base::FilePath& mount_root() const { return mount_root_; }
// Returns an object that provides platform service.
Platform* platform() const { return platform_; }
// Returns an object that collects UMA metrics.
Metrics* metrics() const { return metrics_; }
// Returns an object that monitors children processes.
brillo::ProcessReaper* process_reaper() const { return process_reaper_; }
private:
// Prepares empty directory to mount into. If |mount_path| contains a path
// it may be used, but not necessarily. Returns the status of the operation
// and if successful - fills |mount_path|.
MountErrorType CreateMountPathForSource(const std::string& source,
const std::string& label,
base::FilePath* mount_path);
// Called when the FUSE launcher process finishes.
void OnLauncherExit(MountCallback callback,
const base::FilePath& mount_path,
base::WeakPtr<const MountPoint> mount_point,
MountErrorType error);
// Called when the sandbox holding a FUSE process finishes.
void OnSandboxedProcessExit(const base::FilePath& mount_path,
const base::WeakPtr<MountPoint> mount_point,
const siginfo_t& info);
// The root directory under which mount directories are created.
const base::FilePath mount_root_;
// An object that provides platform service.
Platform* const platform_;
// An object that collects UMA metrics.
Metrics* const metrics_;
// Object that monitors children processes.
brillo::ProcessReaper* const process_reaper_;
// Mount points, in no particular order.
std::vector<std::unique_ptr<MountPoint>> mount_points_;
friend class MountManagerUnderTest;
FRIEND_TEST(MountManagerTest, ExtractMountLabelFromOptions);
FRIEND_TEST(MountManagerTest, ExtractMountLabelFromOptionsWithNoMountLabel);
FRIEND_TEST(MountManagerTest, ExtractMountLabelFromOptionsWithTwoMountLabels);
FRIEND_TEST(MountManagerTest, IsPathImmediateChildOfParent);
FRIEND_TEST(MountManagerTest, IsValidMountPath);
};
} // namespace cros_disks
#endif // CROS_DISKS_MOUNT_MANAGER_H_