blob: 1fafcf5d8d0b5d908b24a3cf7f847df9ca44d770 [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>
Alex Vakulenkoe50371c2016-01-20 16:06:19 -08008#include <linux/limits.h>
Ben Chanda410a02011-08-24 23:37:53 -07009#include <stdlib.h>
Ben Chance7ee542011-04-12 17:02:49 -070010#include <sys/statvfs.h>
Ben Chanbdc39742011-05-11 17:51:26 -070011
Anand K Mistry5757f632019-09-11 13:29:41 +100012#include <utility>
13
14#include <base/bind.h>
Qijiang Fan713061e2021-03-08 15:45:12 +090015#include <base/check.h>
hscham9d835342020-04-16 15:23:37 +090016#include <base/hash/sha1.h>
Chris Masoneec4761f2011-05-12 14:04:13 -070017#include <base/logging.h>
Ben Chan97e20d42014-02-05 18:38:07 -080018#include <base/strings/string_number_conversions.h>
Anand K Mistry5757f632019-09-11 13:29:41 +100019#include <base/strings/string_piece.h>
Ben Chan97e20d42014-02-05 18:38:07 -080020#include <base/strings/string_split.h>
21#include <base/strings/string_util.h>
Anand K Mistry5757f632019-09-11 13:29:41 +100022#include <brillo/udev/udev_device.h>
Ben Chanbdc39742011-05-11 17:51:26 -070023#include <rootdev/rootdev.h>
24
Ben Chan5ccd9fe2013-11-13 18:28:27 -080025#include "cros-disks/mount_info.h"
26#include "cros-disks/usb_device_info.h"
Ben Chance7ee542011-04-12 17:02:49 -070027
Anand K Mistry40cff452019-07-30 10:24:48 +100028namespace cros_disks {
Ben Chan54342622011-08-18 00:57:11 -070029namespace {
Ben Chance7ee542011-04-12 17:02:49 -070030
Ben Chan460439f2011-09-13 09:16:28 -070031const char kNullDeviceFile[] = "/dev/null";
Timothy Lohd8133442020-11-03 16:21:07 +110032const char kAttributeBusNum[] = "busnum";
33const char kAttributeDevNum[] = "devnum";
Ben Chan0a389a62011-10-03 15:02:34 -070034const char kAttributeIdProduct[] = "idProduct";
35const char kAttributeIdVendor[] = "idVendor";
Ben Chan460439f2011-09-13 09:16:28 -070036const char kAttributePartition[] = "partition";
37const char kAttributeRange[] = "range";
38const char kAttributeReadOnly[] = "ro";
39const char kAttributeRemovable[] = "removable";
40const char kAttributeSize[] = "size";
41const char kPropertyBlkIdFilesystemType[] = "TYPE";
42const char kPropertyBlkIdFilesystemLabel[] = "LABEL";
43const char kPropertyBlkIdFilesystemUUID[] = "UUID";
44const char kPropertyCDROM[] = "ID_CDROM";
Ben Chan7d8f9f72012-05-02 10:02:20 -070045const char kPropertyCDROMDVD[] = "ID_CDROM_DVD";
Ben Chan460439f2011-09-13 09:16:28 -070046const char kPropertyCDROMMedia[] = "ID_CDROM_MEDIA";
Ben Chana0fe0ef2012-09-06 23:39:56 -070047const char kPropertyCDROMMediaTrackCountData[] =
48 "ID_CDROM_MEDIA_TRACK_COUNT_DATA";
Ben Chan0a389a62011-10-03 15:02:34 -070049const char kPropertyDeviceType[] = "DEVTYPE";
50const char kPropertyDeviceTypeUSBDevice[] = "usb_device";
Ben Chan460439f2011-09-13 09:16:28 -070051const char kPropertyFilesystemUsage[] = "ID_FS_USAGE";
Ben Chan1f418382013-06-17 23:33:28 -070052const char kPropertyMistSupportedDevice[] = "MIST_SUPPORTED_DEVICE";
Ben Chan5540d902018-07-25 14:52:58 -070053const char kPropertyMmcType[] = "MMC_TYPE";
54const char kPropertyMmcTypeSd[] = "SD";
Ben Chan460439f2011-09-13 09:16:28 -070055const char kPropertyModel[] = "ID_MODEL";
Ben Chancac20332014-02-13 23:21:17 -080056const char kPropertyPartitionEntryType[] = "ID_PART_ENTRY_TYPE";
Ben Chan460439f2011-09-13 09:16:28 -070057const char kPropertyPartitionSize[] = "UDISKS_PARTITION_SIZE";
58const char kPropertyPresentationHide[] = "UDISKS_PRESENTATION_HIDE";
59const char kPropertyRotationRate[] = "ID_ATA_ROTATION_RATE_RPM";
Ben Chan0e1b5502013-07-24 23:39:29 -070060const char kPropertySerial[] = "ID_SERIAL";
Ben Chan1f418382013-06-17 23:33:28 -070061const char kSubsystemUsb[] = "usb";
Austin Tankiang36f5bb52019-03-25 16:49:30 +110062const char kSubsystemMmc[] = "mmc";
63const char kSubsystemNvme[] = "nvme";
64const char kSubsystemScsi[] = "scsi";
Ben Chan460439f2011-09-13 09:16:28 -070065const char kVirtualDevicePathPrefix[] = "/sys/devices/virtual/";
Ben Chan2923ed72013-07-29 15:52:29 -070066const char kLoopDevicePathPrefix[] = "/sys/devices/virtual/block/loop";
Ben Chanccde5122018-09-25 17:46:07 -070067const char kUSBDeviceInfoFile[] = "/usr/share/cros-disks/usb-device-info";
Ben Chan120c11c2012-09-10 23:10:18 -070068const char kUSBIdentifierDatabase[] = "/usr/share/misc/usb.ids";
Ben Chanc79c2962016-10-27 18:03:05 -070069const 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 Chan1c2d4252011-06-03 13:33:49 -070075};
76
Ben Chan54342622011-08-18 00:57:11 -070077} // namespace
78
Anand K Mistry5757f632019-09-11 13:29:41 +100079UdevDevice::UdevDevice(std::unique_ptr<brillo::UdevDevice> dev)
80 : dev_(std::move(dev)), blkid_cache_(nullptr) {
Ben Chance7ee542011-04-12 17:02:49 -070081 CHECK(dev_) << "Invalid udev device";
Ben Chance7ee542011-04-12 17:02:49 -070082}
83
84UdevDevice::~UdevDevice() {
Ben Chanda410a02011-08-24 23:37:53 -070085 if (blkid_cache_) {
86 // It needs to call blkid_put_cache to deallocate the blkid cache.
87 blkid_put_cache(blkid_cache_);
88 }
Ben Chance7ee542011-04-12 17:02:49 -070089}
90
Ben Chan1f418382013-06-17 23:33:28 -070091// static
Ben Chan213c6d92019-04-10 16:21:52 -070092std::string UdevDevice::EnsureUTF8String(const std::string& str) {
Ben Chanaf25ddb2014-05-21 18:32:47 -070093 return base::IsStringUTF8(str) ? str : "";
Ben Chan22c0e602012-02-13 12:37:34 -080094}
95
Ben Chan1f418382013-06-17 23:33:28 -070096// static
Ben Chande0e3f62017-09-26 06:28:39 -070097bool UdevDevice::IsValueBooleanTrue(const char* value) {
Ben Chance7ee542011-04-12 17:02:49 -070098 return value && strcmp(value, "1") == 0;
99}
100
Ben Chan213c6d92019-04-10 16:21:52 -0700101std::string UdevDevice::GetAttribute(const char* key) const {
Anand K Mistry5757f632019-09-11 13:29:41 +1000102 const char* value = dev_->GetSysAttributeValue(key);
Ben Chance7ee542011-04-12 17:02:49 -0700103 return (value) ? value : "";
104}
105
Ben Chande0e3f62017-09-26 06:28:39 -0700106bool UdevDevice::IsAttributeTrue(const char* key) const {
Anand K Mistry5757f632019-09-11 13:29:41 +1000107 const char* value = dev_->GetSysAttributeValue(key);
Ben Chance7ee542011-04-12 17:02:49 -0700108 return IsValueBooleanTrue(value);
109}
110
Ben Chande0e3f62017-09-26 06:28:39 -0700111bool UdevDevice::HasAttribute(const char* key) const {
Anand K Mistry5757f632019-09-11 13:29:41 +1000112 const char* value = dev_->GetSysAttributeValue(key);
Ben Chan44e7ea62014-08-29 18:13:37 -0700113 return value != nullptr;
Ben Chance7ee542011-04-12 17:02:49 -0700114}
115
Ben Chan213c6d92019-04-10 16:21:52 -0700116std::string UdevDevice::GetProperty(const char* key) const {
Anand K Mistry5757f632019-09-11 13:29:41 +1000117 const char* value = dev_->GetPropertyValue(key);
Ben Chance7ee542011-04-12 17:02:49 -0700118 return (value) ? value : "";
119}
120
Ben Chande0e3f62017-09-26 06:28:39 -0700121bool UdevDevice::IsPropertyTrue(const char* key) const {
Anand K Mistry5757f632019-09-11 13:29:41 +1000122 const char* value = dev_->GetPropertyValue(key);
Ben Chance7ee542011-04-12 17:02:49 -0700123 return IsValueBooleanTrue(value);
124}
125
Ben Chande0e3f62017-09-26 06:28:39 -0700126bool UdevDevice::HasProperty(const char* key) const {
Anand K Mistry5757f632019-09-11 13:29:41 +1000127 const char* value = dev_->GetPropertyValue(key);
Ben Chan44e7ea62014-08-29 18:13:37 -0700128 return value != nullptr;
Ben Chance7ee542011-04-12 17:02:49 -0700129}
130
Ben Chan213c6d92019-04-10 16:21:52 -0700131std::string UdevDevice::GetPropertyFromBlkId(const char* key) {
132 std::string value;
Anand K Mistry5757f632019-09-11 13:29:41 +1000133 const char* dev_file = dev_->GetDeviceNode();
Ben Chanda410a02011-08-24 23:37:53 -0700134 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 Chande0e3f62017-09-26 06:28:39 -0700140 char* tag_value = blkid_get_tag_value(blkid_cache_, key, dev_file);
Ben Chanda410a02011-08-24 23:37:53 -0700141 if (tag_value) {
142 value = tag_value;
143 free(tag_value);
144 }
145 }
146 }
147 }
148 return value;
149}
150
Ben Chande0e3f62017-09-26 06:28:39 -0700151void UdevDevice::GetSizeInfo(uint64_t* total_size,
152 uint64_t* remaining_size) const {
Ben Chanf51ff002011-04-25 12:41:57 -0700153 static const int kSectorSize = 512;
Ben Chana169b0a2014-08-06 17:22:40 -0700154 uint64_t total = 0, remaining = 0;
Ben Chance7ee542011-04-12 17:02:49 -0700155
Ben Chanf51ff002011-04-25 12:41:57 -0700156 // If the device is mounted, obtain the total and remaining size in bytes
157 // using statvfs.
Ben Chan213c6d92019-04-10 16:21:52 -0700158 std::vector<std::string> mount_paths = GetMountPaths();
Ben Chanf51ff002011-04-25 12:41:57 -0700159 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 Chance7ee542011-04-12 17:02:49 -0700164 }
165 }
166
Ben Chanf51ff002011-04-25 12:41:57 -0700167 // 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 Mistry5757f632019-09-11 13:29:41 +1000171 const std::string partition_size = GetProperty(kPropertyPartitionSize);
Ben Chana169b0a2014-08-06 17:22:40 -0700172 int64_t size = 0;
Anand K Mistry5757f632019-09-11 13:29:41 +1000173 if (!partition_size.empty()) {
Ben Chanf51ff002011-04-25 12:41:57 -0700174 base::StringToInt64(partition_size, &size);
175 total = size;
176 } else {
Anand K Mistry5757f632019-09-11 13:29:41 +1000177 const std::string size_attr = GetAttribute(kAttributeSize);
178 if (!size_attr.empty()) {
Ben Chanf51ff002011-04-25 12:41:57 -0700179 base::StringToInt64(size_attr, &size);
180 total = size * kSectorSize;
181 }
182 }
183
184 if (total_size)
185 *total_size = total;
Ben Chance7ee542011-04-12 17:02:49 -0700186 if (remaining_size)
Ben Chanf51ff002011-04-25 12:41:57 -0700187 *remaining_size = remaining;
Ben Chance7ee542011-04-12 17:02:49 -0700188}
189
Ben Chan53e12a22014-02-13 23:34:09 -0800190size_t UdevDevice::GetPartitionCount() const {
Ben Chanca369942011-09-10 17:03:05 -0700191 size_t partition_count = 0;
Anand K Mistry5757f632019-09-11 13:29:41 +1000192 const char* dev_file = dev_->GetDeviceNode();
Ben Chanca369942011-09-10 17:03:05 -0700193 if (dev_file) {
Ben Chan53e12a22014-02-13 23:34:09 -0800194 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 Chanca369942011-09-10 17:03:05 -0700199 }
Ben Chan53e12a22014-02-13 23:34:09 -0800200 blkid_free_probe(probe);
Ben Chanca369942011-09-10 17:03:05 -0700201 }
202 }
203 return partition_count;
204}
205
Ben Chan0a389a62011-10-03 15:02:34 -0700206DeviceMediaType UdevDevice::GetDeviceMediaType() const {
Ben Chan7d8f9f72012-05-02 10:02:20 -0700207 if (IsPropertyTrue(kPropertyCDROMDVD))
208 return DEVICE_MEDIA_DVD;
209
Ben Chan0a389a62011-10-03 15:02:34 -0700210 if (IsPropertyTrue(kPropertyCDROM))
Ben Chan6d0b2722011-11-18 08:24:14 -0800211 return DEVICE_MEDIA_OPTICAL_DISC;
Ben Chan0a389a62011-10-03 15:02:34 -0700212
Ben Chan5540d902018-07-25 14:52:58 -0700213 if (IsOnSdDevice())
Ben Chan58aad1d2013-02-26 16:09:34 -0800214 return DEVICE_MEDIA_SD;
215
Ben Chan213c6d92019-04-10 16:21:52 -0700216 std::string vendor_id, product_id;
Ben Chan120c11c2012-09-10 23:10:18 -0700217 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 Mistryc0ece3d2020-01-28 15:55:29 +1100225bool UdevDevice::EnumerateParentDevices(EnumerateCallback callback) const {
Anand K Mistry5757f632019-09-11 13:29:41 +1000226 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 Chan213c6d92019-04-10 16:21:52 -0700238bool UdevDevice::GetVendorAndProductId(std::string* vendor_id,
239 std::string* product_id) const {
Ben Chan0a389a62011-10-03 15:02:34 -0700240 // 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 Mistry5757f632019-09-11 13:29:41 +1000243 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 Chan0a389a62011-10-03 15:02:34 -0700262}
263
Timothy Lohd8133442020-11-03 16:21:07 +1100264void 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 Chance7ee542011-04-12 17:02:49 -0700285bool UdevDevice::IsMediaAvailable() const {
286 bool is_media_available = true;
Ben Chan54342622011-08-18 00:57:11 -0700287 if (IsAttributeTrue(kAttributeRemovable)) {
288 if (IsPropertyTrue(kPropertyCDROM)) {
289 is_media_available = IsPropertyTrue(kPropertyCDROMMedia);
Ben Chance7ee542011-04-12 17:02:49 -0700290 } else {
Anand K Mistry5757f632019-09-11 13:29:41 +1000291 const char* dev_file = dev_->GetDeviceNode();
Ben Chanf51ff002011-04-25 12:41:57 -0700292 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 Chance7ee542011-04-12 17:02:49 -0700299 }
300 }
301 }
302 return is_media_available;
303}
304
Ben Chan1f418382013-06-17 23:33:28 -0700305bool 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 Mistry5757f632019-09-11 13:29:41 +1000309 std::unique_ptr<brillo::UdevDevice> parent =
310 dev_->GetParentWithSubsystemDeviceType(kSubsystemUsb,
311 kPropertyDeviceTypeUSBDevice);
Ben Chan1f418382013-06-17 23:33:28 -0700312 if (!parent)
313 return false;
314
Anand K Mistry5757f632019-09-11 13:29:41 +1000315 return UdevDevice(std::move(parent))
316 .IsPropertyTrue(kPropertyMistSupportedDevice);
Ben Chan1f418382013-06-17 23:33:28 -0700317}
318
Ben Chan0255db62011-09-19 12:14:28 -0700319bool UdevDevice::IsAutoMountable() const {
Ben Chan9b425702011-09-07 10:57:09 -0700320 // 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 Chana4b96512012-04-10 17:37:42 -0700322 return !IsOnBootDevice() && !IsVirtual();
Ben Chan0255db62011-09-19 12:14:28 -0700323}
Ben Chanf8692882011-08-21 10:15:30 -0700324
Ben Chan0255db62011-09-19 12:14:28 -0700325bool UdevDevice::IsHidden() {
326 if (IsPropertyTrue(kPropertyPresentationHide))
327 return true;
328
Ben Chana0fe0ef2012-09-06 23:39:56 -0700329 // 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 Chan1f418382013-06-17 23:33:28 -0700337 // 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 Chan0255db62011-09-19 12:14:28 -0700342 // Hide a device that is neither marked as a partition nor a filesystem,
Ben Chanca369942011-09-10 17:03:05 -0700343 // unless it has no valid partitions (e.g. the device is unformatted or
Ben Chan0255db62011-09-19 12:14:28 -0700344 // 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 Chanf8692882011-08-21 10:15:30 -0700346 if (!HasAttribute(kAttributePartition) &&
Ben Chande0e3f62017-09-26 06:28:39 -0700347 !HasProperty(kPropertyFilesystemUsage) && (GetPartitionCount() > 0))
Ben Chan0255db62011-09-19 12:14:28 -0700348 return true;
Ben Chan1c2d4252011-06-03 13:33:49 -0700349
Ben Chancac20332014-02-13 23:21:17 -0800350 // Hide special partitions based on partition type.
Ben Chan213c6d92019-04-10 16:21:52 -0700351 std::string partition_type = GetProperty(kPropertyPartitionEntryType);
Ben Chancac20332014-02-13 23:21:17 -0800352 if (!partition_type.empty()) {
Ben Chan6057fe62016-12-02 10:08:59 -0800353 for (const char* partition_type_to_hide : kPartitionTypesToHide) {
354 if (partition_type == partition_type_to_hide)
Ben Chan0255db62011-09-19 12:14:28 -0700355 return true;
Ben Chan1c2d4252011-06-03 13:33:49 -0700356 }
357 }
Ben Chan0255db62011-09-19 12:14:28 -0700358 return false;
Ben Chan1c2d4252011-06-03 13:33:49 -0700359}
360
Ben Chan2923ed72013-07-29 15:52:29 -0700361bool UdevDevice::IsIgnored() const {
362 return IsVirtual() && !IsLoopDevice();
363}
364
Ben Chan490319f2011-05-06 14:00:42 -0700365bool 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 Mistry5757f632019-09-11 13:29:41 +1000380 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 Chan490319f2011-05-06 14:00:42 -0700386}
387
Ben Chan5540d902018-07-25 14:52:58 -0700388bool UdevDevice::IsOnSdDevice() const {
Anand K Mistry5757f632019-09-11 13:29:41 +1000389 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 Chan58aad1d2013-02-26 16:09:34 -0800394}
395
Ben Chan54342622011-08-18 00:57:11 -0700396bool UdevDevice::IsOnRemovableDevice() const {
Anand K Mistry5757f632019-09-11 13:29:41 +1000397 return EnumerateParentDevices(
398 base::BindRepeating([](const brillo::UdevDevice& device) {
399 const char* value = device.GetSysAttributeValue(kAttributeRemovable);
400 return (value && IsValueBooleanTrue(value));
401 }));
Ben Chan54342622011-08-18 00:57:11 -0700402}
403
Ben Chan9cda93a2011-05-24 13:31:04 -0700404bool UdevDevice::IsVirtual() const {
Anand K Mistry5757f632019-09-11 13:29:41 +1000405 const char* sys_path = dev_->GetSysPath();
Ben Chan9cda93a2011-05-24 13:31:04 -0700406 if (sys_path) {
Alex Vakulenkoe50371c2016-01-20 16:06:19 -0800407 return base::StartsWith(sys_path, kVirtualDevicePathPrefix,
408 base::CompareCase::SENSITIVE);
Ben Chan9cda93a2011-05-24 13:31:04 -0700409 }
410 // To be safe, mark it as virtual device if sys path cannot be determined.
411 return true;
412}
413
Ben Chan2923ed72013-07-29 15:52:29 -0700414bool UdevDevice::IsLoopDevice() const {
Anand K Mistry5757f632019-09-11 13:29:41 +1000415 const char* sys_path = dev_->GetSysPath();
Ben Chan2923ed72013-07-29 15:52:29 -0700416 if (sys_path) {
Alex Vakulenkoe50371c2016-01-20 16:06:19 -0800417 return base::StartsWith(sys_path, kLoopDevicePathPrefix,
418 base::CompareCase::SENSITIVE);
Ben Chan2923ed72013-07-29 15:52:29 -0700419 }
420 return false;
421}
422
Ben Chan213c6d92019-04-10 16:21:52 -0700423std::string UdevDevice::NativePath() const {
Anand K Mistry5757f632019-09-11 13:29:41 +1000424 const char* sys_path = dev_->GetSysPath();
Ben Chan42888362011-06-09 18:16:24 -0700425 return sys_path ? sys_path : "";
426}
427
Austin Tankiang36f5bb52019-03-25 16:49:30 +1100428std::string UdevDevice::StorageDevicePath() const {
Anand K Mistry5757f632019-09-11 13:29:41 +1000429 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 Tankiang36f5bb52019-03-25 16:49:30 +1100442}
443
Ben Chan213c6d92019-04-10 16:21:52 -0700444std::vector<std::string> UdevDevice::GetMountPaths() const {
Anand K Mistry5757f632019-09-11 13:29:41 +1000445 const char* device_path = dev_->GetDeviceNode();
Ben Chanf51ff002011-04-25 12:41:57 -0700446 if (device_path) {
447 return GetMountPaths(device_path);
Ben Chance7ee542011-04-12 17:02:49 -0700448 }
Ben Chan213c6d92019-04-10 16:21:52 -0700449 return std::vector<std::string>();
Ben Chance7ee542011-04-12 17:02:49 -0700450}
451
Ben Chan213c6d92019-04-10 16:21:52 -0700452std::vector<std::string> UdevDevice::GetMountPaths(
453 const std::string& device_path) {
Ben Chanbeefd0d2011-07-25 09:31:34 -0700454 MountInfo mount_info;
455 if (mount_info.RetrieveFromCurrentProcess()) {
456 return mount_info.GetMountPaths(device_path);
Ben Chanf51ff002011-04-25 12:41:57 -0700457 }
Ben Chan213c6d92019-04-10 16:21:52 -0700458 return std::vector<std::string>();
Ben Chanf51ff002011-04-25 12:41:57 -0700459}
460
Ben Chanda410a02011-08-24 23:37:53 -0700461Disk UdevDevice::ToDisk() {
Ben Chance7ee542011-04-12 17:02:49 -0700462 Disk disk;
463
Ben Chanff92fa32017-10-17 16:17:15 -0700464 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 Tankiang36f5bb52019-03-25 16:49:30 +1100476 disk.storage_device_path = StorageDevicePath();
Ben Chance7ee542011-04-12 17:02:49 -0700477
Ben Chan22c0e602012-02-13 12:37:34 -0800478 // 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 Chanff92fa32017-10-17 16:17:15 -0700481 disk.drive_model = EnsureUTF8String(GetProperty(kPropertyModel));
482 disk.label =
483 EnsureUTF8String(GetPropertyFromBlkId(kPropertyBlkIdFilesystemLabel));
Ben Chan22c0e602012-02-13 12:37:34 -0800484
Ben Chanff92fa32017-10-17 16:17:15 -0700485 if (GetVendorAndProductId(&disk.vendor_id, &disk.product_id)) {
Ben Chan120c11c2012-09-10 23:10:18 -0700486 USBDeviceInfo info;
Ben Chanff92fa32017-10-17 16:17:15 -0700487 info.GetVendorAndProductName(kUSBIdentifierDatabase, disk.vendor_id,
488 disk.product_id, &disk.vendor_name,
489 &disk.product_name);
Ben Chan120c11c2012-09-10 23:10:18 -0700490 }
491
Timothy Lohd8133442020-11-03 16:21:07 +1100492 GetBusAndDeviceNumber(&disk.bus_number, &disk.device_number);
493
Ben Chan0e1b5502013-07-24 23:39:29 -0700494 // TODO(benchan): Add a proper unit test when fixing crbug.com/221380.
Ben Chan213c6d92019-04-10 16:21:52 -0700495 std::string uuid_hash = base::SHA1HashString(
Ben Chanff92fa32017-10-17 16:17:15 -0700496 disk.vendor_id + disk.product_id + GetProperty(kPropertySerial) +
Ben Chan0e1b5502013-07-24 23:39:29 -0700497 GetPropertyFromBlkId(kPropertyBlkIdFilesystemUUID));
Ben Chanff92fa32017-10-17 16:17:15 -0700498 disk.uuid = base::HexEncode(uuid_hash.data(), uuid_hash.size());
Ben Chan0e1b5502013-07-24 23:39:29 -0700499
Anand K Mistry5757f632019-09-11 13:29:41 +1000500 const char* dev_file = dev_->GetDeviceNode();
Ben Chanf51ff002011-04-25 12:41:57 -0700501 if (dev_file)
Ben Chanff92fa32017-10-17 16:17:15 -0700502 disk.device_file = dev_file;
Ben Chance7ee542011-04-12 17:02:49 -0700503
Ben Chanff92fa32017-10-17 16:17:15 -0700504 disk.mount_paths = GetMountPaths();
Ben Chance7ee542011-04-12 17:02:49 -0700505
Ben Chanff92fa32017-10-17 16:17:15 -0700506 GetSizeInfo(&disk.device_capacity, &disk.bytes_remaining);
Ben Chance7ee542011-04-12 17:02:49 -0700507
508 return disk;
509}
510
511} // namespace cros_disks