blob: b8335c6429059ac5a6b4173c070fd6d03d3ea2ab [file] [log] [blame]
// Copyright (c) 2011 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.
// A simple daemon to detect, mount, and eject removable storage devices.
#include <glib.h>
#include <glib-object.h>
#include <libudev.h>
#include <dbus-c++/glib-integration.h>
#include <dbus-c++/util.h>
#include <base/basictypes.h>
#include <base/command_line.h>
#include <base/file_util.h>
#include <base/string_util.h>
#include <chromeos/syslog_logging.h>
#include <gflags/gflags.h>
#include <metrics/metrics_library.h>
#include "cros-disks/archive-manager.h"
#include "cros-disks/cros-disks-server-impl.h"
#include "cros-disks/disk-manager.h"
#include "cros-disks/format-manager.h"
#include "cros-disks/platform.h"
#include "cros-disks/power-manager-proxy.h"
#include "cros-disks/session-manager-proxy.h"
using cros_disks::ArchiveManager;
using cros_disks::CrosDisksServer;
using cros_disks::DiskManager;
using cros_disks::FormatManager;
using cros_disks::Platform;
using cros_disks::PowerManagerProxy;
using cros_disks::SessionManagerProxy;
DEFINE_bool(foreground, false,
"Don't daemon()ize; run in foreground.");
DEFINE_int32(minloglevel, logging::LOG_WARNING,
"Messages logged at a lower level than "
"this don't actually get logged anywhere");
static const char kUsageMessage[] = "Chromium OS Disk Daemon";
static const char kArchiveMountRootDirectory[] = "/media/archive";
static const char kDiskMountRootDirectory[] = "/media/removable";
static const char kNonPrivilegedMountUser[] = "chronos";
// Always logs to the syslog and logs to stderr if
// we are running in the foreground.
void SetupLogging() {
int log_flags = 0;
log_flags |= chromeos::kLogToSyslog;
if (FLAGS_foreground) {
log_flags |= chromeos::kLogToStderr;
}
chromeos::InitLog(log_flags);
logging::SetMinLogLevel(FLAGS_minloglevel);
}
// This callback will be invoked once udev has data about
// new, changed, or removed devices.
gboolean UdevCallback(GIOChannel* source,
GIOCondition condition,
gpointer data) {
CrosDisksServer* server = static_cast<CrosDisksServer*>(data);
server->SignalDeviceChanges();
// This function should always return true so that the main loop
// continues to select on udev monitor's file descriptor.
return true;
}
int main(int argc, char** argv) {
::g_type_init();
g_thread_init(NULL);
google::SetUsageMessage(kUsageMessage);
google::ParseCommandLineFlags(&argc, &argv, true);
CommandLine::Init(argc, argv);
SetupLogging();
if (!FLAGS_foreground) {
LOG(INFO) << "Daemonizing";
PLOG_IF(FATAL, daemon(0, 0) == 1) << "daemon() failed";
}
LOG(INFO) << "Creating a GMainLoop";
GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
CHECK(loop) << "Failed to create a GMainLoop";
LOG(INFO) << "Creating the D-Bus dispatcher";
DBus::Glib::BusDispatcher dispatcher;
DBus::default_dispatcher = &dispatcher;
dispatcher.attach(NULL);
LOG(INFO) << "Creating the cros-disks server";
DBus::Connection server_conn = DBus::Connection::SystemBus();
server_conn.request_name("org.chromium.CrosDisks");
Platform platform;
CHECK(platform.SetMountUser(kNonPrivilegedMountUser))
<< "'" << kNonPrivilegedMountUser
<< "' is not available for non-privileged mount operations.";
LOG(INFO) << "Creating the archive manager";
ArchiveManager archive_manager(kArchiveMountRootDirectory, &platform);
CHECK(archive_manager.Initialize())
<< "Failed to initialize the archive manager";
LOG(INFO) << "Creating the disk manager";
DiskManager disk_manager(kDiskMountRootDirectory, &platform);
CHECK(disk_manager.Initialize()) << "Failed to initialize the disk manager";
FormatManager format_manager;
CrosDisksServer cros_disks_server(server_conn,
&platform,
&archive_manager,
&disk_manager,
&format_manager);
LOG(INFO) << "Creating a power manager proxy";
PowerManagerProxy power_manager_proxy(&server_conn, &cros_disks_server);
LOG(INFO) << "Creating a session manager proxy";
SessionManagerProxy session_manager_proxy(&server_conn, &cros_disks_server);
LOG(INFO) << "Initializing the metrics library";
MetricsLibrary metrics_lib;
metrics_lib.Init();
// Setup a monitor
g_io_add_watch_full(g_io_channel_unix_new(disk_manager.udev_monitor_fd()),
G_PRIORITY_HIGH_IDLE,
GIOCondition(G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_NVAL),
UdevCallback,
&cros_disks_server,
NULL);
g_main_loop_run(loop);
LOG(INFO) << "Cleaining up and exiting";
g_main_loop_unref(loop);
return 0;
}