blob: 6e13863befbd75a221761cc4985b3cb1281f6fb9 [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
Tom Cherrycc054c92017-04-05 17:55:46 -070017#include "devices.h"
18
Elliott Hughesf39f7f12016-08-31 14:41:51 -070019#include <dirent.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070020#include <errno.h>
Elliott Hughesf39f7f12016-08-31 14:41:51 -070021#include <fcntl.h>
Daniel Leungc0c1ffe2012-07-02 11:32:30 -070022#include <fnmatch.h>
Elliott Hughesf39f7f12016-08-31 14:41:51 -070023#include <libgen.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070024#include <linux/netlink.h>
Olivier Baillyb93e5812010-11-17 11:47:23 -080025#include <stddef.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070026#include <stdio.h>
27#include <stdlib.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070028#include <string.h>
Elliott Hughes632e99a2016-11-12 11:44:16 -080029#include <sys/sendfile.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070030#include <sys/socket.h>
Elliott Hughesf39f7f12016-08-31 14:41:51 -070031#include <sys/time.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070032#include <sys/un.h>
Elliott Hughesf39f7f12016-08-31 14:41:51 -070033#include <sys/wait.h>
34#include <unistd.h>
35
Tom Cherry2e344f92017-04-04 17:53:45 -070036#include <algorithm>
James Hawkins588a2ca2016-02-18 14:52:46 -080037#include <memory>
Elliott Hughes290a2282016-11-14 17:08:47 -080038#include <thread>
James Hawkins588a2ca2016-02-18 14:52:46 -080039
Biao Ludc848562016-01-28 16:10:54 +080040#include <android-base/file.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070041#include <android-base/logging.h>
Rob Herring6de783a2016-05-06 10:06:59 -050042#include <android-base/stringprintf.h>
Tom Cherry2e344f92017-04-04 17:53:45 -070043#include <android-base/strings.h>
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +080044#include <android-base/unique_fd.h>
Vernon Tang3f582e92011-04-25 13:08:17 +100045#include <cutils/uevent.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070046#include <private/android_filesystem_config.h>
47#include <selinux/android.h>
48#include <selinux/avc.h>
49#include <selinux/label.h>
50#include <selinux/selinux.h>
Vernon Tang3f582e92011-04-25 13:08:17 +100051
Greg Hackmann3312aa82013-11-18 15:24:40 -080052#include "ueventd_parser.h"
Colin Crossb0ab94b2010-04-08 16:16:20 -070053#include "util.h"
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070054
Stephen Smalleye096e362012-06-11 13:37:39 -040055extern struct selabel_handle *sehandle;
Stephen Smalleye46f9d52012-01-13 08:48:47 -050056
Sandeep Patil35403eb2017-02-08 20:27:12 -080057static android::base::unique_fd device_fd;
Colin Cross0dd7ca62010-04-13 19:25:51 -070058
Tom Cherrycc054c92017-04-05 17:55:46 -070059Permissions::Permissions(const std::string& name, mode_t perm, uid_t uid, gid_t gid)
60 : name_(name), perm_(perm), uid_(uid), gid_(gid), prefix_(false), wildcard_(false) {
61 // If the first * is the last character, then we'll treat name_ as a prefix
62 // Otherwise, if a * is present, then we do a full fnmatch().
63 auto wildcard_position = name_.find('*');
64 if (wildcard_position == name_.length() - 1) {
65 prefix_ = true;
66 name_.pop_back();
67 } else if (wildcard_position != std::string::npos) {
68 wildcard_ = true;
Ting-Yuan Huang09bd41d2016-11-15 15:35:16 -080069 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070070}
71
Tom Cherrycc054c92017-04-05 17:55:46 -070072bool Permissions::Match(const std::string& path) const {
73 if (prefix_) {
74 return android::base::StartsWith(path, name_.c_str());
75 } else if (wildcard_) {
76 return fnmatch(name_.c_str(), path.c_str(), FNM_PATHNAME) == 0;
Colin Cross43d537e2014-07-02 13:08:13 -070077 } else {
Tom Cherrycc054c92017-04-05 17:55:46 -070078 return path == name_;
Colin Cross43d537e2014-07-02 13:08:13 -070079 }
80
81 return false;
82}
83
Tom Cherrycc054c92017-04-05 17:55:46 -070084bool SysfsPermissions::MatchWithSubsystem(const std::string& path,
85 const std::string& subsystem) const {
86 std::string path_basename = android::base::Basename(path);
87 if (name().find(subsystem) != std::string::npos) {
88 if (Match("/sys/class/" + subsystem + "/" + path_basename)) return true;
89 if (Match("/sys/bus/" + subsystem + "/devices/" + path_basename)) return true;
Rob Herring6de783a2016-05-06 10:06:59 -050090 }
Tom Cherrycc054c92017-04-05 17:55:46 -070091 return Match(path);
Rob Herring6de783a2016-05-06 10:06:59 -050092}
Rob Herringe5636a32016-05-06 12:28:48 -050093
Tom Cherrycc054c92017-04-05 17:55:46 -070094void SysfsPermissions::SetPermissions(const std::string& path) const {
95 std::string attribute_file = path + "/" + attribute_;
96 LOG(INFO) << "fixup " << attribute_file << " " << uid() << " " << gid() << " " << std::oct
97 << perm();
98 chown(attribute_file.c_str(), uid(), gid());
99 chmod(attribute_file.c_str(), perm());
100}
101
102// TODO: Move these to be member variables of a future devices class.
103std::vector<Permissions> dev_permissions;
104std::vector<SysfsPermissions> sysfs_permissions;
105
106static void fixup_sys_permissions(const std::string& upath, const std::string& subsystem) {
Rob Herring6de783a2016-05-06 10:06:59 -0500107 // upaths omit the "/sys" that paths in this list
108 // contain, so we prepend it...
Tom Cherrycc054c92017-04-05 17:55:46 -0700109 std::string path = "/sys" + upath;
Rob Herring6de783a2016-05-06 10:06:59 -0500110
Tom Cherrycc054c92017-04-05 17:55:46 -0700111 for (const auto& s : sysfs_permissions) {
112 if (s.MatchWithSubsystem(path, subsystem)) s.SetPermissions(path);
Rob Herringe5636a32016-05-06 12:28:48 -0500113 }
114
115 if (access(path.c_str(), F_OK) == 0) {
Dmitry Shmidt7eed4742016-07-28 13:55:39 -0700116 LOG(VERBOSE) << "restorecon_recursive: " << path;
Paul Lawrencea8d84342016-11-14 15:40:18 -0800117 restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
Rob Herringe5636a32016-05-06 12:28:48 -0500118 }
119}
120
Tom Cherrycc054c92017-04-05 17:55:46 -0700121static std::tuple<mode_t, uid_t, gid_t> get_device_permissions(
122 const std::string& path, const std::vector<std::string>& links) {
123 // Search the perms list in reverse so that ueventd.$hardware can override ueventd.rc.
124 for (auto it = dev_permissions.rbegin(); it != dev_permissions.rend(); ++it) {
125 if (it->Match(path) || std::any_of(links.begin(), links.end(),
126 [it](const auto& link) { return it->Match(link); })) {
127 return {it->perm(), it->uid(), it->gid()};
Colin Cross43d537e2014-07-02 13:08:13 -0700128 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700129 }
Colin Cross44b65d02010-04-20 14:32:50 -0700130 /* Default if nothing found. */
Tom Cherrycc054c92017-04-05 17:55:46 -0700131 return {0600, 0, 0};
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700132}
133
Tom Cherrye3e48212017-04-11 13:53:37 -0700134static void make_device(const std::string& path, int block, int major, int minor,
Tom Cherry2e344f92017-04-04 17:53:45 -0700135 const std::vector<std::string>& links) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700136 dev_t dev;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500137 char *secontext = NULL;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700138
Tom Cherrycc054c92017-04-05 17:55:46 -0700139 auto [mode, uid, gid] = get_device_permissions(path, links);
140 mode |= (block ? S_IFBLK : S_IFCHR);
Kenny Rootb5982bf2012-10-16 23:07:05 -0700141
Sandeep Patilea239832017-02-03 07:51:55 -0800142 if (sehandle) {
Tom Cherry2e344f92017-04-04 17:53:45 -0700143 std::vector<const char*> c_links;
144 for (const auto& link : links) {
145 c_links.emplace_back(link.c_str());
146 }
147 c_links.emplace_back(nullptr);
Tom Cherrye3e48212017-04-11 13:53:37 -0700148 if (selabel_lookup_best_match(sehandle, &secontext, path.c_str(), &c_links[0], mode)) {
Sandeep Patilea239832017-02-03 07:51:55 -0800149 PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
150 return;
151 }
152 setfscreatecon(secontext);
Mihai Serban24a3cbf2016-04-25 18:22:27 +0300153 }
Kenny Rootb5982bf2012-10-16 23:07:05 -0700154
Colin Cross17dcc5c2010-09-03 12:25:34 -0700155 dev = makedev(major, minor);
Nick Pelly6405c692010-01-21 18:13:39 -0800156 /* Temporarily change egid to avoid race condition setting the gid of the
157 * device node. Unforunately changing the euid would prevent creation of
158 * some device nodes, so the uid has to be set with chown() and is still
159 * racy. Fixing the gid race at least fixed the issue with system_server
160 * opening dynamic input devices under the AID_INPUT gid. */
Tom Cherry0506b182017-02-23 13:46:09 -0800161 if (setegid(gid)) {
162 PLOG(ERROR) << "setegid(" << gid << ") for " << path << " device failed";
163 goto out;
164 }
Mihai Serban24a3cbf2016-04-25 18:22:27 +0300165 /* If the node already exists update its SELinux label to handle cases when
166 * it was created with the wrong context during coldboot procedure. */
Tom Cherrye3e48212017-04-11 13:53:37 -0700167 if (mknod(path.c_str(), mode, dev) && (errno == EEXIST) && secontext) {
William Roberts397de142016-06-02 09:53:44 -0700168 char* fcon = nullptr;
Tom Cherrye3e48212017-04-11 13:53:37 -0700169 int rc = lgetfilecon(path.c_str(), &fcon);
William Roberts397de142016-06-02 09:53:44 -0700170 if (rc < 0) {
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700171 PLOG(ERROR) << "Cannot get SELinux label on '" << path << "' device";
William Roberts397de142016-06-02 09:53:44 -0700172 goto out;
173 }
174
175 bool different = strcmp(fcon, secontext) != 0;
176 freecon(fcon);
177
Tom Cherrye3e48212017-04-11 13:53:37 -0700178 if (different && lsetfilecon(path.c_str(), secontext)) {
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700179 PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path << "' device";
Mihai Serban24a3cbf2016-04-25 18:22:27 +0300180 }
181 }
William Roberts397de142016-06-02 09:53:44 -0700182
183out:
Tom Cherrye3e48212017-04-11 13:53:37 -0700184 chown(path.c_str(), uid, -1);
Tom Cherry0506b182017-02-23 13:46:09 -0800185 if (setegid(AID_ROOT)) {
186 PLOG(FATAL) << "setegid(AID_ROOT) failed";
187 }
Kenny Rootb5982bf2012-10-16 23:07:05 -0700188
Sandeep Patilea239832017-02-03 07:51:55 -0800189 if (secontext) {
190 freecon(secontext);
191 setfscreatecon(NULL);
192 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700193}
194
Tom Cherry1ab8f552017-04-06 14:41:30 -0700195// TODO: Move this to be a member variable of a future devices class.
196std::vector<std::string> platform_devices;
Dima Zavinf395c922013-03-06 16:23:57 -0800197
Tom Cherry1ab8f552017-04-06 14:41:30 -0700198// Given a path that may start with a platform device, find the length of the
199// platform device prefix. If it doesn't start with a platform device, return false
200bool find_platform_device(const std::string& path, std::string* out_path) {
201 out_path->clear();
202 // platform_devices is searched backwards, since parents are added before their children,
203 // and we want to match as deep of a child as we can.
204 for (auto it = platform_devices.rbegin(); it != platform_devices.rend(); ++it) {
205 auto platform_device_path_length = it->length();
206 if (platform_device_path_length < path.length() &&
207 path[platform_device_path_length] == '/' &&
208 android::base::StartsWith(path, it->c_str())) {
209 *out_path = *it;
210 return true;
Colin Crossfadb85e2011-03-30 18:32:12 -0700211 }
212 }
Tom Cherry1ab8f552017-04-06 14:41:30 -0700213 return false;
Sandeep Patil35403eb2017-02-08 20:27:12 -0800214}
215
Andrew Boiea885d042013-09-13 17:41:20 -0700216/* Given a path that may start with a PCI device, populate the supplied buffer
217 * with the PCI domain/bus number and the peripheral ID and return 0.
218 * If it doesn't start with a PCI device, or there is some error, return -1 */
Tom Cherry2e344f92017-04-04 17:53:45 -0700219static bool find_pci_device_prefix(const std::string& path, std::string* result) {
220 result->clear();
Andrew Boiea885d042013-09-13 17:41:20 -0700221
Tom Cherry2e344f92017-04-04 17:53:45 -0700222 if (!android::base::StartsWith(path, "/devices/pci")) return false;
Andrew Boiea885d042013-09-13 17:41:20 -0700223
224 /* Beginning of the prefix is the initial "pci" after "/devices/" */
Tom Cherry2e344f92017-04-04 17:53:45 -0700225 std::string::size_type start = 9;
Andrew Boiea885d042013-09-13 17:41:20 -0700226
227 /* End of the prefix is two path '/' later, capturing the domain/bus number
228 * and the peripheral ID. Example: pci0000:00/0000:00:1f.2 */
Tom Cherry2e344f92017-04-04 17:53:45 -0700229 auto end = path.find('/', start);
230 if (end == std::string::npos) return false;
Andrew Boiea885d042013-09-13 17:41:20 -0700231
Tom Cherry2e344f92017-04-04 17:53:45 -0700232 end = path.find('/', end + 1);
233 if (end == std::string::npos) return false;
Andrew Boiea885d042013-09-13 17:41:20 -0700234
Tom Cherry2e344f92017-04-04 17:53:45 -0700235 auto length = end - start;
236 if (length <= 4) {
237 // The minimum string that will get to this check is 'pci/', which is malformed,
238 // so return false
239 return false;
240 }
241
242 *result = path.substr(start, length);
243 return true;
Andrew Boiea885d042013-09-13 17:41:20 -0700244}
245
Jeremy Compostella937309d2017-03-03 16:27:29 +0100246/* Given a path that may start with a virtual block device, populate
247 * the supplied buffer with the virtual block device ID and return 0.
248 * If it doesn't start with a virtual block device, or there is some
249 * error, return -1 */
Tom Cherry2e344f92017-04-04 17:53:45 -0700250static bool find_vbd_device_prefix(const std::string& path, std::string* result) {
251 result->clear();
252
253 if (!android::base::StartsWith(path, "/devices/vbd-")) return false;
Jeremy Compostella937309d2017-03-03 16:27:29 +0100254
255 /* Beginning of the prefix is the initial "vbd-" after "/devices/" */
Tom Cherry2e344f92017-04-04 17:53:45 -0700256 std::string::size_type start = 13;
Jeremy Compostella937309d2017-03-03 16:27:29 +0100257
258 /* End of the prefix is one path '/' later, capturing the
259 virtual block device ID. Example: 768 */
Tom Cherry2e344f92017-04-04 17:53:45 -0700260 auto end = path.find('/', start);
261 if (end == std::string::npos) return false;
Jeremy Compostella937309d2017-03-03 16:27:29 +0100262
Tom Cherry2e344f92017-04-04 17:53:45 -0700263 auto length = end - start;
264 if (length == 0) return false;
Jeremy Compostella937309d2017-03-03 16:27:29 +0100265
Tom Cherry2e344f92017-04-04 17:53:45 -0700266 *result = path.substr(start, length);
267 return true;
Jeremy Compostella937309d2017-03-03 16:27:29 +0100268}
269
Tom Cherrye3e48212017-04-11 13:53:37 -0700270void parse_event(const char* msg, uevent* uevent) {
271 uevent->partition_num = -1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700272 uevent->major = -1;
273 uevent->minor = -1;
Tom Cherrye3e48212017-04-11 13:53:37 -0700274 // currently ignoring SEQNUM
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700275 while(*msg) {
276 if(!strncmp(msg, "ACTION=", 7)) {
277 msg += 7;
278 uevent->action = msg;
279 } else if(!strncmp(msg, "DEVPATH=", 8)) {
280 msg += 8;
281 uevent->path = msg;
282 } else if(!strncmp(msg, "SUBSYSTEM=", 10)) {
283 msg += 10;
284 uevent->subsystem = msg;
285 } else if(!strncmp(msg, "FIRMWARE=", 9)) {
286 msg += 9;
287 uevent->firmware = msg;
288 } else if(!strncmp(msg, "MAJOR=", 6)) {
289 msg += 6;
290 uevent->major = atoi(msg);
291 } else if(!strncmp(msg, "MINOR=", 6)) {
292 msg += 6;
293 uevent->minor = atoi(msg);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700294 } else if(!strncmp(msg, "PARTN=", 6)) {
295 msg += 6;
296 uevent->partition_num = atoi(msg);
297 } else if(!strncmp(msg, "PARTNAME=", 9)) {
298 msg += 9;
299 uevent->partition_name = msg;
Wei Zhongf97b8872012-03-23 14:15:34 -0700300 } else if(!strncmp(msg, "DEVNAME=", 8)) {
301 msg += 8;
302 uevent->device_name = msg;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700303 }
304
Tom Cherrye3e48212017-04-11 13:53:37 -0700305 // advance to after the next \0
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700306 while(*msg++)
307 ;
308 }
309
Elliott Hughesc0e919c2015-02-04 14:46:36 -0800310 if (LOG_UEVENTS) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700311 LOG(INFO) << "event { '" << uevent->action << "', '" << uevent->path << "', '"
312 << uevent->subsystem << "', '" << uevent->firmware << "', " << uevent->major
313 << ", " << uevent->minor << " }";
Elliott Hughesc0e919c2015-02-04 14:46:36 -0800314 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700315}
316
Tom Cherry2e344f92017-04-04 17:53:45 -0700317std::vector<std::string> get_character_device_symlinks(uevent* uevent) {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700318 std::string parent_device;
319 if (!find_platform_device(uevent->path, &parent_device)) return {};
Benoit Gobyd2278632010-08-03 14:36:02 -0700320
Tom Cherry1ab8f552017-04-06 14:41:30 -0700321 // skip path to the parent driver
322 std::string path = uevent->path.substr(parent_device.length());
Benoit Gobyd2278632010-08-03 14:36:02 -0700323
Tom Cherry1ab8f552017-04-06 14:41:30 -0700324 if (!android::base::StartsWith(path, "/usb")) return {};
Tom Cherry2e344f92017-04-04 17:53:45 -0700325
326 // skip root hub name and device. use device interface
327 // skip 3 slashes, including the first / by starting the search at the 1st character, not 0th.
328 // then extract what comes between the 3rd and 4th slash
329 // e.g. "/usb/usb_device/name/tty2-1:1.0" -> "name"
330
331 std::string::size_type start = 0;
Tom Cherry1ab8f552017-04-06 14:41:30 -0700332 start = path.find('/', start + 1);
Tom Cherry2e344f92017-04-04 17:53:45 -0700333 if (start == std::string::npos) return {};
334
Tom Cherry1ab8f552017-04-06 14:41:30 -0700335 start = path.find('/', start + 1);
Tom Cherry2e344f92017-04-04 17:53:45 -0700336 if (start == std::string::npos) return {};
337
Tom Cherry1ab8f552017-04-06 14:41:30 -0700338 auto end = path.find('/', start + 1);
Tom Cherry2e344f92017-04-04 17:53:45 -0700339 if (end == std::string::npos) return {};
340
341 start++; // Skip the first '/'
342
343 auto length = end - start;
344 if (length == 0) return {};
345
Tom Cherry1ab8f552017-04-06 14:41:30 -0700346 auto name_string = path.substr(start, length);
Tom Cherry2e344f92017-04-04 17:53:45 -0700347
Tom Cherry2e344f92017-04-04 17:53:45 -0700348 std::vector<std::string> links;
Tom Cherrye3e48212017-04-11 13:53:37 -0700349 links.emplace_back("/dev/usb/" + uevent->subsystem + name_string);
Tom Cherry2e344f92017-04-04 17:53:45 -0700350
351 mkdir("/dev/usb", 0755);
Benoit Gobyd2278632010-08-03 14:36:02 -0700352
353 return links;
Benoit Gobyd2278632010-08-03 14:36:02 -0700354}
355
Tom Cherryc44f6a42017-04-05 15:58:31 -0700356// replaces any unacceptable characters with '_', the
357// length of the resulting string is equal to the input string
Tom Cherry2e344f92017-04-04 17:53:45 -0700358void sanitize_partition_name(std::string* string) {
Tom Cherryc44f6a42017-04-05 15:58:31 -0700359 const char* accept =
360 "abcdefghijklmnopqrstuvwxyz"
361 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
362 "0123456789"
363 "_-.";
364
Tom Cherry2e344f92017-04-04 17:53:45 -0700365 if (!string) return;
Tom Cherryc44f6a42017-04-05 15:58:31 -0700366
Tom Cherry2e344f92017-04-04 17:53:45 -0700367 std::string::size_type pos = 0;
368 while ((pos = string->find_first_not_of(accept, pos)) != std::string::npos) {
369 (*string)[pos] = '_';
Tom Cherryc44f6a42017-04-05 15:58:31 -0700370 }
371}
372
Tom Cherry2e344f92017-04-04 17:53:45 -0700373std::vector<std::string> get_block_device_symlinks(uevent* uevent) {
374 std::string device;
Tom Cherry2e344f92017-04-04 17:53:45 -0700375 std::string type;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700376
Tom Cherry1ab8f552017-04-06 14:41:30 -0700377 if (find_platform_device(uevent->path, &device)) {
378 // Skip /devices/platform or /devices/ if present
379 static const std::string devices_platform_prefix = "/devices/platform/";
380 static const std::string devices_prefix = "/devices/";
381
382 if (android::base::StartsWith(device, devices_platform_prefix.c_str())) {
383 device = device.substr(devices_platform_prefix.length());
384 } else if (android::base::StartsWith(device, devices_prefix.c_str())) {
385 device = device.substr(devices_prefix.length());
386 }
387
Andrew Boiea885d042013-09-13 17:41:20 -0700388 type = "platform";
Tom Cherry2e344f92017-04-04 17:53:45 -0700389 } else if (find_pci_device_prefix(uevent->path, &device)) {
Andrew Boiea885d042013-09-13 17:41:20 -0700390 type = "pci";
Tom Cherry2e344f92017-04-04 17:53:45 -0700391 } else if (find_vbd_device_prefix(uevent->path, &device)) {
Jeremy Compostella937309d2017-03-03 16:27:29 +0100392 type = "vbd";
Andrew Boiea885d042013-09-13 17:41:20 -0700393 } else {
Tom Cherry2e344f92017-04-04 17:53:45 -0700394 return {};
Andrew Boiea885d042013-09-13 17:41:20 -0700395 }
Dima Zavinf395c922013-03-06 16:23:57 -0800396
Tom Cherry2e344f92017-04-04 17:53:45 -0700397 std::vector<std::string> links;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700398
Sandeep Patil35403eb2017-02-08 20:27:12 -0800399 LOG(VERBOSE) << "found " << type << " device " << device;
Colin Crossfadb85e2011-03-30 18:32:12 -0700400
Tom Cherry2e344f92017-04-04 17:53:45 -0700401 auto link_path = "/dev/block/" + type + "/" + device;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700402
Tom Cherrye3e48212017-04-11 13:53:37 -0700403 if (!uevent->partition_name.empty()) {
Tom Cherry2e344f92017-04-04 17:53:45 -0700404 std::string partition_name_sanitized(uevent->partition_name);
405 sanitize_partition_name(&partition_name_sanitized);
406 if (partition_name_sanitized != uevent->partition_name) {
407 LOG(VERBOSE) << "Linking partition '" << uevent->partition_name << "' as '"
408 << partition_name_sanitized << "'";
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700409 }
Tom Cherry2e344f92017-04-04 17:53:45 -0700410 links.emplace_back(link_path + "/by-name/" + partition_name_sanitized);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700411 }
412
413 if (uevent->partition_num >= 0) {
Tom Cherry2e344f92017-04-04 17:53:45 -0700414 links.emplace_back(link_path + "/by-num/p" + std::to_string(uevent->partition_num));
Colin Crossb0ab94b2010-04-08 16:16:20 -0700415 }
416
Tom Cherrye3e48212017-04-11 13:53:37 -0700417 auto last_slash = uevent->path.rfind('/');
418 links.emplace_back(link_path + "/" + uevent->path.substr(last_slash + 1));
Colin Crossb0ab94b2010-04-08 16:16:20 -0700419
420 return links;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700421}
422
Tom Cherrye3e48212017-04-11 13:53:37 -0700423static void make_link_init(const std::string& oldpath, const std::string& newpath) {
424 if (mkdir_recursive(dirname(newpath.c_str()), 0755)) {
425 PLOG(ERROR) << "Failed to create directory " << dirname(newpath.c_str());
426 }
Elliott Hughesf39f7f12016-08-31 14:41:51 -0700427
Tom Cherrye3e48212017-04-11 13:53:37 -0700428 if (symlink(oldpath.c_str(), newpath.c_str()) && errno != EEXIST) {
429 PLOG(ERROR) << "Failed to symlink " << oldpath << " to " << newpath;
430 }
Elliott Hughesf39f7f12016-08-31 14:41:51 -0700431}
432
Tom Cherrye3e48212017-04-11 13:53:37 -0700433static void remove_link(const std::string& oldpath, const std::string& newpath) {
434 std::string path;
435 if (android::base::Readlink(newpath, &path) && path == oldpath) unlink(newpath.c_str());
Elliott Hughesf39f7f12016-08-31 14:41:51 -0700436}
437
Tom Cherrye3e48212017-04-11 13:53:37 -0700438static void handle_device(const std::string& action, const std::string& devpath, int block,
Tom Cherry2e344f92017-04-04 17:53:45 -0700439 int major, int minor, const std::vector<std::string>& links) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700440 if (action == "add") {
441 make_device(devpath, block, major, minor, links);
Tom Cherry2e344f92017-04-04 17:53:45 -0700442 for (const auto& link : links) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700443 make_link_init(devpath, link);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700444 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700445 }
446
Tom Cherrye3e48212017-04-11 13:53:37 -0700447 if (action == "remove") {
Tom Cherry2e344f92017-04-04 17:53:45 -0700448 for (const auto& link : links) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700449 remove_link(devpath, link);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700450 }
Tom Cherrye3e48212017-04-11 13:53:37 -0700451 unlink(devpath.c_str());
Colin Crossb0ab94b2010-04-08 16:16:20 -0700452 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700453}
454
Tom Cherry1ab8f552017-04-06 14:41:30 -0700455void handle_platform_device_event(uevent* uevent) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700456 if (uevent->action == "add") {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700457 platform_devices.emplace_back(uevent->path);
Tom Cherrye3e48212017-04-11 13:53:37 -0700458 } else if (uevent->action == "remove") {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700459 auto it = std::find(platform_devices.begin(), platform_devices.end(), uevent->path);
460 if (it != platform_devices.end()) platform_devices.erase(it);
Tom Cherrye3e48212017-04-11 13:53:37 -0700461 }
Colin Crossfadb85e2011-03-30 18:32:12 -0700462}
463
Tom Cherry3fa46732017-04-11 14:19:50 -0700464static void handle_block_device_event(uevent* uevent) {
465 // if it's not a /dev device, nothing to do
466 if (uevent->major < 0 || uevent->minor < 0) return;
Colin Crosseb5ba832011-03-30 17:37:17 -0700467
Tom Cherry3fa46732017-04-11 14:19:50 -0700468 const char* base = "/dev/block/";
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500469 make_dir(base, 0755);
Colin Crosseb5ba832011-03-30 17:37:17 -0700470
Tom Cherry3fa46732017-04-11 14:19:50 -0700471 std::string name = android::base::Basename(uevent->path);
472 std::string devpath = base + name;
473
Tom Cherry2e344f92017-04-04 17:53:45 -0700474 std::vector<std::string> links;
Tom Cherrye3e48212017-04-11 13:53:37 -0700475 if (android::base::StartsWith(uevent->path, "/devices")) {
Andrew Boiea885d042013-09-13 17:41:20 -0700476 links = get_block_device_symlinks(uevent);
Tom Cherrye3e48212017-04-11 13:53:37 -0700477 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700478
Tom Cherrye3e48212017-04-11 13:53:37 -0700479 handle_device(uevent->action, devpath, 1, uevent->major, uevent->minor, links);
Colin Crosseb5ba832011-03-30 17:37:17 -0700480}
481
Tom Cherry3fa46732017-04-11 14:19:50 -0700482static void handle_generic_device_event(uevent* uevent) {
483 // if it's not a /dev device, nothing to do
484 if (uevent->major < 0 || uevent->minor < 0) return;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800485
Tom Cherry3fa46732017-04-11 14:19:50 -0700486 std::string name = android::base::Basename(uevent->path);
Tom Cherrye3e48212017-04-11 13:53:37 -0700487 ueventd_subsystem* subsystem = ueventd_subsystem_find_by_name(uevent->subsystem.c_str());
Greg Hackmann3312aa82013-11-18 15:24:40 -0800488
Tom Cherry3fa46732017-04-11 14:19:50 -0700489 std::string devpath;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800490
491 if (subsystem) {
Tom Cherry3fa46732017-04-11 14:19:50 -0700492 std::string devname;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800493
494 switch (subsystem->devname_src) {
495 case DEVNAME_UEVENT_DEVNAME:
496 devname = uevent->device_name;
497 break;
498
499 case DEVNAME_UEVENT_DEVPATH:
500 devname = name;
501 break;
502
503 default:
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700504 LOG(ERROR) << uevent->subsystem << " subsystem's devpath option is not set; ignoring event";
Greg Hackmann3312aa82013-11-18 15:24:40 -0800505 return;
506 }
507
Tom Cherry3fa46732017-04-11 14:19:50 -0700508 // TODO: Remove std::string()
509 devpath = std::string(subsystem->dirname) + "/" + devname;
510 mkdir_recursive(android::base::Dirname(devpath), 0755);
Tom Cherrye3e48212017-04-11 13:53:37 -0700511 } else if (android::base::StartsWith(uevent->subsystem, "usb")) {
512 if (uevent->subsystem == "usb") {
513 if (!uevent->device_name.empty()) {
514 devpath = "/dev/" + uevent->device_name;
Tom Cherry3fa46732017-04-11 14:19:50 -0700515 } else {
516 // This imitates the file system that would be created
517 // if we were using devfs instead.
518 // Minors are broken up into groups of 128, starting at "001"
519 int bus_id = uevent->minor / 128 + 1;
520 int device_id = uevent->minor % 128 + 1;
521 devpath = android::base::StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id);
522 }
523 mkdir_recursive(android::base::Dirname(devpath), 0755);
524 } else {
525 // ignore other USB events
526 return;
527 }
Tom Cherry780a71e2017-04-04 16:30:40 -0700528 } else {
Tom Cherry3fa46732017-04-11 14:19:50 -0700529 devpath = "/dev/" + name;
Tom Cherry780a71e2017-04-04 16:30:40 -0700530 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700531
Tom Cherry780a71e2017-04-04 16:30:40 -0700532 auto links = get_character_device_symlinks(uevent);
Colin Crosseb5ba832011-03-30 17:37:17 -0700533
Tom Cherrye3e48212017-04-11 13:53:37 -0700534 handle_device(uevent->action, devpath, 0, uevent->major, uevent->minor, links);
Colin Crosseb5ba832011-03-30 17:37:17 -0700535}
536
537static void handle_device_event(struct uevent *uevent)
538{
Tom Cherrye3e48212017-04-11 13:53:37 -0700539 if (uevent->action == "add" || uevent->action == "change" || uevent->action == "online") {
Tom Cherrycc054c92017-04-05 17:55:46 -0700540 fixup_sys_permissions(uevent->path, uevent->subsystem);
Tom Cherrye3e48212017-04-11 13:53:37 -0700541 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700542
Tom Cherrye3e48212017-04-11 13:53:37 -0700543 if (uevent->subsystem == "block") {
Colin Crosseb5ba832011-03-30 17:37:17 -0700544 handle_block_device_event(uevent);
Tom Cherrye3e48212017-04-11 13:53:37 -0700545 } else if (uevent->subsystem == "platform") {
Colin Crossfadb85e2011-03-30 18:32:12 -0700546 handle_platform_device_event(uevent);
Colin Crosseb5ba832011-03-30 17:37:17 -0700547 } else {
548 handle_generic_device_event(uevent);
549 }
550}
551
Elliott Hughes632e99a2016-11-12 11:44:16 -0800552static void load_firmware(uevent* uevent, const std::string& root,
553 int fw_fd, size_t fw_size,
554 int loading_fd, int data_fd) {
555 // Start transfer.
556 android::base::WriteFully(loading_fd, "1", 1);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700557
Elliott Hughes632e99a2016-11-12 11:44:16 -0800558 // Copy the firmware.
559 int rc = sendfile(data_fd, fw_fd, nullptr, fw_size);
560 if (rc == -1) {
561 PLOG(ERROR) << "firmware: sendfile failed { '" << root << "', '" << uevent->firmware << "' }";
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700562 }
563
Elliott Hughes632e99a2016-11-12 11:44:16 -0800564 // Tell the firmware whether to abort or commit.
565 const char* response = (rc != -1) ? "0" : "-1";
566 android::base::WriteFully(loading_fd, response, strlen(response));
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700567}
568
Elliott Hughes632e99a2016-11-12 11:44:16 -0800569static int is_booting() {
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700570 return access("/dev/.booting", F_OK) == 0;
571}
572
Elliott Hughes632e99a2016-11-12 11:44:16 -0800573static void process_firmware_event(uevent* uevent) {
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700574 int booting = is_booting();
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700575
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700576 LOG(INFO) << "firmware: loading '" << uevent->firmware << "' for '" << uevent->path << "'";
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700577
Tom Cherrye3e48212017-04-11 13:53:37 -0700578 std::string root = "/sys" + uevent->path;
Elliott Hughes632e99a2016-11-12 11:44:16 -0800579 std::string loading = root + "/loading";
580 std::string data = root + "/data";
581
582 android::base::unique_fd loading_fd(open(loading.c_str(), O_WRONLY|O_CLOEXEC));
583 if (loading_fd == -1) {
584 PLOG(ERROR) << "couldn't open firmware loading fd for " << uevent->firmware;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700585 return;
Elliott Hughes632e99a2016-11-12 11:44:16 -0800586 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700587
Elliott Hughes632e99a2016-11-12 11:44:16 -0800588 android::base::unique_fd data_fd(open(data.c_str(), O_WRONLY|O_CLOEXEC));
589 if (data_fd == -1) {
590 PLOG(ERROR) << "couldn't open firmware data fd for " << uevent->firmware;
591 return;
592 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700593
Tom Cherrye3e48212017-04-11 13:53:37 -0700594 static const char* firmware_dirs[] = {"/etc/firmware/", "/vendor/firmware/",
595 "/firmware/image/"};
596
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700597try_loading_again:
Elliott Hughes632e99a2016-11-12 11:44:16 -0800598 for (size_t i = 0; i < arraysize(firmware_dirs); i++) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700599 std::string file = firmware_dirs[i] + uevent->firmware;
Elliott Hughes632e99a2016-11-12 11:44:16 -0800600 android::base::unique_fd fw_fd(open(file.c_str(), O_RDONLY|O_CLOEXEC));
601 struct stat sb;
602 if (fw_fd != -1 && fstat(fw_fd, &sb) != -1) {
603 load_firmware(uevent, root, fw_fd, sb.st_size, loading_fd, data_fd);
604 return;
Benoit Goby609d8822010-11-09 18:10:24 -0800605 }
Brian Swetland02863b92010-09-19 03:36:39 -0700606 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700607
Elliott Hughes632e99a2016-11-12 11:44:16 -0800608 if (booting) {
609 // If we're not fully booted, we may be missing
610 // filesystems needed for firmware, wait and retry.
Elliott Hughes290a2282016-11-14 17:08:47 -0800611 std::this_thread::sleep_for(100ms);
Elliott Hughes632e99a2016-11-12 11:44:16 -0800612 booting = is_booting();
613 goto try_loading_again;
614 }
615
616 LOG(ERROR) << "firmware: could not find firmware for " << uevent->firmware;
617
618 // Write "-1" as our response to the kernel's firmware request, since we have nothing for it.
619 write(loading_fd, "-1", 2);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700620}
621
Elliott Hughes632e99a2016-11-12 11:44:16 -0800622static void handle_firmware_event(uevent* uevent) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700623 if (uevent->subsystem != "firmware" || uevent->action != "add") return;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700624
Elliott Hughes632e99a2016-11-12 11:44:16 -0800625 // Loading the firmware in a child means we can do that in parallel...
626 // (We ignore SIGCHLD rather than wait for our children.)
627 pid_t pid = fork();
628 if (pid == 0) {
629 Timer t;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700630 process_firmware_event(uevent);
Elliott Hughes331cf2f2016-11-29 19:20:58 +0000631 LOG(INFO) << "loading " << uevent->path << " took " << t;
Kenny Root17baff42014-08-20 16:16:44 -0700632 _exit(EXIT_SUCCESS);
Elliott Hughes632e99a2016-11-12 11:44:16 -0800633 } else if (pid == -1) {
634 PLOG(ERROR) << "could not fork to process firmware event for " << uevent->firmware;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700635 }
636}
637
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800638static bool inline should_stop_coldboot(coldboot_action_t act)
639{
640 return (act == COLDBOOT_STOP || act == COLDBOOT_FINISH);
641}
642
Ruchi Kandoic6037202014-06-23 11:22:09 -0700643#define UEVENT_MSG_LEN 2048
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800644
Sandeep Patil44a3ee22017-02-08 15:49:47 -0800645static inline coldboot_action_t handle_device_fd_with(
646 std::function<coldboot_action_t(uevent* uevent)> handle_uevent)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700647{
Vernon Tang3f582e92011-04-25 13:08:17 +1000648 char msg[UEVENT_MSG_LEN+2];
649 int n;
Nick Kralevich57de8b82011-05-11 14:58:24 -0700650 while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
Nick Kralevich5f5d5c82010-07-19 14:31:20 -0700651 if(n >= UEVENT_MSG_LEN) /* overflow -- discard */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700652 continue;
653
654 msg[n] = '\0';
655 msg[n+1] = '\0';
656
Tom Cherrye3e48212017-04-11 13:53:37 -0700657 uevent uevent;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700658 parse_event(msg, &uevent);
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800659 coldboot_action_t act = handle_uevent(&uevent);
660 if (should_stop_coldboot(act))
661 return act;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700662 }
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800663
664 return COLDBOOT_CONTINUE;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700665}
666
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800667coldboot_action_t handle_device_fd(coldboot_callback fn)
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800668{
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800669 coldboot_action_t ret = handle_device_fd_with(
670 [&](uevent* uevent) -> coldboot_action_t {
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800671 if (selinux_status_updated() > 0) {
672 struct selabel_handle *sehandle2;
673 sehandle2 = selinux_android_file_context_handle();
674 if (sehandle2) {
675 selabel_close(sehandle);
676 sehandle = sehandle2;
677 }
678 }
679
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800680 // default is to always create the devices
681 coldboot_action_t act = COLDBOOT_CREATE;
682 if (fn) {
683 act = fn(uevent);
684 }
685
686 if (act == COLDBOOT_CREATE || act == COLDBOOT_STOP) {
687 handle_device_event(uevent);
688 handle_firmware_event(uevent);
689 }
690
691 return act;
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800692 });
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800693
694 return ret;
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800695}
696
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700697/* Coldboot walks parts of the /sys tree and pokes the uevent files
698** to cause the kernel to regenerate device add events that happened
699** before init's device manager was started
700**
701** We drain any pending events from the netlink socket every time
702** we poke another uevent file to make sure we don't overrun the
Elliott Hughesc0e919c2015-02-04 14:46:36 -0800703** socket's buffer.
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700704*/
705
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800706static coldboot_action_t do_coldboot(DIR *d, coldboot_callback fn)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700707{
708 struct dirent *de;
709 int dfd, fd;
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800710 coldboot_action_t act = COLDBOOT_CONTINUE;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700711
712 dfd = dirfd(d);
713
714 fd = openat(dfd, "uevent", O_WRONLY);
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800715 if (fd >= 0) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700716 write(fd, "add\n", 4);
717 close(fd);
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800718 act = handle_device_fd(fn);
719 if (should_stop_coldboot(act))
720 return act;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700721 }
722
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800723 while (!should_stop_coldboot(act) && (de = readdir(d))) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700724 DIR *d2;
725
726 if(de->d_type != DT_DIR || de->d_name[0] == '.')
727 continue;
728
729 fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
730 if(fd < 0)
731 continue;
732
733 d2 = fdopendir(fd);
734 if(d2 == 0)
735 close(fd);
736 else {
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800737 act = do_coldboot(d2, fn);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700738 closedir(d2);
739 }
740 }
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800741
742 // default is always to continue looking for uevents
743 return act;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700744}
745
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800746static coldboot_action_t coldboot(const char *path, coldboot_callback fn)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700747{
James Hawkins588a2ca2016-02-18 14:52:46 -0800748 std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path), closedir);
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800749 if (d) {
750 return do_coldboot(d.get(), fn);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700751 }
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800752
753 return COLDBOOT_CONTINUE;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700754}
755
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800756void device_init(const char* path, coldboot_callback fn) {
Sandeep Patil971a4602017-02-15 13:37:52 -0800757 if (!sehandle) {
758 sehandle = selinux_android_file_context_handle();
Elliott Hughes56a06562015-03-28 11:23:32 -0700759 }
Sandeep Patil971a4602017-02-15 13:37:52 -0800760 // open uevent socket and selinux status only if it hasn't been
761 // done before
762 if (device_fd == -1) {
763 /* is 256K enough? udev uses 16MB! */
764 device_fd.reset(uevent_open_socket(256 * 1024, true));
765 if (device_fd == -1) {
766 return;
767 }
768 fcntl(device_fd, F_SETFL, O_NONBLOCK);
769 selinux_status_open(true);
770 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700771
Elliott Hughes56a06562015-03-28 11:23:32 -0700772 if (access(COLDBOOT_DONE, F_OK) == 0) {
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700773 LOG(VERBOSE) << "Skipping coldboot, already done!";
Elliott Hughes56a06562015-03-28 11:23:32 -0700774 return;
Colin Crossf83d0b92010-04-21 12:04:20 -0700775 }
Elliott Hughes56a06562015-03-28 11:23:32 -0700776
777 Timer t;
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800778 coldboot_action_t act;
779 if (!path) {
780 act = coldboot("/sys/class", fn);
781 if (!should_stop_coldboot(act)) {
782 act = coldboot("/sys/block", fn);
783 if (!should_stop_coldboot(act)) {
784 act = coldboot("/sys/devices", fn);
785 }
786 }
787 } else {
788 act = coldboot(path, fn);
789 }
790
791 // If we have a callback, then do as it says. If no, then the default is
792 // to always create COLDBOOT_DONE file.
793 if (!fn || (act == COLDBOOT_FINISH)) {
794 close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
795 }
796
Elliott Hughes331cf2f2016-11-29 19:20:58 +0000797 LOG(INFO) << "Coldboot took " << t;
Colin Cross0dd7ca62010-04-13 19:25:51 -0700798}
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700799
Sandeep Patil35403eb2017-02-08 20:27:12 -0800800void device_close() {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700801 platform_devices.clear();
Sandeep Patil35403eb2017-02-08 20:27:12 -0800802 device_fd.reset();
Sandeep Patil971a4602017-02-15 13:37:52 -0800803 selinux_status_close();
Sandeep Patil35403eb2017-02-08 20:27:12 -0800804}
805
Elliott Hughes632e99a2016-11-12 11:44:16 -0800806int get_device_fd() {
Colin Cross0dd7ca62010-04-13 19:25:51 -0700807 return device_fd;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700808}