blob: c52d8f8600e56070ddbcd49e8ef7ebea81fd1f6a [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
150// Given a path that may start with a platform device, find the length of the
151// platform device prefix. If it doesn't start with a platform device, return false
152bool PlatformDeviceList::Find(const std::string& path, std::string* out_path) const {
153 out_path->clear();
154 // platform_devices is searched backwards, since parents are added before their children,
155 // and we want to match as deep of a child as we can.
156 for (auto it = platform_devices_.crbegin(); it != platform_devices_.crend(); ++it) {
157 auto platform_device_path_length = it->length();
158 if (platform_device_path_length < path.length() &&
159 path[platform_device_path_length] == '/' &&
160 android::base::StartsWith(path, it->c_str())) {
161 *out_path = *it;
162 return true;
163 }
164 }
165 return false;
166}
167
168void DeviceHandler::FixupSysPermissions(const std::string& upath,
169 const std::string& subsystem) const {
170 // upaths omit the "/sys" that paths in this list
171 // contain, so we prepend it...
172 std::string path = "/sys" + upath;
173
174 for (const auto& s : sysfs_permissions_) {
175 if (s.MatchWithSubsystem(path, subsystem)) s.SetPermissions(path);
176 }
177
Tom Cherryc5833052017-05-16 15:35:41 -0700178 if (!skip_restorecon_ && access(path.c_str(), F_OK) == 0) {
Tom Cherryed506f72017-05-25 15:58:59 -0700179 LOG(VERBOSE) << "restorecon_recursive: " << path;
180 if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
181 PLOG(ERROR) << "selinux_android_restorecon(" << path << ") failed";
182 }
183 }
184}
185
186std::tuple<mode_t, uid_t, gid_t> DeviceHandler::GetDevicePermissions(
187 const std::string& path, const std::vector<std::string>& links) const {
188 // Search the perms list in reverse so that ueventd.$hardware can override ueventd.rc.
189 for (auto it = dev_permissions_.crbegin(); it != dev_permissions_.crend(); ++it) {
190 if (it->Match(path) || std::any_of(links.cbegin(), links.cend(),
191 [it](const auto& link) { return it->Match(link); })) {
192 return {it->perm(), it->uid(), it->gid()};
193 }
194 }
195 /* Default if nothing found. */
196 return {0600, 0, 0};
197}
198
199void DeviceHandler::MakeDevice(const std::string& path, int block, int major, int minor,
200 const std::vector<std::string>& links) const {
201 auto[mode, uid, gid] = GetDevicePermissions(path, links);
202 mode |= (block ? S_IFBLK : S_IFCHR);
203
204 char* secontext = nullptr;
205 if (sehandle_) {
206 std::vector<const char*> c_links;
207 for (const auto& link : links) {
208 c_links.emplace_back(link.c_str());
209 }
210 c_links.emplace_back(nullptr);
211 if (selabel_lookup_best_match(sehandle_, &secontext, path.c_str(), &c_links[0], mode)) {
212 PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
213 return;
214 }
215 setfscreatecon(secontext);
216 }
217
218 dev_t dev = makedev(major, minor);
219 /* Temporarily change egid to avoid race condition setting the gid of the
220 * device node. Unforunately changing the euid would prevent creation of
221 * some device nodes, so the uid has to be set with chown() and is still
222 * racy. Fixing the gid race at least fixed the issue with system_server
223 * opening dynamic input devices under the AID_INPUT gid. */
224 if (setegid(gid)) {
225 PLOG(ERROR) << "setegid(" << gid << ") for " << path << " device failed";
226 goto out;
227 }
228 /* If the node already exists update its SELinux label to handle cases when
229 * it was created with the wrong context during coldboot procedure. */
230 if (mknod(path.c_str(), mode, dev) && (errno == EEXIST) && secontext) {
231 char* fcon = nullptr;
232 int rc = lgetfilecon(path.c_str(), &fcon);
233 if (rc < 0) {
234 PLOG(ERROR) << "Cannot get SELinux label on '" << path << "' device";
235 goto out;
236 }
237
238 bool different = strcmp(fcon, secontext) != 0;
239 freecon(fcon);
240
241 if (different && lsetfilecon(path.c_str(), secontext)) {
242 PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path
243 << "' device";
244 }
245 }
246
247out:
248 chown(path.c_str(), uid, -1);
249 if (setegid(AID_ROOT)) {
250 PLOG(FATAL) << "setegid(AID_ROOT) failed";
251 }
252
253 if (secontext) {
254 freecon(secontext);
255 setfscreatecon(nullptr);
256 }
257}
258
259std::vector<std::string> DeviceHandler::GetCharacterDeviceSymlinks(const Uevent& uevent) const {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700260 std::string parent_device;
Tom Cherryed506f72017-05-25 15:58:59 -0700261 if (!platform_devices_.Find(uevent.path, &parent_device)) return {};
Benoit Gobyd2278632010-08-03 14:36:02 -0700262
Tom Cherry1ab8f552017-04-06 14:41:30 -0700263 // skip path to the parent driver
Tom Cherryed506f72017-05-25 15:58:59 -0700264 std::string path = uevent.path.substr(parent_device.length());
Benoit Gobyd2278632010-08-03 14:36:02 -0700265
Tom Cherry1ab8f552017-04-06 14:41:30 -0700266 if (!android::base::StartsWith(path, "/usb")) return {};
Tom Cherry2e344f92017-04-04 17:53:45 -0700267
268 // skip root hub name and device. use device interface
269 // skip 3 slashes, including the first / by starting the search at the 1st character, not 0th.
270 // then extract what comes between the 3rd and 4th slash
271 // e.g. "/usb/usb_device/name/tty2-1:1.0" -> "name"
272
273 std::string::size_type start = 0;
Tom Cherry1ab8f552017-04-06 14:41:30 -0700274 start = path.find('/', start + 1);
Tom Cherry2e344f92017-04-04 17:53:45 -0700275 if (start == std::string::npos) return {};
276
Tom Cherry1ab8f552017-04-06 14:41:30 -0700277 start = path.find('/', start + 1);
Tom Cherry2e344f92017-04-04 17:53:45 -0700278 if (start == std::string::npos) return {};
279
Tom Cherry1ab8f552017-04-06 14:41:30 -0700280 auto end = path.find('/', start + 1);
Tom Cherry2e344f92017-04-04 17:53:45 -0700281 if (end == std::string::npos) return {};
282
283 start++; // Skip the first '/'
284
285 auto length = end - start;
286 if (length == 0) return {};
287
Tom Cherry1ab8f552017-04-06 14:41:30 -0700288 auto name_string = path.substr(start, length);
Tom Cherry2e344f92017-04-04 17:53:45 -0700289
Tom Cherry2e344f92017-04-04 17:53:45 -0700290 std::vector<std::string> links;
Tom Cherryed506f72017-05-25 15:58:59 -0700291 links.emplace_back("/dev/usb/" + uevent.subsystem + name_string);
Tom Cherry2e344f92017-04-04 17:53:45 -0700292
293 mkdir("/dev/usb", 0755);
Benoit Gobyd2278632010-08-03 14:36:02 -0700294
295 return links;
Benoit Gobyd2278632010-08-03 14:36:02 -0700296}
297
Tom Cherryc44f6a42017-04-05 15:58:31 -0700298// replaces any unacceptable characters with '_', the
299// length of the resulting string is equal to the input string
Tom Cherryed506f72017-05-25 15:58:59 -0700300void SanitizePartitionName(std::string* string) {
Tom Cherryc44f6a42017-04-05 15:58:31 -0700301 const char* accept =
302 "abcdefghijklmnopqrstuvwxyz"
303 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
304 "0123456789"
305 "_-.";
306
Tom Cherry2e344f92017-04-04 17:53:45 -0700307 if (!string) return;
Tom Cherryc44f6a42017-04-05 15:58:31 -0700308
Tom Cherry2e344f92017-04-04 17:53:45 -0700309 std::string::size_type pos = 0;
310 while ((pos = string->find_first_not_of(accept, pos)) != std::string::npos) {
311 (*string)[pos] = '_';
Tom Cherryc44f6a42017-04-05 15:58:31 -0700312 }
313}
314
Tom Cherryed506f72017-05-25 15:58:59 -0700315std::vector<std::string> DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uevent) const {
Tom Cherry2e344f92017-04-04 17:53:45 -0700316 std::string device;
Tom Cherry2e344f92017-04-04 17:53:45 -0700317 std::string type;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700318
Tom Cherryed506f72017-05-25 15:58:59 -0700319 if (platform_devices_.Find(uevent.path, &device)) {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700320 // Skip /devices/platform or /devices/ if present
321 static const std::string devices_platform_prefix = "/devices/platform/";
322 static const std::string devices_prefix = "/devices/";
323
324 if (android::base::StartsWith(device, devices_platform_prefix.c_str())) {
325 device = device.substr(devices_platform_prefix.length());
326 } else if (android::base::StartsWith(device, devices_prefix.c_str())) {
327 device = device.substr(devices_prefix.length());
328 }
329
Andrew Boiea885d042013-09-13 17:41:20 -0700330 type = "platform";
Tom Cherryed506f72017-05-25 15:58:59 -0700331 } else if (FindPciDevicePrefix(uevent.path, &device)) {
Andrew Boiea885d042013-09-13 17:41:20 -0700332 type = "pci";
Tom Cherryed506f72017-05-25 15:58:59 -0700333 } else if (FindVbdDevicePrefix(uevent.path, &device)) {
Jeremy Compostella937309d2017-03-03 16:27:29 +0100334 type = "vbd";
Andrew Boiea885d042013-09-13 17:41:20 -0700335 } else {
Tom Cherry2e344f92017-04-04 17:53:45 -0700336 return {};
Andrew Boiea885d042013-09-13 17:41:20 -0700337 }
Dima Zavinf395c922013-03-06 16:23:57 -0800338
Tom Cherry2e344f92017-04-04 17:53:45 -0700339 std::vector<std::string> links;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700340
Sandeep Patil35403eb2017-02-08 20:27:12 -0800341 LOG(VERBOSE) << "found " << type << " device " << device;
Colin Crossfadb85e2011-03-30 18:32:12 -0700342
Tom Cherry2e344f92017-04-04 17:53:45 -0700343 auto link_path = "/dev/block/" + type + "/" + device;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700344
Tom Cherryed506f72017-05-25 15:58:59 -0700345 if (!uevent.partition_name.empty()) {
346 std::string partition_name_sanitized(uevent.partition_name);
347 SanitizePartitionName(&partition_name_sanitized);
348 if (partition_name_sanitized != uevent.partition_name) {
349 LOG(VERBOSE) << "Linking partition '" << uevent.partition_name << "' as '"
Tom Cherry2e344f92017-04-04 17:53:45 -0700350 << partition_name_sanitized << "'";
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700351 }
Tom Cherry2e344f92017-04-04 17:53:45 -0700352 links.emplace_back(link_path + "/by-name/" + partition_name_sanitized);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700353 }
354
Tom Cherryed506f72017-05-25 15:58:59 -0700355 if (uevent.partition_num >= 0) {
356 links.emplace_back(link_path + "/by-num/p" + std::to_string(uevent.partition_num));
Colin Crossb0ab94b2010-04-08 16:16:20 -0700357 }
358
Tom Cherryed506f72017-05-25 15:58:59 -0700359 auto last_slash = uevent.path.rfind('/');
360 links.emplace_back(link_path + "/" + uevent.path.substr(last_slash + 1));
Colin Crossb0ab94b2010-04-08 16:16:20 -0700361
362 return links;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700363}
364
Tom Cherryed506f72017-05-25 15:58:59 -0700365void DeviceHandler::HandleDevice(const std::string& action, const std::string& devpath, int block,
366 int major, int minor, const std::vector<std::string>& links) const {
Tom Cherrye3e48212017-04-11 13:53:37 -0700367 if (action == "add") {
Tom Cherryed506f72017-05-25 15:58:59 -0700368 MakeDevice(devpath, block, major, minor, links);
Tom Cherry2e344f92017-04-04 17:53:45 -0700369 for (const auto& link : links) {
Tom Cherryed506f72017-05-25 15:58:59 -0700370 if (mkdir_recursive(android::base::Dirname(link), 0755, sehandle_)) {
371 PLOG(ERROR) << "Failed to create directory " << android::base::Dirname(link);
372 }
373
374 if (symlink(devpath.c_str(), link.c_str()) && errno != EEXIST) {
375 PLOG(ERROR) << "Failed to symlink " << devpath << " to " << link;
376 }
Colin Crossb0ab94b2010-04-08 16:16:20 -0700377 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700378 }
379
Tom Cherrye3e48212017-04-11 13:53:37 -0700380 if (action == "remove") {
Tom Cherry2e344f92017-04-04 17:53:45 -0700381 for (const auto& link : links) {
Tom Cherryed506f72017-05-25 15:58:59 -0700382 std::string link_path;
383 if (android::base::Readlink(link, &link_path) && link_path == devpath) {
384 unlink(link.c_str());
385 }
Colin Crossb0ab94b2010-04-08 16:16:20 -0700386 }
Tom Cherrye3e48212017-04-11 13:53:37 -0700387 unlink(devpath.c_str());
Colin Crossb0ab94b2010-04-08 16:16:20 -0700388 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700389}
390
Tom Cherryed506f72017-05-25 15:58:59 -0700391void DeviceHandler::HandlePlatformDeviceEvent(const Uevent& uevent) {
392 if (uevent.action == "add") {
393 platform_devices_.Add(uevent.path);
394 } else if (uevent.action == "remove") {
395 platform_devices_.Remove(uevent.path);
Tom Cherrye3e48212017-04-11 13:53:37 -0700396 }
Colin Crossfadb85e2011-03-30 18:32:12 -0700397}
398
Tom Cherryed506f72017-05-25 15:58:59 -0700399void DeviceHandler::HandleBlockDeviceEvent(const Uevent& uevent) const {
Tom Cherry3fa46732017-04-11 14:19:50 -0700400 // if it's not a /dev device, nothing to do
Tom Cherryed506f72017-05-25 15:58:59 -0700401 if (uevent.major < 0 || uevent.minor < 0) return;
Colin Crosseb5ba832011-03-30 17:37:17 -0700402
Tom Cherry3fa46732017-04-11 14:19:50 -0700403 const char* base = "/dev/block/";
Tom Cherryed506f72017-05-25 15:58:59 -0700404 make_dir(base, 0755, sehandle_);
Colin Crosseb5ba832011-03-30 17:37:17 -0700405
Tom Cherryed506f72017-05-25 15:58:59 -0700406 std::string name = android::base::Basename(uevent.path);
Tom Cherry3fa46732017-04-11 14:19:50 -0700407 std::string devpath = base + name;
408
Tom Cherry2e344f92017-04-04 17:53:45 -0700409 std::vector<std::string> links;
Tom Cherryed506f72017-05-25 15:58:59 -0700410 if (android::base::StartsWith(uevent.path, "/devices")) {
411 links = GetBlockDeviceSymlinks(uevent);
Tom Cherrye3e48212017-04-11 13:53:37 -0700412 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700413
Tom Cherryed506f72017-05-25 15:58:59 -0700414 HandleDevice(uevent.action, devpath, 1, uevent.major, uevent.minor, links);
Colin Crosseb5ba832011-03-30 17:37:17 -0700415}
416
Tom Cherryed506f72017-05-25 15:58:59 -0700417void DeviceHandler::HandleGenericDeviceEvent(const Uevent& uevent) const {
Tom Cherry3fa46732017-04-11 14:19:50 -0700418 // if it's not a /dev device, nothing to do
Tom Cherryed506f72017-05-25 15:58:59 -0700419 if (uevent.major < 0 || uevent.minor < 0) return;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800420
Tom Cherry3fa46732017-04-11 14:19:50 -0700421 std::string devpath;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800422
Tom Cherryed506f72017-05-25 15:58:59 -0700423 if (android::base::StartsWith(uevent.subsystem, "usb")) {
424 if (uevent.subsystem == "usb") {
425 if (!uevent.device_name.empty()) {
426 devpath = "/dev/" + uevent.device_name;
Tom Cherry3fa46732017-04-11 14:19:50 -0700427 } else {
428 // This imitates the file system that would be created
429 // if we were using devfs instead.
430 // Minors are broken up into groups of 128, starting at "001"
Tom Cherryed506f72017-05-25 15:58:59 -0700431 int bus_id = uevent.minor / 128 + 1;
432 int device_id = uevent.minor % 128 + 1;
Tom Cherry3fa46732017-04-11 14:19:50 -0700433 devpath = android::base::StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id);
434 }
Tom Cherry3fa46732017-04-11 14:19:50 -0700435 } else {
436 // ignore other USB events
437 return;
438 }
Tom Cherryed506f72017-05-25 15:58:59 -0700439 } else if (const auto subsystem =
440 std::find(subsystems_.cbegin(), subsystems_.cend(), uevent.subsystem);
441 subsystem != subsystems_.cend()) {
Tom Cherryfe062052017-04-24 16:59:05 -0700442 devpath = subsystem->ParseDevPath(uevent);
Tom Cherry780a71e2017-04-04 16:30:40 -0700443 } else {
Tom Cherryed506f72017-05-25 15:58:59 -0700444 devpath = "/dev/" + android::base::Basename(uevent.path);
Tom Cherry780a71e2017-04-04 16:30:40 -0700445 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700446
Tom Cherryed506f72017-05-25 15:58:59 -0700447 mkdir_recursive(android::base::Dirname(devpath), 0755, sehandle_);
Tom Cherryfe062052017-04-24 16:59:05 -0700448
Tom Cherryed506f72017-05-25 15:58:59 -0700449 auto links = GetCharacterDeviceSymlinks(uevent);
Colin Crosseb5ba832011-03-30 17:37:17 -0700450
Tom Cherryed506f72017-05-25 15:58:59 -0700451 HandleDevice(uevent.action, devpath, 0, uevent.major, uevent.minor, links);
Colin Crosseb5ba832011-03-30 17:37:17 -0700452}
453
Tom Cherryed506f72017-05-25 15:58:59 -0700454void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) {
455 if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
456 FixupSysPermissions(uevent.path, uevent.subsystem);
Tom Cherrye3e48212017-04-11 13:53:37 -0700457 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700458
Tom Cherryed506f72017-05-25 15:58:59 -0700459 if (uevent.subsystem == "block") {
460 HandleBlockDeviceEvent(uevent);
461 } else if (uevent.subsystem == "platform") {
462 HandlePlatformDeviceEvent(uevent);
Colin Crosseb5ba832011-03-30 17:37:17 -0700463 } else {
Tom Cherryed506f72017-05-25 15:58:59 -0700464 HandleGenericDeviceEvent(uevent);
Colin Crosseb5ba832011-03-30 17:37:17 -0700465 }
466}
467
Tom Cherryed506f72017-05-25 15:58:59 -0700468DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions,
469 std::vector<SysfsPermissions> sysfs_permissions,
Tom Cherryc5833052017-05-16 15:35:41 -0700470 std::vector<Subsystem> subsystems, bool skip_restorecon)
Tom Cherryed506f72017-05-25 15:58:59 -0700471 : dev_permissions_(std::move(dev_permissions)),
472 sysfs_permissions_(std::move(sysfs_permissions)),
473 subsystems_(std::move(subsystems)),
Tom Cherryc5833052017-05-16 15:35:41 -0700474 sehandle_(selinux_android_file_context_handle()),
475 skip_restorecon_(skip_restorecon) {}
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700476
Tom Cherryed506f72017-05-25 15:58:59 -0700477DeviceHandler::DeviceHandler()
478 : DeviceHandler(std::vector<Permissions>{}, std::vector<SysfsPermissions>{},
Tom Cherryc5833052017-05-16 15:35:41 -0700479 std::vector<Subsystem>{}, false) {}