blob: 74f099adee1ffcb5e963e1e371ba55e37764463a [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>
Tom Cherryfe062052017-04-24 16:59:05 -070023#include <grp.h>
Elliott Hughesf39f7f12016-08-31 14:41:51 -070024#include <libgen.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070025#include <linux/netlink.h>
Tom Cherryfe062052017-04-24 16:59:05 -070026#include <pwd.h>
Olivier Baillyb93e5812010-11-17 11:47:23 -080027#include <stddef.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070028#include <stdio.h>
29#include <stdlib.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070030#include <string.h>
Elliott Hughes632e99a2016-11-12 11:44:16 -080031#include <sys/sendfile.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070032#include <sys/socket.h>
Elliott Hughesf39f7f12016-08-31 14:41:51 -070033#include <sys/time.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070034#include <sys/un.h>
Elliott Hughesf39f7f12016-08-31 14:41:51 -070035#include <sys/wait.h>
36#include <unistd.h>
37
Tom Cherry2e344f92017-04-04 17:53:45 -070038#include <algorithm>
James Hawkins588a2ca2016-02-18 14:52:46 -080039#include <memory>
Elliott Hughes290a2282016-11-14 17:08:47 -080040#include <thread>
James Hawkins588a2ca2016-02-18 14:52:46 -080041
Biao Ludc848562016-01-28 16:10:54 +080042#include <android-base/file.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070043#include <android-base/logging.h>
Rob Herring6de783a2016-05-06 10:06:59 -050044#include <android-base/stringprintf.h>
Tom Cherry2e344f92017-04-04 17:53:45 -070045#include <android-base/strings.h>
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +080046#include <android-base/unique_fd.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>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070050#include <selinux/label.h>
51#include <selinux/selinux.h>
Vernon Tang3f582e92011-04-25 13:08:17 +100052
Tom Cherryfe062052017-04-24 16:59:05 -070053#include "keyword_map.h"
54#include "ueventd.h"
Colin Crossb0ab94b2010-04-08 16:16:20 -070055#include "util.h"
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070056
Tom Cherrye7656b72017-05-01 17:10:09 -070057#ifdef _INIT_INIT_H
58#error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
59#endif
60
61static selabel_handle* sehandle;
Stephen Smalleye46f9d52012-01-13 08:48:47 -050062
Sandeep Patil35403eb2017-02-08 20:27:12 -080063static android::base::unique_fd device_fd;
Colin Cross0dd7ca62010-04-13 19:25:51 -070064
Tom Cherrycc054c92017-04-05 17:55:46 -070065Permissions::Permissions(const std::string& name, mode_t perm, uid_t uid, gid_t gid)
66 : name_(name), perm_(perm), uid_(uid), gid_(gid), prefix_(false), wildcard_(false) {
67 // If the first * is the last character, then we'll treat name_ as a prefix
68 // Otherwise, if a * is present, then we do a full fnmatch().
69 auto wildcard_position = name_.find('*');
70 if (wildcard_position == name_.length() - 1) {
71 prefix_ = true;
72 name_.pop_back();
73 } else if (wildcard_position != std::string::npos) {
74 wildcard_ = true;
Ting-Yuan Huang09bd41d2016-11-15 15:35:16 -080075 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070076}
77
Tom Cherrycc054c92017-04-05 17:55:46 -070078bool Permissions::Match(const std::string& path) const {
79 if (prefix_) {
80 return android::base::StartsWith(path, name_.c_str());
81 } else if (wildcard_) {
82 return fnmatch(name_.c_str(), path.c_str(), FNM_PATHNAME) == 0;
Colin Cross43d537e2014-07-02 13:08:13 -070083 } else {
Tom Cherrycc054c92017-04-05 17:55:46 -070084 return path == name_;
Colin Cross43d537e2014-07-02 13:08:13 -070085 }
86
87 return false;
88}
89
Tom Cherrycc054c92017-04-05 17:55:46 -070090bool SysfsPermissions::MatchWithSubsystem(const std::string& path,
91 const std::string& subsystem) const {
92 std::string path_basename = android::base::Basename(path);
93 if (name().find(subsystem) != std::string::npos) {
94 if (Match("/sys/class/" + subsystem + "/" + path_basename)) return true;
95 if (Match("/sys/bus/" + subsystem + "/devices/" + path_basename)) return true;
Rob Herring6de783a2016-05-06 10:06:59 -050096 }
Tom Cherrycc054c92017-04-05 17:55:46 -070097 return Match(path);
Rob Herring6de783a2016-05-06 10:06:59 -050098}
Rob Herringe5636a32016-05-06 12:28:48 -050099
Tom Cherrycc054c92017-04-05 17:55:46 -0700100void SysfsPermissions::SetPermissions(const std::string& path) const {
101 std::string attribute_file = path + "/" + attribute_;
102 LOG(INFO) << "fixup " << attribute_file << " " << uid() << " " << gid() << " " << std::oct
103 << perm();
104 chown(attribute_file.c_str(), uid(), gid());
105 chmod(attribute_file.c_str(), perm());
106}
107
108// TODO: Move these to be member variables of a future devices class.
109std::vector<Permissions> dev_permissions;
110std::vector<SysfsPermissions> sysfs_permissions;
111
Tom Cherryfe062052017-04-24 16:59:05 -0700112bool ParsePermissionsLine(std::vector<std::string>&& args, std::string* err, bool is_sysfs) {
113 if (is_sysfs && args.size() != 5) {
114 *err = "/sys/ lines must have 5 entries";
115 return false;
116 }
117
118 if (!is_sysfs && args.size() != 4) {
119 *err = "/dev/ lines must have 4 entries";
120 return false;
121 }
122
123 auto it = args.begin();
124 const std::string& name = *it++;
125
126 std::string sysfs_attribute;
127 if (is_sysfs) sysfs_attribute = *it++;
128
129 // args is now common to both sys and dev entries and contains: <perm> <uid> <gid>
130 std::string& perm_string = *it++;
131 char* end_pointer = 0;
132 mode_t perm = strtol(perm_string.c_str(), &end_pointer, 8);
133 if (end_pointer == nullptr || *end_pointer != '\0') {
134 *err = "invalid mode '" + perm_string + "'";
135 return false;
136 }
137
138 std::string& uid_string = *it++;
139 passwd* pwd = getpwnam(uid_string.c_str());
140 if (!pwd) {
141 *err = "invalid uid '" + uid_string + "'";
142 return false;
143 }
144 uid_t uid = pwd->pw_uid;
145
146 std::string& gid_string = *it++;
147 struct group* grp = getgrnam(gid_string.c_str());
148 if (!grp) {
149 *err = "invalid gid '" + gid_string + "'";
150 return false;
151 }
152 gid_t gid = grp->gr_gid;
153
154 if (is_sysfs) {
155 sysfs_permissions.emplace_back(name, sysfs_attribute, perm, uid, gid);
156 } else {
157 dev_permissions.emplace_back(name, perm, uid, gid);
158 }
159 return true;
160}
161
162// TODO: Move this to be a member variable of a future devices class.
163static std::vector<Subsystem> subsystems;
164
165std::string Subsystem::ParseDevPath(uevent* uevent) const {
166 std::string devname = devname_source_ == DevnameSource::DEVNAME_UEVENT_DEVNAME
167 ? uevent->device_name
168 : android::base::Basename(uevent->path);
169
170 return dir_name_ + "/" + devname;
171}
172
173bool SubsystemParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
174 int line, std::string* err) {
175 if (args.size() != 2) {
176 *err = "subsystems must have exactly one name";
177 return false;
178 }
179
180 if (std::find(subsystems.begin(), subsystems.end(), args[1]) != subsystems.end()) {
181 *err = "ignoring duplicate subsystem entry";
182 return false;
183 }
184
185 subsystem_.name_ = args[1];
186
187 return true;
188}
189
190bool SubsystemParser::ParseDevName(std::vector<std::string>&& args, std::string* err) {
191 if (args[1] == "uevent_devname") {
192 subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVNAME;
193 return true;
194 }
195 if (args[1] == "uevent_devpath") {
196 subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVPATH;
197 return true;
198 }
199
200 *err = "invalid devname '" + args[1] + "'";
201 return false;
202}
203
204bool SubsystemParser::ParseDirName(std::vector<std::string>&& args, std::string* err) {
205 if (args[1].front() != '/') {
206 *err = "dirname '" + args[1] + " ' does not start with '/'";
207 return false;
208 }
209
210 subsystem_.dir_name_ = args[1];
211 return true;
212}
213
214bool SubsystemParser::ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) {
215 using OptionParser =
216 bool (SubsystemParser::*)(std::vector<std::string> && args, std::string * err);
217 static class OptionParserMap : public KeywordMap<OptionParser> {
218 private:
219 const Map& map() const override {
220 // clang-format off
221 static const Map option_parsers = {
222 {"devname", {1, 1, &SubsystemParser::ParseDevName}},
223 {"dirname", {1, 1, &SubsystemParser::ParseDirName}},
224 };
225 // clang-format on
226 return option_parsers;
227 }
228 } parser_map;
229
230 auto parser = parser_map.FindFunction(args, err);
231
232 if (!parser) {
233 return false;
234 }
235
236 return (this->*parser)(std::move(args), err);
237}
238
239void SubsystemParser::EndSection() {
240 subsystems.emplace_back(std::move(subsystem_));
241}
242
Tom Cherrycc054c92017-04-05 17:55:46 -0700243static void fixup_sys_permissions(const std::string& upath, const std::string& subsystem) {
Rob Herring6de783a2016-05-06 10:06:59 -0500244 // upaths omit the "/sys" that paths in this list
245 // contain, so we prepend it...
Tom Cherrycc054c92017-04-05 17:55:46 -0700246 std::string path = "/sys" + upath;
Rob Herring6de783a2016-05-06 10:06:59 -0500247
Tom Cherrycc054c92017-04-05 17:55:46 -0700248 for (const auto& s : sysfs_permissions) {
249 if (s.MatchWithSubsystem(path, subsystem)) s.SetPermissions(path);
Rob Herringe5636a32016-05-06 12:28:48 -0500250 }
251
252 if (access(path.c_str(), F_OK) == 0) {
Dmitry Shmidt7eed4742016-07-28 13:55:39 -0700253 LOG(VERBOSE) << "restorecon_recursive: " << path;
Paul Lawrencea8d84342016-11-14 15:40:18 -0800254 restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
Rob Herringe5636a32016-05-06 12:28:48 -0500255 }
256}
257
Tom Cherrycc054c92017-04-05 17:55:46 -0700258static std::tuple<mode_t, uid_t, gid_t> get_device_permissions(
259 const std::string& path, const std::vector<std::string>& links) {
260 // Search the perms list in reverse so that ueventd.$hardware can override ueventd.rc.
261 for (auto it = dev_permissions.rbegin(); it != dev_permissions.rend(); ++it) {
262 if (it->Match(path) || std::any_of(links.begin(), links.end(),
263 [it](const auto& link) { return it->Match(link); })) {
264 return {it->perm(), it->uid(), it->gid()};
Colin Cross43d537e2014-07-02 13:08:13 -0700265 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700266 }
Colin Cross44b65d02010-04-20 14:32:50 -0700267 /* Default if nothing found. */
Tom Cherrycc054c92017-04-05 17:55:46 -0700268 return {0600, 0, 0};
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700269}
270
Tom Cherrye3e48212017-04-11 13:53:37 -0700271static void make_device(const std::string& path, int block, int major, int minor,
Tom Cherry2e344f92017-04-04 17:53:45 -0700272 const std::vector<std::string>& links) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700273 dev_t dev;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500274 char *secontext = NULL;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700275
Tom Cherrycc054c92017-04-05 17:55:46 -0700276 auto [mode, uid, gid] = get_device_permissions(path, links);
277 mode |= (block ? S_IFBLK : S_IFCHR);
Kenny Rootb5982bf2012-10-16 23:07:05 -0700278
Sandeep Patilea239832017-02-03 07:51:55 -0800279 if (sehandle) {
Tom Cherry2e344f92017-04-04 17:53:45 -0700280 std::vector<const char*> c_links;
281 for (const auto& link : links) {
282 c_links.emplace_back(link.c_str());
283 }
284 c_links.emplace_back(nullptr);
Tom Cherrye3e48212017-04-11 13:53:37 -0700285 if (selabel_lookup_best_match(sehandle, &secontext, path.c_str(), &c_links[0], mode)) {
Sandeep Patilea239832017-02-03 07:51:55 -0800286 PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
287 return;
288 }
289 setfscreatecon(secontext);
Mihai Serban24a3cbf2016-04-25 18:22:27 +0300290 }
Kenny Rootb5982bf2012-10-16 23:07:05 -0700291
Colin Cross17dcc5c2010-09-03 12:25:34 -0700292 dev = makedev(major, minor);
Nick Pelly6405c692010-01-21 18:13:39 -0800293 /* Temporarily change egid to avoid race condition setting the gid of the
294 * device node. Unforunately changing the euid would prevent creation of
295 * some device nodes, so the uid has to be set with chown() and is still
296 * racy. Fixing the gid race at least fixed the issue with system_server
297 * opening dynamic input devices under the AID_INPUT gid. */
Tom Cherry0506b182017-02-23 13:46:09 -0800298 if (setegid(gid)) {
299 PLOG(ERROR) << "setegid(" << gid << ") for " << path << " device failed";
300 goto out;
301 }
Mihai Serban24a3cbf2016-04-25 18:22:27 +0300302 /* If the node already exists update its SELinux label to handle cases when
303 * it was created with the wrong context during coldboot procedure. */
Tom Cherrye3e48212017-04-11 13:53:37 -0700304 if (mknod(path.c_str(), mode, dev) && (errno == EEXIST) && secontext) {
William Roberts397de142016-06-02 09:53:44 -0700305 char* fcon = nullptr;
Tom Cherrye3e48212017-04-11 13:53:37 -0700306 int rc = lgetfilecon(path.c_str(), &fcon);
William Roberts397de142016-06-02 09:53:44 -0700307 if (rc < 0) {
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700308 PLOG(ERROR) << "Cannot get SELinux label on '" << path << "' device";
William Roberts397de142016-06-02 09:53:44 -0700309 goto out;
310 }
311
312 bool different = strcmp(fcon, secontext) != 0;
313 freecon(fcon);
314
Tom Cherrye3e48212017-04-11 13:53:37 -0700315 if (different && lsetfilecon(path.c_str(), secontext)) {
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700316 PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path << "' device";
Mihai Serban24a3cbf2016-04-25 18:22:27 +0300317 }
318 }
William Roberts397de142016-06-02 09:53:44 -0700319
320out:
Tom Cherrye3e48212017-04-11 13:53:37 -0700321 chown(path.c_str(), uid, -1);
Tom Cherry0506b182017-02-23 13:46:09 -0800322 if (setegid(AID_ROOT)) {
323 PLOG(FATAL) << "setegid(AID_ROOT) failed";
324 }
Kenny Rootb5982bf2012-10-16 23:07:05 -0700325
Sandeep Patilea239832017-02-03 07:51:55 -0800326 if (secontext) {
327 freecon(secontext);
328 setfscreatecon(NULL);
329 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700330}
331
Tom Cherry1ab8f552017-04-06 14:41:30 -0700332// TODO: Move this to be a member variable of a future devices class.
333std::vector<std::string> platform_devices;
Dima Zavinf395c922013-03-06 16:23:57 -0800334
Tom Cherry1ab8f552017-04-06 14:41:30 -0700335// Given a path that may start with a platform device, find the length of the
336// platform device prefix. If it doesn't start with a platform device, return false
337bool find_platform_device(const std::string& path, std::string* out_path) {
338 out_path->clear();
339 // platform_devices is searched backwards, since parents are added before their children,
340 // and we want to match as deep of a child as we can.
341 for (auto it = platform_devices.rbegin(); it != platform_devices.rend(); ++it) {
342 auto platform_device_path_length = it->length();
343 if (platform_device_path_length < path.length() &&
344 path[platform_device_path_length] == '/' &&
345 android::base::StartsWith(path, it->c_str())) {
346 *out_path = *it;
347 return true;
Colin Crossfadb85e2011-03-30 18:32:12 -0700348 }
349 }
Tom Cherry1ab8f552017-04-06 14:41:30 -0700350 return false;
Sandeep Patil35403eb2017-02-08 20:27:12 -0800351}
352
Andrew Boiea885d042013-09-13 17:41:20 -0700353/* Given a path that may start with a PCI device, populate the supplied buffer
354 * with the PCI domain/bus number and the peripheral ID and return 0.
355 * If it doesn't start with a PCI device, or there is some error, return -1 */
Tom Cherry2e344f92017-04-04 17:53:45 -0700356static bool find_pci_device_prefix(const std::string& path, std::string* result) {
357 result->clear();
Andrew Boiea885d042013-09-13 17:41:20 -0700358
Tom Cherry2e344f92017-04-04 17:53:45 -0700359 if (!android::base::StartsWith(path, "/devices/pci")) return false;
Andrew Boiea885d042013-09-13 17:41:20 -0700360
361 /* Beginning of the prefix is the initial "pci" after "/devices/" */
Tom Cherry2e344f92017-04-04 17:53:45 -0700362 std::string::size_type start = 9;
Andrew Boiea885d042013-09-13 17:41:20 -0700363
364 /* End of the prefix is two path '/' later, capturing the domain/bus number
365 * and the peripheral ID. Example: pci0000:00/0000:00:1f.2 */
Tom Cherry2e344f92017-04-04 17:53:45 -0700366 auto end = path.find('/', start);
367 if (end == std::string::npos) return false;
Andrew Boiea885d042013-09-13 17:41:20 -0700368
Tom Cherry2e344f92017-04-04 17:53:45 -0700369 end = path.find('/', end + 1);
370 if (end == std::string::npos) return false;
Andrew Boiea885d042013-09-13 17:41:20 -0700371
Tom Cherry2e344f92017-04-04 17:53:45 -0700372 auto length = end - start;
373 if (length <= 4) {
374 // The minimum string that will get to this check is 'pci/', which is malformed,
375 // so return false
376 return false;
377 }
378
379 *result = path.substr(start, length);
380 return true;
Andrew Boiea885d042013-09-13 17:41:20 -0700381}
382
Jeremy Compostella937309d2017-03-03 16:27:29 +0100383/* Given a path that may start with a virtual block device, populate
384 * the supplied buffer with the virtual block device ID and return 0.
385 * If it doesn't start with a virtual block device, or there is some
386 * error, return -1 */
Tom Cherry2e344f92017-04-04 17:53:45 -0700387static bool find_vbd_device_prefix(const std::string& path, std::string* result) {
388 result->clear();
389
390 if (!android::base::StartsWith(path, "/devices/vbd-")) return false;
Jeremy Compostella937309d2017-03-03 16:27:29 +0100391
392 /* Beginning of the prefix is the initial "vbd-" after "/devices/" */
Tom Cherry2e344f92017-04-04 17:53:45 -0700393 std::string::size_type start = 13;
Jeremy Compostella937309d2017-03-03 16:27:29 +0100394
395 /* End of the prefix is one path '/' later, capturing the
396 virtual block device ID. Example: 768 */
Tom Cherry2e344f92017-04-04 17:53:45 -0700397 auto end = path.find('/', start);
398 if (end == std::string::npos) return false;
Jeremy Compostella937309d2017-03-03 16:27:29 +0100399
Tom Cherry2e344f92017-04-04 17:53:45 -0700400 auto length = end - start;
401 if (length == 0) return false;
Jeremy Compostella937309d2017-03-03 16:27:29 +0100402
Tom Cherry2e344f92017-04-04 17:53:45 -0700403 *result = path.substr(start, length);
404 return true;
Jeremy Compostella937309d2017-03-03 16:27:29 +0100405}
406
Tom Cherrye3e48212017-04-11 13:53:37 -0700407void parse_event(const char* msg, uevent* uevent) {
408 uevent->partition_num = -1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700409 uevent->major = -1;
410 uevent->minor = -1;
Tom Cherrye3e48212017-04-11 13:53:37 -0700411 // currently ignoring SEQNUM
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700412 while(*msg) {
413 if(!strncmp(msg, "ACTION=", 7)) {
414 msg += 7;
415 uevent->action = msg;
416 } else if(!strncmp(msg, "DEVPATH=", 8)) {
417 msg += 8;
418 uevent->path = msg;
419 } else if(!strncmp(msg, "SUBSYSTEM=", 10)) {
420 msg += 10;
421 uevent->subsystem = msg;
422 } else if(!strncmp(msg, "FIRMWARE=", 9)) {
423 msg += 9;
424 uevent->firmware = msg;
425 } else if(!strncmp(msg, "MAJOR=", 6)) {
426 msg += 6;
427 uevent->major = atoi(msg);
428 } else if(!strncmp(msg, "MINOR=", 6)) {
429 msg += 6;
430 uevent->minor = atoi(msg);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700431 } else if(!strncmp(msg, "PARTN=", 6)) {
432 msg += 6;
433 uevent->partition_num = atoi(msg);
434 } else if(!strncmp(msg, "PARTNAME=", 9)) {
435 msg += 9;
436 uevent->partition_name = msg;
Wei Zhongf97b8872012-03-23 14:15:34 -0700437 } else if(!strncmp(msg, "DEVNAME=", 8)) {
438 msg += 8;
439 uevent->device_name = msg;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700440 }
441
Tom Cherrye3e48212017-04-11 13:53:37 -0700442 // advance to after the next \0
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700443 while(*msg++)
444 ;
445 }
446
Elliott Hughesc0e919c2015-02-04 14:46:36 -0800447 if (LOG_UEVENTS) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700448 LOG(INFO) << "event { '" << uevent->action << "', '" << uevent->path << "', '"
449 << uevent->subsystem << "', '" << uevent->firmware << "', " << uevent->major
450 << ", " << uevent->minor << " }";
Elliott Hughesc0e919c2015-02-04 14:46:36 -0800451 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700452}
453
Tom Cherry2e344f92017-04-04 17:53:45 -0700454std::vector<std::string> get_character_device_symlinks(uevent* uevent) {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700455 std::string parent_device;
456 if (!find_platform_device(uevent->path, &parent_device)) return {};
Benoit Gobyd2278632010-08-03 14:36:02 -0700457
Tom Cherry1ab8f552017-04-06 14:41:30 -0700458 // skip path to the parent driver
459 std::string path = uevent->path.substr(parent_device.length());
Benoit Gobyd2278632010-08-03 14:36:02 -0700460
Tom Cherry1ab8f552017-04-06 14:41:30 -0700461 if (!android::base::StartsWith(path, "/usb")) return {};
Tom Cherry2e344f92017-04-04 17:53:45 -0700462
463 // skip root hub name and device. use device interface
464 // skip 3 slashes, including the first / by starting the search at the 1st character, not 0th.
465 // then extract what comes between the 3rd and 4th slash
466 // e.g. "/usb/usb_device/name/tty2-1:1.0" -> "name"
467
468 std::string::size_type start = 0;
Tom Cherry1ab8f552017-04-06 14:41:30 -0700469 start = path.find('/', start + 1);
Tom Cherry2e344f92017-04-04 17:53:45 -0700470 if (start == std::string::npos) return {};
471
Tom Cherry1ab8f552017-04-06 14:41:30 -0700472 start = path.find('/', start + 1);
Tom Cherry2e344f92017-04-04 17:53:45 -0700473 if (start == std::string::npos) return {};
474
Tom Cherry1ab8f552017-04-06 14:41:30 -0700475 auto end = path.find('/', start + 1);
Tom Cherry2e344f92017-04-04 17:53:45 -0700476 if (end == std::string::npos) return {};
477
478 start++; // Skip the first '/'
479
480 auto length = end - start;
481 if (length == 0) return {};
482
Tom Cherry1ab8f552017-04-06 14:41:30 -0700483 auto name_string = path.substr(start, length);
Tom Cherry2e344f92017-04-04 17:53:45 -0700484
Tom Cherry2e344f92017-04-04 17:53:45 -0700485 std::vector<std::string> links;
Tom Cherrye3e48212017-04-11 13:53:37 -0700486 links.emplace_back("/dev/usb/" + uevent->subsystem + name_string);
Tom Cherry2e344f92017-04-04 17:53:45 -0700487
488 mkdir("/dev/usb", 0755);
Benoit Gobyd2278632010-08-03 14:36:02 -0700489
490 return links;
Benoit Gobyd2278632010-08-03 14:36:02 -0700491}
492
Tom Cherryc44f6a42017-04-05 15:58:31 -0700493// replaces any unacceptable characters with '_', the
494// length of the resulting string is equal to the input string
Tom Cherry2e344f92017-04-04 17:53:45 -0700495void sanitize_partition_name(std::string* string) {
Tom Cherryc44f6a42017-04-05 15:58:31 -0700496 const char* accept =
497 "abcdefghijklmnopqrstuvwxyz"
498 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
499 "0123456789"
500 "_-.";
501
Tom Cherry2e344f92017-04-04 17:53:45 -0700502 if (!string) return;
Tom Cherryc44f6a42017-04-05 15:58:31 -0700503
Tom Cherry2e344f92017-04-04 17:53:45 -0700504 std::string::size_type pos = 0;
505 while ((pos = string->find_first_not_of(accept, pos)) != std::string::npos) {
506 (*string)[pos] = '_';
Tom Cherryc44f6a42017-04-05 15:58:31 -0700507 }
508}
509
Tom Cherry2e344f92017-04-04 17:53:45 -0700510std::vector<std::string> get_block_device_symlinks(uevent* uevent) {
511 std::string device;
Tom Cherry2e344f92017-04-04 17:53:45 -0700512 std::string type;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700513
Tom Cherry1ab8f552017-04-06 14:41:30 -0700514 if (find_platform_device(uevent->path, &device)) {
515 // Skip /devices/platform or /devices/ if present
516 static const std::string devices_platform_prefix = "/devices/platform/";
517 static const std::string devices_prefix = "/devices/";
518
519 if (android::base::StartsWith(device, devices_platform_prefix.c_str())) {
520 device = device.substr(devices_platform_prefix.length());
521 } else if (android::base::StartsWith(device, devices_prefix.c_str())) {
522 device = device.substr(devices_prefix.length());
523 }
524
Andrew Boiea885d042013-09-13 17:41:20 -0700525 type = "platform";
Tom Cherry2e344f92017-04-04 17:53:45 -0700526 } else if (find_pci_device_prefix(uevent->path, &device)) {
Andrew Boiea885d042013-09-13 17:41:20 -0700527 type = "pci";
Tom Cherry2e344f92017-04-04 17:53:45 -0700528 } else if (find_vbd_device_prefix(uevent->path, &device)) {
Jeremy Compostella937309d2017-03-03 16:27:29 +0100529 type = "vbd";
Andrew Boiea885d042013-09-13 17:41:20 -0700530 } else {
Tom Cherry2e344f92017-04-04 17:53:45 -0700531 return {};
Andrew Boiea885d042013-09-13 17:41:20 -0700532 }
Dima Zavinf395c922013-03-06 16:23:57 -0800533
Tom Cherry2e344f92017-04-04 17:53:45 -0700534 std::vector<std::string> links;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700535
Sandeep Patil35403eb2017-02-08 20:27:12 -0800536 LOG(VERBOSE) << "found " << type << " device " << device;
Colin Crossfadb85e2011-03-30 18:32:12 -0700537
Tom Cherry2e344f92017-04-04 17:53:45 -0700538 auto link_path = "/dev/block/" + type + "/" + device;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700539
Tom Cherrye3e48212017-04-11 13:53:37 -0700540 if (!uevent->partition_name.empty()) {
Tom Cherry2e344f92017-04-04 17:53:45 -0700541 std::string partition_name_sanitized(uevent->partition_name);
542 sanitize_partition_name(&partition_name_sanitized);
543 if (partition_name_sanitized != uevent->partition_name) {
544 LOG(VERBOSE) << "Linking partition '" << uevent->partition_name << "' as '"
545 << partition_name_sanitized << "'";
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700546 }
Tom Cherry2e344f92017-04-04 17:53:45 -0700547 links.emplace_back(link_path + "/by-name/" + partition_name_sanitized);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700548 }
549
550 if (uevent->partition_num >= 0) {
Tom Cherry2e344f92017-04-04 17:53:45 -0700551 links.emplace_back(link_path + "/by-num/p" + std::to_string(uevent->partition_num));
Colin Crossb0ab94b2010-04-08 16:16:20 -0700552 }
553
Tom Cherrye3e48212017-04-11 13:53:37 -0700554 auto last_slash = uevent->path.rfind('/');
555 links.emplace_back(link_path + "/" + uevent->path.substr(last_slash + 1));
Colin Crossb0ab94b2010-04-08 16:16:20 -0700556
557 return links;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700558}
559
Tom Cherrye3e48212017-04-11 13:53:37 -0700560static void make_link_init(const std::string& oldpath, const std::string& newpath) {
Tom Cherrye7656b72017-05-01 17:10:09 -0700561 if (mkdir_recursive(dirname(newpath.c_str()), 0755, sehandle)) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700562 PLOG(ERROR) << "Failed to create directory " << dirname(newpath.c_str());
563 }
Elliott Hughesf39f7f12016-08-31 14:41:51 -0700564
Tom Cherrye3e48212017-04-11 13:53:37 -0700565 if (symlink(oldpath.c_str(), newpath.c_str()) && errno != EEXIST) {
566 PLOG(ERROR) << "Failed to symlink " << oldpath << " to " << newpath;
567 }
Elliott Hughesf39f7f12016-08-31 14:41:51 -0700568}
569
Tom Cherrye3e48212017-04-11 13:53:37 -0700570static void remove_link(const std::string& oldpath, const std::string& newpath) {
571 std::string path;
572 if (android::base::Readlink(newpath, &path) && path == oldpath) unlink(newpath.c_str());
Elliott Hughesf39f7f12016-08-31 14:41:51 -0700573}
574
Tom Cherrye3e48212017-04-11 13:53:37 -0700575static void handle_device(const std::string& action, const std::string& devpath, int block,
Tom Cherry2e344f92017-04-04 17:53:45 -0700576 int major, int minor, const std::vector<std::string>& links) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700577 if (action == "add") {
578 make_device(devpath, block, major, minor, links);
Tom Cherry2e344f92017-04-04 17:53:45 -0700579 for (const auto& link : links) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700580 make_link_init(devpath, link);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700581 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700582 }
583
Tom Cherrye3e48212017-04-11 13:53:37 -0700584 if (action == "remove") {
Tom Cherry2e344f92017-04-04 17:53:45 -0700585 for (const auto& link : links) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700586 remove_link(devpath, link);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700587 }
Tom Cherrye3e48212017-04-11 13:53:37 -0700588 unlink(devpath.c_str());
Colin Crossb0ab94b2010-04-08 16:16:20 -0700589 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700590}
591
Tom Cherry1ab8f552017-04-06 14:41:30 -0700592void handle_platform_device_event(uevent* uevent) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700593 if (uevent->action == "add") {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700594 platform_devices.emplace_back(uevent->path);
Tom Cherrye3e48212017-04-11 13:53:37 -0700595 } else if (uevent->action == "remove") {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700596 auto it = std::find(platform_devices.begin(), platform_devices.end(), uevent->path);
597 if (it != platform_devices.end()) platform_devices.erase(it);
Tom Cherrye3e48212017-04-11 13:53:37 -0700598 }
Colin Crossfadb85e2011-03-30 18:32:12 -0700599}
600
Tom Cherry3fa46732017-04-11 14:19:50 -0700601static void handle_block_device_event(uevent* uevent) {
602 // if it's not a /dev device, nothing to do
603 if (uevent->major < 0 || uevent->minor < 0) return;
Colin Crosseb5ba832011-03-30 17:37:17 -0700604
Tom Cherry3fa46732017-04-11 14:19:50 -0700605 const char* base = "/dev/block/";
Tom Cherrye7656b72017-05-01 17:10:09 -0700606 make_dir(base, 0755, sehandle);
Colin Crosseb5ba832011-03-30 17:37:17 -0700607
Tom Cherry3fa46732017-04-11 14:19:50 -0700608 std::string name = android::base::Basename(uevent->path);
609 std::string devpath = base + name;
610
Tom Cherry2e344f92017-04-04 17:53:45 -0700611 std::vector<std::string> links;
Tom Cherrye3e48212017-04-11 13:53:37 -0700612 if (android::base::StartsWith(uevent->path, "/devices")) {
Andrew Boiea885d042013-09-13 17:41:20 -0700613 links = get_block_device_symlinks(uevent);
Tom Cherrye3e48212017-04-11 13:53:37 -0700614 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700615
Tom Cherrye3e48212017-04-11 13:53:37 -0700616 handle_device(uevent->action, devpath, 1, uevent->major, uevent->minor, links);
Colin Crosseb5ba832011-03-30 17:37:17 -0700617}
618
Tom Cherry3fa46732017-04-11 14:19:50 -0700619static void handle_generic_device_event(uevent* uevent) {
620 // if it's not a /dev device, nothing to do
621 if (uevent->major < 0 || uevent->minor < 0) return;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800622
Tom Cherry3fa46732017-04-11 14:19:50 -0700623 std::string devpath;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800624
Tom Cherryfe062052017-04-24 16:59:05 -0700625 if (android::base::StartsWith(uevent->subsystem, "usb")) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700626 if (uevent->subsystem == "usb") {
627 if (!uevent->device_name.empty()) {
628 devpath = "/dev/" + uevent->device_name;
Tom Cherry3fa46732017-04-11 14:19:50 -0700629 } else {
630 // This imitates the file system that would be created
631 // if we were using devfs instead.
632 // Minors are broken up into groups of 128, starting at "001"
633 int bus_id = uevent->minor / 128 + 1;
634 int device_id = uevent->minor % 128 + 1;
635 devpath = android::base::StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id);
636 }
Tom Cherry3fa46732017-04-11 14:19:50 -0700637 } else {
638 // ignore other USB events
639 return;
640 }
Tom Cherryfe062052017-04-24 16:59:05 -0700641 } else if (auto subsystem = std::find(subsystems.begin(), subsystems.end(), uevent->subsystem);
642 subsystem != subsystems.end()) {
643 devpath = subsystem->ParseDevPath(uevent);
Tom Cherry780a71e2017-04-04 16:30:40 -0700644 } else {
Tom Cherryfe062052017-04-24 16:59:05 -0700645 devpath = "/dev/" + android::base::Basename(uevent->path);
Tom Cherry780a71e2017-04-04 16:30:40 -0700646 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700647
Tom Cherrye7656b72017-05-01 17:10:09 -0700648 mkdir_recursive(android::base::Dirname(devpath), 0755, sehandle);
Tom Cherryfe062052017-04-24 16:59:05 -0700649
Tom Cherry780a71e2017-04-04 16:30:40 -0700650 auto links = get_character_device_symlinks(uevent);
Colin Crosseb5ba832011-03-30 17:37:17 -0700651
Tom Cherrye3e48212017-04-11 13:53:37 -0700652 handle_device(uevent->action, devpath, 0, uevent->major, uevent->minor, links);
Colin Crosseb5ba832011-03-30 17:37:17 -0700653}
654
655static void handle_device_event(struct uevent *uevent)
656{
Tom Cherrye3e48212017-04-11 13:53:37 -0700657 if (uevent->action == "add" || uevent->action == "change" || uevent->action == "online") {
Tom Cherrycc054c92017-04-05 17:55:46 -0700658 fixup_sys_permissions(uevent->path, uevent->subsystem);
Tom Cherrye3e48212017-04-11 13:53:37 -0700659 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700660
Tom Cherrye3e48212017-04-11 13:53:37 -0700661 if (uevent->subsystem == "block") {
Colin Crosseb5ba832011-03-30 17:37:17 -0700662 handle_block_device_event(uevent);
Tom Cherrye3e48212017-04-11 13:53:37 -0700663 } else if (uevent->subsystem == "platform") {
Colin Crossfadb85e2011-03-30 18:32:12 -0700664 handle_platform_device_event(uevent);
Colin Crosseb5ba832011-03-30 17:37:17 -0700665 } else {
666 handle_generic_device_event(uevent);
667 }
668}
669
Elliott Hughes632e99a2016-11-12 11:44:16 -0800670static void load_firmware(uevent* uevent, const std::string& root,
671 int fw_fd, size_t fw_size,
672 int loading_fd, int data_fd) {
673 // Start transfer.
674 android::base::WriteFully(loading_fd, "1", 1);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700675
Elliott Hughes632e99a2016-11-12 11:44:16 -0800676 // Copy the firmware.
677 int rc = sendfile(data_fd, fw_fd, nullptr, fw_size);
678 if (rc == -1) {
679 PLOG(ERROR) << "firmware: sendfile failed { '" << root << "', '" << uevent->firmware << "' }";
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700680 }
681
Elliott Hughes632e99a2016-11-12 11:44:16 -0800682 // Tell the firmware whether to abort or commit.
683 const char* response = (rc != -1) ? "0" : "-1";
684 android::base::WriteFully(loading_fd, response, strlen(response));
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700685}
686
Elliott Hughes632e99a2016-11-12 11:44:16 -0800687static int is_booting() {
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700688 return access("/dev/.booting", F_OK) == 0;
689}
690
Elliott Hughes632e99a2016-11-12 11:44:16 -0800691static void process_firmware_event(uevent* uevent) {
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700692 int booting = is_booting();
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700693
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700694 LOG(INFO) << "firmware: loading '" << uevent->firmware << "' for '" << uevent->path << "'";
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700695
Tom Cherrye3e48212017-04-11 13:53:37 -0700696 std::string root = "/sys" + uevent->path;
Elliott Hughes632e99a2016-11-12 11:44:16 -0800697 std::string loading = root + "/loading";
698 std::string data = root + "/data";
699
700 android::base::unique_fd loading_fd(open(loading.c_str(), O_WRONLY|O_CLOEXEC));
701 if (loading_fd == -1) {
702 PLOG(ERROR) << "couldn't open firmware loading fd for " << uevent->firmware;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700703 return;
Elliott Hughes632e99a2016-11-12 11:44:16 -0800704 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700705
Elliott Hughes632e99a2016-11-12 11:44:16 -0800706 android::base::unique_fd data_fd(open(data.c_str(), O_WRONLY|O_CLOEXEC));
707 if (data_fd == -1) {
708 PLOG(ERROR) << "couldn't open firmware data fd for " << uevent->firmware;
709 return;
710 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700711
Tom Cherrye3e48212017-04-11 13:53:37 -0700712 static const char* firmware_dirs[] = {"/etc/firmware/", "/vendor/firmware/",
713 "/firmware/image/"};
714
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700715try_loading_again:
Elliott Hughes632e99a2016-11-12 11:44:16 -0800716 for (size_t i = 0; i < arraysize(firmware_dirs); i++) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700717 std::string file = firmware_dirs[i] + uevent->firmware;
Elliott Hughes632e99a2016-11-12 11:44:16 -0800718 android::base::unique_fd fw_fd(open(file.c_str(), O_RDONLY|O_CLOEXEC));
719 struct stat sb;
720 if (fw_fd != -1 && fstat(fw_fd, &sb) != -1) {
721 load_firmware(uevent, root, fw_fd, sb.st_size, loading_fd, data_fd);
722 return;
Benoit Goby609d8822010-11-09 18:10:24 -0800723 }
Brian Swetland02863b92010-09-19 03:36:39 -0700724 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700725
Elliott Hughes632e99a2016-11-12 11:44:16 -0800726 if (booting) {
727 // If we're not fully booted, we may be missing
728 // filesystems needed for firmware, wait and retry.
Elliott Hughes290a2282016-11-14 17:08:47 -0800729 std::this_thread::sleep_for(100ms);
Elliott Hughes632e99a2016-11-12 11:44:16 -0800730 booting = is_booting();
731 goto try_loading_again;
732 }
733
734 LOG(ERROR) << "firmware: could not find firmware for " << uevent->firmware;
735
736 // Write "-1" as our response to the kernel's firmware request, since we have nothing for it.
737 write(loading_fd, "-1", 2);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700738}
739
Elliott Hughes632e99a2016-11-12 11:44:16 -0800740static void handle_firmware_event(uevent* uevent) {
Tom Cherrye3e48212017-04-11 13:53:37 -0700741 if (uevent->subsystem != "firmware" || uevent->action != "add") return;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700742
Elliott Hughes632e99a2016-11-12 11:44:16 -0800743 // Loading the firmware in a child means we can do that in parallel...
744 // (We ignore SIGCHLD rather than wait for our children.)
745 pid_t pid = fork();
746 if (pid == 0) {
747 Timer t;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700748 process_firmware_event(uevent);
Elliott Hughes331cf2f2016-11-29 19:20:58 +0000749 LOG(INFO) << "loading " << uevent->path << " took " << t;
Kenny Root17baff42014-08-20 16:16:44 -0700750 _exit(EXIT_SUCCESS);
Elliott Hughes632e99a2016-11-12 11:44:16 -0800751 } else if (pid == -1) {
752 PLOG(ERROR) << "could not fork to process firmware event for " << uevent->firmware;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700753 }
754}
755
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800756static bool inline should_stop_coldboot(coldboot_action_t act)
757{
758 return (act == COLDBOOT_STOP || act == COLDBOOT_FINISH);
759}
760
Ruchi Kandoic6037202014-06-23 11:22:09 -0700761#define UEVENT_MSG_LEN 2048
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800762
Sandeep Patil44a3ee22017-02-08 15:49:47 -0800763static inline coldboot_action_t handle_device_fd_with(
764 std::function<coldboot_action_t(uevent* uevent)> handle_uevent)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700765{
Vernon Tang3f582e92011-04-25 13:08:17 +1000766 char msg[UEVENT_MSG_LEN+2];
767 int n;
Nick Kralevich57de8b82011-05-11 14:58:24 -0700768 while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
Nick Kralevich5f5d5c82010-07-19 14:31:20 -0700769 if(n >= UEVENT_MSG_LEN) /* overflow -- discard */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700770 continue;
771
772 msg[n] = '\0';
773 msg[n+1] = '\0';
774
Tom Cherrye3e48212017-04-11 13:53:37 -0700775 uevent uevent;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700776 parse_event(msg, &uevent);
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800777 coldboot_action_t act = handle_uevent(&uevent);
778 if (should_stop_coldboot(act))
779 return act;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700780 }
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800781
782 return COLDBOOT_CONTINUE;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700783}
784
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800785coldboot_action_t handle_device_fd(coldboot_callback fn)
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800786{
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800787 coldboot_action_t ret = handle_device_fd_with(
788 [&](uevent* uevent) -> coldboot_action_t {
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800789 // default is to always create the devices
790 coldboot_action_t act = COLDBOOT_CREATE;
791 if (fn) {
792 act = fn(uevent);
793 }
794
795 if (act == COLDBOOT_CREATE || act == COLDBOOT_STOP) {
796 handle_device_event(uevent);
797 handle_firmware_event(uevent);
798 }
799
800 return act;
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800801 });
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800802
803 return ret;
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800804}
805
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700806/* Coldboot walks parts of the /sys tree and pokes the uevent files
807** to cause the kernel to regenerate device add events that happened
808** before init's device manager was started
809**
810** We drain any pending events from the netlink socket every time
811** we poke another uevent file to make sure we don't overrun the
Elliott Hughesc0e919c2015-02-04 14:46:36 -0800812** socket's buffer.
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700813*/
814
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800815static coldboot_action_t do_coldboot(DIR *d, coldboot_callback fn)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700816{
817 struct dirent *de;
818 int dfd, fd;
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800819 coldboot_action_t act = COLDBOOT_CONTINUE;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700820
821 dfd = dirfd(d);
822
823 fd = openat(dfd, "uevent", O_WRONLY);
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800824 if (fd >= 0) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700825 write(fd, "add\n", 4);
826 close(fd);
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800827 act = handle_device_fd(fn);
828 if (should_stop_coldboot(act))
829 return act;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700830 }
831
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800832 while (!should_stop_coldboot(act) && (de = readdir(d))) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700833 DIR *d2;
834
835 if(de->d_type != DT_DIR || de->d_name[0] == '.')
836 continue;
837
838 fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
839 if(fd < 0)
840 continue;
841
842 d2 = fdopendir(fd);
843 if(d2 == 0)
844 close(fd);
845 else {
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800846 act = do_coldboot(d2, fn);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700847 closedir(d2);
848 }
849 }
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800850
851 // default is always to continue looking for uevents
852 return act;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700853}
854
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800855static coldboot_action_t coldboot(const char *path, coldboot_callback fn)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700856{
James Hawkins588a2ca2016-02-18 14:52:46 -0800857 std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path), closedir);
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800858 if (d) {
859 return do_coldboot(d.get(), fn);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700860 }
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800861
862 return COLDBOOT_CONTINUE;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700863}
864
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800865void device_init(const char* path, coldboot_callback fn) {
Sandeep Patil971a4602017-02-15 13:37:52 -0800866 if (!sehandle) {
867 sehandle = selinux_android_file_context_handle();
Elliott Hughes56a06562015-03-28 11:23:32 -0700868 }
Sandeep Patil971a4602017-02-15 13:37:52 -0800869 // open uevent socket and selinux status only if it hasn't been
870 // done before
871 if (device_fd == -1) {
872 /* is 256K enough? udev uses 16MB! */
873 device_fd.reset(uevent_open_socket(256 * 1024, true));
874 if (device_fd == -1) {
875 return;
876 }
877 fcntl(device_fd, F_SETFL, O_NONBLOCK);
Sandeep Patil971a4602017-02-15 13:37:52 -0800878 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700879
Elliott Hughes56a06562015-03-28 11:23:32 -0700880 if (access(COLDBOOT_DONE, F_OK) == 0) {
Elliott Hughesf86b5a62016-06-24 15:12:21 -0700881 LOG(VERBOSE) << "Skipping coldboot, already done!";
Elliott Hughes56a06562015-03-28 11:23:32 -0700882 return;
Colin Crossf83d0b92010-04-21 12:04:20 -0700883 }
Elliott Hughes56a06562015-03-28 11:23:32 -0700884
885 Timer t;
Sandeep Patil957e4ab2017-02-07 18:11:37 -0800886 coldboot_action_t act;
887 if (!path) {
888 act = coldboot("/sys/class", fn);
889 if (!should_stop_coldboot(act)) {
890 act = coldboot("/sys/block", fn);
891 if (!should_stop_coldboot(act)) {
892 act = coldboot("/sys/devices", fn);
893 }
894 }
895 } else {
896 act = coldboot(path, fn);
897 }
898
899 // If we have a callback, then do as it says. If no, then the default is
900 // to always create COLDBOOT_DONE file.
901 if (!fn || (act == COLDBOOT_FINISH)) {
902 close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
903 }
904
Elliott Hughes331cf2f2016-11-29 19:20:58 +0000905 LOG(INFO) << "Coldboot took " << t;
Colin Cross0dd7ca62010-04-13 19:25:51 -0700906}
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700907
Sandeep Patil35403eb2017-02-08 20:27:12 -0800908void device_close() {
Tom Cherry1ab8f552017-04-06 14:41:30 -0700909 platform_devices.clear();
Sandeep Patil35403eb2017-02-08 20:27:12 -0800910 device_fd.reset();
911}
912
Elliott Hughes632e99a2016-11-12 11:44:16 -0800913int get_device_fd() {
Colin Cross0dd7ca62010-04-13 19:25:51 -0700914 return device_fd;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700915}