Populate disk information from udev to disk manager.
BUG=chromium-os:13698
TEST=Built and manually tested udev code.
Review URL: http://codereview.chromium.org/6824082
Change-Id: Ib658cdeb5b68962970dcfaa1d97cdbc08e0fb48d
diff --git a/disk-manager.cc b/disk-manager.cc
index 1568565..2eda988 100644
--- a/disk-manager.cc
+++ b/disk-manager.cc
@@ -3,8 +3,8 @@
// found in the LICENSE file.
#include "disk-manager.h"
-
#include "disk.h"
+#include "udev-device.h"
#include <base/logging.h>
#include <libudev.h>
@@ -30,8 +30,40 @@
}
std::vector<Disk> DiskManager::EnumerateDisks() {
- //TODO(rtc): implement this...
std::vector<Disk> disks;
+
+ struct udev_enumerate *enumerate = udev_enumerate_new(udev_);
+ udev_enumerate_add_match_subsystem(enumerate, "block");
+ udev_enumerate_scan_devices(enumerate);
+
+ struct udev_list_entry *device_list, *device_list_entry;
+ device_list = udev_enumerate_get_list_entry(enumerate);
+ udev_list_entry_foreach(device_list_entry, device_list) {
+ const char *path = udev_list_entry_get_name(device_list_entry);
+ udev_device *dev = udev_device_new_from_syspath(udev_, path);
+
+ LOG(INFO) << "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) << " Devpath: " << udev_device_get_devpath(dev);
+ LOG(INFO) << " Sysname: " << udev_device_get_sysname(dev);
+ LOG(INFO) << " Syspath: " << udev_device_get_syspath(dev);
+ LOG(INFO) << " Properties: ";
+ struct udev_list_entry *property_list, *property_list_entry;
+ property_list = udev_device_get_properties_list_entry(dev);
+ udev_list_entry_foreach (property_list_entry, property_list) {
+ const char *key = udev_list_entry_get_name(property_list_entry);
+ const char *value = udev_list_entry_get_value(property_list_entry);
+ LOG(INFO) << " " << key << " = " << value;
+ }
+
+ disks.push_back(UdevDevice(dev).ToDisk());
+ udev_device_unref(dev);
+ }
+
+ udev_enumerate_unref(enumerate);
+
return disks;
}
diff --git a/udev-device.cc b/udev-device.cc
new file mode 100644
index 0000000..e324706
--- /dev/null
+++ b/udev-device.cc
@@ -0,0 +1,158 @@
+// 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 <base/string_number_conversions.h>
+#include <base/string_util.h>
+#include <fcntl.h>
+#include <libudev.h>
+#include <sys/statvfs.h>
+#include <fstream>
+
+#include "udev-device.h"
+
+namespace cros_disks {
+
+UdevDevice::UdevDevice(struct udev_device *dev)
+ : dev_(dev) {
+
+ CHECK(dev_) << "Invalid udev device";
+ udev_device_ref(dev_);
+}
+
+UdevDevice::~UdevDevice() {
+ udev_device_unref(dev_);
+}
+
+bool UdevDevice::IsValueBooleanTrue(const char *value) const {
+ return value && strcmp(value, "1") == 0;
+}
+
+std::string UdevDevice::GetAttribute(const char *key) const {
+ const char *value = udev_device_get_sysattr_value(dev_, key);
+ return (value) ? value : "";
+}
+
+bool UdevDevice::IsAttributeTrue(const char *key) const {
+ const char *value = udev_device_get_sysattr_value(dev_, key);
+ return IsValueBooleanTrue(value);
+}
+
+bool UdevDevice::HasAttribute(const char *key) const {
+ const char *value = udev_device_get_sysattr_value(dev_, key);
+ return value != NULL;
+}
+
+std::string UdevDevice::GetProperty(const char *key) const {
+ const char *value = udev_device_get_property_value(dev_, key);
+ return (value) ? value : "";
+}
+
+bool UdevDevice::IsPropertyTrue(const char *key) const {
+ const char *value = udev_device_get_property_value(dev_, key);
+ return IsValueBooleanTrue(value);
+}
+
+bool UdevDevice::HasProperty(const char *key) const {
+ const char *value = udev_device_get_property_value(dev_, key);
+ return value != NULL;
+}
+
+void UdevDevice::GetSizeInfo(uint64 *total_size, uint64 *remaining_size) const {
+ const char *dev_file = udev_device_get_devnode(dev_);
+
+ struct statvfs stat;
+ bool stat_available = (statvfs(dev_file, &stat) == 0);
+
+ if (total_size) {
+ *total_size = (stat_available) ? (stat.f_blocks * stat.f_frsize) : 0;
+ const char *partition_size = udev_device_get_property_value(dev_,
+ "UDISKS_PARTITION_SIZE");
+ int64 size = 0;
+ if (partition_size) {
+ base::StringToInt64(partition_size, &size);
+ *total_size = size;
+ } else {
+ const char *size_attr = udev_device_get_sysattr_value(dev_, "size");
+ if (size_attr) {
+ base::StringToInt64(size_attr, &size);
+ *total_size = size;
+ }
+ }
+ }
+
+ if (remaining_size)
+ *remaining_size = (stat_available) ? (stat.f_bfree * stat.f_frsize) : 0;
+}
+
+bool UdevDevice::IsMediaAvailable() const {
+ bool is_media_available = true;
+ if (IsAttributeTrue("removable")) {
+ if (IsPropertyTrue("ID_CDROM")) {
+ is_media_available = IsPropertyTrue("ID_CDROM_MEDIA");
+ } else {
+ const char *dev_file = udev_device_get_devnode(dev_);
+ int fd = open(dev_file, O_RDONLY);
+ if (fd < 0) {
+ is_media_available = true;
+ } else {
+ close(fd);
+ }
+ }
+ }
+ return is_media_available;
+}
+
+std::vector<std::string> UdevDevice::GetMountedPaths() const {
+ const std::string dev_file = udev_device_get_devnode(dev_);
+ std::ifstream fs("/proc/mounts");
+ if (fs.is_open()) {
+ return ParseMountedPaths(dev_file, fs);
+ }
+ return std::vector<std::string>();
+}
+
+std::vector<std::string> UdevDevice::ParseMountedPaths(
+ const std::string& device_path, std::istream& stream) {
+ std::vector<std::string> mounted_paths;
+ std::string line;
+ while (std::getline(stream, line)) {
+ std::vector<std::string> tokens;
+ SplitString(line, ' ', &tokens);
+ if (tokens.size() >= 2) {
+ if (tokens[0] == device_path)
+ mounted_paths.push_back(tokens[1]);
+ }
+ }
+ return mounted_paths;
+}
+
+Disk UdevDevice::ToDisk() const {
+ Disk disk;
+
+ disk.set_is_read_only(IsAttributeTrue("ro"));
+ disk.set_is_drive(HasAttribute("range"));
+ disk.set_is_rotational(HasProperty("ID_ATA_ROTATION_RATE_RPM"));
+ disk.set_is_optical_disk(IsPropertyTrue("ID_CDROM"));
+ disk.set_is_hidden(IsPropertyTrue("UDISKS_PRESENTATION_HIDE"));
+ disk.set_is_media_available(IsMediaAvailable());
+ disk.set_drive_model(GetProperty("ID_MODEL"));
+ disk.set_label(GetProperty("ID_FS_LABEL"));
+ disk.set_native_path(udev_device_get_syspath(dev_));
+
+ const char *dev_file = udev_device_get_devnode(dev_);
+ disk.set_device_file(dev_file);
+
+ std::vector<std::string> mounted_paths = GetMountedPaths();
+ disk.set_is_mounted(!mounted_paths.empty());
+ disk.set_mount_path(mounted_paths[0]); // TODO(benchan): multiple paths
+
+ uint64 total_size, remaining_size;
+ GetSizeInfo(&total_size, &remaining_size);
+ disk.set_device_capacity(total_size);
+ disk.set_bytes_remaining(remaining_size);
+
+ return disk;
+}
+
+} // namespace cros_disks
diff --git a/udev-device.h b/udev-device.h
new file mode 100644
index 0000000..ef5c6c1
--- /dev/null
+++ b/udev-device.h
@@ -0,0 +1,70 @@
+// 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 CHOS_DISKS_UDEV_DEVICE_H_
+#define CROS_DISKS_UDEV_DEVICE_H_
+
+#include <base/basictypes.h>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "disk.h"
+
+struct udev_device;
+
+namespace cros_disks {
+
+// A utility class that helps query information about a udev device.
+class UdevDevice {
+ public:
+
+ explicit UdevDevice(struct udev_device *dev);
+ ~UdevDevice();
+
+ // Gets the string value of a device attribute.
+ std::string GetAttribute(const char *key) const;
+
+ // Checks if the value of a device attribute represents a Boolean true.
+ bool IsAttributeTrue(const char *key) const;
+
+ // Checks if a device attribute exists.
+ bool HasAttribute(const char *key) const;
+
+ // Gets the string value of a device property.
+ std::string GetProperty(const char *key) const;
+
+ // Checks if the value of a device property represents a Boolean true.
+ bool IsPropertyTrue(const char *key) const;
+
+ // Checks if a device property exists.
+ bool HasProperty(const char *key) const;
+
+ // Gets the total and remaining capacity of the device.
+ void GetSizeInfo(uint64 *total_size, uint64 *remaining_size) const;
+
+ // Checks if any media is available in the device.
+ bool IsMediaAvailable() const;
+
+ // Gets the mounted paths for the device.
+ std::vector<std::string> GetMountedPaths() const;
+
+ // Gets the mounted paths for an input stream that has the
+ // same format as /proc/mounts
+ static std::vector<std::string> ParseMountedPaths(
+ const std::string& device_path, std::istream& stream);
+
+ // Returns a Disk object based on the device information.
+ Disk ToDisk() const;
+
+ private:
+
+ bool IsValueBooleanTrue(const char *value) const;
+
+ mutable struct udev_device *dev_;
+};
+
+} // namespace cros_disks
+
+#endif // CROS_DISKS_UDEV_DEVICE_H_