Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 1 | // Copyright 2019 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 "cros-disks/disk_monitor.h" |
| 6 | |
| 7 | #include <inttypes.h> |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 8 | #include <string.h> |
| 9 | #include <sys/mount.h> |
| 10 | #include <time.h> |
| 11 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 12 | #include <utility> |
| 13 | |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 14 | #include <base/bind.h> |
Qijiang Fan | 713061e | 2021-03-08 15:45:12 +0900 | [diff] [blame] | 15 | #include <base/check.h> |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 16 | #include <base/logging.h> |
| 17 | #include <base/stl_util.h> |
| 18 | #include <base/strings/string_piece.h> |
| 19 | #include <base/strings/string_util.h> |
| 20 | #include <base/strings/stringprintf.h> |
| 21 | #include <base/time/time.h> |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 22 | #include <brillo/udev/udev.h> |
| 23 | #include <brillo/udev/udev_device.h> |
| 24 | #include <brillo/udev/udev_enumerate.h> |
| 25 | #include <brillo/udev/udev_monitor.h> |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 26 | |
| 27 | #include "cros-disks/device_ejector.h" |
François Degros | 16ad1ae | 2019-07-17 16:02:39 +1000 | [diff] [blame] | 28 | #include "cros-disks/quote.h" |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 29 | #include "cros-disks/udev_device.h" |
| 30 | |
| 31 | namespace cros_disks { |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 32 | namespace { |
| 33 | |
| 34 | const char kBlockSubsystem[] = "block"; |
| 35 | const char kMmcSubsystem[] = "mmc"; |
| 36 | const char kScsiSubsystem[] = "scsi"; |
| 37 | const char kScsiDevice[] = "scsi_device"; |
| 38 | const char kUdevAddAction[] = "add"; |
| 39 | const char kUdevChangeAction[] = "change"; |
| 40 | const char kUdevRemoveAction[] = "remove"; |
| 41 | const char kPropertyDiskEjectRequest[] = "DISK_EJECT_REQUEST"; |
| 42 | const char kPropertyDiskMediaChange[] = "DISK_MEDIA_CHANGE"; |
| 43 | |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 44 | // Checks if the device is allowed to be used through cros-disks. |
| 45 | bool IsDeviceAllowed(const UdevDevice& device, |
| 46 | const std::set<std::string>& allowlist) { |
| 47 | if (device.IsIgnored()) |
| 48 | return false; |
| 49 | if (base::Contains(allowlist, device.NativePath())) |
| 50 | return true; |
| 51 | if (device.IsLoopDevice()) |
| 52 | return false; |
| 53 | if (device.IsMobileBroadbandDevice()) |
| 54 | return false; |
| 55 | if (device.IsOnBootDevice()) |
| 56 | return false; |
| 57 | return true; |
| 58 | } |
| 59 | |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 60 | // An EnumerateBlockDevices callback that appends a Disk object, created from |
| 61 | // |dev|, to |disks| if |dev| should not be ignored by cros-disks. Always |
| 62 | // returns true to continue the enumeration in EnumerateBlockDevices. |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 63 | bool AppendDiskIfNotIgnored(const std::set<std::string>& allowlist, |
| 64 | std::vector<Disk>* disks, |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 65 | std::unique_ptr<brillo::UdevDevice> dev) { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 66 | UdevDevice device(std::move(dev)); |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 67 | if (IsDeviceAllowed(device, allowlist)) |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 68 | disks->push_back(device.ToDisk()); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 69 | return true; // Continue the enumeration. |
| 70 | } |
| 71 | |
| 72 | // An EnumerateBlockDevices callback that checks if |dev| matches |path|. If |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 73 | // it's a match, populates |device| and returns false to stop the enumeration in |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 74 | // EnumerateBlockDevices. |
| 75 | bool MatchDiskByPath(const std::string& path, |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 76 | std::unique_ptr<UdevDevice>* device, |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 77 | std::unique_ptr<brillo::UdevDevice> dev) { |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 78 | DCHECK(dev); |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 79 | DCHECK(device); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 80 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 81 | const char* sys_path = dev->GetSysPath(); |
| 82 | const char* dev_path = dev->GetDevicePath(); |
| 83 | const char* dev_file = dev->GetDeviceNode(); |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 84 | bool match = (sys_path && path == sys_path) || |
| 85 | (dev_path && path == dev_path) || (dev_file && path == dev_file); |
| 86 | if (!match) |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 87 | return true; // Not a match. Continue the enumeration. |
| 88 | |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 89 | *device = std::make_unique<UdevDevice>(std::move(dev)); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 90 | return false; // Match. Stop enumeration. |
| 91 | } |
| 92 | |
François Degros | 16ad1ae | 2019-07-17 16:02:39 +1000 | [diff] [blame] | 93 | // Logs a device with its properties. |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 94 | void LogUdevDevice(const brillo::UdevDevice& dev) { |
François Degros | 16ad1ae | 2019-07-17 16:02:39 +1000 | [diff] [blame] | 95 | if (!VLOG_IS_ON(1)) |
| 96 | return; |
| 97 | |
| 98 | // Some device events (eg USB drive removal) result in devnode being null. |
| 99 | // This is gracefully handled by quote() without crashing. |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 100 | VLOG(1) << " node: " << quote(dev.GetDeviceNode()); |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 101 | VLOG(1) << " devtype: " << quote(dev.GetDeviceType()); |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 102 | VLOG(1) << " syspath: " << quote(dev.GetSysPath()); |
François Degros | 16ad1ae | 2019-07-17 16:02:39 +1000 | [diff] [blame] | 103 | |
| 104 | if (!VLOG_IS_ON(2)) |
| 105 | return; |
| 106 | |
| 107 | // Log all properties. |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 108 | for (std::unique_ptr<brillo::UdevListEntry> prop = |
| 109 | dev.GetPropertiesListEntry(); |
| 110 | prop; prop = prop->GetNext()) { |
| 111 | VLOG(2) << " " << prop->GetName() << ": " << quote(prop->GetValue()); |
François Degros | 16ad1ae | 2019-07-17 16:02:39 +1000 | [diff] [blame] | 112 | } |
| 113 | } |
| 114 | |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 115 | void LogDevice(const UdevDevice& dev) { |
| 116 | if (!VLOG_IS_ON(1)) |
| 117 | return; |
| 118 | |
| 119 | VLOG(1) << "path: " << quote(dev.NativePath()); |
| 120 | VLOG(1) << " attributes: virtual=" << dev.IsVirtual() |
| 121 | << " loop=" << dev.IsLoopDevice() << " boot=" << dev.IsOnBootDevice() |
| 122 | << " removable=" << dev.IsOnRemovableDevice() |
| 123 | << " broadband=" << dev.IsMobileBroadbandDevice() |
| 124 | << " automount=" << dev.IsAutoMountable() |
| 125 | << " media=" << dev.IsMediaAvailable(); |
| 126 | } |
| 127 | |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 128 | } // namespace |
| 129 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 130 | DiskMonitor::DiskMonitor() : udev_(brillo::Udev::Create()) { |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 131 | CHECK(udev_) << "Failed to initialize udev"; |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 132 | udev_monitor_ = udev_->CreateMonitorFromNetlink("udev"); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 133 | CHECK(udev_monitor_) << "Failed to create a udev monitor"; |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 134 | udev_monitor_->FilterAddMatchSubsystemDeviceType(kBlockSubsystem, nullptr); |
| 135 | udev_monitor_->FilterAddMatchSubsystemDeviceType(kMmcSubsystem, nullptr); |
| 136 | udev_monitor_->FilterAddMatchSubsystemDeviceType(kScsiSubsystem, kScsiDevice); |
| 137 | CHECK(udev_monitor_->EnableReceiving()); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 138 | } |
| 139 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 140 | DiskMonitor::~DiskMonitor() = default; |
| 141 | |
| 142 | int DiskMonitor::udev_monitor_fd() const { |
| 143 | return udev_monitor_->GetFileDescriptor(); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 144 | } |
| 145 | |
| 146 | bool DiskMonitor::Initialize() { |
| 147 | // Since there are no udev add events for the devices that already exist |
| 148 | // when the disk manager starts, emulate udev add events for these devices |
| 149 | // to correctly populate |disks_detected_|. |
Anand K Mistry | c0ece3d | 2020-01-28 15:55:29 +1100 | [diff] [blame] | 150 | EnumerateBlockDevices(base::BindRepeating( |
| 151 | &DiskMonitor::EmulateAddBlockDeviceEvent, base::Unretained(this))); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 152 | return true; |
| 153 | } |
| 154 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 155 | bool DiskMonitor::EmulateAddBlockDeviceEvent( |
| 156 | std::unique_ptr<brillo::UdevDevice> dev) { |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 157 | DeviceEventList events; |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 158 | LOG(INFO) << "Emulating action 'add' on device " << quote(dev->GetSysName()); |
| 159 | LogUdevDevice(*dev); |
| 160 | ProcessBlockDeviceEvents(std::move(dev), kUdevAddAction, &events); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 161 | return true; // Continue the enumeration. |
| 162 | } |
| 163 | |
| 164 | std::vector<Disk> DiskMonitor::EnumerateDisks() const { |
| 165 | std::vector<Disk> disks; |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 166 | EnumerateBlockDevices(base::BindRepeating(&AppendDiskIfNotIgnored, allowlist_, |
| 167 | base::Unretained(&disks))); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 168 | return disks; |
| 169 | } |
| 170 | |
| 171 | void DiskMonitor::EnumerateBlockDevices( |
Anand K Mistry | c0ece3d | 2020-01-28 15:55:29 +1100 | [diff] [blame] | 172 | base::RepeatingCallback<bool(std::unique_ptr<brillo::UdevDevice> dev)> |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 173 | callback) const { |
| 174 | std::unique_ptr<brillo::UdevEnumerate> enumerate = udev_->CreateEnumerate(); |
| 175 | enumerate->AddMatchSubsystem(kBlockSubsystem); |
| 176 | enumerate->ScanDevices(); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 177 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 178 | for (std::unique_ptr<brillo::UdevListEntry> entry = enumerate->GetListEntry(); |
| 179 | entry; entry = entry->GetNext()) { |
| 180 | std::unique_ptr<brillo::UdevDevice> dev = |
| 181 | udev_->CreateDeviceFromSysPath(entry->GetName()); |
| 182 | if (!dev) |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 183 | continue; |
| 184 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 185 | VLOG(1) << "Found device " << quote(dev->GetSysName()); |
| 186 | LogUdevDevice(*dev); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 187 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 188 | bool continue_enumeration = callback.Run(std::move(dev)); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 189 | if (!continue_enumeration) |
| 190 | break; |
| 191 | } |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 192 | } |
| 193 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 194 | void DiskMonitor::ProcessBlockDeviceEvents( |
| 195 | std::unique_ptr<brillo::UdevDevice> dev, |
| 196 | const char* action, |
| 197 | DeviceEventList* events) { |
| 198 | brillo::UdevDevice* raw_dev = dev.get(); |
| 199 | UdevDevice device(std::move(dev)); |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 200 | LogDevice(device); |
| 201 | if (!IsDeviceAllowed(device, allowlist_)) |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 202 | return; |
| 203 | |
| 204 | bool disk_added = false; |
| 205 | bool disk_removed = false; |
| 206 | bool child_disk_removed = false; |
| 207 | if (strcmp(action, kUdevAddAction) == 0) { |
| 208 | disk_added = true; |
| 209 | } else if (strcmp(action, kUdevRemoveAction) == 0) { |
| 210 | disk_removed = true; |
| 211 | } else if (strcmp(action, kUdevChangeAction) == 0) { |
| 212 | // For removable devices like CD-ROM, an eject request event |
| 213 | // is treated as disk removal, while a media change event with |
| 214 | // media available is treated as disk insertion. |
| 215 | if (device.IsPropertyTrue(kPropertyDiskEjectRequest)) { |
| 216 | disk_removed = true; |
| 217 | } else if (device.IsPropertyTrue(kPropertyDiskMediaChange)) { |
| 218 | if (device.IsMediaAvailable()) { |
| 219 | disk_added = true; |
| 220 | } else { |
| 221 | child_disk_removed = true; |
| 222 | } |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | std::string device_path = device.NativePath(); |
| 227 | if (disk_added) { |
| 228 | if (device.IsAutoMountable()) { |
Qijiang Fan | 5243904 | 2020-06-17 15:34:38 +0900 | [diff] [blame] | 229 | if (base::Contains(disks_detected_, device_path)) { |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 230 | // Disk already exists, so remove it and then add it again. |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 231 | LOG(INFO) << "Re-add block device " << quote(device_path); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 232 | events->push_back(DeviceEvent(DeviceEvent::kDiskRemoved, device_path)); |
| 233 | } else { |
| 234 | disks_detected_[device_path] = {}; |
| 235 | |
| 236 | // Add the disk as a child of its parent if the parent is already |
| 237 | // added to |disks_detected_|. |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 238 | std::unique_ptr<brillo::UdevDevice> parent = raw_dev->GetParent(); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 239 | if (parent) { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 240 | std::string parent_device_path = |
| 241 | UdevDevice(std::move(parent)).NativePath(); |
Qijiang Fan | 5243904 | 2020-06-17 15:34:38 +0900 | [diff] [blame] | 242 | if (base::Contains(disks_detected_, parent_device_path)) { |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 243 | disks_detected_[parent_device_path].insert(device_path); |
| 244 | } |
| 245 | } |
| 246 | } |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 247 | LOG(INFO) << "Add block device " << quote(device_path); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 248 | events->push_back(DeviceEvent(DeviceEvent::kDiskAdded, device_path)); |
| 249 | } |
| 250 | } else if (disk_removed) { |
| 251 | disks_detected_.erase(device_path); |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 252 | LOG(INFO) << "Remove block device " << quote(device_path); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 253 | events->push_back(DeviceEvent(DeviceEvent::kDiskRemoved, device_path)); |
| 254 | } else if (child_disk_removed) { |
| 255 | bool no_child_disks_found = true; |
Qijiang Fan | 5243904 | 2020-06-17 15:34:38 +0900 | [diff] [blame] | 256 | if (base::Contains(disks_detected_, device_path)) { |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 257 | auto& child_disks = disks_detected_[device_path]; |
| 258 | no_child_disks_found = child_disks.empty(); |
| 259 | for (const auto& child_disk : child_disks) { |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 260 | LOG(INFO) << "Remove child device " << quote(child_disk); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 261 | events->push_back(DeviceEvent(DeviceEvent::kDiskRemoved, child_disk)); |
| 262 | } |
| 263 | } |
| 264 | // When the device contains a full-disk partition, there are no child disks. |
| 265 | // Remove the device instead. |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 266 | if (no_child_disks_found) { |
| 267 | LOG(INFO) << "Remove parent device " << quote(device_path); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 268 | events->push_back(DeviceEvent(DeviceEvent::kDiskRemoved, device_path)); |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 269 | } |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 270 | } |
| 271 | } |
| 272 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 273 | void DiskMonitor::ProcessMmcOrScsiDeviceEvents( |
| 274 | std::unique_ptr<brillo::UdevDevice> dev, |
| 275 | const char* action, |
| 276 | DeviceEventList* events) { |
| 277 | UdevDevice device(std::move(dev)); |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 278 | LogDevice(device); |
| 279 | if (!IsDeviceAllowed(device, allowlist_)) |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 280 | return; |
| 281 | |
| 282 | std::string device_path = device.NativePath(); |
| 283 | if (strcmp(action, kUdevAddAction) == 0) { |
Qijiang Fan | 5243904 | 2020-06-17 15:34:38 +0900 | [diff] [blame] | 284 | if (base::Contains(devices_detected_, device_path)) { |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 285 | LOG(INFO) << "Re-add device " << quote(device_path); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 286 | events->push_back(DeviceEvent(DeviceEvent::kDeviceScanned, device_path)); |
| 287 | } else { |
| 288 | devices_detected_.insert(device_path); |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 289 | LOG(INFO) << "Add device " << quote(device_path); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 290 | events->push_back(DeviceEvent(DeviceEvent::kDeviceAdded, device_path)); |
| 291 | } |
| 292 | } else if (strcmp(action, kUdevRemoveAction) == 0) { |
Qijiang Fan | 5243904 | 2020-06-17 15:34:38 +0900 | [diff] [blame] | 293 | if (base::Contains(devices_detected_, device_path)) { |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 294 | devices_detected_.erase(device_path); |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 295 | LOG(INFO) << "Remove device " << quote(device_path); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 296 | events->push_back(DeviceEvent(DeviceEvent::kDeviceRemoved, device_path)); |
| 297 | } |
| 298 | } |
| 299 | } |
| 300 | |
| 301 | bool DiskMonitor::GetDeviceEvents(DeviceEventList* events) { |
| 302 | CHECK(events) << "Invalid device event list"; |
| 303 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 304 | std::unique_ptr<brillo::UdevDevice> dev = udev_monitor_->ReceiveDevice(); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 305 | if (!dev) { |
| 306 | LOG(WARNING) << "Ignore device event with no associated udev device."; |
| 307 | return false; |
| 308 | } |
| 309 | |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 310 | const char* sys_path = dev->GetSysPath(); |
| 311 | const char* subsystem = dev->GetSubsystem(); |
| 312 | const char* action = dev->GetAction(); |
François Degros | 16ad1ae | 2019-07-17 16:02:39 +1000 | [diff] [blame] | 313 | |
| 314 | LOG(INFO) << "Got action " << quote(action) << " on device " |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 315 | << quote(dev->GetSysName()); |
| 316 | LogUdevDevice(*dev); |
François Degros | 16ad1ae | 2019-07-17 16:02:39 +1000 | [diff] [blame] | 317 | |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 318 | if (!sys_path || !subsystem || !action) { |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 319 | return false; |
| 320 | } |
| 321 | |
| 322 | // |udev_monitor_| only monitors block, mmc, and scsi device changes, so |
| 323 | // subsystem is either "block", "mmc", or "scsi". |
| 324 | if (strcmp(subsystem, kBlockSubsystem) == 0) { |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 325 | ProcessBlockDeviceEvents(std::move(dev), action, events); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 326 | } else { |
| 327 | // strcmp(subsystem, kMmcSubsystem) == 0 || |
| 328 | // strcmp(subsystem, kScsiSubsystem) == 0 |
Anand K Mistry | 5757f63 | 2019-09-11 13:29:41 +1000 | [diff] [blame] | 329 | ProcessMmcOrScsiDeviceEvents(std::move(dev), action, events); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 330 | } |
| 331 | |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 332 | return true; |
| 333 | } |
| 334 | |
| 335 | bool DiskMonitor::GetDiskByDevicePath(const base::FilePath& device_path, |
| 336 | Disk* disk) const { |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 337 | LOG(INFO) << "Get disk by path " << quote(device_path); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 338 | if (device_path.empty()) |
| 339 | return false; |
| 340 | |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 341 | std::unique_ptr<UdevDevice> device; |
Anand K Mistry | c0ece3d | 2020-01-28 15:55:29 +1100 | [diff] [blame] | 342 | EnumerateBlockDevices(base::BindRepeating( |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 343 | &MatchDiskByPath, device_path.value(), base::Unretained(&device))); |
| 344 | if (!device) |
| 345 | return false; |
| 346 | |
| 347 | LogDevice(*device); |
| 348 | if (!IsDeviceAllowed(*device, allowlist_)) |
| 349 | return false; |
| 350 | |
| 351 | if (disk) |
| 352 | *disk = device->ToDisk(); |
| 353 | return true; |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 354 | } |
| 355 | |
Sergei Datsenko | ad8b504 | 2020-09-21 22:39:04 +1000 | [diff] [blame] | 356 | void DiskMonitor::AddDeviceToAllowlist(const base::FilePath& device) { |
| 357 | allowlist_.insert(device.value()); |
| 358 | } |
| 359 | |
| 360 | void DiskMonitor::RemoveDeviceFromAllowlist(const base::FilePath& device) { |
| 361 | allowlist_.erase(device.value()); |
Sergei Datsenko | 1682189 | 2019-04-05 11:26:38 +1100 | [diff] [blame] | 362 | } |
| 363 | |
| 364 | } // namespace cros_disks |