blob: 02698eff14f7ccf78dee885a5949afbf1dc55090 [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
17#include <errno.h>
Olivier Baillyb93e5812010-11-17 11:47:23 -080018#include <stddef.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070019#include <stdio.h>
20#include <stdlib.h>
21#include <sys/stat.h>
22#include <sys/types.h>
23
24#include <fcntl.h>
25#include <dirent.h>
26#include <unistd.h>
27#include <string.h>
28
29#include <sys/socket.h>
30#include <sys/un.h>
31#include <linux/netlink.h>
Stephen Smalleye46f9d52012-01-13 08:48:47 -050032
Stephen Smalleye46f9d52012-01-13 08:48:47 -050033#include <selinux/selinux.h>
34#include <selinux/label.h>
Stephen Smalleyae6f3d72012-05-01 15:02:53 -040035#include <selinux/android.h>
Stephen Smalleye2eb69d2013-04-16 09:30:30 -040036#include <selinux/avc.h>
Stephen Smalleye46f9d52012-01-13 08:48:47 -050037
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070038#include <private/android_filesystem_config.h>
39#include <sys/time.h>
Colin Cross982a8152010-06-03 12:21:01 -070040#include <sys/wait.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070041
Dima Zavinda04c522011-09-01 17:09:44 -070042#include <cutils/list.h>
Vernon Tang3f582e92011-04-25 13:08:17 +100043#include <cutils/uevent.h>
44
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070045#include "devices.h"
Greg Hackmann3312aa82013-11-18 15:24:40 -080046#include "ueventd_parser.h"
Colin Crossb0ab94b2010-04-08 16:16:20 -070047#include "util.h"
Colin Crossed8a7d82010-04-19 17:05:34 -070048#include "log.h"
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070049
Mark Salyzyn154f4602014-02-20 14:59:07 -080050#define UNUSED __attribute__((__unused__))
51
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070052#define SYSFS_PREFIX "/sys"
Brian Swetland02863b92010-09-19 03:36:39 -070053#define FIRMWARE_DIR1 "/etc/firmware"
54#define FIRMWARE_DIR2 "/vendor/firmware"
Iliyan Malchev029d44e2012-06-08 10:42:26 -070055#define FIRMWARE_DIR3 "/firmware/image"
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070056
Stephen Smalleye096e362012-06-11 13:37:39 -040057extern struct selabel_handle *sehandle;
Stephen Smalleye46f9d52012-01-13 08:48:47 -050058
Colin Cross0dd7ca62010-04-13 19:25:51 -070059static int device_fd = -1;
60
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070061struct uevent {
62 const char *action;
63 const char *path;
64 const char *subsystem;
65 const char *firmware;
Colin Crossb0ab94b2010-04-08 16:16:20 -070066 const char *partition_name;
Wei Zhongf97b8872012-03-23 14:15:34 -070067 const char *device_name;
Colin Crossb0ab94b2010-04-08 16:16:20 -070068 int partition_num;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070069 int major;
70 int minor;
71};
72
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070073struct perms_ {
74 char *name;
Brian Swetlandbc57d4c2010-10-26 15:09:43 -070075 char *attr;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070076 mode_t perm;
77 unsigned int uid;
78 unsigned int gid;
79 unsigned short prefix;
80};
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070081
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070082struct perm_node {
83 struct perms_ dp;
84 struct listnode plist;
85};
Brian Swetlandbc57d4c2010-10-26 15:09:43 -070086
Colin Crossfadb85e2011-03-30 18:32:12 -070087struct platform_node {
88 char *name;
Dima Zavinf395c922013-03-06 16:23:57 -080089 char *path;
90 int path_len;
Colin Crossfadb85e2011-03-30 18:32:12 -070091 struct listnode list;
92};
93
Brian Swetlandbc57d4c2010-10-26 15:09:43 -070094static list_declare(sys_perms);
Colin Cross44b65d02010-04-20 14:32:50 -070095static list_declare(dev_perms);
Colin Crossfadb85e2011-03-30 18:32:12 -070096static list_declare(platform_names);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070097
Brian Swetlandbc57d4c2010-10-26 15:09:43 -070098int add_dev_perms(const char *name, const char *attr,
99 mode_t perm, unsigned int uid, unsigned int gid,
100 unsigned short prefix) {
101 struct perm_node *node = calloc(1, sizeof(*node));
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700102 if (!node)
103 return -ENOMEM;
104
Brian Swetlandbc57d4c2010-10-26 15:09:43 -0700105 node->dp.name = strdup(name);
106 if (!node->dp.name)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700107 return -ENOMEM;
108
Brian Swetlandbc57d4c2010-10-26 15:09:43 -0700109 if (attr) {
110 node->dp.attr = strdup(attr);
111 if (!node->dp.attr)
112 return -ENOMEM;
113 }
114
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700115 node->dp.perm = perm;
116 node->dp.uid = uid;
117 node->dp.gid = gid;
118 node->dp.prefix = prefix;
119
Brian Swetlandbc57d4c2010-10-26 15:09:43 -0700120 if (attr)
121 list_add_tail(&sys_perms, &node->plist);
122 else
123 list_add_tail(&dev_perms, &node->plist);
124
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700125 return 0;
126}
127
Brian Swetlandbc57d4c2010-10-26 15:09:43 -0700128void fixup_sys_perms(const char *upath)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700129{
Brian Swetlandbc57d4c2010-10-26 15:09:43 -0700130 char buf[512];
131 struct listnode *node;
132 struct perms_ *dp;
Stephen Smalley5f7b0172013-04-03 13:15:01 -0400133 char *secontext;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700134
Brian Swetlandbc57d4c2010-10-26 15:09:43 -0700135 /* upaths omit the "/sys" that paths in this list
136 * contain, so we add 4 when comparing...
137 */
138 list_for_each(node, &sys_perms) {
139 dp = &(node_to_item(node, struct perm_node, plist))->dp;
140 if (dp->prefix) {
141 if (strncmp(upath, dp->name + 4, strlen(dp->name + 4)))
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700142 continue;
143 } else {
Brian Swetlandbc57d4c2010-10-26 15:09:43 -0700144 if (strcmp(upath, dp->name + 4))
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700145 continue;
146 }
Brian Swetlandbc57d4c2010-10-26 15:09:43 -0700147
148 if ((strlen(upath) + strlen(dp->attr) + 6) > sizeof(buf))
149 return;
150
151 sprintf(buf,"/sys%s/%s", upath, dp->attr);
152 INFO("fixup %s %d %d 0%o\n", buf, dp->uid, dp->gid, dp->perm);
153 chown(buf, dp->uid, dp->gid);
154 chmod(buf, dp->perm);
Stephen Smalley5f7b0172013-04-03 13:15:01 -0400155 if (sehandle) {
156 secontext = NULL;
157 selabel_lookup(sehandle, &secontext, buf, 0);
158 if (secontext) {
159 setfilecon(buf, secontext);
160 freecon(secontext);
161 }
162 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700163 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700164}
165
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700166static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid)
167{
168 mode_t perm;
Colin Cross44b65d02010-04-20 14:32:50 -0700169 struct listnode *node;
170 struct perm_node *perm_node;
171 struct perms_ *dp;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700172
Colin Cross44b65d02010-04-20 14:32:50 -0700173 /* search the perms list in reverse so that ueventd.$hardware can
174 * override ueventd.rc
175 */
176 list_for_each_reverse(node, &dev_perms) {
177 perm_node = node_to_item(node, struct perm_node, plist);
178 dp = &perm_node->dp;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700179
Colin Cross44b65d02010-04-20 14:32:50 -0700180 if (dp->prefix) {
181 if (strncmp(path, dp->name, strlen(dp->name)))
182 continue;
183 } else {
184 if (strcmp(path, dp->name))
185 continue;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700186 }
Colin Cross44b65d02010-04-20 14:32:50 -0700187 *uid = dp->uid;
188 *gid = dp->gid;
189 return dp->perm;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700190 }
Colin Cross44b65d02010-04-20 14:32:50 -0700191 /* Default if nothing found. */
192 *uid = 0;
193 *gid = 0;
194 return 0600;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700195}
196
Brian Swetlandbc57d4c2010-10-26 15:09:43 -0700197static void make_device(const char *path,
Mark Salyzyn154f4602014-02-20 14:59:07 -0800198 const char *upath UNUSED,
Stephen Smalleyb4c52002014-06-12 12:29:14 -0400199 int block, int major, int minor,
200 const char **links)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700201{
202 unsigned uid;
203 unsigned gid;
204 mode_t mode;
205 dev_t dev;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500206 char *secontext = NULL;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700207
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700208 mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
Kenny Rootb5982bf2012-10-16 23:07:05 -0700209
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500210 if (sehandle) {
Stephen Smalleyb4c52002014-06-12 12:29:14 -0400211 selabel_lookup_best_match(sehandle, &secontext, path, links, mode);
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500212 setfscreatecon(secontext);
213 }
Kenny Rootb5982bf2012-10-16 23:07:05 -0700214
Colin Cross17dcc5c2010-09-03 12:25:34 -0700215 dev = makedev(major, minor);
Nick Pelly6405c692010-01-21 18:13:39 -0800216 /* Temporarily change egid to avoid race condition setting the gid of the
217 * device node. Unforunately changing the euid would prevent creation of
218 * some device nodes, so the uid has to be set with chown() and is still
219 * racy. Fixing the gid race at least fixed the issue with system_server
220 * opening dynamic input devices under the AID_INPUT gid. */
221 setegid(gid);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700222 mknod(path, mode, dev);
Nick Pelly6405c692010-01-21 18:13:39 -0800223 chown(path, uid, -1);
224 setegid(AID_ROOT);
Kenny Rootb5982bf2012-10-16 23:07:05 -0700225
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500226 if (secontext) {
227 freecon(secontext);
228 setfscreatecon(NULL);
229 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700230}
231
Dima Zavinf395c922013-03-06 16:23:57 -0800232static void add_platform_device(const char *path)
Colin Crossfadb85e2011-03-30 18:32:12 -0700233{
Dima Zavinf395c922013-03-06 16:23:57 -0800234 int path_len = strlen(path);
Colin Crossfadb85e2011-03-30 18:32:12 -0700235 struct listnode *node;
236 struct platform_node *bus;
Dima Zavinf395c922013-03-06 16:23:57 -0800237 const char *name = path;
238
239 if (!strncmp(path, "/devices/", 9)) {
240 name += 9;
241 if (!strncmp(name, "platform/", 9))
242 name += 9;
243 }
Colin Crossfadb85e2011-03-30 18:32:12 -0700244
245 list_for_each_reverse(node, &platform_names) {
246 bus = node_to_item(node, struct platform_node, list);
Dima Zavinf395c922013-03-06 16:23:57 -0800247 if ((bus->path_len < path_len) &&
248 (path[bus->path_len] == '/') &&
249 !strncmp(path, bus->path, bus->path_len))
Colin Crossfadb85e2011-03-30 18:32:12 -0700250 /* subdevice of an existing platform, ignore it */
251 return;
252 }
253
Dima Zavinf395c922013-03-06 16:23:57 -0800254 INFO("adding platform device %s (%s)\n", name, path);
Colin Crossfadb85e2011-03-30 18:32:12 -0700255
256 bus = calloc(1, sizeof(struct platform_node));
Dima Zavinf395c922013-03-06 16:23:57 -0800257 bus->path = strdup(path);
258 bus->path_len = path_len;
259 bus->name = bus->path + (name - path);
Colin Crossfadb85e2011-03-30 18:32:12 -0700260 list_add_tail(&platform_names, &bus->list);
261}
262
263/*
Dima Zavinf395c922013-03-06 16:23:57 -0800264 * given a path that may start with a platform device, find the length of the
Colin Crossfadb85e2011-03-30 18:32:12 -0700265 * platform device prefix. If it doesn't start with a platform device, return
266 * 0.
267 */
Dima Zavinf395c922013-03-06 16:23:57 -0800268static struct platform_node *find_platform_device(const char *path)
Colin Crossfadb85e2011-03-30 18:32:12 -0700269{
Dima Zavinf395c922013-03-06 16:23:57 -0800270 int path_len = strlen(path);
Colin Crossfadb85e2011-03-30 18:32:12 -0700271 struct listnode *node;
272 struct platform_node *bus;
273
274 list_for_each_reverse(node, &platform_names) {
275 bus = node_to_item(node, struct platform_node, list);
Dima Zavinf395c922013-03-06 16:23:57 -0800276 if ((bus->path_len < path_len) &&
277 (path[bus->path_len] == '/') &&
278 !strncmp(path, bus->path, bus->path_len))
279 return bus;
Colin Crossfadb85e2011-03-30 18:32:12 -0700280 }
281
282 return NULL;
283}
284
Dima Zavinf395c922013-03-06 16:23:57 -0800285static void remove_platform_device(const char *path)
Colin Crossfadb85e2011-03-30 18:32:12 -0700286{
287 struct listnode *node;
288 struct platform_node *bus;
289
290 list_for_each_reverse(node, &platform_names) {
291 bus = node_to_item(node, struct platform_node, list);
Dima Zavinf395c922013-03-06 16:23:57 -0800292 if (!strcmp(path, bus->path)) {
293 INFO("removing platform device %s\n", bus->name);
294 free(bus->path);
Colin Crossfadb85e2011-03-30 18:32:12 -0700295 list_remove(node);
296 free(bus);
297 return;
298 }
299 }
300}
301
Andrew Boiea885d042013-09-13 17:41:20 -0700302/* Given a path that may start with a PCI device, populate the supplied buffer
303 * with the PCI domain/bus number and the peripheral ID and return 0.
304 * If it doesn't start with a PCI device, or there is some error, return -1 */
305static int find_pci_device_prefix(const char *path, char *buf, ssize_t buf_sz)
306{
307 const char *start, *end;
308
309 if (strncmp(path, "/devices/pci", 12))
310 return -1;
311
312 /* Beginning of the prefix is the initial "pci" after "/devices/" */
313 start = path + 9;
314
315 /* End of the prefix is two path '/' later, capturing the domain/bus number
316 * and the peripheral ID. Example: pci0000:00/0000:00:1f.2 */
317 end = strchr(start, '/');
318 if (!end)
319 return -1;
320 end = strchr(end + 1, '/');
321 if (!end)
322 return -1;
323
324 /* Make sure we have enough room for the string plus null terminator */
325 if (end - start + 1 > buf_sz)
326 return -1;
327
328 strncpy(buf, start, end - start);
329 buf[end - start] = '\0';
330 return 0;
331}
332
Chuck Tuffli1e070842008-12-15 14:26:56 -0800333#if LOG_UEVENTS
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700334
335static inline suseconds_t get_usecs(void)
336{
337 struct timeval tv;
338 gettimeofday(&tv, 0);
339 return tv.tv_sec * (suseconds_t) 1000000 + tv.tv_usec;
340}
341
342#define log_event_print(x...) INFO(x)
343
344#else
345
346#define log_event_print(fmt, args...) do { } while (0)
347#define get_usecs() 0
348
349#endif
350
351static void parse_event(const char *msg, struct uevent *uevent)
352{
353 uevent->action = "";
354 uevent->path = "";
355 uevent->subsystem = "";
356 uevent->firmware = "";
357 uevent->major = -1;
358 uevent->minor = -1;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700359 uevent->partition_name = NULL;
360 uevent->partition_num = -1;
Wei Zhongf97b8872012-03-23 14:15:34 -0700361 uevent->device_name = NULL;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700362
363 /* currently ignoring SEQNUM */
364 while(*msg) {
365 if(!strncmp(msg, "ACTION=", 7)) {
366 msg += 7;
367 uevent->action = msg;
368 } else if(!strncmp(msg, "DEVPATH=", 8)) {
369 msg += 8;
370 uevent->path = msg;
371 } else if(!strncmp(msg, "SUBSYSTEM=", 10)) {
372 msg += 10;
373 uevent->subsystem = msg;
374 } else if(!strncmp(msg, "FIRMWARE=", 9)) {
375 msg += 9;
376 uevent->firmware = msg;
377 } else if(!strncmp(msg, "MAJOR=", 6)) {
378 msg += 6;
379 uevent->major = atoi(msg);
380 } else if(!strncmp(msg, "MINOR=", 6)) {
381 msg += 6;
382 uevent->minor = atoi(msg);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700383 } else if(!strncmp(msg, "PARTN=", 6)) {
384 msg += 6;
385 uevent->partition_num = atoi(msg);
386 } else if(!strncmp(msg, "PARTNAME=", 9)) {
387 msg += 9;
388 uevent->partition_name = msg;
Wei Zhongf97b8872012-03-23 14:15:34 -0700389 } else if(!strncmp(msg, "DEVNAME=", 8)) {
390 msg += 8;
391 uevent->device_name = msg;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700392 }
393
Wei Zhongf97b8872012-03-23 14:15:34 -0700394 /* advance to after the next \0 */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700395 while(*msg++)
396 ;
397 }
398
399 log_event_print("event { '%s', '%s', '%s', '%s', %d, %d }\n",
400 uevent->action, uevent->path, uevent->subsystem,
401 uevent->firmware, uevent->major, uevent->minor);
402}
403
Benoit Gobyd2278632010-08-03 14:36:02 -0700404static char **get_character_device_symlinks(struct uevent *uevent)
405{
406 const char *parent;
407 char *slash;
408 char **links;
409 int link_num = 0;
410 int width;
Dima Zavinf395c922013-03-06 16:23:57 -0800411 struct platform_node *pdev;
Benoit Gobyd2278632010-08-03 14:36:02 -0700412
Dima Zavinf395c922013-03-06 16:23:57 -0800413 pdev = find_platform_device(uevent->path);
414 if (!pdev)
Benoit Gobyd2278632010-08-03 14:36:02 -0700415 return NULL;
416
417 links = malloc(sizeof(char *) * 2);
418 if (!links)
419 return NULL;
420 memset(links, 0, sizeof(char *) * 2);
421
422 /* skip "/devices/platform/<driver>" */
Dima Zavinf395c922013-03-06 16:23:57 -0800423 parent = strchr(uevent->path + pdev->path_len, '/');
Benoit Gobyd2278632010-08-03 14:36:02 -0700424 if (!*parent)
425 goto err;
426
427 if (!strncmp(parent, "/usb", 4)) {
428 /* skip root hub name and device. use device interface */
429 while (*++parent && *parent != '/');
430 if (*parent)
431 while (*++parent && *parent != '/');
432 if (!*parent)
433 goto err;
434 slash = strchr(++parent, '/');
435 if (!slash)
436 goto err;
437 width = slash - parent;
438 if (width <= 0)
439 goto err;
440
441 if (asprintf(&links[link_num], "/dev/usb/%s%.*s", uevent->subsystem, width, parent) > 0)
442 link_num++;
443 else
444 links[link_num] = NULL;
445 mkdir("/dev/usb", 0755);
446 }
447 else {
448 goto err;
449 }
450
451 return links;
452err:
453 free(links);
454 return NULL;
455}
456
Andrew Boiea885d042013-09-13 17:41:20 -0700457static char **get_block_device_symlinks(struct uevent *uevent)
Colin Crossb0ab94b2010-04-08 16:16:20 -0700458{
Colin Crossfadb85e2011-03-30 18:32:12 -0700459 const char *device;
Dima Zavinf395c922013-03-06 16:23:57 -0800460 struct platform_node *pdev;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700461 char *slash;
Andrew Boiea885d042013-09-13 17:41:20 -0700462 const char *type;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700463 int width;
464 char buf[256];
465 char link_path[256];
466 int fd;
467 int link_num = 0;
468 int ret;
469 char *p;
470 unsigned int size;
471 struct stat info;
472
Dima Zavinf395c922013-03-06 16:23:57 -0800473 pdev = find_platform_device(uevent->path);
Andrew Boiea885d042013-09-13 17:41:20 -0700474 if (pdev) {
475 device = pdev->name;
476 type = "platform";
477 } else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) {
478 device = buf;
479 type = "pci";
480 } else {
Dima Zavinf395c922013-03-06 16:23:57 -0800481 return NULL;
Andrew Boiea885d042013-09-13 17:41:20 -0700482 }
Dima Zavinf395c922013-03-06 16:23:57 -0800483
Colin Crossb0ab94b2010-04-08 16:16:20 -0700484 char **links = malloc(sizeof(char *) * 4);
485 if (!links)
486 return NULL;
487 memset(links, 0, sizeof(char *) * 4);
488
Andrew Boiea885d042013-09-13 17:41:20 -0700489 INFO("found %s device %s\n", type, device);
Colin Crossfadb85e2011-03-30 18:32:12 -0700490
Andrew Boiea885d042013-09-13 17:41:20 -0700491 snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700492
493 if (uevent->partition_name) {
494 p = strdup(uevent->partition_name);
495 sanitize(p);
Johan Redestig93ca79b2012-04-18 16:41:19 +0200496 if (strcmp(uevent->partition_name, p))
497 NOTICE("Linking partition '%s' as '%s'\n", uevent->partition_name, p);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700498 if (asprintf(&links[link_num], "%s/by-name/%s", link_path, p) > 0)
499 link_num++;
500 else
501 links[link_num] = NULL;
502 free(p);
503 }
504
505 if (uevent->partition_num >= 0) {
506 if (asprintf(&links[link_num], "%s/by-num/p%d", link_path, uevent->partition_num) > 0)
507 link_num++;
508 else
509 links[link_num] = NULL;
510 }
511
Dima Zavinf395c922013-03-06 16:23:57 -0800512 slash = strrchr(uevent->path, '/');
Colin Crossb0ab94b2010-04-08 16:16:20 -0700513 if (asprintf(&links[link_num], "%s/%s", link_path, slash + 1) > 0)
514 link_num++;
515 else
516 links[link_num] = NULL;
517
518 return links;
Colin Crossb0ab94b2010-04-08 16:16:20 -0700519}
520
Colin Crosseb5ba832011-03-30 17:37:17 -0700521static void handle_device(const char *action, const char *devpath,
522 const char *path, int block, int major, int minor, char **links)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700523{
Colin Crossb0ab94b2010-04-08 16:16:20 -0700524 int i;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700525
Colin Crosseb5ba832011-03-30 17:37:17 -0700526 if(!strcmp(action, "add")) {
Stephen Smalleyb4c52002014-06-12 12:29:14 -0400527 make_device(devpath, path, block, major, minor, (const char **)links);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700528 if (links) {
529 for (i = 0; links[i]; i++)
530 make_link(devpath, links[i]);
531 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700532 }
533
Colin Crosseb5ba832011-03-30 17:37:17 -0700534 if(!strcmp(action, "remove")) {
Colin Crossb0ab94b2010-04-08 16:16:20 -0700535 if (links) {
536 for (i = 0; links[i]; i++)
537 remove_link(devpath, links[i]);
538 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700539 unlink(devpath);
Colin Crossb0ab94b2010-04-08 16:16:20 -0700540 }
541
542 if (links) {
543 for (i = 0; links[i]; i++)
544 free(links[i]);
545 free(links);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700546 }
547}
548
Colin Crossfadb85e2011-03-30 18:32:12 -0700549static void handle_platform_device_event(struct uevent *uevent)
550{
Dima Zavinf395c922013-03-06 16:23:57 -0800551 const char *path = uevent->path;
Colin Crossfadb85e2011-03-30 18:32:12 -0700552
553 if (!strcmp(uevent->action, "add"))
Dima Zavinf395c922013-03-06 16:23:57 -0800554 add_platform_device(path);
Colin Crossfadb85e2011-03-30 18:32:12 -0700555 else if (!strcmp(uevent->action, "remove"))
Dima Zavinf395c922013-03-06 16:23:57 -0800556 remove_platform_device(path);
Colin Crossfadb85e2011-03-30 18:32:12 -0700557}
558
Colin Crosseb5ba832011-03-30 17:37:17 -0700559static const char *parse_device_name(struct uevent *uevent, unsigned int len)
560{
561 const char *name;
562
563 /* if it's not a /dev device, nothing else to do */
564 if((uevent->major < 0) || (uevent->minor < 0))
565 return NULL;
566
567 /* do we have a name? */
568 name = strrchr(uevent->path, '/');
569 if(!name)
570 return NULL;
571 name++;
572
573 /* too-long names would overrun our buffer */
Greg Hackmannf6e009e2013-11-21 13:26:48 -0800574 if(strlen(name) > len) {
575 ERROR("DEVPATH=%s exceeds %u-character limit on filename; ignoring event\n",
576 name, len);
Colin Crosseb5ba832011-03-30 17:37:17 -0700577 return NULL;
Greg Hackmannf6e009e2013-11-21 13:26:48 -0800578 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700579
580 return name;
581}
582
583static void handle_block_device_event(struct uevent *uevent)
584{
585 const char *base = "/dev/block/";
586 const char *name;
587 char devpath[96];
588 char **links = NULL;
589
590 name = parse_device_name(uevent, 64);
591 if (!name)
592 return;
593
594 snprintf(devpath, sizeof(devpath), "%s%s", base, name);
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500595 make_dir(base, 0755);
Colin Crosseb5ba832011-03-30 17:37:17 -0700596
Dima Zavinf395c922013-03-06 16:23:57 -0800597 if (!strncmp(uevent->path, "/devices/", 9))
Andrew Boiea885d042013-09-13 17:41:20 -0700598 links = get_block_device_symlinks(uevent);
Colin Crosseb5ba832011-03-30 17:37:17 -0700599
600 handle_device(uevent->action, devpath, uevent->path, 1,
601 uevent->major, uevent->minor, links);
Colin Crosseb5ba832011-03-30 17:37:17 -0700602}
603
Greg Hackmann3312aa82013-11-18 15:24:40 -0800604#define DEVPATH_LEN 96
605
606static bool assemble_devpath(char *devpath, const char *dirname,
607 const char *devname)
608{
609 int s = snprintf(devpath, DEVPATH_LEN, "%s/%s", dirname, devname);
610 if (s < 0) {
611 ERROR("failed to assemble device path (%s); ignoring event\n",
612 strerror(errno));
613 return false;
614 } else if (s >= DEVPATH_LEN) {
615 ERROR("%s/%s exceeds %u-character limit on path; ignoring event\n",
616 dirname, devname, DEVPATH_LEN);
617 return false;
618 }
619 return true;
620}
621
622static void mkdir_recursive_for_devpath(const char *devpath)
623{
624 char dir[DEVPATH_LEN];
625 char *slash;
626
627 strcpy(dir, devpath);
628 slash = strrchr(dir, '/');
629 *slash = '\0';
630 mkdir_recursive(dir, 0755);
631}
632
Mark Salyzyn154f4602014-02-20 14:59:07 -0800633static inline void __attribute__((__deprecated__)) kernel_logger()
634{
635 INFO("kernel logger is deprecated\n");
636}
637
Colin Crosseb5ba832011-03-30 17:37:17 -0700638static void handle_generic_device_event(struct uevent *uevent)
639{
640 char *base;
641 const char *name;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800642 char devpath[DEVPATH_LEN] = {0};
Colin Crosseb5ba832011-03-30 17:37:17 -0700643 char **links = NULL;
644
645 name = parse_device_name(uevent, 64);
646 if (!name)
647 return;
648
Greg Hackmann3312aa82013-11-18 15:24:40 -0800649 struct ueventd_subsystem *subsystem =
650 ueventd_subsystem_find_by_name(uevent->subsystem);
651
652 if (subsystem) {
653 const char *devname;
654
655 switch (subsystem->devname_src) {
656 case DEVNAME_UEVENT_DEVNAME:
657 devname = uevent->device_name;
658 break;
659
660 case DEVNAME_UEVENT_DEVPATH:
661 devname = name;
662 break;
663
664 default:
665 ERROR("%s subsystem's devpath option is not set; ignoring event\n",
666 uevent->subsystem);
667 return;
668 }
669
670 if (!assemble_devpath(devpath, subsystem->dirname, devname))
671 return;
672 mkdir_recursive_for_devpath(devpath);
673 } else if (!strncmp(uevent->subsystem, "usb", 3)) {
Colin Crosseb5ba832011-03-30 17:37:17 -0700674 if (!strcmp(uevent->subsystem, "usb")) {
Wei Zhongf97b8872012-03-23 14:15:34 -0700675 if (uevent->device_name) {
Greg Hackmann3312aa82013-11-18 15:24:40 -0800676 if (!assemble_devpath(devpath, "/dev", uevent->device_name))
Greg Hackmannf6e009e2013-11-21 13:26:48 -0800677 return;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800678 mkdir_recursive_for_devpath(devpath);
Wei Zhongf97b8872012-03-23 14:15:34 -0700679 }
680 else {
681 /* This imitates the file system that would be created
682 * if we were using devfs instead.
683 * Minors are broken up into groups of 128, starting at "001"
684 */
685 int bus_id = uevent->minor / 128 + 1;
686 int device_id = uevent->minor % 128 + 1;
687 /* build directories */
688 make_dir("/dev/bus", 0755);
689 make_dir("/dev/bus/usb", 0755);
690 snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d", bus_id);
691 make_dir(devpath, 0755);
692 snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d/%03d", bus_id, device_id);
693 }
Colin Crosseb5ba832011-03-30 17:37:17 -0700694 } else {
695 /* ignore other USB events */
696 return;
697 }
698 } else if (!strncmp(uevent->subsystem, "graphics", 8)) {
699 base = "/dev/graphics/";
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500700 make_dir(base, 0755);
Lukasz Anaczkowskie6f8d452011-09-28 15:30:07 +0200701 } else if (!strncmp(uevent->subsystem, "drm", 3)) {
702 base = "/dev/dri/";
703 make_dir(base, 0755);
Colin Crosseb5ba832011-03-30 17:37:17 -0700704 } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) {
705 base = "/dev/oncrpc/";
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500706 make_dir(base, 0755);
Colin Crosseb5ba832011-03-30 17:37:17 -0700707 } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
708 base = "/dev/adsp/";
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500709 make_dir(base, 0755);
Colin Crosseb5ba832011-03-30 17:37:17 -0700710 } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) {
711 base = "/dev/msm_camera/";
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500712 make_dir(base, 0755);
Colin Crosseb5ba832011-03-30 17:37:17 -0700713 } else if(!strncmp(uevent->subsystem, "input", 5)) {
714 base = "/dev/input/";
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500715 make_dir(base, 0755);
Colin Crosseb5ba832011-03-30 17:37:17 -0700716 } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
717 base = "/dev/mtd/";
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500718 make_dir(base, 0755);
Colin Crosseb5ba832011-03-30 17:37:17 -0700719 } else if(!strncmp(uevent->subsystem, "sound", 5)) {
720 base = "/dev/snd/";
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500721 make_dir(base, 0755);
Colin Crosseb5ba832011-03-30 17:37:17 -0700722 } else if(!strncmp(uevent->subsystem, "misc", 4) &&
723 !strncmp(name, "log_", 4)) {
Mark Salyzyn154f4602014-02-20 14:59:07 -0800724 kernel_logger();
Colin Crosseb5ba832011-03-30 17:37:17 -0700725 base = "/dev/log/";
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500726 make_dir(base, 0755);
Colin Crosseb5ba832011-03-30 17:37:17 -0700727 name += 4;
728 } else
729 base = "/dev/";
730 links = get_character_device_symlinks(uevent);
731
732 if (!devpath[0])
733 snprintf(devpath, sizeof(devpath), "%s%s", base, name);
734
735 handle_device(uevent->action, devpath, uevent->path, 0,
736 uevent->major, uevent->minor, links);
737}
738
739static void handle_device_event(struct uevent *uevent)
740{
Ruchi Kandoi75b287b2014-04-29 19:14:37 -0700741 if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
Colin Crosseb5ba832011-03-30 17:37:17 -0700742 fixup_sys_perms(uevent->path);
743
744 if (!strncmp(uevent->subsystem, "block", 5)) {
745 handle_block_device_event(uevent);
Colin Crossfadb85e2011-03-30 18:32:12 -0700746 } else if (!strncmp(uevent->subsystem, "platform", 8)) {
747 handle_platform_device_event(uevent);
Colin Crosseb5ba832011-03-30 17:37:17 -0700748 } else {
749 handle_generic_device_event(uevent);
750 }
751}
752
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700753static int load_firmware(int fw_fd, int loading_fd, int data_fd)
754{
755 struct stat st;
756 long len_to_copy;
757 int ret = 0;
758
759 if(fstat(fw_fd, &st) < 0)
760 return -1;
761 len_to_copy = st.st_size;
762
763 write(loading_fd, "1", 1); /* start transfer */
764
765 while (len_to_copy > 0) {
766 char buf[PAGE_SIZE];
767 ssize_t nr;
768
769 nr = read(fw_fd, buf, sizeof(buf));
770 if(!nr)
771 break;
772 if(nr < 0) {
773 ret = -1;
774 break;
775 }
776
777 len_to_copy -= nr;
778 while (nr > 0) {
779 ssize_t nw = 0;
780
781 nw = write(data_fd, buf + nw, nr);
782 if(nw <= 0) {
783 ret = -1;
784 goto out;
785 }
786 nr -= nw;
787 }
788 }
789
790out:
791 if(!ret)
792 write(loading_fd, "0", 1); /* successful end of transfer */
793 else
794 write(loading_fd, "-1", 2); /* abort transfer */
795
796 return ret;
797}
798
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700799static int is_booting(void)
800{
801 return access("/dev/.booting", F_OK) == 0;
802}
803
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700804static void process_firmware_event(struct uevent *uevent)
805{
Iliyan Malchev029d44e2012-06-08 10:42:26 -0700806 char *root, *loading, *data, *file1 = NULL, *file2 = NULL, *file3 = NULL;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700807 int l, loading_fd, data_fd, fw_fd;
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700808 int booting = is_booting();
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700809
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700810 INFO("firmware: loading '%s' for '%s'\n",
811 uevent->firmware, uevent->path);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700812
813 l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);
814 if (l == -1)
815 return;
816
817 l = asprintf(&loading, "%sloading", root);
818 if (l == -1)
819 goto root_free_out;
820
821 l = asprintf(&data, "%sdata", root);
822 if (l == -1)
823 goto loading_free_out;
824
Brian Swetland02863b92010-09-19 03:36:39 -0700825 l = asprintf(&file1, FIRMWARE_DIR1"/%s", uevent->firmware);
826 if (l == -1)
827 goto data_free_out;
828
829 l = asprintf(&file2, FIRMWARE_DIR2"/%s", uevent->firmware);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700830 if (l == -1)
831 goto data_free_out;
832
Iliyan Malchev029d44e2012-06-08 10:42:26 -0700833 l = asprintf(&file3, FIRMWARE_DIR3"/%s", uevent->firmware);
834 if (l == -1)
835 goto data_free_out;
836
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700837 loading_fd = open(loading, O_WRONLY);
838 if(loading_fd < 0)
839 goto file_free_out;
840
841 data_fd = open(data, O_WRONLY);
842 if(data_fd < 0)
843 goto loading_close_out;
844
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700845try_loading_again:
Brian Swetland02863b92010-09-19 03:36:39 -0700846 fw_fd = open(file1, O_RDONLY);
847 if(fw_fd < 0) {
848 fw_fd = open(file2, O_RDONLY);
Benoit Goby609d8822010-11-09 18:10:24 -0800849 if (fw_fd < 0) {
Iliyan Malchev029d44e2012-06-08 10:42:26 -0700850 fw_fd = open(file3, O_RDONLY);
851 if (fw_fd < 0) {
852 if (booting) {
853 /* If we're not fully booted, we may be missing
854 * filesystems needed for firmware, wait and retry.
855 */
856 usleep(100000);
857 booting = is_booting();
858 goto try_loading_again;
859 }
860 INFO("firmware: could not open '%s' %d\n", uevent->firmware, errno);
861 write(loading_fd, "-1", 2);
862 goto data_close_out;
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700863 }
Benoit Goby609d8822010-11-09 18:10:24 -0800864 }
Brian Swetland02863b92010-09-19 03:36:39 -0700865 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700866
867 if(!load_firmware(fw_fd, loading_fd, data_fd))
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700868 INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700869 else
Brian Swetland8d48c8e2011-03-24 15:45:30 -0700870 INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700871
872 close(fw_fd);
873data_close_out:
874 close(data_fd);
875loading_close_out:
876 close(loading_fd);
877file_free_out:
Brian Swetland02863b92010-09-19 03:36:39 -0700878 free(file1);
879 free(file2);
Ajay Dudani76c58892013-06-12 15:55:26 -0700880 free(file3);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700881data_free_out:
882 free(data);
883loading_free_out:
884 free(loading);
885root_free_out:
886 free(root);
887}
888
889static void handle_firmware_event(struct uevent *uevent)
890{
891 pid_t pid;
Colin Cross982a8152010-06-03 12:21:01 -0700892 int ret;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700893
894 if(strcmp(uevent->subsystem, "firmware"))
895 return;
896
897 if(strcmp(uevent->action, "add"))
898 return;
899
900 /* we fork, to avoid making large memory allocations in init proper */
901 pid = fork();
902 if (!pid) {
903 process_firmware_event(uevent);
904 exit(EXIT_SUCCESS);
905 }
906}
907
908#define UEVENT_MSG_LEN 1024
Colin Cross0dd7ca62010-04-13 19:25:51 -0700909void handle_device_fd()
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700910{
Vernon Tang3f582e92011-04-25 13:08:17 +1000911 char msg[UEVENT_MSG_LEN+2];
912 int n;
Nick Kralevich57de8b82011-05-11 14:58:24 -0700913 while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
Nick Kralevich5f5d5c82010-07-19 14:31:20 -0700914 if(n >= UEVENT_MSG_LEN) /* overflow -- discard */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700915 continue;
916
917 msg[n] = '\0';
918 msg[n+1] = '\0';
919
Nick Kralevich5f5d5c82010-07-19 14:31:20 -0700920 struct uevent uevent;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700921 parse_event(msg, &uevent);
922
Stephen Smalleye2eb69d2013-04-16 09:30:30 -0400923 if (sehandle && selinux_status_updated() > 0) {
924 struct selabel_handle *sehandle2;
925 sehandle2 = selinux_android_file_context_handle();
926 if (sehandle2) {
927 selabel_close(sehandle);
928 sehandle = sehandle2;
929 }
930 }
931
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700932 handle_device_event(&uevent);
933 handle_firmware_event(&uevent);
934 }
935}
936
937/* Coldboot walks parts of the /sys tree and pokes the uevent files
938** to cause the kernel to regenerate device add events that happened
939** before init's device manager was started
940**
941** We drain any pending events from the netlink socket every time
942** we poke another uevent file to make sure we don't overrun the
943** socket's buffer.
944*/
945
Colin Cross0dd7ca62010-04-13 19:25:51 -0700946static void do_coldboot(DIR *d)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700947{
948 struct dirent *de;
949 int dfd, fd;
950
951 dfd = dirfd(d);
952
953 fd = openat(dfd, "uevent", O_WRONLY);
954 if(fd >= 0) {
955 write(fd, "add\n", 4);
956 close(fd);
Colin Cross0dd7ca62010-04-13 19:25:51 -0700957 handle_device_fd();
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700958 }
959
960 while((de = readdir(d))) {
961 DIR *d2;
962
963 if(de->d_type != DT_DIR || de->d_name[0] == '.')
964 continue;
965
966 fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
967 if(fd < 0)
968 continue;
969
970 d2 = fdopendir(fd);
971 if(d2 == 0)
972 close(fd);
973 else {
Colin Cross0dd7ca62010-04-13 19:25:51 -0700974 do_coldboot(d2);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700975 closedir(d2);
976 }
977 }
978}
979
Colin Cross0dd7ca62010-04-13 19:25:51 -0700980static void coldboot(const char *path)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700981{
982 DIR *d = opendir(path);
983 if(d) {
Colin Cross0dd7ca62010-04-13 19:25:51 -0700984 do_coldboot(d);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700985 closedir(d);
986 }
987}
988
Colin Cross0dd7ca62010-04-13 19:25:51 -0700989void device_init(void)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700990{
991 suseconds_t t0, t1;
Colin Crossf83d0b92010-04-21 12:04:20 -0700992 struct stat info;
993 int fd;
Kenny Rootb5982bf2012-10-16 23:07:05 -0700994
Stephen Smalleyae6f3d72012-05-01 15:02:53 -0400995 sehandle = NULL;
996 if (is_selinux_enabled() > 0) {
997 sehandle = selinux_android_file_context_handle();
Stephen Smalleye2eb69d2013-04-16 09:30:30 -0400998 selinux_status_open(true);
Stephen Smalleyae6f3d72012-05-01 15:02:53 -0400999 }
Kenny Rootb5982bf2012-10-16 23:07:05 -07001000
Andrew Boied562ca72012-12-04 15:47:20 -08001001 /* is 256K enough? udev uses 16MB! */
1002 device_fd = uevent_open_socket(256*1024, true);
Colin Cross0dd7ca62010-04-13 19:25:51 -07001003 if(device_fd < 0)
1004 return;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001005
Colin Cross0dd7ca62010-04-13 19:25:51 -07001006 fcntl(device_fd, F_SETFD, FD_CLOEXEC);
1007 fcntl(device_fd, F_SETFL, O_NONBLOCK);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001008
Colin Crossf83d0b92010-04-21 12:04:20 -07001009 if (stat(coldboot_done, &info) < 0) {
1010 t0 = get_usecs();
1011 coldboot("/sys/class");
1012 coldboot("/sys/block");
1013 coldboot("/sys/devices");
1014 t1 = get_usecs();
1015 fd = open(coldboot_done, O_WRONLY|O_CREAT, 0000);
1016 close(fd);
1017 log_event_print("coldboot %ld uS\n", ((long) (t1 - t0)));
1018 } else {
1019 log_event_print("skipping coldboot, already done\n");
1020 }
Colin Cross0dd7ca62010-04-13 19:25:51 -07001021}
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001022
Colin Cross0dd7ca62010-04-13 19:25:51 -07001023int get_device_fd()
1024{
1025 return device_fd;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001026}