Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 1 | // 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 Chan | 5ccd9fe | 2013-11-13 18:28:27 -0800 | [diff] [blame] | 5 | #include "cros-disks/udev_device.h" |
Ben Chan | beefd0d | 2011-07-25 09:31:34 -0700 | [diff] [blame] | 6 | |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 7 | #include <fcntl.h> |
Alex Vakulenko | e50371c | 2016-01-20 16:06:19 -0800 | [diff] [blame] | 8 | #include <linux/limits.h> |
Ben Chan | da410a0 | 2011-08-24 23:37:53 -0700 | [diff] [blame] | 9 | #include <stdlib.h> |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 10 | #include <sys/statvfs.h> |
Ben Chan | bdc3974 | 2011-05-11 17:51:26 -0700 | [diff] [blame] | 11 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 12 | #include <utility> |
| 13 | |
| 14 | #include <base/bind.h> |
Qijiang Fan | 713061e | 2021-03-08 15:45:12 +0900 | [diff] [blame] | 15 | #include <base/check.h> |
hscham | 9d83534 | 2020-04-16 15:23:37 +0900 | [diff] [blame] | 16 | #include <base/hash/sha1.h> |
Chris Masone | ec4761f | 2011-05-12 14:04:13 -0700 | [diff] [blame] | 17 | #include <base/logging.h> |
Ben Chan | 97e20d4 | 2014-02-05 18:38:07 -0800 | [diff] [blame] | 18 | #include <base/strings/string_number_conversions.h> |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 19 | #include <base/strings/string_piece.h> |
Ben Chan | 97e20d4 | 2014-02-05 18:38:07 -0800 | [diff] [blame] | 20 | #include <base/strings/string_split.h> |
| 21 | #include <base/strings/string_util.h> |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 22 | #include <brillo/udev/udev_device.h> |
Ben Chan | bdc3974 | 2011-05-11 17:51:26 -0700 | [diff] [blame] | 23 | #include <rootdev/rootdev.h> |
| 24 | |
Ben Chan | 5ccd9fe | 2013-11-13 18:28:27 -0800 | [diff] [blame] | 25 | #include "cros-disks/mount_info.h" |
| 26 | #include "cros-disks/usb_device_info.h" |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 27 | |
Anand K Mistry | 40cff45 | 2019-07-30 10:24:48 +1000 | [diff] [blame] | 28 | namespace cros_disks { |
Ben Chan | 5434262 | 2011-08-18 00:57:11 -0700 | [diff] [blame] | 29 | namespace { |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 30 | |
Ben Chan | 460439f | 2011-09-13 09:16:28 -0700 | [diff] [blame] | 31 | const char kNullDeviceFile[] = "/dev/null"; |
Timothy Loh | d813344 | 2020-11-03 16:21:07 +1100 | [diff] [blame] | 32 | const char kAttributeBusNum[] = "busnum"; |
| 33 | const char kAttributeDevNum[] = "devnum"; |
Ben Chan | 0a389a6 | 2011-10-03 15:02:34 -0700 | [diff] [blame] | 34 | const char kAttributeIdProduct[] = "idProduct"; |
| 35 | const char kAttributeIdVendor[] = "idVendor"; |
Ben Chan | 460439f | 2011-09-13 09:16:28 -0700 | [diff] [blame] | 36 | const char kAttributePartition[] = "partition"; |
| 37 | const char kAttributeRange[] = "range"; |
| 38 | const char kAttributeReadOnly[] = "ro"; |
| 39 | const char kAttributeRemovable[] = "removable"; |
| 40 | const char kAttributeSize[] = "size"; |
| 41 | const char kPropertyBlkIdFilesystemType[] = "TYPE"; |
| 42 | const char kPropertyBlkIdFilesystemLabel[] = "LABEL"; |
| 43 | const char kPropertyBlkIdFilesystemUUID[] = "UUID"; |
| 44 | const char kPropertyCDROM[] = "ID_CDROM"; |
Ben Chan | 7d8f9f7 | 2012-05-02 10:02:20 -0700 | [diff] [blame] | 45 | const char kPropertyCDROMDVD[] = "ID_CDROM_DVD"; |
Ben Chan | 460439f | 2011-09-13 09:16:28 -0700 | [diff] [blame] | 46 | const char kPropertyCDROMMedia[] = "ID_CDROM_MEDIA"; |
Ben Chan | a0fe0ef | 2012-09-06 23:39:56 -0700 | [diff] [blame] | 47 | const char kPropertyCDROMMediaTrackCountData[] = |
| 48 | "ID_CDROM_MEDIA_TRACK_COUNT_DATA"; |
Ben Chan | 0a389a6 | 2011-10-03 15:02:34 -0700 | [diff] [blame] | 49 | const char kPropertyDeviceType[] = "DEVTYPE"; |
| 50 | const char kPropertyDeviceTypeUSBDevice[] = "usb_device"; |
Ben Chan | 460439f | 2011-09-13 09:16:28 -0700 | [diff] [blame] | 51 | const char kPropertyFilesystemUsage[] = "ID_FS_USAGE"; |
Ben Chan | 1f41838 | 2013-06-17 23:33:28 -0700 | [diff] [blame] | 52 | const char kPropertyMistSupportedDevice[] = "MIST_SUPPORTED_DEVICE"; |
Ben Chan | 5540d90 | 2018-07-25 14:52:58 -0700 | [diff] [blame] | 53 | const char kPropertyMmcType[] = "MMC_TYPE"; |
| 54 | const char kPropertyMmcTypeSd[] = "SD"; |
Ben Chan | 460439f | 2011-09-13 09:16:28 -0700 | [diff] [blame] | 55 | const char kPropertyModel[] = "ID_MODEL"; |
Ben Chan | cac2033 | 2014-02-13 23:21:17 -0800 | [diff] [blame] | 56 | const char kPropertyPartitionEntryType[] = "ID_PART_ENTRY_TYPE"; |
Ben Chan | 460439f | 2011-09-13 09:16:28 -0700 | [diff] [blame] | 57 | const char kPropertyPartitionSize[] = "UDISKS_PARTITION_SIZE"; |
| 58 | const char kPropertyPresentationHide[] = "UDISKS_PRESENTATION_HIDE"; |
| 59 | const char kPropertyRotationRate[] = "ID_ATA_ROTATION_RATE_RPM"; |
Ben Chan | 0e1b550 | 2013-07-24 23:39:29 -0700 | [diff] [blame] | 60 | const char kPropertySerial[] = "ID_SERIAL"; |
Ben Chan | 1f41838 | 2013-06-17 23:33:28 -0700 | [diff] [blame] | 61 | const char kSubsystemUsb[] = "usb"; |
Austin Tankiang | 36f5bb5 | 2019-03-25 16:49:30 +1100 | [diff] [blame] | 62 | const char kSubsystemMmc[] = "mmc"; |
| 63 | const char kSubsystemNvme[] = "nvme"; |
| 64 | const char kSubsystemScsi[] = "scsi"; |
Ben Chan | 460439f | 2011-09-13 09:16:28 -0700 | [diff] [blame] | 65 | const char kVirtualDevicePathPrefix[] = "/sys/devices/virtual/"; |
Ben Chan | 2923ed7 | 2013-07-29 15:52:29 -0700 | [diff] [blame] | 66 | const char kLoopDevicePathPrefix[] = "/sys/devices/virtual/block/loop"; |
Ben Chan | ccde512 | 2018-09-25 17:46:07 -0700 | [diff] [blame] | 67 | const char kUSBDeviceInfoFile[] = "/usr/share/cros-disks/usb-device-info"; |
Ben Chan | 120c11c | 2012-09-10 23:10:18 -0700 | [diff] [blame] | 68 | const char kUSBIdentifierDatabase[] = "/usr/share/misc/usb.ids"; |
Ben Chan | c79c296 | 2016-10-27 18:03:05 -0700 | [diff] [blame] | 69 | const char* const kPartitionTypesToHide[] = { |
| 70 | "c12a7328-f81f-11d2-ba4b-00a0c93ec93b", // EFI system partition |
| 71 | "fe3a2a5d-4f32-41a7-b725-accc3285a309", // Chrome OS kernel |
| 72 | "3cb8e202-3b7e-47dd-8a3c-7ff2a13cfcec", // Chrome OS root filesystem |
| 73 | "cab6e88e-abf3-4102-a07a-d4bb9be3c1d3", // Chrome OS firmware |
| 74 | "2e0a753d-9e48-43b0-8337-b15192cb1b5e", // Chrome OS reserved |
Ben Chan | 1c2d425 | 2011-06-03 13:33:49 -0700 | [diff] [blame] | 75 | }; |
| 76 | |
Ben Chan | 5434262 | 2011-08-18 00:57:11 -0700 | [diff] [blame] | 77 | } // namespace |
| 78 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 79 | UdevDevice::UdevDevice(std::unique_ptr<brillo::UdevDevice> dev) |
| 80 | : dev_(std::move(dev)), blkid_cache_(nullptr) { |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 81 | CHECK(dev_) << "Invalid udev device"; |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 82 | } |
| 83 | |
| 84 | UdevDevice::~UdevDevice() { |
Ben Chan | da410a0 | 2011-08-24 23:37:53 -0700 | [diff] [blame] | 85 | if (blkid_cache_) { |
| 86 | // It needs to call blkid_put_cache to deallocate the blkid cache. |
| 87 | blkid_put_cache(blkid_cache_); |
| 88 | } |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 89 | } |
| 90 | |
Ben Chan | 1f41838 | 2013-06-17 23:33:28 -0700 | [diff] [blame] | 91 | // static |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 92 | std::string UdevDevice::EnsureUTF8String(const std::string& str) { |
Ben Chan | af25ddb | 2014-05-21 18:32:47 -0700 | [diff] [blame] | 93 | return base::IsStringUTF8(str) ? str : ""; |
Ben Chan | 22c0e60 | 2012-02-13 12:37:34 -0800 | [diff] [blame] | 94 | } |
| 95 | |
Ben Chan | 1f41838 | 2013-06-17 23:33:28 -0700 | [diff] [blame] | 96 | // static |
Ben Chan | de0e3f6 | 2017-09-26 06:28:39 -0700 | [diff] [blame] | 97 | bool UdevDevice::IsValueBooleanTrue(const char* value) { |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 98 | return value && strcmp(value, "1") == 0; |
| 99 | } |
| 100 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 101 | std::string UdevDevice::GetAttribute(const char* key) const { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 102 | const char* value = dev_->GetSysAttributeValue(key); |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 103 | return (value) ? value : ""; |
| 104 | } |
| 105 | |
Ben Chan | de0e3f6 | 2017-09-26 06:28:39 -0700 | [diff] [blame] | 106 | bool UdevDevice::IsAttributeTrue(const char* key) const { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 107 | const char* value = dev_->GetSysAttributeValue(key); |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 108 | return IsValueBooleanTrue(value); |
| 109 | } |
| 110 | |
Ben Chan | de0e3f6 | 2017-09-26 06:28:39 -0700 | [diff] [blame] | 111 | bool UdevDevice::HasAttribute(const char* key) const { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 112 | const char* value = dev_->GetSysAttributeValue(key); |
Ben Chan | 44e7ea6 | 2014-08-29 18:13:37 -0700 | [diff] [blame] | 113 | return value != nullptr; |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 114 | } |
| 115 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 116 | std::string UdevDevice::GetProperty(const char* key) const { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 117 | const char* value = dev_->GetPropertyValue(key); |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 118 | return (value) ? value : ""; |
| 119 | } |
| 120 | |
Ben Chan | de0e3f6 | 2017-09-26 06:28:39 -0700 | [diff] [blame] | 121 | bool UdevDevice::IsPropertyTrue(const char* key) const { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 122 | const char* value = dev_->GetPropertyValue(key); |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 123 | return IsValueBooleanTrue(value); |
| 124 | } |
| 125 | |
Ben Chan | de0e3f6 | 2017-09-26 06:28:39 -0700 | [diff] [blame] | 126 | bool UdevDevice::HasProperty(const char* key) const { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 127 | const char* value = dev_->GetPropertyValue(key); |
Ben Chan | 44e7ea6 | 2014-08-29 18:13:37 -0700 | [diff] [blame] | 128 | return value != nullptr; |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 129 | } |
| 130 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 131 | std::string UdevDevice::GetPropertyFromBlkId(const char* key) { |
| 132 | std::string value; |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 133 | const char* dev_file = dev_->GetDeviceNode(); |
Ben Chan | da410a0 | 2011-08-24 23:37:53 -0700 | [diff] [blame] | 134 | if (dev_file) { |
| 135 | // No cache file is used as it should always query information from |
| 136 | // the device, i.e. setting cache file to /dev/null. |
| 137 | if (blkid_cache_ || blkid_get_cache(&blkid_cache_, kNullDeviceFile) == 0) { |
| 138 | blkid_dev dev = blkid_get_dev(blkid_cache_, dev_file, BLKID_DEV_NORMAL); |
| 139 | if (dev) { |
Ben Chan | de0e3f6 | 2017-09-26 06:28:39 -0700 | [diff] [blame] | 140 | char* tag_value = blkid_get_tag_value(blkid_cache_, key, dev_file); |
Ben Chan | da410a0 | 2011-08-24 23:37:53 -0700 | [diff] [blame] | 141 | if (tag_value) { |
| 142 | value = tag_value; |
| 143 | free(tag_value); |
| 144 | } |
| 145 | } |
| 146 | } |
| 147 | } |
| 148 | return value; |
| 149 | } |
| 150 | |
Ben Chan | de0e3f6 | 2017-09-26 06:28:39 -0700 | [diff] [blame] | 151 | void UdevDevice::GetSizeInfo(uint64_t* total_size, |
| 152 | uint64_t* remaining_size) const { |
Ben Chan | f51ff00 | 2011-04-25 12:41:57 -0700 | [diff] [blame] | 153 | static const int kSectorSize = 512; |
Ben Chan | a169b0a | 2014-08-06 17:22:40 -0700 | [diff] [blame] | 154 | uint64_t total = 0, remaining = 0; |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 155 | |
Ben Chan | f51ff00 | 2011-04-25 12:41:57 -0700 | [diff] [blame] | 156 | // If the device is mounted, obtain the total and remaining size in bytes |
| 157 | // using statvfs. |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 158 | std::vector<std::string> mount_paths = GetMountPaths(); |
Ben Chan | f51ff00 | 2011-04-25 12:41:57 -0700 | [diff] [blame] | 159 | if (!mount_paths.empty()) { |
| 160 | struct statvfs stat; |
| 161 | if (statvfs(mount_paths[0].c_str(), &stat) == 0) { |
| 162 | total = stat.f_blocks * stat.f_frsize; |
| 163 | remaining = stat.f_bfree * stat.f_frsize; |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 164 | } |
| 165 | } |
| 166 | |
Ben Chan | f51ff00 | 2011-04-25 12:41:57 -0700 | [diff] [blame] | 167 | // If the UDISKS_PARTITION_SIZE property is set, use it as the total size |
| 168 | // instead. If the UDISKS_PARTITION_SIZE property is not set but sysfs |
| 169 | // provides a size value, which is the actual size in bytes divided by 512, |
| 170 | // use that as the total size instead. |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 171 | const std::string partition_size = GetProperty(kPropertyPartitionSize); |
Ben Chan | a169b0a | 2014-08-06 17:22:40 -0700 | [diff] [blame] | 172 | int64_t size = 0; |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 173 | if (!partition_size.empty()) { |
Ben Chan | f51ff00 | 2011-04-25 12:41:57 -0700 | [diff] [blame] | 174 | base::StringToInt64(partition_size, &size); |
| 175 | total = size; |
| 176 | } else { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 177 | const std::string size_attr = GetAttribute(kAttributeSize); |
| 178 | if (!size_attr.empty()) { |
Ben Chan | f51ff00 | 2011-04-25 12:41:57 -0700 | [diff] [blame] | 179 | base::StringToInt64(size_attr, &size); |
| 180 | total = size * kSectorSize; |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | if (total_size) |
| 185 | *total_size = total; |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 186 | if (remaining_size) |
Ben Chan | f51ff00 | 2011-04-25 12:41:57 -0700 | [diff] [blame] | 187 | *remaining_size = remaining; |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 188 | } |
| 189 | |
Ben Chan | 53e12a2 | 2014-02-13 23:34:09 -0800 | [diff] [blame] | 190 | size_t UdevDevice::GetPartitionCount() const { |
Ben Chan | ca36994 | 2011-09-10 17:03:05 -0700 | [diff] [blame] | 191 | size_t partition_count = 0; |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 192 | const char* dev_file = dev_->GetDeviceNode(); |
Ben Chan | ca36994 | 2011-09-10 17:03:05 -0700 | [diff] [blame] | 193 | if (dev_file) { |
Ben Chan | 53e12a2 | 2014-02-13 23:34:09 -0800 | [diff] [blame] | 194 | blkid_probe probe = blkid_new_probe_from_filename(dev_file); |
| 195 | if (probe) { |
| 196 | blkid_partlist partitions = blkid_probe_get_partitions(probe); |
| 197 | if (partitions) { |
| 198 | partition_count = blkid_partlist_numof_partitions(partitions); |
Ben Chan | ca36994 | 2011-09-10 17:03:05 -0700 | [diff] [blame] | 199 | } |
Ben Chan | 53e12a2 | 2014-02-13 23:34:09 -0800 | [diff] [blame] | 200 | blkid_free_probe(probe); |
Ben Chan | ca36994 | 2011-09-10 17:03:05 -0700 | [diff] [blame] | 201 | } |
| 202 | } |
| 203 | return partition_count; |
| 204 | } |
| 205 | |
Ben Chan | 0a389a6 | 2011-10-03 15:02:34 -0700 | [diff] [blame] | 206 | DeviceMediaType UdevDevice::GetDeviceMediaType() const { |
Ben Chan | 7d8f9f7 | 2012-05-02 10:02:20 -0700 | [diff] [blame] | 207 | if (IsPropertyTrue(kPropertyCDROMDVD)) |
| 208 | return DEVICE_MEDIA_DVD; |
| 209 | |
Ben Chan | 0a389a6 | 2011-10-03 15:02:34 -0700 | [diff] [blame] | 210 | if (IsPropertyTrue(kPropertyCDROM)) |
Ben Chan | 6d0b272 | 2011-11-18 08:24:14 -0800 | [diff] [blame] | 211 | return DEVICE_MEDIA_OPTICAL_DISC; |
Ben Chan | 0a389a6 | 2011-10-03 15:02:34 -0700 | [diff] [blame] | 212 | |
Ben Chan | 5540d90 | 2018-07-25 14:52:58 -0700 | [diff] [blame] | 213 | if (IsOnSdDevice()) |
Ben Chan | 58aad1d | 2013-02-26 16:09:34 -0800 | [diff] [blame] | 214 | return DEVICE_MEDIA_SD; |
| 215 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 216 | std::string vendor_id, product_id; |
Ben Chan | 120c11c | 2012-09-10 23:10:18 -0700 | [diff] [blame] | 217 | if (GetVendorAndProductId(&vendor_id, &product_id)) { |
| 218 | USBDeviceInfo info; |
| 219 | info.RetrieveFromFile(kUSBDeviceInfoFile); |
| 220 | return info.GetDeviceMediaType(vendor_id, product_id); |
| 221 | } |
| 222 | return DEVICE_MEDIA_UNKNOWN; |
| 223 | } |
| 224 | |
Anand K Mistry | c0ece3d | 2020-01-28 15:55:29 +1100 | [diff] [blame] | 225 | bool UdevDevice::EnumerateParentDevices(EnumerateCallback callback) const { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 226 | if (callback.Run(*dev_)) { |
| 227 | return true; |
| 228 | } |
| 229 | |
| 230 | for (auto parent = dev_->GetParent(); parent; parent = parent->GetParent()) { |
| 231 | if (callback.Run(*parent)) { |
| 232 | return true; |
| 233 | } |
| 234 | } |
| 235 | return false; |
| 236 | } |
| 237 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 238 | bool UdevDevice::GetVendorAndProductId(std::string* vendor_id, |
| 239 | std::string* product_id) const { |
Ben Chan | 0a389a6 | 2011-10-03 15:02:34 -0700 | [diff] [blame] | 240 | // Search up the parent device tree to obtain the vendor and product ID |
| 241 | // of the first device with a device type "usb_device". Then look up the |
| 242 | // media type based on the vendor and product ID from a USB device info file. |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 243 | return EnumerateParentDevices(base::BindRepeating( |
| 244 | [](std::string* vendor_id, std::string* product_id, |
| 245 | const brillo::UdevDevice& device) { |
| 246 | const char* device_type = device.GetPropertyValue(kPropertyDeviceType); |
| 247 | if (device_type && |
| 248 | strcmp(device_type, kPropertyDeviceTypeUSBDevice) == 0) { |
| 249 | const char* vendor_id_attr = |
| 250 | device.GetSysAttributeValue(kAttributeIdVendor); |
| 251 | const char* product_id_attr = |
| 252 | device.GetSysAttributeValue(kAttributeIdProduct); |
| 253 | if (vendor_id_attr && product_id_attr) { |
| 254 | *vendor_id = vendor_id_attr; |
| 255 | *product_id = product_id_attr; |
| 256 | return true; |
| 257 | } |
| 258 | } |
| 259 | return false; |
| 260 | }, |
| 261 | vendor_id, product_id)); |
Ben Chan | 0a389a6 | 2011-10-03 15:02:34 -0700 | [diff] [blame] | 262 | } |
| 263 | |
Timothy Loh | d813344 | 2020-11-03 16:21:07 +1100 | [diff] [blame] | 264 | void UdevDevice::GetBusAndDeviceNumber(int* bus_number, |
| 265 | int* device_number) const { |
| 266 | *bus_number = 0; |
| 267 | *device_number = 0; |
| 268 | EnumerateParentDevices(base::BindRepeating( |
| 269 | [](int* bus_number, int* device_number, |
| 270 | const brillo::UdevDevice& device) { |
| 271 | const char* bus_number_attr = |
| 272 | device.GetSysAttributeValue(kAttributeBusNum); |
| 273 | const char* device_number_attr = |
| 274 | device.GetSysAttributeValue(kAttributeDevNum); |
| 275 | if (bus_number_attr && device_number_attr) { |
| 276 | base::StringToInt(bus_number_attr, bus_number); |
| 277 | base::StringToInt(device_number_attr, device_number); |
| 278 | return true; |
| 279 | } |
| 280 | return false; |
| 281 | }, |
| 282 | bus_number, device_number)); |
| 283 | } |
| 284 | |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 285 | bool UdevDevice::IsMediaAvailable() const { |
| 286 | bool is_media_available = true; |
Ben Chan | 5434262 | 2011-08-18 00:57:11 -0700 | [diff] [blame] | 287 | if (IsAttributeTrue(kAttributeRemovable)) { |
| 288 | if (IsPropertyTrue(kPropertyCDROM)) { |
| 289 | is_media_available = IsPropertyTrue(kPropertyCDROMMedia); |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 290 | } else { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 291 | const char* dev_file = dev_->GetDeviceNode(); |
Ben Chan | f51ff00 | 2011-04-25 12:41:57 -0700 | [diff] [blame] | 292 | if (dev_file) { |
| 293 | int fd = open(dev_file, O_RDONLY); |
| 294 | if (fd < 0) { |
| 295 | is_media_available = false; |
| 296 | } else { |
| 297 | close(fd); |
| 298 | } |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 299 | } |
| 300 | } |
| 301 | } |
| 302 | return is_media_available; |
| 303 | } |
| 304 | |
Ben Chan | 1f41838 | 2013-06-17 23:33:28 -0700 | [diff] [blame] | 305 | bool UdevDevice::IsMobileBroadbandDevice() const { |
| 306 | // Check if a parent device, which belongs to the "usb" subsystem and has a |
| 307 | // device type "usb_device", has a property "MIST_SUPPORTED_DEVICE=1". If so, |
| 308 | // it is a mobile broadband device supported by mist. |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 309 | std::unique_ptr<brillo::UdevDevice> parent = |
| 310 | dev_->GetParentWithSubsystemDeviceType(kSubsystemUsb, |
| 311 | kPropertyDeviceTypeUSBDevice); |
Ben Chan | 1f41838 | 2013-06-17 23:33:28 -0700 | [diff] [blame] | 312 | if (!parent) |
| 313 | return false; |
| 314 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 315 | return UdevDevice(std::move(parent)) |
| 316 | .IsPropertyTrue(kPropertyMistSupportedDevice); |
Ben Chan | 1f41838 | 2013-06-17 23:33:28 -0700 | [diff] [blame] | 317 | } |
| 318 | |
Ben Chan | 0255db6 | 2011-09-19 12:14:28 -0700 | [diff] [blame] | 319 | bool UdevDevice::IsAutoMountable() const { |
Ben Chan | 9b42570 | 2011-09-07 10:57:09 -0700 | [diff] [blame] | 320 | // TODO(benchan): Find a reliable way to detect if a device is a removable |
| 321 | // storage as the removable attribute in sysfs does not always tell the truth. |
Ben Chan | a4b9651 | 2012-04-10 17:37:42 -0700 | [diff] [blame] | 322 | return !IsOnBootDevice() && !IsVirtual(); |
Ben Chan | 0255db6 | 2011-09-19 12:14:28 -0700 | [diff] [blame] | 323 | } |
Ben Chan | f869288 | 2011-08-21 10:15:30 -0700 | [diff] [blame] | 324 | |
Ben Chan | 0255db6 | 2011-09-19 12:14:28 -0700 | [diff] [blame] | 325 | bool UdevDevice::IsHidden() { |
| 326 | if (IsPropertyTrue(kPropertyPresentationHide)) |
| 327 | return true; |
| 328 | |
Ben Chan | a0fe0ef | 2012-09-06 23:39:56 -0700 | [diff] [blame] | 329 | // Hide an optical disc without any data track. |
| 330 | // udev/cdrom_id only sets ID_CDROM_MEDIA_TRACK_COUNT_DATA when there is at |
| 331 | // least one data track. |
| 332 | if (IsPropertyTrue(kPropertyCDROM) && |
| 333 | !HasProperty(kPropertyCDROMMediaTrackCountData)) { |
| 334 | return true; |
| 335 | } |
| 336 | |
Ben Chan | 1f41838 | 2013-06-17 23:33:28 -0700 | [diff] [blame] | 337 | // Hide a mobile broadband device, which may initially expose itself as a USB |
| 338 | // mass storage device and later be switched to a modem by mist. |
| 339 | if (IsMobileBroadbandDevice()) |
| 340 | return true; |
| 341 | |
Ben Chan | 0255db6 | 2011-09-19 12:14:28 -0700 | [diff] [blame] | 342 | // Hide a device that is neither marked as a partition nor a filesystem, |
Ben Chan | ca36994 | 2011-09-10 17:03:05 -0700 | [diff] [blame] | 343 | // unless it has no valid partitions (e.g. the device is unformatted or |
Ben Chan | 0255db6 | 2011-09-19 12:14:28 -0700 | [diff] [blame] | 344 | // corrupted). An unformatted or corrupted device is visible in the file |
| 345 | // the file browser so that we can provide a way to format it. |
Ben Chan | f869288 | 2011-08-21 10:15:30 -0700 | [diff] [blame] | 346 | if (!HasAttribute(kAttributePartition) && |
Ben Chan | de0e3f6 | 2017-09-26 06:28:39 -0700 | [diff] [blame] | 347 | !HasProperty(kPropertyFilesystemUsage) && (GetPartitionCount() > 0)) |
Ben Chan | 0255db6 | 2011-09-19 12:14:28 -0700 | [diff] [blame] | 348 | return true; |
Ben Chan | 1c2d425 | 2011-06-03 13:33:49 -0700 | [diff] [blame] | 349 | |
Ben Chan | cac2033 | 2014-02-13 23:21:17 -0800 | [diff] [blame] | 350 | // Hide special partitions based on partition type. |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 351 | std::string partition_type = GetProperty(kPropertyPartitionEntryType); |
Ben Chan | cac2033 | 2014-02-13 23:21:17 -0800 | [diff] [blame] | 352 | if (!partition_type.empty()) { |
Ben Chan | 6057fe6 | 2016-12-02 10:08:59 -0800 | [diff] [blame] | 353 | for (const char* partition_type_to_hide : kPartitionTypesToHide) { |
| 354 | if (partition_type == partition_type_to_hide) |
Ben Chan | 0255db6 | 2011-09-19 12:14:28 -0700 | [diff] [blame] | 355 | return true; |
Ben Chan | 1c2d425 | 2011-06-03 13:33:49 -0700 | [diff] [blame] | 356 | } |
| 357 | } |
Ben Chan | 0255db6 | 2011-09-19 12:14:28 -0700 | [diff] [blame] | 358 | return false; |
Ben Chan | 1c2d425 | 2011-06-03 13:33:49 -0700 | [diff] [blame] | 359 | } |
| 360 | |
Ben Chan | 2923ed7 | 2013-07-29 15:52:29 -0700 | [diff] [blame] | 361 | bool UdevDevice::IsIgnored() const { |
| 362 | return IsVirtual() && !IsLoopDevice(); |
| 363 | } |
| 364 | |
Ben Chan | 490319f | 2011-05-06 14:00:42 -0700 | [diff] [blame] | 365 | bool UdevDevice::IsOnBootDevice() const { |
| 366 | // Obtain the boot device path, e.g. /dev/sda |
| 367 | char boot_device_path[PATH_MAX]; |
| 368 | if (rootdev(boot_device_path, sizeof(boot_device_path), true, true)) { |
| 369 | LOG(ERROR) << "Could not determine root device"; |
| 370 | // Assume it is on the boot device when there is any uncertainty. |
| 371 | // This is to prevent a device, which is potentially on the boot device, |
| 372 | // from being auto mounted and exposed to users. |
| 373 | // TODO(benchan): Find a way to eliminate the uncertainty. |
| 374 | return true; |
| 375 | } |
| 376 | |
| 377 | // Compare the device file path of the current device and all its parents |
| 378 | // with the boot device path. Any match indicates that the current device |
| 379 | // is on the boot device. |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 380 | return EnumerateParentDevices(base::BindRepeating( |
| 381 | [](const char* boot_device_path, const brillo::UdevDevice& device) { |
| 382 | const char* dev_file = device.GetDeviceNode(); |
| 383 | return (dev_file && strncmp(boot_device_path, dev_file, PATH_MAX) == 0); |
| 384 | }, |
| 385 | boot_device_path)); |
Ben Chan | 490319f | 2011-05-06 14:00:42 -0700 | [diff] [blame] | 386 | } |
| 387 | |
Ben Chan | 5540d90 | 2018-07-25 14:52:58 -0700 | [diff] [blame] | 388 | bool UdevDevice::IsOnSdDevice() const { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 389 | return EnumerateParentDevices( |
| 390 | base::BindRepeating([](const brillo::UdevDevice& device) { |
| 391 | const char* mmc_type = device.GetPropertyValue(kPropertyMmcType); |
| 392 | return (mmc_type && strcmp(mmc_type, kPropertyMmcTypeSd) == 0); |
| 393 | })); |
Ben Chan | 58aad1d | 2013-02-26 16:09:34 -0800 | [diff] [blame] | 394 | } |
| 395 | |
Ben Chan | 5434262 | 2011-08-18 00:57:11 -0700 | [diff] [blame] | 396 | bool UdevDevice::IsOnRemovableDevice() const { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 397 | return EnumerateParentDevices( |
| 398 | base::BindRepeating([](const brillo::UdevDevice& device) { |
| 399 | const char* value = device.GetSysAttributeValue(kAttributeRemovable); |
| 400 | return (value && IsValueBooleanTrue(value)); |
| 401 | })); |
Ben Chan | 5434262 | 2011-08-18 00:57:11 -0700 | [diff] [blame] | 402 | } |
| 403 | |
Ben Chan | 9cda93a | 2011-05-24 13:31:04 -0700 | [diff] [blame] | 404 | bool UdevDevice::IsVirtual() const { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 405 | const char* sys_path = dev_->GetSysPath(); |
Ben Chan | 9cda93a | 2011-05-24 13:31:04 -0700 | [diff] [blame] | 406 | if (sys_path) { |
Alex Vakulenko | e50371c | 2016-01-20 16:06:19 -0800 | [diff] [blame] | 407 | return base::StartsWith(sys_path, kVirtualDevicePathPrefix, |
| 408 | base::CompareCase::SENSITIVE); |
Ben Chan | 9cda93a | 2011-05-24 13:31:04 -0700 | [diff] [blame] | 409 | } |
| 410 | // To be safe, mark it as virtual device if sys path cannot be determined. |
| 411 | return true; |
| 412 | } |
| 413 | |
Ben Chan | 2923ed7 | 2013-07-29 15:52:29 -0700 | [diff] [blame] | 414 | bool UdevDevice::IsLoopDevice() const { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 415 | const char* sys_path = dev_->GetSysPath(); |
Ben Chan | 2923ed7 | 2013-07-29 15:52:29 -0700 | [diff] [blame] | 416 | if (sys_path) { |
Alex Vakulenko | e50371c | 2016-01-20 16:06:19 -0800 | [diff] [blame] | 417 | return base::StartsWith(sys_path, kLoopDevicePathPrefix, |
| 418 | base::CompareCase::SENSITIVE); |
Ben Chan | 2923ed7 | 2013-07-29 15:52:29 -0700 | [diff] [blame] | 419 | } |
| 420 | return false; |
| 421 | } |
| 422 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 423 | std::string UdevDevice::NativePath() const { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 424 | const char* sys_path = dev_->GetSysPath(); |
Ben Chan | 4288836 | 2011-06-09 18:16:24 -0700 | [diff] [blame] | 425 | return sys_path ? sys_path : ""; |
| 426 | } |
| 427 | |
Austin Tankiang | 36f5bb5 | 2019-03-25 16:49:30 +1100 | [diff] [blame] | 428 | std::string UdevDevice::StorageDevicePath() const { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 429 | std::string path; |
| 430 | EnumerateParentDevices(base::BindRepeating( |
| 431 | [](std::string* path, const brillo::UdevDevice& device) { |
| 432 | base::StringPiece subsystem(device.GetSubsystem()); |
| 433 | if (subsystem == kSubsystemMmc || subsystem == kSubsystemNvme || |
| 434 | subsystem == kSubsystemScsi) { |
| 435 | *path = device.GetSysPath(); |
| 436 | return true; |
| 437 | } |
| 438 | return false; |
| 439 | }, |
| 440 | &path)); |
| 441 | return path; |
Austin Tankiang | 36f5bb5 | 2019-03-25 16:49:30 +1100 | [diff] [blame] | 442 | } |
| 443 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 444 | std::vector<std::string> UdevDevice::GetMountPaths() const { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 445 | const char* device_path = dev_->GetDeviceNode(); |
Ben Chan | f51ff00 | 2011-04-25 12:41:57 -0700 | [diff] [blame] | 446 | if (device_path) { |
| 447 | return GetMountPaths(device_path); |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 448 | } |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 449 | return std::vector<std::string>(); |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 450 | } |
| 451 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 452 | std::vector<std::string> UdevDevice::GetMountPaths( |
| 453 | const std::string& device_path) { |
Ben Chan | beefd0d | 2011-07-25 09:31:34 -0700 | [diff] [blame] | 454 | MountInfo mount_info; |
| 455 | if (mount_info.RetrieveFromCurrentProcess()) { |
| 456 | return mount_info.GetMountPaths(device_path); |
Ben Chan | f51ff00 | 2011-04-25 12:41:57 -0700 | [diff] [blame] | 457 | } |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 458 | return std::vector<std::string>(); |
Ben Chan | f51ff00 | 2011-04-25 12:41:57 -0700 | [diff] [blame] | 459 | } |
| 460 | |
Ben Chan | da410a0 | 2011-08-24 23:37:53 -0700 | [diff] [blame] | 461 | Disk UdevDevice::ToDisk() { |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 462 | Disk disk; |
| 463 | |
Ben Chan | ff92fa3 | 2017-10-17 16:17:15 -0700 | [diff] [blame] | 464 | disk.is_auto_mountable = IsAutoMountable(); |
| 465 | disk.is_read_only = IsAttributeTrue(kAttributeReadOnly); |
| 466 | disk.is_drive = HasAttribute(kAttributeRange); |
| 467 | disk.is_rotational = HasProperty(kPropertyRotationRate); |
| 468 | disk.is_hidden = IsHidden(); |
| 469 | disk.is_media_available = IsMediaAvailable(); |
| 470 | disk.is_on_boot_device = IsOnBootDevice(); |
| 471 | disk.is_on_removable_device = IsOnRemovableDevice(); |
| 472 | disk.is_virtual = IsVirtual(); |
| 473 | disk.media_type = GetDeviceMediaType(); |
| 474 | disk.filesystem_type = GetPropertyFromBlkId(kPropertyBlkIdFilesystemType); |
| 475 | disk.native_path = NativePath(); |
Austin Tankiang | 36f5bb5 | 2019-03-25 16:49:30 +1100 | [diff] [blame] | 476 | disk.storage_device_path = StorageDevicePath(); |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 477 | |
Ben Chan | 22c0e60 | 2012-02-13 12:37:34 -0800 | [diff] [blame] | 478 | // Drive model and filesystem label may not be UTF-8 encoded, so we |
| 479 | // need to ensure that they are either set to a valid UTF-8 string or |
| 480 | // an empty string before later passed to a DBus message iterator. |
Ben Chan | ff92fa3 | 2017-10-17 16:17:15 -0700 | [diff] [blame] | 481 | disk.drive_model = EnsureUTF8String(GetProperty(kPropertyModel)); |
| 482 | disk.label = |
| 483 | EnsureUTF8String(GetPropertyFromBlkId(kPropertyBlkIdFilesystemLabel)); |
Ben Chan | 22c0e60 | 2012-02-13 12:37:34 -0800 | [diff] [blame] | 484 | |
Ben Chan | ff92fa3 | 2017-10-17 16:17:15 -0700 | [diff] [blame] | 485 | if (GetVendorAndProductId(&disk.vendor_id, &disk.product_id)) { |
Ben Chan | 120c11c | 2012-09-10 23:10:18 -0700 | [diff] [blame] | 486 | USBDeviceInfo info; |
Ben Chan | ff92fa3 | 2017-10-17 16:17:15 -0700 | [diff] [blame] | 487 | info.GetVendorAndProductName(kUSBIdentifierDatabase, disk.vendor_id, |
| 488 | disk.product_id, &disk.vendor_name, |
| 489 | &disk.product_name); |
Ben Chan | 120c11c | 2012-09-10 23:10:18 -0700 | [diff] [blame] | 490 | } |
| 491 | |
Timothy Loh | d813344 | 2020-11-03 16:21:07 +1100 | [diff] [blame] | 492 | GetBusAndDeviceNumber(&disk.bus_number, &disk.device_number); |
| 493 | |
Ben Chan | 0e1b550 | 2013-07-24 23:39:29 -0700 | [diff] [blame] | 494 | // TODO(benchan): Add a proper unit test when fixing crbug.com/221380. |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 495 | std::string uuid_hash = base::SHA1HashString( |
Ben Chan | ff92fa3 | 2017-10-17 16:17:15 -0700 | [diff] [blame] | 496 | disk.vendor_id + disk.product_id + GetProperty(kPropertySerial) + |
Ben Chan | 0e1b550 | 2013-07-24 23:39:29 -0700 | [diff] [blame] | 497 | GetPropertyFromBlkId(kPropertyBlkIdFilesystemUUID)); |
Ben Chan | ff92fa3 | 2017-10-17 16:17:15 -0700 | [diff] [blame] | 498 | disk.uuid = base::HexEncode(uuid_hash.data(), uuid_hash.size()); |
Ben Chan | 0e1b550 | 2013-07-24 23:39:29 -0700 | [diff] [blame] | 499 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 500 | const char* dev_file = dev_->GetDeviceNode(); |
Ben Chan | f51ff00 | 2011-04-25 12:41:57 -0700 | [diff] [blame] | 501 | if (dev_file) |
Ben Chan | ff92fa3 | 2017-10-17 16:17:15 -0700 | [diff] [blame] | 502 | disk.device_file = dev_file; |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 503 | |
Ben Chan | ff92fa3 | 2017-10-17 16:17:15 -0700 | [diff] [blame] | 504 | disk.mount_paths = GetMountPaths(); |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 505 | |
Ben Chan | ff92fa3 | 2017-10-17 16:17:15 -0700 | [diff] [blame] | 506 | GetSizeInfo(&disk.device_capacity, &disk.bytes_remaining); |
Ben Chan | ce7ee54 | 2011-04-12 17:02:49 -0700 | [diff] [blame] | 507 | |
| 508 | return disk; |
| 509 | } |
| 510 | |
| 511 | } // namespace cros_disks |