blob: 2943fb73232bf81ac0939bacf63f5f41a0900734 [file] [log] [blame]
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001/*
Tom Cherryed506f72017-05-25 15:58:59 -07002 * Copyright (C) 2007 The Android Open Source Project
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Tom Cherrycc054c92017-04-05 17:55:46 -070017#include "devices.h"
18
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070019#include <errno.h>
Daniel Leungc0c1ffe2012-07-02 11:32:30 -070020#include <fnmatch.h>
Elliott Hughes51056c42017-05-18 09:13:15 -070021#include <sys/sysmacros.h>
Elliott Hughesf39f7f12016-08-31 14:41:51 -070022#include <unistd.h>
23
James Hawkins588a2ca2016-02-18 14:52:46 -080024#include <memory>
25
Tom Cherry3f5eaae52017-04-06 16:30:22 -070026#include <android-base/logging.h>
Rob Herring6de783a2016-05-06 10:06:59 -050027#include <android-base/stringprintf.h>
Tom Cherry2e344f92017-04-04 17:53:45 -070028#include <android-base/strings.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070029#include <private/android_filesystem_config.h>
30#include <selinux/android.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070031#include <selinux/selinux.h>
Vernon Tang3f582e92011-04-25 13:08:17 +100032
Tom Cherryfe062052017-04-24 16:59:05 -070033#include "ueventd.h"
Colin Crossb0ab94b2010-04-08 16:16:20 -070034#include "util.h"
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070035
Tom Cherrye7656b72017-05-01 17:10:09 -070036#ifdef _INIT_INIT_H
37#error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
38#endif
39
Andrew Boiea885d042013-09-13 17:41:20 -070040/* Given a path that may start with a PCI device, populate the supplied buffer
41 * with the PCI domain/bus number and the peripheral ID and return 0.
42 * If it doesn't start with a PCI device, or there is some error, return -1 */
Tom Cherryed506f72017-05-25 15:58:59 -070043static bool FindPciDevicePrefix(const std::string& path, std::string* result) {
Tom Cherry2e344f92017-04-04 17:53:45 -070044 result->clear();
Andrew Boiea885d042013-09-13 17:41:20 -070045
Tom Cherry2e344f92017-04-04 17:53:45 -070046 if (!android::base::StartsWith(path, "/devices/pci")) return false;
Andrew Boiea885d042013-09-13 17:41:20 -070047
48 /* Beginning of the prefix is the initial "pci" after "/devices/" */
Tom Cherry2e344f92017-04-04 17:53:45 -070049 std::string::size_type start = 9;
Andrew Boiea885d042013-09-13 17:41:20 -070050
51 /* End of the prefix is two path '/' later, capturing the domain/bus number
52 * and the peripheral ID. Example: pci0000:00/0000:00:1f.2 */
Tom Cherry2e344f92017-04-04 17:53:45 -070053 auto end = path.find('/', start);
54 if (end == std::string::npos) return false;
Andrew Boiea885d042013-09-13 17:41:20 -070055
Tom Cherry2e344f92017-04-04 17:53:45 -070056 end = path.find('/', end + 1);
57 if (end == std::string::npos) return false;
Andrew Boiea885d042013-09-13 17:41:20 -070058
Tom Cherry2e344f92017-04-04 17:53:45 -070059 auto length = end - start;
60 if (length <= 4) {
61 // The minimum string that will get to this check is 'pci/', which is malformed,
62 // so return false
63 return false;
64 }
65
66 *result = path.substr(start, length);
67 return true;
Andrew Boiea885d042013-09-13 17:41:20 -070068}
69
Jeremy Compostella937309d2017-03-03 16:27:29 +010070/* Given a path that may start with a virtual block device, populate
71 * the supplied buffer with the virtual block device ID and return 0.
72 * If it doesn't start with a virtual block device, or there is some
73 * error, return -1 */
Tom Cherryed506f72017-05-25 15:58:59 -070074static bool FindVbdDevicePrefix(const std::string& path, std::string* result) {
Tom Cherry2e344f92017-04-04 17:53:45 -070075 result->clear();
76
77 if (!android::base::StartsWith(path, "/devices/vbd-")) return false;
Jeremy Compostella937309d2017-03-03 16:27:29 +010078
79 /* Beginning of the prefix is the initial "vbd-" after "/devices/" */
Tom Cherry2e344f92017-04-04 17:53:45 -070080 std::string::size_type start = 13;
Jeremy Compostella937309d2017-03-03 16:27:29 +010081
82 /* End of the prefix is one path '/' later, capturing the
83 virtual block device ID. Example: 768 */
Tom Cherry2e344f92017-04-04 17:53:45 -070084 auto end = path.find('/', start);
85 if (end == std::string::npos) return false;
Jeremy Compostella937309d2017-03-03 16:27:29 +010086
Tom Cherry2e344f92017-04-04 17:53:45 -070087 auto length = end - start;
88 if (length == 0) return false;
Jeremy Compostella937309d2017-03-03 16:27:29 +010089
Tom Cherry2e344f92017-04-04 17:53:45 -070090 *result = path.substr(start, length);
91 return true;
Jeremy Compostella937309d2017-03-03 16:27:29 +010092}
93
Tom Cherryed506f72017-05-25 15:58:59 -070094Permissions::Permissions(const std::string& name, mode_t perm, uid_t uid, gid_t gid)
95 : name_(name), perm_(perm), uid_(uid), gid_(gid), prefix_(false), wildcard_(false) {
96 // Set 'prefix_' or 'wildcard_' based on the below cases:
97 //
98 // 1) No '*' in 'name' -> Neither are set and Match() checks a given path for strict
99 // equality with 'name'
100 //
101 // 2) '*' only appears as the last character in 'name' -> 'prefix'_ is set to true and
102 // Match() checks if 'name' is a prefix of a given path.
103 //
104 // 3) '*' appears elsewhere -> 'wildcard_' is set to true and Match() uses fnmatch()
105 // with FNM_PATHNAME to compare 'name' to a given path.
106
107 auto wildcard_position = name_.find('*');
108 if (wildcard_position != std::string::npos) {
109 if (wildcard_position == name_.length() - 1) {
110 prefix_ = true;
111 name_.pop_back();
112 } else {
113 wildcard_ = true;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700114 }
Elliott Hughesc0e919c2015-02-04 14:46:36 -0800115 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700116}
117
Tom Cherryed506f72017-05-25 15:58:59 -0700118bool Permissions::Match(const std::string& path) const {
119 if (prefix_) return android::base::StartsWith(path, name_.c_str());
120 if (wildcard_) return fnmatch(name_.c_str(), path.c_str(), FNM_PATHNAME) == 0;
121 return path == name_;
122}
123
124bool SysfsPermissions::MatchWithSubsystem(const std::string& path,
125 const std::string& subsystem) const {
126 std::string path_basename = android::base::Basename(path);
127 if (name().find(subsystem) != std::string::npos) {
128 if (Match("/sys/class/" + subsystem + "/" + path_basename)) return true;
129 if (Match("/sys/bus/" + subsystem + "/devices/" + path_basename)) return true;
130 }
131 return Match(path);
132}
133
134void SysfsPermissions::SetPermissions(const std::string& path) const {
135 std::string attribute_file = path + "/" + attribute_;
136 LOG(VERBOSE) << "fixup " << attribute_file << " " << uid() << " " << gid() << " " << std::oct
137 << perm();
138
139 if (access(attribute_file.c_str(), F_OK) == 0) {
140 if (chown(attribute_file.c_str(), uid(), gid()) != 0) {
141 PLOG(ERROR) << "chown(" << attribute_file << ", " << uid() << ", " << gid()
142 << ") failed";
143 }
144 if (chmod(attribute_file.c_str(), perm()) != 0) {
145 PLOG(ERROR) << "chmod(" << attribute_file << ", " << perm() << ") failed";
146 }
147 }
148}
149
Sandeep Patilcd2ba0d2017-06-21 12:46:41 -0700150// Given a path that may start with a platform device, find the parent platform device by finding a
151// parent directory with a 'subsystem' symlink that points to the platform bus.
152// If it doesn't start with a platform device, return false
153bool DeviceHandler::FindPlatformDevice(std::string path, std::string* platform_device_path) const {
154 platform_device_path->clear();
155
156 // Uevents don't contain the mount point, so we need to add it here.
157 path.insert(0, sysfs_mount_point_);
158
159 std::string directory = android::base::Dirname(path);
160
161 while (directory != "/" && directory != ".") {
162 std::string subsystem_link_path;
163 if (android::base::Realpath(directory + "/subsystem", &subsystem_link_path) &&
164 subsystem_link_path == sysfs_mount_point_ + "/bus/platform") {
165 // We need to remove the mount point that we added above before returning.
166 directory.erase(0, sysfs_mount_point_.size());
167 *platform_device_path = directory;
Tom Cherryed506f72017-05-25 15:58:59 -0700168 return true;
169 }
Sandeep Patilcd2ba0d2017-06-21 12:46:41 -0700170
171 auto last_slash = path.rfind('/');
172 if (last_slash == std::string::npos) return false;
173
174 path.erase(last_slash);
175 directory = android::base::Dirname(path);
Tom Cherryed506f72017-05-25 15:58:59 -0700176 }
Sandeep Patilcd2ba0d2017-06-21 12:46:41 -0700177
Tom Cherryed506f72017-05-25 15:58:59 -0700178 return false;
179}
180
181void DeviceHandler::FixupSysPermissions(const std::string& upath,
182 const std::string& subsystem) const {
183 // upaths omit the "/sys" that paths in this list
184 // contain, so we prepend it...
185 std::string path = "/sys" + upath;
186
187 for (const auto& s : sysfs_permissions_) {
188 if (s.MatchWithSubsystem(path, subsystem)) s.SetPermissions(path);
189 }
190
Tom Cherryc5833052017-05-16 15:35:41 -0700191 if (!skip_restorecon_ && access(path.c_str(), F_OK) == 0) {
Tom Cherryed506f72017-05-25 15:58:59 -0700192 LOG(VERBOSE) << "restorecon_recursive: " << path;
193 if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
194 PLOG(ERROR) << "selinux_android_restorecon(" << path << ") failed";
195 }
196 }
197}
198
199std::tuple<mode_t, uid_t, gid_t> DeviceHandler::GetDevicePermissions(
200 const std::string& path, const std::vector<std::string>& links) const {
201 // Search the perms list in reverse so that ueventd.$hardware can override ueventd.rc.
202 for (auto it = dev_permissions_.crbegin(); it != dev_permissions_.crend(); ++it) {
203 if (it->Match(path) || std::any_of(links.cbegin(), links.cend(),
204 [it](const auto& link) { return it->Match(link); })) {
205 return {it->perm(), it->uid(), it->gid()};
206 }
207 }
208 /* Default if nothing found. */
209 return {0600, 0, 0};
210}
211
212void DeviceHandler::MakeDevice(const std::string& path, int block, int major, int minor,
213 const std::vector<std::string>& links) const {
214 auto[mode, uid, gid] = GetDevicePermissions(path, links);
215 mode |= (block ? S_IFBLK : S_IFCHR);
216
217 char* secontext = nullptr;
218 if (sehandle_) {
219 std::vector<const char*> c_links;
220 for (const auto& link : links) {
221 c_links.emplace_back(link.c_str());
222 }
223 c_links.emplace_back(nullptr);
224 if (selabel_lookup_best_match(sehandle_, &secontext, path.c_str(), &c_links[0], mode)) {
225 PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
226 return;
227 }
228 setfscreatecon(secontext);
229 }
230
231 dev_t dev = makedev(major, minor);
232 /* Temporarily change egid to avoid race condition setting the gid of the
233 * device node. Unforunately changing the euid would prevent creation of
234 * some device nodes, so the uid has to be set with chown() and is still
235 * racy. Fixing the gid race at least fixed the issue with system_server
236 * opening dynamic input devices under the AID_INPUT gid. */
237 if (setegid(gid)) {
238 PLOG(ERROR) << "setegid(" << gid << ") for " << path << " device failed";
239 goto out;
240 }
241 /* If the node already exists update its SELinux label to handle cases when
242 * it was created with the wrong context during coldboot procedure. */
243 if (mknod(path.c_str(), mode, dev) && (errno == EEXIST) && secontext) {
244 char* fcon = nullptr;
245 int rc = lgetfilecon(path.c_str(), &fcon);
246 if (rc < 0) {
247 PLOG(ERROR) << "Cannot get SELinux label on '" << path << "' device";
248 goto out;
249 }
250
251 bool different = strcmp(fcon, secontext) != 0;
252 freecon(fcon);
253
254 if (different && lsetfilecon(path.c_str(), secontext)) {
255 PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path
256 << "' device";
257 }
258 }
259
260out:
261 chown(path.c_str(), uid, -1);
262 if (setegid(AID_ROOT)) {
263 PLOG(FATAL) << "setegid(AID_ROOT) failed";
264 }
265
266 if (secontext) {
267 freecon(secontext);
268 setfscreatecon(nullptr);
269 }
270}
271
272std::vector<std::string> DeviceHandler::GetCharacterDeviceSymlinks(const Uevent& uevent) const {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700273 std::string parent_device;
Sandeep Patilcd2ba0d2017-06-21 12:46:41 -0700274 if (!FindPlatformDevice(uevent.path, &parent_device)) return {};
Benoit Gobyd2278632010-08-03 14:36:02 -0700275
Tom Cherry1ab8f552017-04-06 14:41:30 -0700276 // skip path to the parent driver
Tom Cherryed506f72017-05-25 15:58:59 -0700277 std::string path = uevent.path.substr(parent_device.length());
Benoit Gobyd2278632010-08-03 14:36:02 -0700278
Tom Cherry1ab8f552017-04-06 14:41:30 -0700279 if (!android::base::StartsWith(path, "/usb")) return {};
Tom Cherry2e344f92017-04-04 17:53:45 -0700280
281 // skip root hub name and device. use device interface
282 // skip 3 slashes, including the first / by starting the search at the 1st character, not 0th.
283 // then extract what comes between the 3rd and 4th slash
284 // e.g. "/usb/usb_device/name/tty2-1:1.0" -> "name"
285
286 std::string::size_type start = 0;
Tom Cherry1ab8f552017-04-06 14:41:30 -0700287 start = path.find('/', start + 1);
Tom Cherry2e344f92017-04-04 17:53:45 -0700288 if (start == std::string::npos) return {};
289
Tom Cherry1ab8f552017-04-06 14:41:30 -0700290 start = path.find('/', start + 1);
Tom Cherry2e344f92017-04-04 17:53:45 -0700291 if (start == std::string::npos) return {};
292
Tom Cherry1ab8f552017-04-06 14:41:30 -0700293 auto end = path.find('/', start + 1);
Tom Cherry2e344f92017-04-04 17:53:45 -0700294 if (end == std::string::npos) return {};
295
296 start++; // Skip the first '/'
297
298 auto length = end - start;
299 if (length == 0) return {};
300
Tom Cherry1ab8f552017-04-06 14:41:30 -0700301 auto name_string = path.substr(start, length);
Tom Cherry2e344f92017-04-04 17:53:45 -0700302
Tom Cherry2e344f92017-04-04 17:53:45 -0700303 std::vector<std::string> links;
Tom Cherryed506f72017-05-25 15:58:59 -0700304 links.emplace_back("/dev/usb/" + uevent.subsystem + name_string);
Tom Cherry2e344f92017-04-04 17:53:45 -0700305
306 mkdir("/dev/usb", 0755);
Benoit Gobyd2278632010-08-03 14:36:02 -0700307
308 return links;
Benoit Gobyd2278632010-08-03 14:36:02 -0700309}
310
Tom Cherryc44f6a42017-04-05 15:58:31 -0700311// replaces any unacceptable characters with '_', the
312// length of the resulting string is equal to the input string
Tom Cherryed506f72017-05-25 15:58:59 -0700313void SanitizePartitionName(std::string* string) {
Tom Cherryc44f6a42017-04-05 15:58:31 -0700314 const char* accept =
315 "abcdefghijklmnopqrstuvwxyz"
316 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
317 "0123456789"
318 "_-.";
319
Tom Cherry2e344f92017-04-04 17:53:45 -0700320 if (!string) return;
Tom Cherryc44f6a42017-04-05 15:58:31 -0700321
Tom Cherry2e344f92017-04-04 17:53:45 -0700322 std::string::size_type pos = 0;
323 while ((pos = string->find_first_not_of(accept, pos)) != std::string::npos) {
324 (*string)[pos] = '_';
Tom Cherryc44f6a42017-04-05 15:58:31 -0700325 }
326}
327
Tom Cherryed506f72017-05-25 15:58:59 -0700328std::vector<std::string> DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uevent) const {
Tom Cherry2e344f92017-04-04 17:53:45 -0700329 std::string device;
Tom Cherry2e344f92017-04-04 17:53:45 -0700330 std::string type;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700331
Sandeep Patilcd2ba0d2017-06-21 12:46:41 -0700332 if (FindPlatformDevice(uevent.path, &device)) {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700333 // Skip /devices/platform or /devices/ if present
334 static const std::string devices_platform_prefix = "/devices/platform/";
335 static const std::string devices_prefix = "/devices/";
336
337 if (android::base::StartsWith(device, devices_platform_prefix.c_str())) {
338 device = device.substr(devices_platform_prefix.length());
339 } else if (android::base::StartsWith(device, devices_prefix.c_str())) {
340 device = device.substr(devices_prefix.length());
341 }
342
Andrew Boiea885d042013-09-13 17:41:20 -0700343 type = "platform";
Tom Cherryed506f72017-05-25 15:58:59 -0700344 } else if (FindPciDevicePrefix(uevent.path, &device)) {
Andrew Boiea885d042013-09-13 17:41:20 -0700345 type = "pci";
Tom Cherryed506f72017-05-25 15:58:59 -0700346 } else if (FindVbdDevicePrefix(uevent.path, &device)) {
Jeremy Compostella937309d2017-03-03 16:27:29 +0100347 type = "vbd";
Andrew Boiea885d042013-09-13 17:41:20 -0700348 } else {
Tom Cherry2e344f92017-04-04 17:53:45 -0700349 return {};
Andrew Boiea885d042013-09-13 17:41:20 -0700350 }
Dima Zavinf395c922013-03-06 16:23:57 -0800351
Tom Cherry2e344f92017-04-04 17:53:45 -0700352 std::vector<std::string> links;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700353
Sandeep Patil35403eb2017-02-08 20:27:12 -0800354 LOG(VERBOSE) << "found " << type << " device " << device;
Colin Crossfadb85e2011-03-30 18:32:12 -0700355
Tom Cherry2e344f92017-04-04 17:53:45 -0700356 auto link_path = "/dev/block/" + type + "/" + device;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700357
Tom Cherryed506f72017-05-25 15:58:59 -0700358 if (!uevent.partition_name.empty()) {
359 std::string partition_name_sanitized(uevent.partition_name);
360 SanitizePartitionName(&partition_name_sanitized);
361 if (partition_name_sanitized != uevent.partition_name) {
362 LOG(VERBOSE) << "Linking partition '" << uevent.partition_name << "' as '"
Tom Cherry2e344f92017-04-04 17:53:45 -0700363 << partition_name_sanitized << "'";
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700364 }
Tom Cherry2e344f92017-04-04 17:53:45 -0700365 links.emplace_back(link_path + "/by-name/" + partition_name_sanitized);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700366 }
367
Tom Cherryed506f72017-05-25 15:58:59 -0700368 if (uevent.partition_num >= 0) {
369 links.emplace_back(link_path + "/by-num/p" + std::to_string(uevent.partition_num));
Colin Crossb0ab94b2010-04-08 16:16:20 -0700370 }
371
Tom Cherryed506f72017-05-25 15:58:59 -0700372 auto last_slash = uevent.path.rfind('/');
373 links.emplace_back(link_path + "/" + uevent.path.substr(last_slash + 1));
Colin Crossb0ab94b2010-04-08 16:16:20 -0700374
375 return links;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700376}
377
Tom Cherryed506f72017-05-25 15:58:59 -0700378void DeviceHandler::HandleDevice(const std::string& action, const std::string& devpath, int block,
379 int major, int minor, const std::vector<std::string>& links) const {
Tom Cherrye3e48212017-04-11 13:53:37 -0700380 if (action == "add") {
Tom Cherryed506f72017-05-25 15:58:59 -0700381 MakeDevice(devpath, block, major, minor, links);
Tom Cherry2e344f92017-04-04 17:53:45 -0700382 for (const auto& link : links) {
Tom Cherryed506f72017-05-25 15:58:59 -0700383 if (mkdir_recursive(android::base::Dirname(link), 0755, sehandle_)) {
384 PLOG(ERROR) << "Failed to create directory " << android::base::Dirname(link);
385 }
386
387 if (symlink(devpath.c_str(), link.c_str()) && errno != EEXIST) {
388 PLOG(ERROR) << "Failed to symlink " << devpath << " to " << link;
389 }
Colin Crossb0ab94b2010-04-08 16:16:20 -0700390 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700391 }
392
Tom Cherrye3e48212017-04-11 13:53:37 -0700393 if (action == "remove") {
Tom Cherry2e344f92017-04-04 17:53:45 -0700394 for (const auto& link : links) {
Tom Cherryed506f72017-05-25 15:58:59 -0700395 std::string link_path;
396 if (android::base::Readlink(link, &link_path) && link_path == devpath) {
397 unlink(link.c_str());
398 }
Colin Crossb0ab94b2010-04-08 16:16:20 -0700399 }
Tom Cherrye3e48212017-04-11 13:53:37 -0700400 unlink(devpath.c_str());
Colin Crossb0ab94b2010-04-08 16:16:20 -0700401 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700402}
403
Tom Cherryed506f72017-05-25 15:58:59 -0700404void DeviceHandler::HandleBlockDeviceEvent(const Uevent& uevent) const {
Tom Cherry3fa46732017-04-11 14:19:50 -0700405 // if it's not a /dev device, nothing to do
Tom Cherryed506f72017-05-25 15:58:59 -0700406 if (uevent.major < 0 || uevent.minor < 0) return;
Colin Crosseb5ba832011-03-30 17:37:17 -0700407
Tom Cherry3fa46732017-04-11 14:19:50 -0700408 const char* base = "/dev/block/";
Tom Cherryed506f72017-05-25 15:58:59 -0700409 make_dir(base, 0755, sehandle_);
Colin Crosseb5ba832011-03-30 17:37:17 -0700410
Tom Cherryed506f72017-05-25 15:58:59 -0700411 std::string name = android::base::Basename(uevent.path);
Tom Cherry3fa46732017-04-11 14:19:50 -0700412 std::string devpath = base + name;
413
Tom Cherry2e344f92017-04-04 17:53:45 -0700414 std::vector<std::string> links;
Tom Cherryed506f72017-05-25 15:58:59 -0700415 if (android::base::StartsWith(uevent.path, "/devices")) {
416 links = GetBlockDeviceSymlinks(uevent);
Tom Cherrye3e48212017-04-11 13:53:37 -0700417 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700418
Tom Cherryed506f72017-05-25 15:58:59 -0700419 HandleDevice(uevent.action, devpath, 1, uevent.major, uevent.minor, links);
Colin Crosseb5ba832011-03-30 17:37:17 -0700420}
421
Tom Cherryed506f72017-05-25 15:58:59 -0700422void DeviceHandler::HandleGenericDeviceEvent(const Uevent& uevent) const {
Tom Cherry3fa46732017-04-11 14:19:50 -0700423 // if it's not a /dev device, nothing to do
Tom Cherryed506f72017-05-25 15:58:59 -0700424 if (uevent.major < 0 || uevent.minor < 0) return;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800425
Tom Cherry3fa46732017-04-11 14:19:50 -0700426 std::string devpath;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800427
Tom Cherryed506f72017-05-25 15:58:59 -0700428 if (android::base::StartsWith(uevent.subsystem, "usb")) {
429 if (uevent.subsystem == "usb") {
430 if (!uevent.device_name.empty()) {
431 devpath = "/dev/" + uevent.device_name;
Tom Cherry3fa46732017-04-11 14:19:50 -0700432 } else {
433 // This imitates the file system that would be created
434 // if we were using devfs instead.
435 // Minors are broken up into groups of 128, starting at "001"
Tom Cherryed506f72017-05-25 15:58:59 -0700436 int bus_id = uevent.minor / 128 + 1;
437 int device_id = uevent.minor % 128 + 1;
Tom Cherry3fa46732017-04-11 14:19:50 -0700438 devpath = android::base::StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id);
439 }
Tom Cherry3fa46732017-04-11 14:19:50 -0700440 } else {
441 // ignore other USB events
442 return;
443 }
Tom Cherryed506f72017-05-25 15:58:59 -0700444 } else if (const auto subsystem =
445 std::find(subsystems_.cbegin(), subsystems_.cend(), uevent.subsystem);
446 subsystem != subsystems_.cend()) {
Tom Cherryfe062052017-04-24 16:59:05 -0700447 devpath = subsystem->ParseDevPath(uevent);
Tom Cherry780a71e2017-04-04 16:30:40 -0700448 } else {
Tom Cherryed506f72017-05-25 15:58:59 -0700449 devpath = "/dev/" + android::base::Basename(uevent.path);
Tom Cherry780a71e2017-04-04 16:30:40 -0700450 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700451
Tom Cherryed506f72017-05-25 15:58:59 -0700452 mkdir_recursive(android::base::Dirname(devpath), 0755, sehandle_);
Tom Cherryfe062052017-04-24 16:59:05 -0700453
Tom Cherryed506f72017-05-25 15:58:59 -0700454 auto links = GetCharacterDeviceSymlinks(uevent);
Colin Crosseb5ba832011-03-30 17:37:17 -0700455
Tom Cherryed506f72017-05-25 15:58:59 -0700456 HandleDevice(uevent.action, devpath, 0, uevent.major, uevent.minor, links);
Colin Crosseb5ba832011-03-30 17:37:17 -0700457}
458
Tom Cherryed506f72017-05-25 15:58:59 -0700459void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) {
460 if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
461 FixupSysPermissions(uevent.path, uevent.subsystem);
Tom Cherrye3e48212017-04-11 13:53:37 -0700462 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700463
Tom Cherryed506f72017-05-25 15:58:59 -0700464 if (uevent.subsystem == "block") {
465 HandleBlockDeviceEvent(uevent);
Colin Crosseb5ba832011-03-30 17:37:17 -0700466 } else {
Tom Cherryed506f72017-05-25 15:58:59 -0700467 HandleGenericDeviceEvent(uevent);
Colin Crosseb5ba832011-03-30 17:37:17 -0700468 }
469}
470
Tom Cherryed506f72017-05-25 15:58:59 -0700471DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions,
472 std::vector<SysfsPermissions> sysfs_permissions,
Tom Cherryc5833052017-05-16 15:35:41 -0700473 std::vector<Subsystem> subsystems, bool skip_restorecon)
Tom Cherryed506f72017-05-25 15:58:59 -0700474 : dev_permissions_(std::move(dev_permissions)),
475 sysfs_permissions_(std::move(sysfs_permissions)),
476 subsystems_(std::move(subsystems)),
Tom Cherryc5833052017-05-16 15:35:41 -0700477 sehandle_(selinux_android_file_context_handle()),
Sandeep Patilcd2ba0d2017-06-21 12:46:41 -0700478 skip_restorecon_(skip_restorecon),
479 sysfs_mount_point_("/sys") {}
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700480
Tom Cherryed506f72017-05-25 15:58:59 -0700481DeviceHandler::DeviceHandler()
482 : DeviceHandler(std::vector<Permissions>{}, std::vector<SysfsPermissions>{},
Tom Cherryc5833052017-05-16 15:35:41 -0700483 std::vector<Subsystem>{}, false) {}