blob: d990ff76c4b4c6cef347258549fb6f7359eb4baf [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
Ben Chan5ccd9fe2013-11-13 18:28:27 -08005#include "cros-disks/udev_device.h"
Ben Chanbeefd0d2011-07-25 09:31:34 -07006
Ben Chance7ee542011-04-12 17:02:49 -07007#include <fcntl.h>
8#include <libudev.h>
Alex Vakulenkoe50371c2016-01-20 16:06:19 -08009#include <linux/limits.h>
Ben Chanda410a02011-08-24 23:37:53 -070010#include <stdlib.h>
Ben Chance7ee542011-04-12 17:02:49 -070011#include <sys/statvfs.h>
Ben Chanbdc39742011-05-11 17:51:26 -070012
Chris Masoneec4761f2011-05-12 14:04:13 -070013#include <base/logging.h>
Ben Chan0e1b5502013-07-24 23:39:29 -070014#include <base/sha1.h>
Ben Chan97e20d42014-02-05 18:38:07 -080015#include <base/strings/string_number_conversions.h>
16#include <base/strings/string_split.h>
17#include <base/strings/string_util.h>
Ben Chanbdc39742011-05-11 17:51:26 -070018#include <rootdev/rootdev.h>
19
Ben Chan5ccd9fe2013-11-13 18:28:27 -080020#include "cros-disks/mount_info.h"
21#include "cros-disks/usb_device_info.h"
Ben Chance7ee542011-04-12 17:02:49 -070022
Anand K Mistry40cff452019-07-30 10:24:48 +100023namespace cros_disks {
Ben Chan54342622011-08-18 00:57:11 -070024namespace {
Ben Chance7ee542011-04-12 17:02:49 -070025
Ben Chan460439f2011-09-13 09:16:28 -070026const char kNullDeviceFile[] = "/dev/null";
Ben Chan0a389a62011-10-03 15:02:34 -070027const char kAttributeIdProduct[] = "idProduct";
28const char kAttributeIdVendor[] = "idVendor";
Ben Chan460439f2011-09-13 09:16:28 -070029const char kAttributePartition[] = "partition";
30const char kAttributeRange[] = "range";
31const char kAttributeReadOnly[] = "ro";
32const char kAttributeRemovable[] = "removable";
33const char kAttributeSize[] = "size";
34const char kPropertyBlkIdFilesystemType[] = "TYPE";
35const char kPropertyBlkIdFilesystemLabel[] = "LABEL";
36const char kPropertyBlkIdFilesystemUUID[] = "UUID";
37const char kPropertyCDROM[] = "ID_CDROM";
Ben Chan7d8f9f72012-05-02 10:02:20 -070038const char kPropertyCDROMDVD[] = "ID_CDROM_DVD";
Ben Chan460439f2011-09-13 09:16:28 -070039const char kPropertyCDROMMedia[] = "ID_CDROM_MEDIA";
Ben Chana0fe0ef2012-09-06 23:39:56 -070040const char kPropertyCDROMMediaTrackCountData[] =
41 "ID_CDROM_MEDIA_TRACK_COUNT_DATA";
Ben Chan0a389a62011-10-03 15:02:34 -070042const char kPropertyDeviceType[] = "DEVTYPE";
43const char kPropertyDeviceTypeUSBDevice[] = "usb_device";
Ben Chan460439f2011-09-13 09:16:28 -070044const char kPropertyFilesystemUsage[] = "ID_FS_USAGE";
Ben Chan1f418382013-06-17 23:33:28 -070045const char kPropertyMistSupportedDevice[] = "MIST_SUPPORTED_DEVICE";
Ben Chan5540d902018-07-25 14:52:58 -070046const char kPropertyMmcType[] = "MMC_TYPE";
47const char kPropertyMmcTypeSd[] = "SD";
Ben Chan460439f2011-09-13 09:16:28 -070048const char kPropertyModel[] = "ID_MODEL";
Ben Chancac20332014-02-13 23:21:17 -080049const char kPropertyPartitionEntryType[] = "ID_PART_ENTRY_TYPE";
Ben Chan460439f2011-09-13 09:16:28 -070050const char kPropertyPartitionSize[] = "UDISKS_PARTITION_SIZE";
51const char kPropertyPresentationHide[] = "UDISKS_PRESENTATION_HIDE";
52const char kPropertyRotationRate[] = "ID_ATA_ROTATION_RATE_RPM";
Ben Chan0e1b5502013-07-24 23:39:29 -070053const char kPropertySerial[] = "ID_SERIAL";
Ben Chan1f418382013-06-17 23:33:28 -070054const char kSubsystemUsb[] = "usb";
Austin Tankiang36f5bb52019-03-25 16:49:30 +110055const char kSubsystemMmc[] = "mmc";
56const char kSubsystemNvme[] = "nvme";
57const char kSubsystemScsi[] = "scsi";
Ben Chan460439f2011-09-13 09:16:28 -070058const char kVirtualDevicePathPrefix[] = "/sys/devices/virtual/";
Ben Chan2923ed72013-07-29 15:52:29 -070059const char kLoopDevicePathPrefix[] = "/sys/devices/virtual/block/loop";
Ben Chanccde5122018-09-25 17:46:07 -070060const char kUSBDeviceInfoFile[] = "/usr/share/cros-disks/usb-device-info";
Ben Chan120c11c2012-09-10 23:10:18 -070061const char kUSBIdentifierDatabase[] = "/usr/share/misc/usb.ids";
Ben Chanc79c2962016-10-27 18:03:05 -070062const char* const kPartitionTypesToHide[] = {
63 "c12a7328-f81f-11d2-ba4b-00a0c93ec93b", // EFI system partition
64 "fe3a2a5d-4f32-41a7-b725-accc3285a309", // Chrome OS kernel
65 "3cb8e202-3b7e-47dd-8a3c-7ff2a13cfcec", // Chrome OS root filesystem
66 "cab6e88e-abf3-4102-a07a-d4bb9be3c1d3", // Chrome OS firmware
67 "2e0a753d-9e48-43b0-8337-b15192cb1b5e", // Chrome OS reserved
Ben Chan1c2d4252011-06-03 13:33:49 -070068};
69
Ben Chan54342622011-08-18 00:57:11 -070070} // namespace
71
Ben Chande0e3f62017-09-26 06:28:39 -070072UdevDevice::UdevDevice(udev_device* dev) : dev_(dev), blkid_cache_(nullptr) {
Ben Chance7ee542011-04-12 17:02:49 -070073 CHECK(dev_) << "Invalid udev device";
74 udev_device_ref(dev_);
75}
76
77UdevDevice::~UdevDevice() {
Ben Chanda410a02011-08-24 23:37:53 -070078 if (blkid_cache_) {
79 // It needs to call blkid_put_cache to deallocate the blkid cache.
80 blkid_put_cache(blkid_cache_);
81 }
Ben Chance7ee542011-04-12 17:02:49 -070082 udev_device_unref(dev_);
83}
84
Ben Chan1f418382013-06-17 23:33:28 -070085// static
Ben Chan213c6d92019-04-10 16:21:52 -070086std::string UdevDevice::EnsureUTF8String(const std::string& str) {
Ben Chanaf25ddb2014-05-21 18:32:47 -070087 return base::IsStringUTF8(str) ? str : "";
Ben Chan22c0e602012-02-13 12:37:34 -080088}
89
Ben Chan1f418382013-06-17 23:33:28 -070090// static
Ben Chande0e3f62017-09-26 06:28:39 -070091bool UdevDevice::IsValueBooleanTrue(const char* value) {
Ben Chance7ee542011-04-12 17:02:49 -070092 return value && strcmp(value, "1") == 0;
93}
94
Ben Chan213c6d92019-04-10 16:21:52 -070095std::string UdevDevice::GetAttribute(const char* key) const {
Ben Chande0e3f62017-09-26 06:28:39 -070096 const char* value = udev_device_get_sysattr_value(dev_, key);
Ben Chance7ee542011-04-12 17:02:49 -070097 return (value) ? value : "";
98}
99
Ben Chande0e3f62017-09-26 06:28:39 -0700100bool UdevDevice::IsAttributeTrue(const char* key) const {
101 const char* value = udev_device_get_sysattr_value(dev_, key);
Ben Chance7ee542011-04-12 17:02:49 -0700102 return IsValueBooleanTrue(value);
103}
104
Ben Chande0e3f62017-09-26 06:28:39 -0700105bool UdevDevice::HasAttribute(const char* key) const {
106 const char* value = udev_device_get_sysattr_value(dev_, key);
Ben Chan44e7ea62014-08-29 18:13:37 -0700107 return value != nullptr;
Ben Chance7ee542011-04-12 17:02:49 -0700108}
109
Ben Chan213c6d92019-04-10 16:21:52 -0700110std::string UdevDevice::GetProperty(const char* key) const {
Ben Chande0e3f62017-09-26 06:28:39 -0700111 const char* value = udev_device_get_property_value(dev_, key);
Ben Chance7ee542011-04-12 17:02:49 -0700112 return (value) ? value : "";
113}
114
Ben Chande0e3f62017-09-26 06:28:39 -0700115bool UdevDevice::IsPropertyTrue(const char* key) const {
116 const char* value = udev_device_get_property_value(dev_, key);
Ben Chance7ee542011-04-12 17:02:49 -0700117 return IsValueBooleanTrue(value);
118}
119
Ben Chande0e3f62017-09-26 06:28:39 -0700120bool UdevDevice::HasProperty(const char* key) const {
121 const char* value = udev_device_get_property_value(dev_, key);
Ben Chan44e7ea62014-08-29 18:13:37 -0700122 return value != nullptr;
Ben Chance7ee542011-04-12 17:02:49 -0700123}
124
Ben Chan213c6d92019-04-10 16:21:52 -0700125std::string UdevDevice::GetPropertyFromBlkId(const char* key) {
126 std::string value;
Ben Chande0e3f62017-09-26 06:28:39 -0700127 const char* dev_file = udev_device_get_devnode(dev_);
Ben Chanda410a02011-08-24 23:37:53 -0700128 if (dev_file) {
129 // No cache file is used as it should always query information from
130 // the device, i.e. setting cache file to /dev/null.
131 if (blkid_cache_ || blkid_get_cache(&blkid_cache_, kNullDeviceFile) == 0) {
132 blkid_dev dev = blkid_get_dev(blkid_cache_, dev_file, BLKID_DEV_NORMAL);
133 if (dev) {
Ben Chande0e3f62017-09-26 06:28:39 -0700134 char* tag_value = blkid_get_tag_value(blkid_cache_, key, dev_file);
Ben Chanda410a02011-08-24 23:37:53 -0700135 if (tag_value) {
136 value = tag_value;
137 free(tag_value);
138 }
139 }
140 }
141 }
142 return value;
143}
144
Ben Chande0e3f62017-09-26 06:28:39 -0700145void UdevDevice::GetSizeInfo(uint64_t* total_size,
146 uint64_t* remaining_size) const {
Ben Chanf51ff002011-04-25 12:41:57 -0700147 static const int kSectorSize = 512;
Ben Chana169b0a2014-08-06 17:22:40 -0700148 uint64_t total = 0, remaining = 0;
Ben Chance7ee542011-04-12 17:02:49 -0700149
Ben Chanf51ff002011-04-25 12:41:57 -0700150 // If the device is mounted, obtain the total and remaining size in bytes
151 // using statvfs.
Ben Chan213c6d92019-04-10 16:21:52 -0700152 std::vector<std::string> mount_paths = GetMountPaths();
Ben Chanf51ff002011-04-25 12:41:57 -0700153 if (!mount_paths.empty()) {
154 struct statvfs stat;
155 if (statvfs(mount_paths[0].c_str(), &stat) == 0) {
156 total = stat.f_blocks * stat.f_frsize;
157 remaining = stat.f_bfree * stat.f_frsize;
Ben Chance7ee542011-04-12 17:02:49 -0700158 }
159 }
160
Ben Chanf51ff002011-04-25 12:41:57 -0700161 // If the UDISKS_PARTITION_SIZE property is set, use it as the total size
162 // instead. If the UDISKS_PARTITION_SIZE property is not set but sysfs
163 // provides a size value, which is the actual size in bytes divided by 512,
164 // use that as the total size instead.
Ben Chande0e3f62017-09-26 06:28:39 -0700165 const char* partition_size =
Ben Chan54342622011-08-18 00:57:11 -0700166 udev_device_get_property_value(dev_, kPropertyPartitionSize);
Ben Chana169b0a2014-08-06 17:22:40 -0700167 int64_t size = 0;
Ben Chanf51ff002011-04-25 12:41:57 -0700168 if (partition_size) {
169 base::StringToInt64(partition_size, &size);
170 total = size;
171 } else {
Ben Chande0e3f62017-09-26 06:28:39 -0700172 const char* size_attr = udev_device_get_sysattr_value(dev_, kAttributeSize);
Ben Chanf51ff002011-04-25 12:41:57 -0700173 if (size_attr) {
174 base::StringToInt64(size_attr, &size);
175 total = size * kSectorSize;
176 }
177 }
178
179 if (total_size)
180 *total_size = total;
Ben Chance7ee542011-04-12 17:02:49 -0700181 if (remaining_size)
Ben Chanf51ff002011-04-25 12:41:57 -0700182 *remaining_size = remaining;
Ben Chance7ee542011-04-12 17:02:49 -0700183}
184
Ben Chan53e12a22014-02-13 23:34:09 -0800185size_t UdevDevice::GetPartitionCount() const {
Ben Chanca369942011-09-10 17:03:05 -0700186 size_t partition_count = 0;
Ben Chande0e3f62017-09-26 06:28:39 -0700187 const char* dev_file = udev_device_get_devnode(dev_);
Ben Chanca369942011-09-10 17:03:05 -0700188 if (dev_file) {
Ben Chan53e12a22014-02-13 23:34:09 -0800189 blkid_probe probe = blkid_new_probe_from_filename(dev_file);
190 if (probe) {
191 blkid_partlist partitions = blkid_probe_get_partitions(probe);
192 if (partitions) {
193 partition_count = blkid_partlist_numof_partitions(partitions);
Ben Chanca369942011-09-10 17:03:05 -0700194 }
Ben Chan53e12a22014-02-13 23:34:09 -0800195 blkid_free_probe(probe);
Ben Chanca369942011-09-10 17:03:05 -0700196 }
197 }
198 return partition_count;
199}
200
Ben Chan0a389a62011-10-03 15:02:34 -0700201DeviceMediaType UdevDevice::GetDeviceMediaType() const {
Ben Chan7d8f9f72012-05-02 10:02:20 -0700202 if (IsPropertyTrue(kPropertyCDROMDVD))
203 return DEVICE_MEDIA_DVD;
204
Ben Chan0a389a62011-10-03 15:02:34 -0700205 if (IsPropertyTrue(kPropertyCDROM))
Ben Chan6d0b2722011-11-18 08:24:14 -0800206 return DEVICE_MEDIA_OPTICAL_DISC;
Ben Chan0a389a62011-10-03 15:02:34 -0700207
Ben Chan5540d902018-07-25 14:52:58 -0700208 if (IsOnSdDevice())
Ben Chan58aad1d2013-02-26 16:09:34 -0800209 return DEVICE_MEDIA_SD;
210
Ben Chan213c6d92019-04-10 16:21:52 -0700211 std::string vendor_id, product_id;
Ben Chan120c11c2012-09-10 23:10:18 -0700212 if (GetVendorAndProductId(&vendor_id, &product_id)) {
213 USBDeviceInfo info;
214 info.RetrieveFromFile(kUSBDeviceInfoFile);
215 return info.GetDeviceMediaType(vendor_id, product_id);
216 }
217 return DEVICE_MEDIA_UNKNOWN;
218}
219
Ben Chan213c6d92019-04-10 16:21:52 -0700220bool UdevDevice::GetVendorAndProductId(std::string* vendor_id,
221 std::string* product_id) const {
Ben Chan0a389a62011-10-03 15:02:34 -0700222 // Search up the parent device tree to obtain the vendor and product ID
223 // of the first device with a device type "usb_device". Then look up the
224 // media type based on the vendor and product ID from a USB device info file.
Ben Chande0e3f62017-09-26 06:28:39 -0700225 for (udev_device* dev = dev_; dev; dev = udev_device_get_parent(dev)) {
226 const char* device_type =
Ben Chan0a389a62011-10-03 15:02:34 -0700227 udev_device_get_property_value(dev, kPropertyDeviceType);
228 if (device_type && strcmp(device_type, kPropertyDeviceTypeUSBDevice) == 0) {
Ben Chande0e3f62017-09-26 06:28:39 -0700229 const char* vendor_id_attr =
Ben Chan0a389a62011-10-03 15:02:34 -0700230 udev_device_get_sysattr_value(dev, kAttributeIdVendor);
Ben Chande0e3f62017-09-26 06:28:39 -0700231 const char* product_id_attr =
Ben Chan0a389a62011-10-03 15:02:34 -0700232 udev_device_get_sysattr_value(dev, kAttributeIdProduct);
Ben Chan120c11c2012-09-10 23:10:18 -0700233 if (vendor_id_attr && product_id_attr) {
234 *vendor_id = vendor_id_attr;
235 *product_id = product_id_attr;
236 return true;
Ben Chan0a389a62011-10-03 15:02:34 -0700237 }
238 }
239 }
Ben Chan120c11c2012-09-10 23:10:18 -0700240 return false;
Ben Chan0a389a62011-10-03 15:02:34 -0700241}
242
Ben Chance7ee542011-04-12 17:02:49 -0700243bool UdevDevice::IsMediaAvailable() const {
244 bool is_media_available = true;
Ben Chan54342622011-08-18 00:57:11 -0700245 if (IsAttributeTrue(kAttributeRemovable)) {
246 if (IsPropertyTrue(kPropertyCDROM)) {
247 is_media_available = IsPropertyTrue(kPropertyCDROMMedia);
Ben Chance7ee542011-04-12 17:02:49 -0700248 } else {
Ben Chande0e3f62017-09-26 06:28:39 -0700249 const char* dev_file = udev_device_get_devnode(dev_);
Ben Chanf51ff002011-04-25 12:41:57 -0700250 if (dev_file) {
251 int fd = open(dev_file, O_RDONLY);
252 if (fd < 0) {
253 is_media_available = false;
254 } else {
255 close(fd);
256 }
Ben Chance7ee542011-04-12 17:02:49 -0700257 }
258 }
259 }
260 return is_media_available;
261}
262
Ben Chan1f418382013-06-17 23:33:28 -0700263bool UdevDevice::IsMobileBroadbandDevice() const {
264 // Check if a parent device, which belongs to the "usb" subsystem and has a
265 // device type "usb_device", has a property "MIST_SUPPORTED_DEVICE=1". If so,
266 // it is a mobile broadband device supported by mist.
Ben Chande0e3f62017-09-26 06:28:39 -0700267 udev_device* parent = udev_device_get_parent_with_subsystem_devtype(
Ben Chan1f418382013-06-17 23:33:28 -0700268 dev_, kSubsystemUsb, kPropertyDeviceTypeUSBDevice);
269 if (!parent)
270 return false;
271
272 const char* value =
273 udev_device_get_property_value(parent, kPropertyMistSupportedDevice);
274 return IsValueBooleanTrue(value);
275}
276
Ben Chan0255db62011-09-19 12:14:28 -0700277bool UdevDevice::IsAutoMountable() const {
Ben Chan9b425702011-09-07 10:57:09 -0700278 // TODO(benchan): Find a reliable way to detect if a device is a removable
279 // storage as the removable attribute in sysfs does not always tell the truth.
Ben Chana4b96512012-04-10 17:37:42 -0700280 return !IsOnBootDevice() && !IsVirtual();
Ben Chan0255db62011-09-19 12:14:28 -0700281}
Ben Chanf8692882011-08-21 10:15:30 -0700282
Ben Chan0255db62011-09-19 12:14:28 -0700283bool UdevDevice::IsHidden() {
284 if (IsPropertyTrue(kPropertyPresentationHide))
285 return true;
286
Ben Chana0fe0ef2012-09-06 23:39:56 -0700287 // Hide an optical disc without any data track.
288 // udev/cdrom_id only sets ID_CDROM_MEDIA_TRACK_COUNT_DATA when there is at
289 // least one data track.
290 if (IsPropertyTrue(kPropertyCDROM) &&
291 !HasProperty(kPropertyCDROMMediaTrackCountData)) {
292 return true;
293 }
294
Ben Chan1f418382013-06-17 23:33:28 -0700295 // Hide a mobile broadband device, which may initially expose itself as a USB
296 // mass storage device and later be switched to a modem by mist.
297 if (IsMobileBroadbandDevice())
298 return true;
299
Ben Chan0255db62011-09-19 12:14:28 -0700300 // Hide a device that is neither marked as a partition nor a filesystem,
Ben Chanca369942011-09-10 17:03:05 -0700301 // unless it has no valid partitions (e.g. the device is unformatted or
Ben Chan0255db62011-09-19 12:14:28 -0700302 // corrupted). An unformatted or corrupted device is visible in the file
303 // the file browser so that we can provide a way to format it.
Ben Chanf8692882011-08-21 10:15:30 -0700304 if (!HasAttribute(kAttributePartition) &&
Ben Chande0e3f62017-09-26 06:28:39 -0700305 !HasProperty(kPropertyFilesystemUsage) && (GetPartitionCount() > 0))
Ben Chan0255db62011-09-19 12:14:28 -0700306 return true;
Ben Chan1c2d4252011-06-03 13:33:49 -0700307
Ben Chancac20332014-02-13 23:21:17 -0800308 // Hide special partitions based on partition type.
Ben Chan213c6d92019-04-10 16:21:52 -0700309 std::string partition_type = GetProperty(kPropertyPartitionEntryType);
Ben Chancac20332014-02-13 23:21:17 -0800310 if (!partition_type.empty()) {
Ben Chan6057fe62016-12-02 10:08:59 -0800311 for (const char* partition_type_to_hide : kPartitionTypesToHide) {
312 if (partition_type == partition_type_to_hide)
Ben Chan0255db62011-09-19 12:14:28 -0700313 return true;
Ben Chan1c2d4252011-06-03 13:33:49 -0700314 }
315 }
Ben Chan0255db62011-09-19 12:14:28 -0700316 return false;
Ben Chan1c2d4252011-06-03 13:33:49 -0700317}
318
Ben Chan2923ed72013-07-29 15:52:29 -0700319bool UdevDevice::IsIgnored() const {
320 return IsVirtual() && !IsLoopDevice();
321}
322
Ben Chan490319f2011-05-06 14:00:42 -0700323bool UdevDevice::IsOnBootDevice() const {
324 // Obtain the boot device path, e.g. /dev/sda
325 char boot_device_path[PATH_MAX];
326 if (rootdev(boot_device_path, sizeof(boot_device_path), true, true)) {
327 LOG(ERROR) << "Could not determine root device";
328 // Assume it is on the boot device when there is any uncertainty.
329 // This is to prevent a device, which is potentially on the boot device,
330 // from being auto mounted and exposed to users.
331 // TODO(benchan): Find a way to eliminate the uncertainty.
332 return true;
333 }
334
335 // Compare the device file path of the current device and all its parents
336 // with the boot device path. Any match indicates that the current device
337 // is on the boot device.
Ben Chande0e3f62017-09-26 06:28:39 -0700338 for (udev_device* dev = dev_; dev; dev = udev_device_get_parent(dev)) {
339 const char* dev_file = udev_device_get_devnode(dev);
Ben Chan490319f2011-05-06 14:00:42 -0700340 if (dev_file) {
341 if (strncmp(boot_device_path, dev_file, PATH_MAX) == 0) {
342 return true;
343 }
344 }
345 }
346 return false;
347}
348
Ben Chan5540d902018-07-25 14:52:58 -0700349bool UdevDevice::IsOnSdDevice() const {
Ben Chande0e3f62017-09-26 06:28:39 -0700350 for (udev_device* dev = dev_; dev; dev = udev_device_get_parent(dev)) {
Ben Chan5540d902018-07-25 14:52:58 -0700351 const char* mmc_type =
352 udev_device_get_property_value(dev, kPropertyMmcType);
353 if (mmc_type && strcmp(mmc_type, kPropertyMmcTypeSd) == 0) {
Ben Chan58aad1d2013-02-26 16:09:34 -0800354 return true;
355 }
356 }
357 return false;
358}
359
Ben Chan54342622011-08-18 00:57:11 -0700360bool UdevDevice::IsOnRemovableDevice() const {
Ben Chande0e3f62017-09-26 06:28:39 -0700361 for (udev_device* dev = dev_; dev; dev = udev_device_get_parent(dev)) {
362 const char* value = udev_device_get_sysattr_value(dev, kAttributeRemovable);
Ben Chan54342622011-08-18 00:57:11 -0700363 if (IsValueBooleanTrue(value))
364 return true;
365 }
366 return false;
367}
368
Ben Chan9cda93a2011-05-24 13:31:04 -0700369bool UdevDevice::IsVirtual() const {
Ben Chande0e3f62017-09-26 06:28:39 -0700370 const char* sys_path = udev_device_get_syspath(dev_);
Ben Chan9cda93a2011-05-24 13:31:04 -0700371 if (sys_path) {
Alex Vakulenkoe50371c2016-01-20 16:06:19 -0800372 return base::StartsWith(sys_path, kVirtualDevicePathPrefix,
373 base::CompareCase::SENSITIVE);
Ben Chan9cda93a2011-05-24 13:31:04 -0700374 }
375 // To be safe, mark it as virtual device if sys path cannot be determined.
376 return true;
377}
378
Ben Chan2923ed72013-07-29 15:52:29 -0700379bool UdevDevice::IsLoopDevice() const {
Ben Chande0e3f62017-09-26 06:28:39 -0700380 const char* sys_path = udev_device_get_syspath(dev_);
Ben Chan2923ed72013-07-29 15:52:29 -0700381 if (sys_path) {
Alex Vakulenkoe50371c2016-01-20 16:06:19 -0800382 return base::StartsWith(sys_path, kLoopDevicePathPrefix,
383 base::CompareCase::SENSITIVE);
Ben Chan2923ed72013-07-29 15:52:29 -0700384 }
385 return false;
386}
387
Ben Chan213c6d92019-04-10 16:21:52 -0700388std::string UdevDevice::NativePath() const {
Ben Chande0e3f62017-09-26 06:28:39 -0700389 const char* sys_path = udev_device_get_syspath(dev_);
Ben Chan42888362011-06-09 18:16:24 -0700390 return sys_path ? sys_path : "";
391}
392
Austin Tankiang36f5bb52019-03-25 16:49:30 +1100393std::string UdevDevice::StorageDevicePath() const {
394 for (udev_device* dev = dev_; dev; dev = udev_device_get_parent(dev)) {
395 const char* subsystem = udev_device_get_subsystem(dev);
396 if (subsystem && (strcmp(subsystem, kSubsystemMmc) == 0 ||
397 strcmp(subsystem, kSubsystemNvme) == 0 ||
398 strcmp(subsystem, kSubsystemScsi) == 0)) {
399 return udev_device_get_syspath(dev);
400 }
401 }
402 return "";
403}
404
Ben Chan213c6d92019-04-10 16:21:52 -0700405std::vector<std::string> UdevDevice::GetMountPaths() const {
Ben Chande0e3f62017-09-26 06:28:39 -0700406 const char* device_path = udev_device_get_devnode(dev_);
Ben Chanf51ff002011-04-25 12:41:57 -0700407 if (device_path) {
408 return GetMountPaths(device_path);
Ben Chance7ee542011-04-12 17:02:49 -0700409 }
Ben Chan213c6d92019-04-10 16:21:52 -0700410 return std::vector<std::string>();
Ben Chance7ee542011-04-12 17:02:49 -0700411}
412
Ben Chan213c6d92019-04-10 16:21:52 -0700413std::vector<std::string> UdevDevice::GetMountPaths(
414 const std::string& device_path) {
Ben Chanbeefd0d2011-07-25 09:31:34 -0700415 MountInfo mount_info;
416 if (mount_info.RetrieveFromCurrentProcess()) {
417 return mount_info.GetMountPaths(device_path);
Ben Chanf51ff002011-04-25 12:41:57 -0700418 }
Ben Chan213c6d92019-04-10 16:21:52 -0700419 return std::vector<std::string>();
Ben Chanf51ff002011-04-25 12:41:57 -0700420}
421
Ben Chanda410a02011-08-24 23:37:53 -0700422Disk UdevDevice::ToDisk() {
Ben Chance7ee542011-04-12 17:02:49 -0700423 Disk disk;
424
Ben Chanff92fa32017-10-17 16:17:15 -0700425 disk.is_auto_mountable = IsAutoMountable();
426 disk.is_read_only = IsAttributeTrue(kAttributeReadOnly);
427 disk.is_drive = HasAttribute(kAttributeRange);
428 disk.is_rotational = HasProperty(kPropertyRotationRate);
429 disk.is_hidden = IsHidden();
430 disk.is_media_available = IsMediaAvailable();
431 disk.is_on_boot_device = IsOnBootDevice();
432 disk.is_on_removable_device = IsOnRemovableDevice();
433 disk.is_virtual = IsVirtual();
434 disk.media_type = GetDeviceMediaType();
435 disk.filesystem_type = GetPropertyFromBlkId(kPropertyBlkIdFilesystemType);
436 disk.native_path = NativePath();
Austin Tankiang36f5bb52019-03-25 16:49:30 +1100437 disk.storage_device_path = StorageDevicePath();
Ben Chance7ee542011-04-12 17:02:49 -0700438
Ben Chan22c0e602012-02-13 12:37:34 -0800439 // Drive model and filesystem label may not be UTF-8 encoded, so we
440 // need to ensure that they are either set to a valid UTF-8 string or
441 // an empty string before later passed to a DBus message iterator.
Ben Chanff92fa32017-10-17 16:17:15 -0700442 disk.drive_model = EnsureUTF8String(GetProperty(kPropertyModel));
443 disk.label =
444 EnsureUTF8String(GetPropertyFromBlkId(kPropertyBlkIdFilesystemLabel));
Ben Chan22c0e602012-02-13 12:37:34 -0800445
Ben Chanff92fa32017-10-17 16:17:15 -0700446 if (GetVendorAndProductId(&disk.vendor_id, &disk.product_id)) {
Ben Chan120c11c2012-09-10 23:10:18 -0700447 USBDeviceInfo info;
Ben Chanff92fa32017-10-17 16:17:15 -0700448 info.GetVendorAndProductName(kUSBIdentifierDatabase, disk.vendor_id,
449 disk.product_id, &disk.vendor_name,
450 &disk.product_name);
Ben Chan120c11c2012-09-10 23:10:18 -0700451 }
452
Ben Chan0e1b5502013-07-24 23:39:29 -0700453 // TODO(benchan): Add a proper unit test when fixing crbug.com/221380.
Ben Chan213c6d92019-04-10 16:21:52 -0700454 std::string uuid_hash = base::SHA1HashString(
Ben Chanff92fa32017-10-17 16:17:15 -0700455 disk.vendor_id + disk.product_id + GetProperty(kPropertySerial) +
Ben Chan0e1b5502013-07-24 23:39:29 -0700456 GetPropertyFromBlkId(kPropertyBlkIdFilesystemUUID));
Ben Chanff92fa32017-10-17 16:17:15 -0700457 disk.uuid = base::HexEncode(uuid_hash.data(), uuid_hash.size());
Ben Chan0e1b5502013-07-24 23:39:29 -0700458
Ben Chande0e3f62017-09-26 06:28:39 -0700459 const char* dev_file = udev_device_get_devnode(dev_);
Ben Chanf51ff002011-04-25 12:41:57 -0700460 if (dev_file)
Ben Chanff92fa32017-10-17 16:17:15 -0700461 disk.device_file = dev_file;
Ben Chance7ee542011-04-12 17:02:49 -0700462
Ben Chanff92fa32017-10-17 16:17:15 -0700463 disk.mount_paths = GetMountPaths();
Ben Chance7ee542011-04-12 17:02:49 -0700464
Ben Chanff92fa32017-10-17 16:17:15 -0700465 GetSizeInfo(&disk.device_capacity, &disk.bytes_remaining);
Ben Chance7ee542011-04-12 17:02:49 -0700466
467 return disk;
468}
469
470} // namespace cros_disks