blob: b5cdef990babaf673af45509b61b5581517308d7 [file] [log] [blame]
Ben Chance7ee542011-04-12 17:02:49 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <base/string_number_conversions.h>
6#include <base/string_util.h>
7#include <fcntl.h>
8#include <libudev.h>
9#include <sys/statvfs.h>
10#include <fstream>
11
12#include "udev-device.h"
13
14namespace cros_disks {
15
16UdevDevice::UdevDevice(struct udev_device *dev)
17 : dev_(dev) {
18
19 CHECK(dev_) << "Invalid udev device";
20 udev_device_ref(dev_);
21}
22
23UdevDevice::~UdevDevice() {
24 udev_device_unref(dev_);
25}
26
27bool UdevDevice::IsValueBooleanTrue(const char *value) const {
28 return value && strcmp(value, "1") == 0;
29}
30
31std::string UdevDevice::GetAttribute(const char *key) const {
32 const char *value = udev_device_get_sysattr_value(dev_, key);
33 return (value) ? value : "";
34}
35
36bool UdevDevice::IsAttributeTrue(const char *key) const {
37 const char *value = udev_device_get_sysattr_value(dev_, key);
38 return IsValueBooleanTrue(value);
39}
40
41bool UdevDevice::HasAttribute(const char *key) const {
42 const char *value = udev_device_get_sysattr_value(dev_, key);
43 return value != NULL;
44}
45
46std::string UdevDevice::GetProperty(const char *key) const {
47 const char *value = udev_device_get_property_value(dev_, key);
48 return (value) ? value : "";
49}
50
51bool UdevDevice::IsPropertyTrue(const char *key) const {
52 const char *value = udev_device_get_property_value(dev_, key);
53 return IsValueBooleanTrue(value);
54}
55
56bool UdevDevice::HasProperty(const char *key) const {
57 const char *value = udev_device_get_property_value(dev_, key);
58 return value != NULL;
59}
60
61void UdevDevice::GetSizeInfo(uint64 *total_size, uint64 *remaining_size) const {
Ben Chanf51ff002011-04-25 12:41:57 -070062 static const int kSectorSize = 512;
63 uint64 total = 0, remaining = 0;
Ben Chance7ee542011-04-12 17:02:49 -070064
Ben Chanf51ff002011-04-25 12:41:57 -070065 // If the device is mounted, obtain the total and remaining size in bytes
66 // using statvfs.
67 std::vector<std::string> mount_paths = GetMountPaths();
68 if (!mount_paths.empty()) {
69 struct statvfs stat;
70 if (statvfs(mount_paths[0].c_str(), &stat) == 0) {
71 total = stat.f_blocks * stat.f_frsize;
72 remaining = stat.f_bfree * stat.f_frsize;
Ben Chance7ee542011-04-12 17:02:49 -070073 }
74 }
75
Ben Chanf51ff002011-04-25 12:41:57 -070076 // If the UDISKS_PARTITION_SIZE property is set, use it as the total size
77 // instead. If the UDISKS_PARTITION_SIZE property is not set but sysfs
78 // provides a size value, which is the actual size in bytes divided by 512,
79 // use that as the total size instead.
80 const char *partition_size = udev_device_get_property_value(dev_,
81 "UDISKS_PARTITION_SIZE");
82 int64 size = 0;
83 if (partition_size) {
84 base::StringToInt64(partition_size, &size);
85 total = size;
86 } else {
87 const char *size_attr = udev_device_get_sysattr_value(dev_, "size");
88 if (size_attr) {
89 base::StringToInt64(size_attr, &size);
90 total = size * kSectorSize;
91 }
92 }
93
94 if (total_size)
95 *total_size = total;
Ben Chance7ee542011-04-12 17:02:49 -070096 if (remaining_size)
Ben Chanf51ff002011-04-25 12:41:57 -070097 *remaining_size = remaining;
Ben Chance7ee542011-04-12 17:02:49 -070098}
99
100bool UdevDevice::IsMediaAvailable() const {
101 bool is_media_available = true;
102 if (IsAttributeTrue("removable")) {
103 if (IsPropertyTrue("ID_CDROM")) {
104 is_media_available = IsPropertyTrue("ID_CDROM_MEDIA");
105 } else {
106 const char *dev_file = udev_device_get_devnode(dev_);
Ben Chanf51ff002011-04-25 12:41:57 -0700107 if (dev_file) {
108 int fd = open(dev_file, O_RDONLY);
109 if (fd < 0) {
110 is_media_available = false;
111 } else {
112 close(fd);
113 }
Ben Chance7ee542011-04-12 17:02:49 -0700114 }
115 }
116 }
117 return is_media_available;
118}
119
Ben Chanf51ff002011-04-25 12:41:57 -0700120std::vector<std::string> UdevDevice::GetMountPaths() const {
121 const char *device_path = udev_device_get_devnode(dev_);
122 if (device_path) {
123 return GetMountPaths(device_path);
Ben Chance7ee542011-04-12 17:02:49 -0700124 }
125 return std::vector<std::string>();
126}
127
Ben Chanf51ff002011-04-25 12:41:57 -0700128std::vector<std::string> UdevDevice::GetMountPaths(
129 const std::string& device_path) {
130 std::ifstream fs("/proc/mounts");
131 if (fs.is_open()) {
132 return ParseMountPaths(device_path, fs);
133 }
134 LOG(ERROR) << "Unable to parse /proc/mounts";
135 return std::vector<std::string>();
136}
137
138std::vector<std::string> UdevDevice::ParseMountPaths(
Ben Chance7ee542011-04-12 17:02:49 -0700139 const std::string& device_path, std::istream& stream) {
Ben Chanf51ff002011-04-25 12:41:57 -0700140 std::vector<std::string> mount_paths;
Ben Chance7ee542011-04-12 17:02:49 -0700141 std::string line;
142 while (std::getline(stream, line)) {
143 std::vector<std::string> tokens;
144 SplitString(line, ' ', &tokens);
145 if (tokens.size() >= 2) {
146 if (tokens[0] == device_path)
Ben Chanf51ff002011-04-25 12:41:57 -0700147 mount_paths.push_back(tokens[1]);
Ben Chance7ee542011-04-12 17:02:49 -0700148 }
149 }
Ben Chanf51ff002011-04-25 12:41:57 -0700150 return mount_paths;
Ben Chance7ee542011-04-12 17:02:49 -0700151}
152
153Disk UdevDevice::ToDisk() const {
154 Disk disk;
155
156 disk.set_is_read_only(IsAttributeTrue("ro"));
157 disk.set_is_drive(HasAttribute("range"));
158 disk.set_is_rotational(HasProperty("ID_ATA_ROTATION_RATE_RPM"));
159 disk.set_is_optical_disk(IsPropertyTrue("ID_CDROM"));
160 disk.set_is_hidden(IsPropertyTrue("UDISKS_PRESENTATION_HIDE"));
161 disk.set_is_media_available(IsMediaAvailable());
162 disk.set_drive_model(GetProperty("ID_MODEL"));
163 disk.set_label(GetProperty("ID_FS_LABEL"));
Ben Chanf51ff002011-04-25 12:41:57 -0700164 const char *sys_path = udev_device_get_syspath(dev_);
165 if (sys_path)
166 disk.set_native_path(sys_path);
Ben Chance7ee542011-04-12 17:02:49 -0700167
168 const char *dev_file = udev_device_get_devnode(dev_);
Ben Chanf51ff002011-04-25 12:41:57 -0700169 if (dev_file)
170 disk.set_device_file(dev_file);
Ben Chance7ee542011-04-12 17:02:49 -0700171
Ben Chanf51ff002011-04-25 12:41:57 -0700172 std::vector<std::string> mount_paths = GetMountPaths();
173 disk.set_is_mounted(!mount_paths.empty());
174 disk.set_mount_paths(mount_paths);
Ben Chance7ee542011-04-12 17:02:49 -0700175
176 uint64 total_size, remaining_size;
177 GetSizeInfo(&total_size, &remaining_size);
178 disk.set_device_capacity(total_size);
179 disk.set_bytes_remaining(remaining_size);
180
181 return disk;
182}
183
184} // namespace cros_disks