blob: ad313a0e340e325628e7c998340466f2f43f89e4 [file] [log] [blame]
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001/*
Mark Salyzyn154f4602014-02-20 14:59:07 -08002 * Copyright (C) 2007-2014 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
Elliott Hughesf39f7f12016-08-31 14:41:51 -070017#include <dirent.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070018#include <errno.h>
Elliott Hughesf39f7f12016-08-31 14:41:51 -070019#include <fcntl.h>
Daniel Leungc0c1ffe2012-07-02 11:32:30 -070020#include <fnmatch.h>
Elliott Hughesf39f7f12016-08-31 14:41:51 -070021#include <libgen.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070022#include <linux/netlink.h>
Olivier Baillyb93e5812010-11-17 11:47:23 -080023#include <stddef.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070024#include <stdio.h>
25#include <stdlib.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070026#include <string.h>
Elliott Hughes632e99a2016-11-12 11:44:16 -080027#include <sys/sendfile.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070028#include <sys/socket.h>
Elliott Hughesf39f7f12016-08-31 14:41:51 -070029#include <sys/time.h>
30#include <sys/types.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070031#include <sys/un.h>
Elliott Hughesf39f7f12016-08-31 14:41:51 -070032#include <sys/wait.h>
33#include <unistd.h>
34
Tom Cherry2e344f92017-04-04 17:53:45 -070035#include <algorithm>
James Hawkins588a2ca2016-02-18 14:52:46 -080036#include <memory>
Tom Cherry2e344f92017-04-04 17:53:45 -070037#include <string>
Elliott Hughes290a2282016-11-14 17:08:47 -080038#include <thread>
Tom Cherry2e344f92017-04-04 17:53:45 -070039#include <vector>
James Hawkins588a2ca2016-02-18 14:52:46 -080040
Biao Ludc848562016-01-28 16:10:54 +080041#include <android-base/file.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070042#include <android-base/logging.h>
Rob Herring6de783a2016-05-06 10:06:59 -050043#include <android-base/stringprintf.h>
Tom Cherry2e344f92017-04-04 17:53:45 -070044#include <android-base/strings.h>
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +080045#include <android-base/unique_fd.h>
Dima Zavinda04c522011-09-01 17:09:44 -070046#include <cutils/list.h>
Vernon Tang3f582e92011-04-25 13:08:17 +100047#include <cutils/uevent.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070048#include <private/android_filesystem_config.h>
49#include <selinux/android.h>
50#include <selinux/avc.h>
51#include <selinux/label.h>
52#include <selinux/selinux.h>
Vernon Tang3f582e92011-04-25 13:08:17 +100053
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070054#include "devices.h"
Greg Hackmann3312aa82013-11-18 15:24:40 -080055#include "ueventd_parser.h"
Colin Crossb0ab94b2010-04-08 16:16:20 -070056#include "util.h"
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070057
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070058#define SYSFS_PREFIX "/sys"
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070059
Stephen Smalleye096e362012-06-11 13:37:39 -040060extern struct selabel_handle *sehandle;
Stephen Smalleye46f9d52012-01-13 08:48:47 -050061
Sandeep Patil35403eb2017-02-08 20:27:12 -080062static android::base::unique_fd device_fd;
Colin Cross0dd7ca62010-04-13 19:25:51 -070063
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070064struct perms_ {
65 char *name;
Brian Swetlandbc57d4c2010-10-26 15:09:43 -070066 char *attr;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070067 mode_t perm;
68 unsigned int uid;
69 unsigned int gid;
70 unsigned short prefix;
Daniel Leungc0c1ffe2012-07-02 11:32:30 -070071 unsigned short wildcard;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070072};
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070073
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070074struct perm_node {
75 struct perms_ dp;
76 struct listnode plist;
77};
Brian Swetlandbc57d4c2010-10-26 15:09:43 -070078
79static list_declare(sys_perms);
Colin Cross44b65d02010-04-20 14:32:50 -070080static list_declare(dev_perms);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070081
Brian Swetlandbc57d4c2010-10-26 15:09:43 -070082int add_dev_perms(const char *name, const char *attr,
83 mode_t perm, unsigned int uid, unsigned int gid,
Daniel Leungc0c1ffe2012-07-02 11:32:30 -070084 unsigned short prefix,
85 unsigned short wildcard) {
Elliott Hughesf3cf4382015-02-03 17:12:07 -080086 struct perm_node *node = (perm_node*) calloc(1, sizeof(*node));
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070087 if (!node)
88 return -ENOMEM;
89
Brian Swetlandbc57d4c2010-10-26 15:09:43 -070090 node->dp.name = strdup(name);
Ting-Yuan Huang09bd41d2016-11-15 15:35:16 -080091 if (!node->dp.name) {
92 free(node);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070093 return -ENOMEM;
Ting-Yuan Huang09bd41d2016-11-15 15:35:16 -080094 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070095
Brian Swetlandbc57d4c2010-10-26 15:09:43 -070096 if (attr) {
97 node->dp.attr = strdup(attr);
Ting-Yuan Huang09bd41d2016-11-15 15:35:16 -080098 if (!node->dp.attr) {
99 free(node->dp.name);
100 free(node);
Brian Swetlandbc57d4c2010-10-26 15:09:43 -0700101 return -ENOMEM;
Ting-Yuan Huang09bd41d2016-11-15 15:35:16 -0800102 }
Brian Swetlandbc57d4c2010-10-26 15:09:43 -0700103 }
104
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700105 node->dp.perm = perm;
106 node->dp.uid = uid;
107 node->dp.gid = gid;
108 node->dp.prefix = prefix;
Daniel Leungc0c1ffe2012-07-02 11:32:30 -0700109 node->dp.wildcard = wildcard;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700110
Brian Swetlandbc57d4c2010-10-26 15:09:43 -0700111 if (attr)
112 list_add_tail(&sys_perms, &node->plist);
113 else
114 list_add_tail(&dev_perms, &node->plist);
115
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700116 return 0;
117}
118
Colin Cross43d537e2014-07-02 13:08:13 -0700119static bool perm_path_matches(const char *path, struct perms_ *dp)
120{
121 if (dp->prefix) {
122 if (strncmp(path, dp->name, strlen(dp->name)) == 0)
123 return true;
124 } else if (dp->wildcard) {
125 if (fnmatch(dp->name, path, FNM_PATHNAME) == 0)
126 return true;
127 } else {
128 if (strcmp(path, dp->name) == 0)
129 return true;
130 }
131
132 return false;
133}
134
Rob Herring6de783a2016-05-06 10:06:59 -0500135static bool match_subsystem(perms_* dp, const char* pattern,
136 const char* path, const char* subsystem) {
137 if (!pattern || !subsystem || strstr(dp->name, subsystem) == NULL) {
138 return false;
139 }
Rob Herringe5636a32016-05-06 12:28:48 -0500140
Rob Herring6de783a2016-05-06 10:06:59 -0500141 std::string subsys_path = android::base::StringPrintf(pattern, subsystem, basename(path));
142 return perm_path_matches(subsys_path.c_str(), dp);
143}
Rob Herringe5636a32016-05-06 12:28:48 -0500144
Tom Cherrye3e48212017-04-11 13:53:37 -0700145static void fixup_sys_perms(const std::string& upath, const std::string& subsystem) {
Rob Herring6de783a2016-05-06 10:06:59 -0500146 // upaths omit the "/sys" that paths in this list
147 // contain, so we prepend it...
Tom Cherrye3e48212017-04-11 13:53:37 -0700148 std::string path = SYSFS_PREFIX + upath;
Rob Herring6de783a2016-05-06 10:06:59 -0500149
150 listnode* node;
Rob Herringe5636a32016-05-06 12:28:48 -0500151 list_for_each(node, &sys_perms) {
Rob Herring6de783a2016-05-06 10:06:59 -0500152 perms_* dp = &(node_to_item(node, perm_node, plist))->dp;
Tom Cherrye3e48212017-04-11 13:53:37 -0700153 if (match_subsystem(dp, SYSFS_PREFIX "/class/%s/%s", path.c_str(), subsystem.c_str())) {
Rob Herring6de783a2016-05-06 10:06:59 -0500154 ; // matched
Tom Cherrye3e48212017-04-11 13:53:37 -0700155 } else if (match_subsystem(dp, SYSFS_PREFIX "/bus/%s/devices/%s", path.c_str(),
156 subsystem.c_str())) {
Rob Herring6de783a2016-05-06 10:06:59 -0500157 ; // matched
158 } else if (!perm_path_matches(path.c_str(), dp)) {
159 continue;
Rob Herringe5636a32016-05-06 12:28:48 -0500160 }
161
162 std::string attr_file = path + "/" + dp->attr;
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700163 LOG(INFO) << "fixup " << attr_file
164 << " " << dp->uid << " " << dp->gid << " " << std::oct << dp->perm;
Rob Herringe5636a32016-05-06 12:28:48 -0500165 chown(attr_file.c_str(), dp->uid, dp->gid);
166 chmod(attr_file.c_str(), dp->perm);
167 }
168
169 if (access(path.c_str(), F_OK) == 0) {
Dmitry Shmidt7eed4742016-07-28 13:55:39 -0700170 LOG(VERBOSE) << "restorecon_recursive: " << path;
Paul Lawrencea8d84342016-11-14 15:40:18 -0800171 restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
Rob Herringe5636a32016-05-06 12:28:48 -0500172 }
173}
174
Tom Cherry2e344f92017-04-04 17:53:45 -0700175static mode_t get_device_perm(const char* path, const std::vector<std::string>& links,
176 unsigned* uid, unsigned* gid) {
Colin Cross44b65d02010-04-20 14:32:50 -0700177 struct listnode *node;
178 struct perm_node *perm_node;
179 struct perms_ *dp;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700180
Colin Cross44b65d02010-04-20 14:32:50 -0700181 /* search the perms list in reverse so that ueventd.$hardware can
182 * override ueventd.rc
183 */
184 list_for_each_reverse(node, &dev_perms) {
185 perm_node = node_to_item(node, struct perm_node, plist);
186 dp = &perm_node->dp;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700187
Tom Cherry2e344f92017-04-04 17:53:45 -0700188 if (perm_path_matches(path, dp) ||
189 std::any_of(links.begin(), links.end(),
190 [dp](const auto& link) { return perm_path_matches(link.c_str(), dp); })) {
Colin Cross43d537e2014-07-02 13:08:13 -0700191 *uid = dp->uid;
192 *gid = dp->gid;
193 return dp->perm;
194 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700195 }
Colin Cross44b65d02010-04-20 14:32:50 -0700196 /* Default if nothing found. */
197 *uid = 0;
198 *gid = 0;
199 return 0600;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700200}
201
Tom Cherrye3e48212017-04-11 13:53:37 -0700202static void make_device(const std::string& path, int block, int major, int minor,
Tom Cherry2e344f92017-04-04 17:53:45 -0700203 const std::vector<std::string>& links) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700204 unsigned uid;
205 unsigned gid;
206 mode_t mode;
207 dev_t dev;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500208 char *secontext = NULL;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700209
Tom Cherrye3e48212017-04-11 13:53:37 -0700210 mode = get_device_perm(path.c_str(), links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
Kenny Rootb5982bf2012-10-16 23:07:05 -0700211
Sandeep Patilea239832017-02-03 07:51:55 -0800212 if (sehandle) {
Tom Cherry2e344f92017-04-04 17:53:45 -0700213 std::vector<const char*> c_links;
214 for (const auto& link : links) {
215 c_links.emplace_back(link.c_str());
216 }
217 c_links.emplace_back(nullptr);
Tom Cherrye3e48212017-04-11 13:53:37 -0700218 if (selabel_lookup_best_match(sehandle, &secontext, path.c_str(), &c_links[0], mode)) {
Sandeep Patilea239832017-02-03 07:51:55 -0800219 PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
220 return;
221 }
222 setfscreatecon(secontext);
Mihai Serban24a3cbf2016-04-25 18:22:27 +0300223 }
Kenny Rootb5982bf2012-10-16 23:07:05 -0700224
Colin Cross17dcc5c2010-09-03 12:25:34 -0700225 dev = makedev(major, minor);
Nick Pelly6405c692010-01-21 18:13:39 -0800226 /* Temporarily change egid to avoid race condition setting the gid of the
227 * device node. Unforunately changing the euid would prevent creation of
228 * some device nodes, so the uid has to be set with chown() and is still
229 * racy. Fixing the gid race at least fixed the issue with system_server
230 * opening dynamic input devices under the AID_INPUT gid. */
Tom Cherry0506b182017-02-23 13:46:09 -0800231 if (setegid(gid)) {
232 PLOG(ERROR) << "setegid(" << gid << ") for " << path << " device failed";
233 goto out;
234 }
Mihai Serban24a3cbf2016-04-25 18:22:27 +0300235 /* If the node already exists update its SELinux label to handle cases when
236 * it was created with the wrong context during coldboot procedure. */
Tom Cherrye3e48212017-04-11 13:53:37 -0700237 if (mknod(path.c_str(), mode, dev) && (errno == EEXIST) && secontext) {
William Roberts397de142016-06-02 09:53:44 -0700238 char* fcon = nullptr;
Tom Cherrye3e48212017-04-11 13:53:37 -0700239 int rc = lgetfilecon(path.c_str(), &fcon);
William Roberts397de142016-06-02 09:53:44 -0700240 if (rc < 0) {
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700241 PLOG(ERROR) << "Cannot get SELinux label on '" << path << "' device";
William Roberts397de142016-06-02 09:53:44 -0700242 goto out;
243 }
244
245 bool different = strcmp(fcon, secontext) != 0;
246 freecon(fcon);
247
Tom Cherrye3e48212017-04-11 13:53:37 -0700248 if (different && lsetfilecon(path.c_str(), secontext)) {
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700249 PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path << "' device";
Mihai Serban24a3cbf2016-04-25 18:22:27 +0300250 }
251 }
William Roberts397de142016-06-02 09:53:44 -0700252
253out:
Tom Cherrye3e48212017-04-11 13:53:37 -0700254 chown(path.c_str(), uid, -1);
Tom Cherry0506b182017-02-23 13:46:09 -0800255 if (setegid(AID_ROOT)) {
256 PLOG(FATAL) << "setegid(AID_ROOT) failed";
257 }
Kenny Rootb5982bf2012-10-16 23:07:05 -0700258
Sandeep Patilea239832017-02-03 07:51:55 -0800259 if (secontext) {
260 freecon(secontext);
261 setfscreatecon(NULL);
262 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700263}
264
Tom Cherry1ab8f552017-04-06 14:41:30 -0700265// TODO: Move this to be a member variable of a future devices class.
266std::vector<std::string> platform_devices;
Dima Zavinf395c922013-03-06 16:23:57 -0800267
Tom Cherry1ab8f552017-04-06 14:41:30 -0700268// Given a path that may start with a platform device, find the length of the
269// platform device prefix. If it doesn't start with a platform device, return false
270bool find_platform_device(const std::string& path, std::string* out_path) {
271 out_path->clear();
272 // platform_devices is searched backwards, since parents are added before their children,
273 // and we want to match as deep of a child as we can.
274 for (auto it = platform_devices.rbegin(); it != platform_devices.rend(); ++it) {
275 auto platform_device_path_length = it->length();
276 if (platform_device_path_length < path.length() &&
277 path[platform_device_path_length] == '/' &&
278 android::base::StartsWith(path, it->c_str())) {
279 *out_path = *it;
280 return true;
Colin Crossfadb85e2011-03-30 18:32:12 -0700281 }
282 }
Tom Cherry1ab8f552017-04-06 14:41:30 -0700283 return false;
Sandeep Patil35403eb2017-02-08 20:27:12 -0800284}
285
Andrew Boiea885d042013-09-13 17:41:20 -0700286/* Given a path that may start with a PCI device, populate the supplied buffer
287 * with the PCI domain/bus number and the peripheral ID and return 0.
288 * If it doesn't start with a PCI device, or there is some error, return -1 */
Tom Cherry2e344f92017-04-04 17:53:45 -0700289static bool find_pci_device_prefix(const std::string& path, std::string* result) {
290 result->clear();
Andrew Boiea885d042013-09-13 17:41:20 -0700291
Tom Cherry2e344f92017-04-04 17:53:45 -0700292 if (!android::base::StartsWith(path, "/devices/pci")) return false;
Andrew Boiea885d042013-09-13 17:41:20 -0700293
294 /* Beginning of the prefix is the initial "pci" after "/devices/" */
Tom Cherry2e344f92017-04-04 17:53:45 -0700295 std::string::size_type start = 9;
Andrew Boiea885d042013-09-13 17:41:20 -0700296
297 /* End of the prefix is two path '/' later, capturing the domain/bus number
298 * and the peripheral ID. Example: pci0000:00/0000:00:1f.2 */
Tom Cherry2e344f92017-04-04 17:53:45 -0700299 auto end = path.find('/', start);
300 if (end == std::string::npos) return false;
Andrew Boiea885d042013-09-13 17:41:20 -0700301
Tom Cherry2e344f92017-04-04 17:53:45 -0700302 end = path.find('/', end + 1);
303 if (end == std::string::npos) return false;
Andrew Boiea885d042013-09-13 17:41:20 -0700304
Tom Cherry2e344f92017-04-04 17:53:45 -0700305 auto length = end - start;
306 if (length <= 4) {
307 // The minimum string that will get to this check is 'pci/', which is malformed,
308 // so return false
309 return false;
310 }
311
312 *result = path.substr(start, length);
313 return true;
Andrew Boiea885d042013-09-13 17:41:20 -0700314}
315
Jeremy Compostella937309d2017-03-03 16:27:29 +0100316/* Given a path that may start with a virtual block device, populate
317 * the supplied buffer with the virtual block device ID and return 0.
318 * If it doesn't start with a virtual block device, or there is some
319 * error, return -1 */
Tom Cherry2e344f92017-04-04 17:53:45 -0700320static bool find_vbd_device_prefix(const std::string& path, std::string* result) {
321 result->clear();
322
323 if (!android::base::StartsWith(path, "/devices/vbd-")) return false;
Jeremy Compostella937309d2017-03-03 16:27:29 +0100324
325 /* Beginning of the prefix is the initial "vbd-" after "/devices/" */
Tom Cherry2e344f92017-04-04 17:53:45 -0700326 std::string::size_type start = 13;
Jeremy Compostella937309d2017-03-03 16:27:29 +0100327
328 /* End of the prefix is one path '/' later, capturing the
329 virtual block device ID. Example: 768 */
Tom Cherry2e344f92017-04-04 17:53:45 -0700330 auto end = path.find('/', start);
331 if (end == std::string::npos) return false;
Jeremy Compostella937309d2017-03-03 16:27:29 +0100332
Tom Cherry2e344f92017-04-04 17:53:45 -0700333 auto length = end - start;
334 if (length == 0) return false;
Jeremy Compostella937309d2017-03-03 16:27:29 +0100335
Tom Cherry2e344f92017-04-04 17:53:45 -0700336 *result = path.substr(start, length);
337 return true;
Jeremy Compostella937309d2017-03-03 16:27:29 +0100338}
339
Tom Cherrye3e48212017-04-11 13:53:37 -0700340void parse_event(const char* msg, uevent* uevent) {
341 uevent->partition_num = -1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700342 uevent->major = -1;
343 uevent->minor = -1;
Tom Cherrye3e48212017-04-11 13:53:37 -0700344 // currently ignoring SEQNUM
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700345 while(*msg) {
346 if(!strncmp(msg, "ACTION=", 7)) {
347 msg += 7;
348 uevent->action = msg;
349 } else if(!strncmp(msg, "DEVPATH=", 8)) {
350 msg += 8;
351 uevent->path = msg;
352 } else if(!strncmp(msg, "SUBSYSTEM=", 10)) {
353 msg += 10;
354 uevent->subsystem = msg;
355 } else if(!strncmp(msg, "FIRMWARE=", 9)) {
356 msg += 9;
357 uevent->firmware = msg;
358 } else if(!strncmp(msg, "MAJOR=", 6)) {
359 msg += 6;
360 uevent->major = atoi(msg);
361 } else if(!strncmp(msg, "MINOR=", 6)) {
362 msg += 6;
363 uevent->minor = atoi(msg);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700364 } else if(!strncmp(msg, "PARTN=", 6)) {
365 msg += 6;
366 uevent->partition_num = atoi(msg);
367 } else if(!strncmp(msg, "PARTNAME=", 9)) {
368 msg += 9;
369 uevent->partition_name = msg;
Wei Zhongf97b8872012-03-23 14:15:34 -0700370 } else if(!strncmp(msg, "DEVNAME=", 8)) {
371 msg += 8;
372 uevent->device_name = msg;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700373 }
374
Tom Cherrye3e48212017-04-11 13:53:37 -0700375 // advance to after the next \0
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700376 while(*msg++)
377 ;
378 }
379
Elliott Hughesc0e919c2015-02-04 14:46:36 -0800380 if (LOG_UEVENTS) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700381 LOG(INFO) << "event { '" << uevent->action << "', '" << uevent->path << "', '"
382 << uevent->subsystem << "', '" << uevent->firmware << "', " << uevent->major
383 << ", " << uevent->minor << " }";
Elliott Hughesc0e919c2015-02-04 14:46:36 -0800384 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700385}
386
Tom Cherry2e344f92017-04-04 17:53:45 -0700387std::vector<std::string> get_character_device_symlinks(uevent* uevent) {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700388 std::string parent_device;
389 if (!find_platform_device(uevent->path, &parent_device)) return {};
Benoit Gobyd2278632010-08-03 14:36:02 -0700390
Tom Cherry1ab8f552017-04-06 14:41:30 -0700391 // skip path to the parent driver
392 std::string path = uevent->path.substr(parent_device.length());
Benoit Gobyd2278632010-08-03 14:36:02 -0700393
Tom Cherry1ab8f552017-04-06 14:41:30 -0700394 if (!android::base::StartsWith(path, "/usb")) return {};
Tom Cherry2e344f92017-04-04 17:53:45 -0700395
396 // skip root hub name and device. use device interface
397 // skip 3 slashes, including the first / by starting the search at the 1st character, not 0th.
398 // then extract what comes between the 3rd and 4th slash
399 // e.g. "/usb/usb_device/name/tty2-1:1.0" -> "name"
400
401 std::string::size_type start = 0;
Tom Cherry1ab8f552017-04-06 14:41:30 -0700402 start = path.find('/', start + 1);
Tom Cherry2e344f92017-04-04 17:53:45 -0700403 if (start == std::string::npos) return {};
404
Tom Cherry1ab8f552017-04-06 14:41:30 -0700405 start = path.find('/', start + 1);
Tom Cherry2e344f92017-04-04 17:53:45 -0700406 if (start == std::string::npos) return {};
407
Tom Cherry1ab8f552017-04-06 14:41:30 -0700408 auto end = path.find('/', start + 1);
Tom Cherry2e344f92017-04-04 17:53:45 -0700409 if (end == std::string::npos) return {};
410
411 start++; // Skip the first '/'
412
413 auto length = end - start;
414 if (length == 0) return {};
415
Tom Cherry1ab8f552017-04-06 14:41:30 -0700416 auto name_string = path.substr(start, length);
Tom Cherry2e344f92017-04-04 17:53:45 -0700417
Tom Cherry2e344f92017-04-04 17:53:45 -0700418 std::vector<std::string> links;
Tom Cherrye3e48212017-04-11 13:53:37 -0700419 links.emplace_back("/dev/usb/" + uevent->subsystem + name_string);
Tom Cherry2e344f92017-04-04 17:53:45 -0700420
421 mkdir("/dev/usb", 0755);
Benoit Gobyd2278632010-08-03 14:36:02 -0700422
423 return links;
Benoit Gobyd2278632010-08-03 14:36:02 -0700424}
425
Tom Cherryc44f6a42017-04-05 15:58:31 -0700426// replaces any unacceptable characters with '_', the
427// length of the resulting string is equal to the input string
Tom Cherry2e344f92017-04-04 17:53:45 -0700428void sanitize_partition_name(std::string* string) {
Tom Cherryc44f6a42017-04-05 15:58:31 -0700429 const char* accept =
430 "abcdefghijklmnopqrstuvwxyz"
431 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
432 "0123456789"
433 "_-.";
434
Tom Cherry2e344f92017-04-04 17:53:45 -0700435 if (!string) return;
Tom Cherryc44f6a42017-04-05 15:58:31 -0700436
Tom Cherry2e344f92017-04-04 17:53:45 -0700437 std::string::size_type pos = 0;
438 while ((pos = string->find_first_not_of(accept, pos)) != std::string::npos) {
439 (*string)[pos] = '_';
Tom Cherryc44f6a42017-04-05 15:58:31 -0700440 }
441}
442
Tom Cherry2e344f92017-04-04 17:53:45 -0700443std::vector<std::string> get_block_device_symlinks(uevent* uevent) {
444 std::string device;
Tom Cherry2e344f92017-04-04 17:53:45 -0700445 std::string type;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700446
Tom Cherry1ab8f552017-04-06 14:41:30 -0700447 if (find_platform_device(uevent->path, &device)) {
448 // Skip /devices/platform or /devices/ if present
449 static const std::string devices_platform_prefix = "/devices/platform/";
450 static const std::string devices_prefix = "/devices/";
451
452 if (android::base::StartsWith(device, devices_platform_prefix.c_str())) {
453 device = device.substr(devices_platform_prefix.length());
454 } else if (android::base::StartsWith(device, devices_prefix.c_str())) {
455 device = device.substr(devices_prefix.length());
456 }
457
Andrew Boiea885d042013-09-13 17:41:20 -0700458 type = "platform";
Tom Cherry2e344f92017-04-04 17:53:45 -0700459 } else if (find_pci_device_prefix(uevent->path, &device)) {
Andrew Boiea885d042013-09-13 17:41:20 -0700460 type = "pci";
Tom Cherry2e344f92017-04-04 17:53:45 -0700461 } else if (find_vbd_device_prefix(uevent->path, &device)) {
Jeremy Compostella937309d2017-03-03 16:27:29 +0100462 type = "vbd";
Andrew Boiea885d042013-09-13 17:41:20 -0700463 } else {
Tom Cherry2e344f92017-04-04 17:53:45 -0700464 return {};
Andrew Boiea885d042013-09-13 17:41:20 -0700465 }
Dima Zavinf395c922013-03-06 16:23:57 -0800466
Tom Cherry2e344f92017-04-04 17:53:45 -0700467 std::vector<std::string> links;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700468
Sandeep Patil35403eb2017-02-08 20:27:12 -0800469 LOG(VERBOSE) << "found " << type << " device " << device;
Colin Crossfadb85e2011-03-30 18:32:12 -0700470
Tom Cherry2e344f92017-04-04 17:53:45 -0700471 auto link_path = "/dev/block/" + type + "/" + device;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700472
Tom Cherrye3e48212017-04-11 13:53:37 -0700473 if (!uevent->partition_name.empty()) {
Tom Cherry2e344f92017-04-04 17:53:45 -0700474 std::string partition_name_sanitized(uevent->partition_name);
475 sanitize_partition_name(&partition_name_sanitized);
476 if (partition_name_sanitized != uevent->partition_name) {
477 LOG(VERBOSE) << "Linking partition '" << uevent->partition_name << "' as '"
478 << partition_name_sanitized << "'";
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700479 }
Tom Cherry2e344f92017-04-04 17:53:45 -0700480 links.emplace_back(link_path + "/by-name/" + partition_name_sanitized);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700481 }
482
483 if (uevent->partition_num >= 0) {
Tom Cherry2e344f92017-04-04 17:53:45 -0700484 links.emplace_back(link_path + "/by-num/p" + std::to_string(uevent->partition_num));
Colin Crossb0ab94b2010-04-08 16:16:20 -0700485 }
486
Tom Cherrye3e48212017-04-11 13:53:37 -0700487 auto last_slash = uevent->path.rfind('/');
488 links.emplace_back(link_path + "/" + uevent->path.substr(last_slash + 1));
Colin Crossb0ab94b2010-04-08 16:16:20 -0700489
490 return links;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700491}
492
Tom Cherrye3e48212017-04-11 13:53:37 -0700493static void make_link_init(const std::string& oldpath, const std::string& newpath) {
494 if (mkdir_recursive(dirname(newpath.c_str()), 0755)) {
495 PLOG(ERROR) << "Failed to create directory " << dirname(newpath.c_str());
496 }
Elliott Hughesf39f7f12016-08-31 14:41:51 -0700497
Tom Cherrye3e48212017-04-11 13:53:37 -0700498 if (symlink(oldpath.c_str(), newpath.c_str()) && errno != EEXIST) {
499 PLOG(ERROR) << "Failed to symlink " << oldpath << " to " << newpath;
500 }
Elliott Hughesf39f7f12016-08-31 14:41:51 -0700501}
502
Tom Cherrye3e48212017-04-11 13:53:37 -0700503static void remove_link(const std::string& oldpath, const std::string& newpath) {
504 std::string path;
505 if (android::base::Readlink(newpath, &path) && path == oldpath) unlink(newpath.c_str());
Elliott Hughesf39f7f12016-08-31 14:41:51 -0700506}
507
Tom Cherrye3e48212017-04-11 13:53:37 -0700508static void handle_device(const std::string& action, const std::string& devpath, int block,
Tom Cherry2e344f92017-04-04 17:53:45 -0700509 int major, int minor, const std::vector<std::string>& links) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700510 if (action == "add") {
511 make_device(devpath, block, major, minor, links);
Tom Cherry2e344f92017-04-04 17:53:45 -0700512 for (const auto& link : links) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700513 make_link_init(devpath, link);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700514 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700515 }
516
Tom Cherrye3e48212017-04-11 13:53:37 -0700517 if (action == "remove") {
Tom Cherry2e344f92017-04-04 17:53:45 -0700518 for (const auto& link : links) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700519 remove_link(devpath, link);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700520 }
Tom Cherrye3e48212017-04-11 13:53:37 -0700521 unlink(devpath.c_str());
Colin Crossb0ab94b2010-04-08 16:16:20 -0700522 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700523}
524
Tom Cherry1ab8f552017-04-06 14:41:30 -0700525void handle_platform_device_event(uevent* uevent) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700526 if (uevent->action == "add") {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700527 platform_devices.emplace_back(uevent->path);
Tom Cherrye3e48212017-04-11 13:53:37 -0700528 } else if (uevent->action == "remove") {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700529 auto it = std::find(platform_devices.begin(), platform_devices.end(), uevent->path);
530 if (it != platform_devices.end()) platform_devices.erase(it);
Tom Cherrye3e48212017-04-11 13:53:37 -0700531 }
Colin Crossfadb85e2011-03-30 18:32:12 -0700532}
533
Tom Cherry3fa46732017-04-11 14:19:50 -0700534static void handle_block_device_event(uevent* uevent) {
535 // if it's not a /dev device, nothing to do
536 if (uevent->major < 0 || uevent->minor < 0) return;
Colin Crosseb5ba832011-03-30 17:37:17 -0700537
Tom Cherry3fa46732017-04-11 14:19:50 -0700538 const char* base = "/dev/block/";
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500539 make_dir(base, 0755);
Colin Crosseb5ba832011-03-30 17:37:17 -0700540
Tom Cherry3fa46732017-04-11 14:19:50 -0700541 std::string name = android::base::Basename(uevent->path);
542 std::string devpath = base + name;
543
Tom Cherry2e344f92017-04-04 17:53:45 -0700544 std::vector<std::string> links;
Tom Cherrye3e48212017-04-11 13:53:37 -0700545 if (android::base::StartsWith(uevent->path, "/devices")) {
Andrew Boiea885d042013-09-13 17:41:20 -0700546 links = get_block_device_symlinks(uevent);
Tom Cherrye3e48212017-04-11 13:53:37 -0700547 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700548
Tom Cherrye3e48212017-04-11 13:53:37 -0700549 handle_device(uevent->action, devpath, 1, uevent->major, uevent->minor, links);
Colin Crosseb5ba832011-03-30 17:37:17 -0700550}
551
Tom Cherry3fa46732017-04-11 14:19:50 -0700552static void handle_generic_device_event(uevent* uevent) {
553 // if it's not a /dev device, nothing to do
554 if (uevent->major < 0 || uevent->minor < 0) return;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800555
Tom Cherry3fa46732017-04-11 14:19:50 -0700556 std::string name = android::base::Basename(uevent->path);
Tom Cherrye3e48212017-04-11 13:53:37 -0700557 ueventd_subsystem* subsystem = ueventd_subsystem_find_by_name(uevent->subsystem.c_str());
Greg Hackmann3312aa82013-11-18 15:24:40 -0800558
Tom Cherry3fa46732017-04-11 14:19:50 -0700559 std::string devpath;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800560
561 if (subsystem) {
Tom Cherry3fa46732017-04-11 14:19:50 -0700562 std::string devname;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800563
564 switch (subsystem->devname_src) {
565 case DEVNAME_UEVENT_DEVNAME:
566 devname = uevent->device_name;
567 break;
568
569 case DEVNAME_UEVENT_DEVPATH:
570 devname = name;
571 break;
572
573 default:
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700574 LOG(ERROR) << uevent->subsystem << " subsystem's devpath option is not set; ignoring event";
Greg Hackmann3312aa82013-11-18 15:24:40 -0800575 return;
576 }
577
Tom Cherry3fa46732017-04-11 14:19:50 -0700578 // TODO: Remove std::string()
579 devpath = std::string(subsystem->dirname) + "/" + devname;
580 mkdir_recursive(android::base::Dirname(devpath), 0755);
Tom Cherrye3e48212017-04-11 13:53:37 -0700581 } else if (android::base::StartsWith(uevent->subsystem, "usb")) {
582 if (uevent->subsystem == "usb") {
583 if (!uevent->device_name.empty()) {
584 devpath = "/dev/" + uevent->device_name;
Tom Cherry3fa46732017-04-11 14:19:50 -0700585 } else {
586 // This imitates the file system that would be created
587 // if we were using devfs instead.
588 // Minors are broken up into groups of 128, starting at "001"
589 int bus_id = uevent->minor / 128 + 1;
590 int device_id = uevent->minor % 128 + 1;
591 devpath = android::base::StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id);
592 }
593 mkdir_recursive(android::base::Dirname(devpath), 0755);
594 } else {
595 // ignore other USB events
596 return;
597 }
Tom Cherry780a71e2017-04-04 16:30:40 -0700598 } else {
Tom Cherry3fa46732017-04-11 14:19:50 -0700599 devpath = "/dev/" + name;
Tom Cherry780a71e2017-04-04 16:30:40 -0700600 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700601
Tom Cherry780a71e2017-04-04 16:30:40 -0700602 auto links = get_character_device_symlinks(uevent);
Colin Crosseb5ba832011-03-30 17:37:17 -0700603
Tom Cherrye3e48212017-04-11 13:53:37 -0700604 handle_device(uevent->action, devpath, 0, uevent->major, uevent->minor, links);
Colin Crosseb5ba832011-03-30 17:37:17 -0700605}
606
607static void handle_device_event(struct uevent *uevent)
608{
Tom Cherrye3e48212017-04-11 13:53:37 -0700609 if (uevent->action == "add" || uevent->action == "change" || uevent->action == "online") {
Rob Herring6de783a2016-05-06 10:06:59 -0500610 fixup_sys_perms(uevent->path, uevent->subsystem);
Tom Cherrye3e48212017-04-11 13:53:37 -0700611 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700612
Tom Cherrye3e48212017-04-11 13:53:37 -0700613 if (uevent->subsystem == "block") {
Colin Crosseb5ba832011-03-30 17:37:17 -0700614 handle_block_device_event(uevent);
Tom Cherrye3e48212017-04-11 13:53:37 -0700615 } else if (uevent->subsystem == "platform") {
Colin Crossfadb85e2011-03-30 18:32:12 -0700616 handle_platform_device_event(uevent);
Colin Crosseb5ba832011-03-30 17:37:17 -0700617 } else {
618 handle_generic_device_event(uevent);
619 }
620}
621
Elliott Hughes632e99a2016-11-12 11:44:16 -0800622static void load_firmware(uevent* uevent, const std::string& root,
623 int fw_fd, size_t fw_size,
624 int loading_fd, int data_fd) {
625 // Start transfer.
626 android::base::WriteFully(loading_fd, "1", 1);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700627
Elliott Hughes632e99a2016-11-12 11:44:16 -0800628 // Copy the firmware.
629 int rc = sendfile(data_fd, fw_fd, nullptr, fw_size);
630 if (rc == -1) {
631 PLOG(ERROR) << "firmware: sendfile failed { '" << root << "', '" << uevent->firmware << "' }";
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700632 }
633
Elliott Hughes632e99a2016-11-12 11:44:16 -0800634 // Tell the firmware whether to abort or commit.
635 const char* response = (rc != -1) ? "0" : "-1";
636 android::base::WriteFully(loading_fd, response, strlen(response));
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700637}
638
Elliott Hughes632e99a2016-11-12 11:44:16 -0800639static int is_booting() {
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700640 return access("/dev/.booting", F_OK) == 0;
641}
642
Elliott Hughes632e99a2016-11-12 11:44:16 -0800643static void process_firmware_event(uevent* uevent) {
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700644 int booting = is_booting();
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700645
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700646 LOG(INFO) << "firmware: loading '" << uevent->firmware << "' for '" << uevent->path << "'";
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700647
Tom Cherrye3e48212017-04-11 13:53:37 -0700648 std::string root = "/sys" + uevent->path;
Elliott Hughes632e99a2016-11-12 11:44:16 -0800649 std::string loading = root + "/loading";
650 std::string data = root + "/data";
651
652 android::base::unique_fd loading_fd(open(loading.c_str(), O_WRONLY|O_CLOEXEC));
653 if (loading_fd == -1) {
654 PLOG(ERROR) << "couldn't open firmware loading fd for " << uevent->firmware;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700655 return;
Elliott Hughes632e99a2016-11-12 11:44:16 -0800656 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700657
Elliott Hughes632e99a2016-11-12 11:44:16 -0800658 android::base::unique_fd data_fd(open(data.c_str(), O_WRONLY|O_CLOEXEC));
659 if (data_fd == -1) {
660 PLOG(ERROR) << "couldn't open firmware data fd for " << uevent->firmware;
661 return;
662 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700663
Tom Cherrye3e48212017-04-11 13:53:37 -0700664 static const char* firmware_dirs[] = {"/etc/firmware/", "/vendor/firmware/",
665 "/firmware/image/"};
666
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700667try_loading_again:
Elliott Hughes632e99a2016-11-12 11:44:16 -0800668 for (size_t i = 0; i < arraysize(firmware_dirs); i++) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700669 std::string file = firmware_dirs[i] + uevent->firmware;
Elliott Hughes632e99a2016-11-12 11:44:16 -0800670 android::base::unique_fd fw_fd(open(file.c_str(), O_RDONLY|O_CLOEXEC));
671 struct stat sb;
672 if (fw_fd != -1 && fstat(fw_fd, &sb) != -1) {
673 load_firmware(uevent, root, fw_fd, sb.st_size, loading_fd, data_fd);
674 return;
Benoit Goby609d8822010-11-09 18:10:24 -0800675 }
Brian Swetland02863b92010-09-19 03:36:39 -0700676 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700677
Elliott Hughes632e99a2016-11-12 11:44:16 -0800678 if (booting) {
679 // If we're not fully booted, we may be missing
680 // filesystems needed for firmware, wait and retry.
Elliott Hughes290a2282016-11-14 17:08:47 -0800681 std::this_thread::sleep_for(100ms);
Elliott Hughes632e99a2016-11-12 11:44:16 -0800682 booting = is_booting();
683 goto try_loading_again;
684 }
685
686 LOG(ERROR) << "firmware: could not find firmware for " << uevent->firmware;
687
688 // Write "-1" as our response to the kernel's firmware request, since we have nothing for it.
689 write(loading_fd, "-1", 2);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700690}
691
Elliott Hughes632e99a2016-11-12 11:44:16 -0800692static void handle_firmware_event(uevent* uevent) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700693 if (uevent->subsystem != "firmware" || uevent->action != "add") return;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700694
Elliott Hughes632e99a2016-11-12 11:44:16 -0800695 // Loading the firmware in a child means we can do that in parallel...
696 // (We ignore SIGCHLD rather than wait for our children.)
697 pid_t pid = fork();
698 if (pid == 0) {
699 Timer t;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700700 process_firmware_event(uevent);
Elliott Hughes331cf2f2016-11-29 19:20:58 +0000701 LOG(INFO) << "loading " << uevent->path << " took " << t;
Kenny Root17baff42014-08-20 16:16:44 -0700702 _exit(EXIT_SUCCESS);
Elliott Hughes632e99a2016-11-12 11:44:16 -0800703 } else if (pid == -1) {
704 PLOG(ERROR) << "could not fork to process firmware event for " << uevent->firmware;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700705 }
706}
707
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800708static bool inline should_stop_coldboot(coldboot_action_t act)
709{
710 return (act == COLDBOOT_STOP || act == COLDBOOT_FINISH);
711}
712
Ruchi Kandoic6037202014-06-23 11:22:09 -0700713#define UEVENT_MSG_LEN 2048
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800714
Sandeep Patil44a3ee22017-02-08 15:49:47 -0800715static inline coldboot_action_t handle_device_fd_with(
716 std::function<coldboot_action_t(uevent* uevent)> handle_uevent)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700717{
Vernon Tang3f582e92011-04-25 13:08:17 +1000718 char msg[UEVENT_MSG_LEN+2];
719 int n;
Nick Kralevich57de8b82011-05-11 14:58:24 -0700720 while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
Nick Kralevich5f5d5c82010-07-19 14:31:20 -0700721 if(n >= UEVENT_MSG_LEN) /* overflow -- discard */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700722 continue;
723
724 msg[n] = '\0';
725 msg[n+1] = '\0';
726
Tom Cherrye3e48212017-04-11 13:53:37 -0700727 uevent uevent;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700728 parse_event(msg, &uevent);
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800729 coldboot_action_t act = handle_uevent(&uevent);
730 if (should_stop_coldboot(act))
731 return act;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700732 }
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800733
734 return COLDBOOT_CONTINUE;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700735}
736
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800737coldboot_action_t handle_device_fd(coldboot_callback fn)
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800738{
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800739 coldboot_action_t ret = handle_device_fd_with(
740 [&](uevent* uevent) -> coldboot_action_t {
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800741 if (selinux_status_updated() > 0) {
742 struct selabel_handle *sehandle2;
743 sehandle2 = selinux_android_file_context_handle();
744 if (sehandle2) {
745 selabel_close(sehandle);
746 sehandle = sehandle2;
747 }
748 }
749
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800750 // default is to always create the devices
751 coldboot_action_t act = COLDBOOT_CREATE;
752 if (fn) {
753 act = fn(uevent);
754 }
755
756 if (act == COLDBOOT_CREATE || act == COLDBOOT_STOP) {
757 handle_device_event(uevent);
758 handle_firmware_event(uevent);
759 }
760
761 return act;
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800762 });
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800763
764 return ret;
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800765}
766
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700767/* Coldboot walks parts of the /sys tree and pokes the uevent files
768** to cause the kernel to regenerate device add events that happened
769** before init's device manager was started
770**
771** We drain any pending events from the netlink socket every time
772** we poke another uevent file to make sure we don't overrun the
Elliott Hughesc0e919c2015-02-04 14:46:36 -0800773** socket's buffer.
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700774*/
775
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800776static coldboot_action_t do_coldboot(DIR *d, coldboot_callback fn)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700777{
778 struct dirent *de;
779 int dfd, fd;
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800780 coldboot_action_t act = COLDBOOT_CONTINUE;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700781
782 dfd = dirfd(d);
783
784 fd = openat(dfd, "uevent", O_WRONLY);
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800785 if (fd >= 0) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700786 write(fd, "add\n", 4);
787 close(fd);
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800788 act = handle_device_fd(fn);
789 if (should_stop_coldboot(act))
790 return act;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700791 }
792
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800793 while (!should_stop_coldboot(act) && (de = readdir(d))) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700794 DIR *d2;
795
796 if(de->d_type != DT_DIR || de->d_name[0] == '.')
797 continue;
798
799 fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
800 if(fd < 0)
801 continue;
802
803 d2 = fdopendir(fd);
804 if(d2 == 0)
805 close(fd);
806 else {
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800807 act = do_coldboot(d2, fn);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700808 closedir(d2);
809 }
810 }
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800811
812 // default is always to continue looking for uevents
813 return act;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700814}
815
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800816static coldboot_action_t coldboot(const char *path, coldboot_callback fn)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700817{
James Hawkins588a2ca2016-02-18 14:52:46 -0800818 std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path), closedir);
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800819 if (d) {
820 return do_coldboot(d.get(), fn);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700821 }
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800822
823 return COLDBOOT_CONTINUE;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700824}
825
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800826void device_init(const char* path, coldboot_callback fn) {
Sandeep Patil971a4602017-02-15 13:37:52 -0800827 if (!sehandle) {
828 sehandle = selinux_android_file_context_handle();
Elliott Hughes56a06562015-03-28 11:23:32 -0700829 }
Sandeep Patil971a4602017-02-15 13:37:52 -0800830 // open uevent socket and selinux status only if it hasn't been
831 // done before
832 if (device_fd == -1) {
833 /* is 256K enough? udev uses 16MB! */
834 device_fd.reset(uevent_open_socket(256 * 1024, true));
835 if (device_fd == -1) {
836 return;
837 }
838 fcntl(device_fd, F_SETFL, O_NONBLOCK);
839 selinux_status_open(true);
840 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700841
Elliott Hughes56a06562015-03-28 11:23:32 -0700842 if (access(COLDBOOT_DONE, F_OK) == 0) {
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700843 LOG(VERBOSE) << "Skipping coldboot, already done!";
Elliott Hughes56a06562015-03-28 11:23:32 -0700844 return;
Colin Crossf83d0b92010-04-21 12:04:20 -0700845 }
Elliott Hughes56a06562015-03-28 11:23:32 -0700846
847 Timer t;
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800848 coldboot_action_t act;
849 if (!path) {
850 act = coldboot("/sys/class", fn);
851 if (!should_stop_coldboot(act)) {
852 act = coldboot("/sys/block", fn);
853 if (!should_stop_coldboot(act)) {
854 act = coldboot("/sys/devices", fn);
855 }
856 }
857 } else {
858 act = coldboot(path, fn);
859 }
860
861 // If we have a callback, then do as it says. If no, then the default is
862 // to always create COLDBOOT_DONE file.
863 if (!fn || (act == COLDBOOT_FINISH)) {
864 close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
865 }
866
Elliott Hughes331cf2f2016-11-29 19:20:58 +0000867 LOG(INFO) << "Coldboot took " << t;
Colin Cross0dd7ca62010-04-13 19:25:51 -0700868}
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700869
Sandeep Patil35403eb2017-02-08 20:27:12 -0800870void device_close() {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700871 platform_devices.clear();
Sandeep Patil35403eb2017-02-08 20:27:12 -0800872 device_fd.reset();
Sandeep Patil971a4602017-02-15 13:37:52 -0800873 selinux_status_close();
Sandeep Patil35403eb2017-02-08 20:27:12 -0800874}
875
Elliott Hughes632e99a2016-11-12 11:44:16 -0800876int get_device_fd() {
Colin Cross0dd7ca62010-04-13 19:25:51 -0700877 return device_fd;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700878}