blob: b22fb37b01bde61c6b6503f478120e5a80a42cd5 [file] [log] [blame]
// Copyright 2018 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.
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <base/command_line.h>
#include <base/logging.h>
#include <base/macros.h>
#include <base/memory/ref_counted.h>
#include <brillo/daemons/dbus_daemon.h>
#include <brillo/syslog_logging.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/bus.h>
#include "appfuse/dbus_adaptors/org.chromium.ArcAppfuseProvider.h"
#include "arc/container/appfuse/appfuse_mount.h"
namespace {
constexpr char kMountRoot[] = "mount_root";
brillo::ErrorPtr CreateDBusError(const std::string& code,
const std::string& message) {
return brillo::Error::Create(FROM_HERE, brillo::errors::dbus::kDomain, code,
message);
}
class DBusAdaptor : public org::chromium::ArcAppfuseProviderAdaptor,
public org::chromium::ArcAppfuseProviderInterface,
public arc::appfuse::AppfuseMount::Delegate {
public:
explicit DBusAdaptor(scoped_refptr<dbus::Bus> bus)
: org::chromium::ArcAppfuseProviderAdaptor(this),
mount_root_(base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
kMountRoot)),
dbus_object_(
nullptr,
bus,
dbus::ObjectPath(arc::appfuse::kArcAppfuseProviderServicePath)) {}
DBusAdaptor(const DBusAdaptor&) = delete;
DBusAdaptor& operator=(const DBusAdaptor&) = delete;
~DBusAdaptor() override = default;
void RegisterAsync(
const brillo::dbus_utils::AsyncEventSequencer::CompletionAction& cb) {
RegisterWithDBusObject(&dbus_object_);
dbus_object_.RegisterAsync(cb);
}
// org::chromium::ArcAppfuseProviderInterface overrides:
bool Mount(brillo::ErrorPtr* error,
uint32_t uid,
int32_t mount_id,
brillo::dbus_utils::FileDescriptor* out_fd) override {
// Remove existing mount.
auto it = mounts_.find(std::make_pair(uid, mount_id));
if (it != mounts_.end()) {
LOG(INFO) << "Unmounting an existing mount for a new mount: " << uid
<< " " << mount_id;
if (!it->second->Unmount()) {
LOG(ERROR) << "Failed to unmount an existing mount for a new mount: "
<< uid << " " << mount_id;
*error = CreateDBusError(DBUS_ERROR_FAILED, "Failed to unmount");
return false;
}
mounts_.erase(it);
}
// Create a new mount.
auto mount = std::make_unique<arc::appfuse::AppfuseMount>(mount_root_, uid,
mount_id, this);
base::ScopedFD fd = mount->Mount();
if (!fd.is_valid()) {
LOG(ERROR) << "Failed to mount: " << uid << " " << mount_id;
*error = CreateDBusError(DBUS_ERROR_FAILED, "Failed to mount");
return false;
}
mounts_[std::make_pair(uid, mount_id)] = std::move(mount);
*out_fd = std::move(fd);
return true;
}
bool Unmount(brillo::ErrorPtr* error,
uint32_t uid,
int32_t mount_id) override {
auto it = mounts_.find(std::make_pair(uid, mount_id));
if (it == mounts_.end()) {
LOG(ERROR) << "No mount found: " << uid << " " << mount_id;
*error = CreateDBusError(DBUS_ERROR_FAILED, "No mount found");
return false;
}
if (!it->second->Unmount()) {
LOG(ERROR) << "Failed to unmount: " << uid << " " << mount_id;
*error = CreateDBusError(DBUS_ERROR_FAILED, "Failed to unmount");
return false;
}
mounts_.erase(it);
return true;
}
bool OpenFile(brillo::ErrorPtr* error,
uint32_t uid,
int32_t mount_id,
int32_t file_id,
int32_t flags,
brillo::dbus_utils::FileDescriptor* out_fd) override {
auto it = mounts_.find(std::make_pair(uid, mount_id));
if (it == mounts_.end()) {
LOG(ERROR) << "No mount found: " << uid << " " << mount_id;
*error = CreateDBusError(DBUS_ERROR_FAILED, "No mount found");
return false;
}
base::ScopedFD fd = it->second->OpenFile(file_id, flags);
if (!fd.is_valid()) {
LOG(ERROR) << "Failed to open: " << uid << " " << mount_id;
*error = CreateDBusError(DBUS_ERROR_FAILED, "Failed to open");
return false;
}
*out_fd = std::move(fd);
return true;
}
// AppfuseMount::Delegate override:
void OnAppfuseMountAborted(arc::appfuse::AppfuseMount* mount) override {
mounts_.erase(std::make_pair(mount->uid(), mount->mount_id()));
}
private:
const base::FilePath mount_root_;
brillo::dbus_utils::DBusObject dbus_object_;
// Maps (UID, mount ID) to AppfuseMount.
using UIDMountIDPair = std::pair<uid_t, int>;
using AppfuseMountMap =
std::map<UIDMountIDPair, std::unique_ptr<arc::appfuse::AppfuseMount>>;
AppfuseMountMap mounts_;
};
class Daemon : public brillo::DBusServiceDaemon {
public:
Daemon() : DBusServiceDaemon(arc::appfuse::kArcAppfuseProviderServiceName) {}
Daemon(const Daemon&) = delete;
Daemon& operator=(const Daemon&) = delete;
~Daemon() override = default;
protected:
void RegisterDBusObjectsAsync(
brillo::dbus_utils::AsyncEventSequencer* sequencer) override {
adaptor_ = std::make_unique<DBusAdaptor>(bus_);
adaptor_->RegisterAsync(
sequencer->GetHandler("RegisterAsync() failed.", true));
}
private:
std::unique_ptr<DBusAdaptor> adaptor_;
};
} // namespace
int main(int argc, char** argv) {
base::CommandLine::Init(argc, argv);
brillo::InitLog(brillo::kLogToSyslog | brillo::kLogToStderrIfTty);
CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(kMountRoot))
<< "--" << kMountRoot << " must be specified.";
return Daemon().Run();
}