First batch of cros-disk changes
A couple of things in this CL.
1. Adds an upstart script that runs the daemon as cros-disks.
2. Adds some functions to the d-bus API.
3. Adds support for watching udev for changes.
4. Adds a DiskManager class for processing disk changes.
5. Adds a Disk class to store the properties that we care about.
6. Some Makefile changes to fix NDEBUG and gflags issues.
Change-Id: I92f7d9199b71aa0150ad82cabe36c5396a4603c8
BUG=13698
TEST=Ran the autotest and manually tested that I was getting udev changes on a cr-48.
Review URL: http://codereview.chromium.org/6824032
diff --git a/Makefile b/Makefile
index 03e1930..8121151 100644
--- a/Makefile
+++ b/Makefile
@@ -10,19 +10,28 @@
include common.mk
PKG_CONFIG ?= pkg-config
+DBUSXX_XML2CPP = dbusxx-xml2cpp
-INCLUDE_DIRS = -I.. $(shell $(PKG_CONFIG) --cflags dbus-1 dbus-glib-1\
+INCLUDE_DIRS = -I.. -I$(OUT)include $(shell $(PKG_CONFIG) --cflags dbus-1 dbus-glib-1\
dbus-c++-1 glib-2.0)
LIB_DIRS = $(shell $(PKG_CONFIG) --libs dbus-1 dbus-glib-1 dbus-c++-1 glib-2.0)
CFLAGS := -Iinclude $(CFLAGS)
CXXFLAGS := -Iinclude -I../ $(INCLUDE_DIRS) $(CXXFLAGS)
-LDFLAGS += -lbase -lgflags -lmetrics $(LIB_DIRS)
+LDFLAGS += -lbase -lgflags -lmetrics -ludev $(LIB_DIRS)
-disks: $(OUT)disks
+$(OUT)include/cros-disks-server.h: cros-disks.xml
+ mkdir -p $(OUT)include
+ $(DBUSXX_XML2CPP) cros-disks.xml --adaptor=$@
+RM_ON_CLEAN += $(OUT)include/cros-disks-server.h
$(OUT)disks: $(filter-out %_testrunner.o %_unittest.o,$(C_OBJECTS)) \
+ $(OUT)include/cros-disks-server.h \
$(CXX_OBJECTS)
$(call cxx_binary)
all: $(OUT)disks
RM_ON_CLEAN += $(OUT)disks
+
+# Some shortcuts
+disks: $(OUT)disks
+dbus-headers: $(OUT)include/cros-disks-server.h
diff --git a/common.mk b/common.mk
index 36d8532..1a55220 100644
--- a/common.mk
+++ b/common.mk
@@ -165,10 +165,10 @@
# CXXFLAGS := -mahflag $(CXXFLAGS) # Prepend to the list
# CXXFLAGS := $(filter-out badflag,$(CXXFLAGS)) # Filter out a value
# The same goes for CFLAGS.
-CXXFLAGS := $(CXXFLAGS) -Wall -Werror -fstack-protector-all -DFORTIFY_SOURCE \
- -O2 -ggdb3 -DNDEBUG -Wa,--noexecstack
-CFLAGS := $(CFLAGS) -Wall -Werror -fstack-protector-all -DFORTIFY_SOURCE \
- -O2 -ggdb3 -DNDEBUG -Wa,--noexecstack
+CXXFLAGS := $(CXXFLAGS) -Wall -Werror -fstack-protector-all -fno-strict-aliasing -DFORTIFY_SOURCE \
+ -ggdb3 -Wa,--noexecstack
+CFLAGS := $(CFLAGS) -Wall -Werror -fstack-protector-all -fno-strict-aliasing -DFORTIFY_SOURCE \
+ -ggdb3 -Wa,--noexecstack
ifeq ($(PROFILING),1)
CFLAGS := -pg
diff --git a/cros-disks-server-impl.cc b/cros-disks-server-impl.cc
new file mode 100644
index 0000000..4b61906
--- /dev/null
+++ b/cros-disks-server-impl.cc
@@ -0,0 +1,45 @@
+// 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.
+
+#include "cros-disks-server-impl.h"
+
+#include "disk.h"
+
+#include <sys/mount.h>
+
+namespace cros_disks {
+
+// TODO(rtc): this should probably be a flag.
+static const char* kServicePath = "/org/chromium/CrosDisks";
+
+CrosDisksServer::CrosDisksServer(DBus::Connection& connection)
+ : DBus::ObjectAdaptor(connection, kServicePath) { }
+
+CrosDisksServer::~CrosDisksServer() { }
+
+bool CrosDisksServer::IsAlive(DBus::Error& error) { // NOLINT
+ return true;
+}
+
+void CrosDisksServer::FilesystemMount(
+ const std::string& nullArgument,
+ const std::vector<std::string>& mountOptions,
+ DBus::Error& error) { // NOLINT
+
+ return;
+}
+
+void CrosDisksServer::FilesystemUnmount(
+ const std::vector<std::string>& mountOptions,
+ DBus::Error& error) { // NOLINT
+
+ return;
+}
+
+DBusDisks CrosDisksServer::GetAll(DBus::Error& error) { // NOLINT
+ DBusDisks v;
+ return v;
+}
+
+} // namespace cros_disks
diff --git a/cros-disks-server-impl.h b/cros-disks-server-impl.h
new file mode 100644
index 0000000..cd2af8d
--- /dev/null
+++ b/cros-disks-server-impl.h
@@ -0,0 +1,50 @@
+// 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.
+
+#ifndef CROS_DISKS_SERVER_IMPL_H__
+#define CROS_DISKS_SERVER_IMPL_H__
+
+#include "cros-disks-server.h"
+#include "disk.h"
+
+#include <string>
+#include <vector>
+
+namespace cros_disks {
+
+// The d-bus server for the cros-disks daemon.
+//
+// Example Usage:
+//
+// DBus::Connection server_conn = DBus::Connection::SystemBus();
+// server_conn.request_name("org.chromium.CrosDisks");
+// CrosDisksServer* server = new(std::nothrow) CrosDisksServer(server_conn);
+//
+// At this point the server should be attached to the main loop.
+//
+class CrosDisksServer : public org::chromium::CrosDisks_adaptor,
+ public DBus::IntrospectableAdaptor,
+ public DBus::ObjectAdaptor {
+ public:
+ CrosDisksServer(DBus::Connection& connection);
+ virtual ~CrosDisksServer();
+
+ // A method for checking if the daemon is running. Always returns true.
+ virtual bool IsAlive(DBus::Error& error); // NOLINT
+
+ // Unmounts a device when invoked.
+ virtual void FilesystemUnmount(const std::vector<std::string>& mountOptions,
+ DBus::Error& error); // NOLINT
+
+ // Mounts a device when invoked.
+ virtual void FilesystemMount(const std::string& nullArgument,
+ const std::vector<std::string>& mountOptions,
+ DBus::Error& error); // NOLINT
+
+ // Returns a description of every disk device attached to the sytem.
+ virtual DBusDisks GetAll(DBus::Error& error); // NOLINT
+};
+} // namespace cros_disks
+
+#endif // CROS_DISKS_SERVER_IMPL_H__
diff --git a/cros-disks.conf b/cros-disks.conf
new file mode 100644
index 0000000..a04a6df
--- /dev/null
+++ b/cros-disks.conf
@@ -0,0 +1,23 @@
+# 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.
+
+# cros-disks upstart job
+
+env CROS_DISKS_LOG_DIR=/var/log/cros-disks
+env CROS_DISKS_UID=213
+env CROS_DISKS_GID=213
+
+start on started dbus
+stop on starting halt or starting reboot
+
+respawn
+expect fork
+
+pre-start script
+ mkdir -p -m 0755 "${CROS_DISKS_LOG_DIR}"
+ chown -R cros-disks:cros-disks "${CROS_DISKS_LOG_DIR}"
+end script
+
+exec /sbin/minijail --uid="${CROS_DISKS_UID}" --gid="${CROS_DISKS_GID}" -- /opt/google/cros-disks/disks
+
diff --git a/cros-disks.xml b/cros-disks.xml
new file mode 100644
index 0000000..9c6eb29
--- /dev/null
+++ b/cros-disks.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
+ <interface name="org.chromium.CrosDisks">
+ <tp:struct name="DiskDevice" array-name="DiskDevices">
+ <tp:member name="deviceIsDrive" type="b"> </tp:member>
+ <tp:member name="devicePresentationHide" type="b"> </tp:member>
+ <tp:member name="deviceIsMounted" type="b"> </tp:member>
+ <tp:member name="deviceMountPath" type="s"> </tp:member>
+ <tp:member name="label" type="s"> </tp:member>
+ <tp:member name="driveModel" type="s"> </tp:member>
+ <tp:member name="isRotational" type="b"> </tp:member>
+ <tp:member name="isOptical" type="b"> </tp:member>
+ <tp:member name="isReadOnly" type="b"> </tp:member>
+ <tp:member name="capacity" type="d"> </tp:member>
+ <tp:member name="bytes_remaining" type="d"> </tp:member>
+ </tp:struct>
+ <method name="FilesystemMount">
+ <arg name="nullArgument" type="s" direction="in">
+ </arg>
+ <arg name="mountOptions" type="as" direction="in">
+ </arg>
+ </method>
+ <method name="FilesystemUnmount">
+ <arg name="mountOptions" type="as" direction="in">
+ </arg>
+ </method>
+ <method name="GetAll">
+ <arg name="disks" type="aa{sv}" direction="out" tp:type="DiskDevices">
+ </arg>
+ </method>
+ <method name="IsAlive">
+ <tp:docstring>
+ Test method to verify that Cashew service is working.
+ </tp:docstring>
+ <arg name="result" type="b" direction="out">
+ <tp:docstring>
+ Boolean indicating whether Cashew service is alive.
+ </tp:docstring>
+ </arg>
+ </method>
+ </interface>
+</node>
diff --git a/disk-manager.cc b/disk-manager.cc
new file mode 100644
index 0000000..1568565
--- /dev/null
+++ b/disk-manager.cc
@@ -0,0 +1,50 @@
+// 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.
+
+#include "disk-manager.h"
+
+#include "disk.h"
+
+#include <base/logging.h>
+#include <libudev.h>
+#include <vector>
+
+
+namespace cros_disks {
+
+DiskManager::DiskManager()
+ : udev_(udev_new()),
+ udev_monitor_fd_(0) {
+
+ CHECK(udev_) << "Failed to initialize udev";
+ udev_monitor_ = udev_monitor_new_from_netlink(udev_, "udev");
+ udev_monitor_filter_add_match_subsystem_devtype(udev_monitor_, "block", NULL);
+ udev_monitor_enable_receiving(udev_monitor_);
+ udev_monitor_fd_ = udev_monitor_get_fd(udev_monitor_);
+}
+
+DiskManager::~DiskManager() {
+ udev_monitor_unref(udev_monitor_);
+ udev_unref(udev_);
+}
+
+std::vector<Disk> DiskManager::EnumerateDisks() {
+ //TODO(rtc): implement this...
+ std::vector<Disk> disks;
+ return disks;
+}
+
+bool DiskManager::ProcessUdevChanges() {
+ struct udev_device *dev = udev_monitor_receive_device(udev_monitor_);
+ CHECK(dev) << "Unknown udev device";
+ LOG(INFO) << "Got Device";
+ LOG(INFO) << " Node: " << udev_device_get_devnode(dev);
+ LOG(INFO) << " Subsystem: " << udev_device_get_subsystem(dev);
+ LOG(INFO) << " Devtype: " << udev_device_get_devtype(dev);
+ LOG(INFO) << " Action: " << udev_device_get_action(dev);
+ udev_device_unref(dev);
+ return true;
+}
+
+} // namespace cros_disks
diff --git a/disk-manager.h b/disk-manager.h
new file mode 100644
index 0000000..1714558
--- /dev/null
+++ b/disk-manager.h
@@ -0,0 +1,56 @@
+// 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.
+
+#ifndef DISK_MANAGER_H__
+#define DISK_MANAGER_H__
+
+#include <libudev.h>
+#include <vector>
+
+namespace cros_disks {
+
+class Disk;
+
+// 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:
+//
+// DiskManager manager;
+// 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:
+ DiskManager();
+ virtual ~DiskManager();
+
+ // Lists the current block devices attached to the system.
+ virtual std::vector<Disk> EnumerateDisks();
+
+ // Reads the changes from udev. Must be called to clear the
+ // fd.
+ bool ProcessUdevChanges();
+
+ // A file descriptor that can be select()ed or poll()ed for system changes.
+ int udev_monitor_fd() const { return udev_monitor_fd_; }
+
+ private:
+
+ // The root udev object.
+ struct udev* udev_;
+
+ // Provides access to udev changes as they occur.
+ struct udev_monitor* udev_monitor_;
+
+ // A file descriptor that indicates changes to the system.
+ int udev_monitor_fd_;
+};
+
+} // namespace cros_disks
+
+#endif // DISK_MANAGER_H__
diff --git a/disk.cc b/disk.cc
new file mode 100644
index 0000000..fe0bf8c
--- /dev/null
+++ b/disk.cc
@@ -0,0 +1,35 @@
+// 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.
+
+#include "disk.h"
+
+namespace cros_disks {
+
+// Keys that libcros expects to see on the wire.
+// TODO(rtc): We should probably stuff these in a shared header...
+const char kDeviceIsDrive[] = "DeviceIsDrive";
+const char kDevicePresentationHide[] = "DevicePresentationHide";
+const char kDeviceIsMounted[] = "DeviceIsMounted";
+const char kDeviceMountPaths[] = "DeviceMountPaths";
+const char kDeviceIsMediaAvailable[] = "DeviceIsMediaAvailable";
+const char kNativePath[] = "NativePath";
+const char kDeviceFile[] = "DeviceFile";
+const char kLabel[] = "IdLabel";
+const char kDriveModel[] = "DriveModel";
+const char kPartitionSlave[] = "PartitionSlave";
+const char kDriveIsRotational[] = "DriveIsRotational";
+const char kDeviceIsOpticalDisc[] = "DeviceIsOpticalDisc";
+const char kDeviceSize[] = "DeviceSize";
+const char kReadOnly[] = "DeviceIsReadOnly";
+
+
+// TODO(rtc): The constructor should set some defaults, but I'm still iterating
+// on the data model.
+Disk::Disk() {
+}
+
+Disk::~Disk() {
+}
+
+} // namespace cros_disks
diff --git a/disk.h b/disk.h
new file mode 100644
index 0000000..14cc059
--- /dev/null
+++ b/disk.h
@@ -0,0 +1,106 @@
+// 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.
+
+#ifndef DISK_H__
+#define DISK_H__
+
+#include <base/basictypes.h>
+#include <dbus-c++/dbus.h> // NOLINT
+#include <map>
+#include <string>
+#include <vector>
+
+namespace cros_disks {
+
+typedef std::map<std::string, DBus::Variant> DBusDisk;
+typedef std::vector<DBusDisk> DBusDisks;
+
+// A simple type that describes a storage device attached to our system.
+//
+// This class was designed to run in a single threaded context and should not
+// be considered thread safe.
+class Disk {
+ public:
+
+ Disk();
+ virtual ~Disk();
+
+ bool is_drive() const { return is_drive_; }
+ void set_is_drive(bool is_drive) { is_drive_ = is_drive; }
+
+ bool is_hidden() const { return is_hidden_; }
+ void set_is_hidden(bool is_hidden) { is_hidden_ = is_hidden; }
+
+ bool is_mounted() const { return is_mounted_; }
+ void set_is_mounted(bool is_mounted) { is_mounted_ = is_mounted; }
+
+ bool is_media_available() const { return is_media_available_; }
+ void set_is_media_available(bool is_media_available) {
+ is_media_available_ = is_media_available;
+ }
+
+ bool is_rotational() const { return is_rotational_; }
+ void set_is_rotational(bool is_rotational) { is_rotational_ = is_rotational; }
+
+ bool is_optical_disk() const { return is_optical_disk_; }
+ void set_is_optical_disk(bool is_optical_disk) {
+ is_optical_disk_ = is_optical_disk;
+ }
+
+ bool is_read_only() const { return is_read_only_; }
+ void set_is_read_only(bool is_read_only) { is_read_only_ = is_read_only; }
+
+ std::string mount_path() const { return mount_path_; }
+ void set_mount_path(const std::string& mount_path) { mount_path_ = mount_path; }
+
+ std::string native_path() const { return native_path_; }
+ void set_native_path(const std::string& native_path) {
+ native_path_ = native_path;
+ }
+
+ std::string device_file() const { return device_file_; }
+ void set_device_file(const std::string& device_file) {
+ device_file_ = device_file;
+ }
+
+ std::string label() const { return label_; }
+ void set_label(const std::string& label) { label_ = label; }
+
+ std::string drive_model() const { return drive_model_; }
+ void set_drive_model(const std::string& drive_model) {
+ drive_model_ = drive_model;
+ }
+
+ uint64 device_capacity() const { return device_capacity_; }
+ void set_device_capacity(uint64 device_capacity) {
+ device_capacity_ = device_capacity;
+ }
+
+ uint64 bytes_remaining() { return bytes_remaining_; }
+ void set_bytes_remaining(uint64 bytes_remaining) {
+ bytes_remaining_ = bytes_remaining;
+ }
+
+ private:
+
+ bool is_drive_;
+ bool is_hidden_;
+ bool is_mounted_;
+ bool is_media_available_;
+ bool is_rotational_;
+ bool is_optical_disk_;
+ bool is_read_only_;
+ std::string mount_path_;
+ std::string native_path_;
+ std::string device_file_;
+ std::string label_;
+ std::string drive_model_;
+ uint64 device_capacity_;
+ uint64 bytes_remaining_;
+};
+
+} // namespace cros_disks
+
+
+#endif // DISK_H__
diff --git a/main.cc b/main.cc
index a38faa0..56bb11f 100644
--- a/main.cc
+++ b/main.cc
@@ -4,6 +4,9 @@
// A simple daemon to detect, mount, and eject removable storage devices.
+#include "cros-disks-server-impl.h"
+#include "disk-manager.h"
+#include <base/basictypes.h>
#include <base/file_util.h>
#include <base/logging.h>
#include <base/string_util.h>
@@ -12,23 +15,86 @@
#include <gflags/gflags.h>
#include <glib-object.h>
#include <glib.h>
+#include <libudev.h>
#include <metrics/metrics_library.h>
+
+using cros_disks::CrosDisksServer;
+using cros_disks::DiskManager;
+
+DEFINE_bool(foreground, false,
+ "Don't daemon()ize; run in foreground.");
+
+// TODO(rtc): gflags string defines require the use of
+// -fno-strict-aliasing for some reason. Verify that disabling this check
+// is sane.
+DEFINE_string(log_dir, "/var/log/cros-disks", "log directory");
+
+void SetupLogging() {
+ logging::InitLogging(FLAGS_log_dir.c_str(),
+ logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG,
+ logging::DONT_LOCK_LOG_FILE,
+ logging::APPEND_TO_OLD_LOG_FILE);
+}
+
+// This callback will be invoked once udev has data about
+// new, changed, or removed devices.
+gboolean UdevCallback(GIOChannel* source,
+ GIOCondition condition,
+ gpointer data) {
+ DiskManager* mgr = static_cast<DiskManager*>(data);
+ mgr->ProcessUdevChanges();
+ return true;
+}
+
int main(int argc, char** argv) {
::g_type_init();
g_thread_init(NULL);
google::ParseCommandLineFlags(&argc, &argv, true);
+ if(!FLAGS_foreground) {
+ PLOG_IF(FATAL, daemon(0, 0) == 1) << "daemon() failed";
+ // SetupLogging();
+ }
+
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 dbus dispatcher";
+ DBus::Glib::BusDispatcher* dispatcher =
+ new(std::nothrow) DBus::Glib::BusDispatcher();
+ CHECK(dispatcher) << "Failed to create a dbus-dispatcher";
+ DBus::default_dispatcher = dispatcher;
+ dispatcher->attach(NULL);
+
+ LOG(INFO) << "creating server";
+ DBus::Connection server_conn = DBus::Connection::SystemBus();
+ server_conn.request_name("org.chromium.CrosDisks");
+ CrosDisksServer* server = new(std::nothrow) CrosDisksServer(server_conn);
+ CHECK(server) << "Failed to create the cros-disks server";
LOG(INFO) << "Initializing the metrics library";
MetricsLibrary metrics_lib;
metrics_lib.Init();
- // Run the main loop until exit time:
- // TODO(rtc): daemonize this
+
+ DiskManager manager;
+ manager.EnumerateDisks();
+
+ // Setup a monitor
+ g_io_add_watch_full(g_io_channel_unix_new(manager.udev_monitor_fd()),
+ G_PRIORITY_HIGH_IDLE,
+ GIOCondition(G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_NVAL),
+ UdevCallback,
+ &manager,
+ NULL);
g_main_loop_run(loop);
+ LOG(INFO) << "Cleaining up and exiting";
+ g_main_loop_unref(loop);
+ delete server;
+ delete dispatcher;
+
return 0;
}
diff --git a/org.chromium.CrosDisks.conf b/org.chromium.CrosDisks.conf
new file mode 100644
index 0000000..5c07baa
--- /dev/null
+++ b/org.chromium.CrosDisks.conf
@@ -0,0 +1,12 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <policy user="cros-disks">
+ <allow own="org.chromium.CrosDisks"/>
+ </policy>
+ <policy context="default">
+ <allow send_destination="org.chromium.CrosDisks"/>
+ </policy>
+ <limit name="max_replies_per_connection">512</limit>
+</busconfig>