devices.cpp revision 35403ebaf85aa229973275be9f5229d453799811
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007-2014 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <dirent.h>
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <errno.h>
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <fcntl.h>
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <fnmatch.h>
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <libgen.h>
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stddef.h>
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdio.h>
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdlib.h>
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <string.h>
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/sendfile.h>
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/socket.h>
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/stat.h>
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/time.h>
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/types.h>
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/un.h>
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/wait.h>
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <unistd.h>
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <linux/netlink.h>
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <memory>
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <thread>
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <selinux/selinux.h>
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <selinux/label.h>
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <selinux/android.h>
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <selinux/avc.h>
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <private/android_filesystem_config.h>
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <android-base/file.h>
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <android-base/stringprintf.h>
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <android-base/unique_fd.h>
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <cutils/list.h>
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <cutils/uevent.h>
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "devices.h"
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "ueventd_parser.h"
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "util.h"
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "log.h"
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define SYSFS_PREFIX    "/sys"
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic const char *firmware_dirs[] = { "/etc/firmware",
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       "/vendor/firmware",
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       "/firmware/image" };
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectextern struct selabel_handle *sehandle;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic android::base::unique_fd device_fd;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct perms_ {
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char *name;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char *attr;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mode_t perm;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned int uid;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned int gid;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned short prefix;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned short wildcard;
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct perm_node {
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct perms_ dp;
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct listnode plist;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct platform_node {
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char *name;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char *path;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int path_len;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct listnode list;
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic list_declare(sys_perms);
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic list_declare(dev_perms);
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic list_declare(platform_names);
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint add_dev_perms(const char *name, const char *attr,
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  mode_t perm, unsigned int uid, unsigned int gid,
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  unsigned short prefix,
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  unsigned short wildcard) {
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct perm_node *node = (perm_node*) calloc(1, sizeof(*node));
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!node)
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -ENOMEM;
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    node->dp.name = strdup(name);
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!node->dp.name) {
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        free(node);
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -ENOMEM;
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (attr) {
108a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru        node->dp.attr = strdup(attr);
109a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru        if (!node->dp.attr) {
110a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru            free(node->dp.name);
111a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru            free(node);
112a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru            return -ENOMEM;
113a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru        }
114a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru    }
115a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru
116a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru    node->dp.perm = perm;
117a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru    node->dp.uid = uid;
118a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru    node->dp.gid = gid;
119a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru    node->dp.prefix = prefix;
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    node->dp.wildcard = wildcard;
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (attr)
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        list_add_tail(&sys_perms, &node->plist);
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    else
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        list_add_tail(&dev_perms, &node->plist);
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return 0;
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic bool perm_path_matches(const char *path, struct perms_ *dp)
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (dp->prefix) {
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (strncmp(path, dp->name, strlen(dp->name)) == 0)
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else if (dp->wildcard) {
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fnmatch(dp->name, path, FNM_PATHNAME) == 0)
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (strcmp(path, dp->name) == 0)
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return false;
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic bool match_subsystem(perms_* dp, const char* pattern,
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            const char* path, const char* subsystem) {
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!pattern || !subsystem || strstr(dp->name, subsystem) == NULL) {
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    std::string subsys_path = android::base::StringPrintf(pattern, subsystem, basename(path));
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return perm_path_matches(subsys_path.c_str(), dp);
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void fixup_sys_perms(const char* upath, const char* subsystem) {
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // upaths omit the "/sys" that paths in this list
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // contain, so we prepend it...
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    std::string path = std::string(SYSFS_PREFIX) + upath;
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    listnode* node;
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    list_for_each(node, &sys_perms) {
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        perms_* dp = &(node_to_item(node, perm_node, plist))->dp;
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (match_subsystem(dp, SYSFS_PREFIX "/class/%s/%s", path.c_str(), subsystem)) {
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ; // matched
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (match_subsystem(dp, SYSFS_PREFIX "/bus/%s/devices/%s", path.c_str(), subsystem)) {
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ; // matched
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (!perm_path_matches(path.c_str(), dp)) {
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            continue;
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        std::string attr_file = path + "/" + dp->attr;
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOG(INFO) << "fixup " << attr_file
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  << " " << dp->uid << " " << dp->gid << " " << std::oct << dp->perm;
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        chown(attr_file.c_str(), dp->uid, dp->gid);
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        chmod(attr_file.c_str(), dp->perm);
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (access(path.c_str(), F_OK) == 0) {
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOG(VERBOSE) << "restorecon_recursive: " << path;
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic mode_t get_device_perm(const char *path, const char **links,
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                unsigned *uid, unsigned *gid)
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct listnode *node;
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct perm_node *perm_node;
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct perms_ *dp;
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* search the perms list in reverse so that ueventd.$hardware can
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * override ueventd.rc
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    list_for_each_reverse(node, &dev_perms) {
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        bool match = false;
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        perm_node = node_to_item(node, struct perm_node, plist);
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        dp = &perm_node->dp;
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (perm_path_matches(path, dp)) {
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            match = true;
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (links) {
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int i;
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (i = 0; links[i]; i++) {
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (perm_path_matches(links[i], dp)) {
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        match = true;
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (match) {
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            *uid = dp->uid;
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            *gid = dp->gid;
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return dp->perm;
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Default if nothing found. */
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    *uid = 0;
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    *gid = 0;
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return 0600;
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void make_device(const char *path,
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        const char */*upath*/,
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        int block, int major, int minor,
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        const char **links)
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned uid;
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned gid;
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mode_t mode;
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    dev_t dev;
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char *secontext = NULL;
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (sehandle) {
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setfscreatecon(secontext);
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    dev = makedev(major, minor);
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Temporarily change egid to avoid race condition setting the gid of the
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * device node. Unforunately changing the euid would prevent creation of
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * some device nodes, so the uid has to be set with chown() and is still
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * racy. Fixing the gid race at least fixed the issue with system_server
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * opening dynamic input devices under the AID_INPUT gid. */
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    setegid(gid);
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* If the node already exists update its SELinux label to handle cases when
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * it was created with the wrong context during coldboot procedure. */
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mknod(path, mode, dev) && (errno == EEXIST) && secontext) {
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        char* fcon = nullptr;
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rc = lgetfilecon(path, &fcon);
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (rc < 0) {
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            PLOG(ERROR) << "Cannot get SELinux label on '" << path << "' device";
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            goto out;
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        bool different = strcmp(fcon, secontext) != 0;
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        freecon(fcon);
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (different && lsetfilecon(path, secontext)) {
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path << "' device";
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectout:
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    chown(path, uid, -1);
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    setegid(AID_ROOT);
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (secontext) {
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        freecon(secontext);
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setfscreatecon(NULL);
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void add_platform_device(const char *path)
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int path_len = strlen(path);
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct platform_node *bus;
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char *name = path;
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!strncmp(path, "/devices/", 9)) {
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        name += 9;
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!strncmp(name, "platform/", 9))
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            name += 9;
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LOG(VERBOSE) << "adding platform device " << name << " (" << path << ")";
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bus = (platform_node*) calloc(1, sizeof(struct platform_node));
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bus->path = strdup(path);
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bus->path_len = path_len;
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bus->name = bus->path + (name - path);
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    list_add_tail(&platform_names, &bus->list);
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * given a path that may start with a platform device, find the length of the
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * platform device prefix.  If it doesn't start with a platform device, return
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 0.
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic struct platform_node *find_platform_device(const char *path)
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int path_len = strlen(path);
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct listnode *node;
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct platform_node *bus;
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    list_for_each_reverse(node, &platform_names) {
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        bus = node_to_item(node, struct platform_node, list);
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((bus->path_len < path_len) &&
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (path[bus->path_len] == '/') &&
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                !strncmp(path, bus->path, bus->path_len))
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return bus;
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NULL;
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void remove_platform_device(const char *path)
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct listnode *node;
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct platform_node *bus;
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    list_for_each_reverse(node, &platform_names) {
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        bus = node_to_item(node, struct platform_node, list);
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!strcmp(path, bus->path)) {
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOG(INFO) << "removing platform device " << bus->name;
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            free(bus->path);
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            list_remove(node);
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            free(bus);
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void destroy_platform_devices() {
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct listnode* node;
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct listnode* n;
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct platform_node* bus;
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    list_for_each_safe(node, n, &platform_names) {
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        list_remove(node);
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        bus = node_to_item(node, struct platform_node, list);
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        free(bus->path);
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        free(bus);
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* Given a path that may start with a PCI device, populate the supplied buffer
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * with the PCI domain/bus number and the peripheral ID and return 0.
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If it doesn't start with a PCI device, or there is some error, return -1 */
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic int find_pci_device_prefix(const char *path, char *buf, ssize_t buf_sz)
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char *start, *end;
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (strncmp(path, "/devices/pci", 12))
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Beginning of the prefix is the initial "pci" after "/devices/" */
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    start = path + 9;
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* End of the prefix is two path '/' later, capturing the domain/bus number
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * and the peripheral ID. Example: pci0000:00/0000:00:1f.2 */
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    end = strchr(start, '/');
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!end)
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    end = strchr(end + 1, '/');
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!end)
3778aa393b03f6d1f25313c658334e9b86a86a6f61fSimon Schoar        return -1;
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Make sure we have enough room for the string plus null terminator */
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (end - start + 1 > buf_sz)
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    strncpy(buf, start, end - start);
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    buf[end - start] = '\0';
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return 0;
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void parse_event(const char *msg, struct uevent *uevent)
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uevent->action = "";
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uevent->path = "";
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uevent->subsystem = "";
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uevent->firmware = "";
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uevent->major = -1;
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uevent->minor = -1;
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uevent->partition_name = NULL;
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uevent->partition_num = -1;
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uevent->device_name = NULL;
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* currently ignoring SEQNUM */
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while(*msg) {
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if(!strncmp(msg, "ACTION=", 7)) {
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            msg += 7;
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uevent->action = msg;
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if(!strncmp(msg, "DEVPATH=", 8)) {
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            msg += 8;
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uevent->path = msg;
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if(!strncmp(msg, "SUBSYSTEM=", 10)) {
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            msg += 10;
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uevent->subsystem = msg;
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if(!strncmp(msg, "FIRMWARE=", 9)) {
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            msg += 9;
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uevent->firmware = msg;
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if(!strncmp(msg, "MAJOR=", 6)) {
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            msg += 6;
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uevent->major = atoi(msg);
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if(!strncmp(msg, "MINOR=", 6)) {
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            msg += 6;
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uevent->minor = atoi(msg);
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if(!strncmp(msg, "PARTN=", 6)) {
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            msg += 6;
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uevent->partition_num = atoi(msg);
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if(!strncmp(msg, "PARTNAME=", 9)) {
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            msg += 9;
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uevent->partition_name = msg;
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if(!strncmp(msg, "DEVNAME=", 8)) {
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            msg += 8;
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uevent->device_name = msg;
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* advance to after the next \0 */
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while(*msg++)
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ;
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (LOG_UEVENTS) {
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOG(INFO) << android::base::StringPrintf("event { '%s', '%s', '%s', '%s', %d, %d }",
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                 uevent->action, uevent->path, uevent->subsystem,
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                 uevent->firmware, uevent->major, uevent->minor);
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic char **get_character_device_symlinks(struct uevent *uevent)
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char *parent;
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char *slash;
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char **links;
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int link_num = 0;
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int width;
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct platform_node *pdev;
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pdev = find_platform_device(uevent->path);
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!pdev)
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    links = (char**) malloc(sizeof(char *) * 2);
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!links)
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    memset(links, 0, sizeof(char *) * 2);
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* skip "/devices/platform/<driver>" */
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    parent = strchr(uevent->path + pdev->path_len, '/');
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!parent)
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto err;
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!strncmp(parent, "/usb", 4)) {
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* skip root hub name and device. use device interface */
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (*++parent && *parent != '/');
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (*parent)
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (*++parent && *parent != '/');
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!*parent)
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            goto err;
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        slash = strchr(++parent, '/');
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!slash)
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            goto err;
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        width = slash - parent;
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (width <= 0)
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            goto err;
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (asprintf(&links[link_num], "/dev/usb/%s%.*s", uevent->subsystem, width, parent) > 0)
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            link_num++;
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            links[link_num] = NULL;
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mkdir("/dev/usb", 0755);
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    else {
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto err;
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return links;
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projecterr:
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    free(links);
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NULL;
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic char **get_block_device_symlinks(struct uevent *uevent)
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char *device;
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct platform_node *pdev;
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char *slash;
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char *type;
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char buf[256];
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char link_path[256];
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int link_num = 0;
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char *p;
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pdev = find_platform_device(uevent->path);
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (pdev) {
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        device = pdev->name;
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        type = "platform";
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) {
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        device = buf;
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        type = "pci";
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char **links = (char**) malloc(sizeof(char *) * 4);
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!links)
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    memset(links, 0, sizeof(char *) * 4);
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LOG(VERBOSE) << "found " << type << " device " << device;
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (uevent->partition_name) {
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        p = strdup(uevent->partition_name);
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sanitize(p);
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (strcmp(uevent->partition_name, p)) {
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOG(VERBOSE) << "Linking partition '" << uevent->partition_name << "' as '" << p << "'";
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (asprintf(&links[link_num], "%s/by-name/%s", link_path, p) > 0)
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            link_num++;
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            links[link_num] = NULL;
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        free(p);
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (uevent->partition_num >= 0) {
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (asprintf(&links[link_num], "%s/by-num/p%d", link_path, uevent->partition_num) > 0)
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            link_num++;
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            links[link_num] = NULL;
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    slash = strrchr(uevent->path, '/');
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (asprintf(&links[link_num], "%s/%s", link_path, slash + 1) > 0)
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        link_num++;
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    else
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        links[link_num] = NULL;
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return links;
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void make_link_init(const char* oldpath, const char* newpath) {
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  const char* slash = strrchr(newpath, '/');
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  if (!slash) return;
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  if (mkdir_recursive(dirname(newpath), 0755)) {
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    PLOG(ERROR) << "Failed to create directory " << dirname(newpath);
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  if (symlink(oldpath, newpath) && errno != EEXIST) {
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    PLOG(ERROR) << "Failed to symlink " << oldpath << " to " << newpath;
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void remove_link(const char* oldpath, const char* newpath) {
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  std::string path;
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  if (android::base::Readlink(newpath, &path) && path == oldpath) unlink(newpath);
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void handle_device(const char *action, const char *devpath,
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const char *path, int block, int major, int minor, char **links)
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if(!strcmp(action, "add")) {
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        make_device(devpath, path, block, major, minor, (const char **)links);
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (links) {
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; links[i]; i++) {
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                make_link_init(devpath, links[i]);
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if(!strcmp(action, "remove")) {
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (links) {
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; links[i]; i++) {
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                remove_link(devpath, links[i]);
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        unlink(devpath);
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (links) {
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; links[i]; i++) {
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            free(links[i]);
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        free(links);
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void handle_platform_device_event(struct uevent *uevent)
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char *path = uevent->path;
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!strcmp(uevent->action, "add"))
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        add_platform_device(path);
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    else if (!strcmp(uevent->action, "remove"))
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        remove_platform_device(path);
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic const char *parse_device_name(struct uevent *uevent, unsigned int len)
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char *name;
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* if it's not a /dev device, nothing else to do */
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if((uevent->major < 0) || (uevent->minor < 0))
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* do we have a name? */
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    name = strrchr(uevent->path, '/');
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if(!name)
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    name++;
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* too-long names would overrun our buffer */
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if(strlen(name) > len) {
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOG(ERROR) << "DEVPATH=" << name << " exceeds " << len << "-character limit on filename; ignoring event";
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return name;
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define DEVPATH_LEN 96
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define MAX_DEV_NAME 64
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void handle_block_device_event(struct uevent *uevent)
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char *base = "/dev/block/";
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char *name;
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char devpath[DEVPATH_LEN];
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char **links = NULL;
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    name = parse_device_name(uevent, MAX_DEV_NAME);
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!name)
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    snprintf(devpath, sizeof(devpath), "%s%s", base, name);
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    make_dir(base, 0755);
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!strncmp(uevent->path, "/devices/", 9))
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        links = get_block_device_symlinks(uevent);
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    handle_device(uevent->action, devpath, uevent->path, 1,
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uevent->major, uevent->minor, links);
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic bool assemble_devpath(char *devpath, const char *dirname,
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const char *devname)
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int s = snprintf(devpath, DEVPATH_LEN, "%s/%s", dirname, devname);
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (s < 0) {
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PLOG(ERROR) << "failed to assemble device path; ignoring event";
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else if (s >= DEVPATH_LEN) {
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOG(ERROR) << dirname << "/" << devname
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                   << " exceeds " << DEVPATH_LEN << "-character limit on path; ignoring event";
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return true;
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void mkdir_recursive_for_devpath(const char *devpath)
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char dir[DEVPATH_LEN];
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char *slash;
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    strcpy(dir, devpath);
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    slash = strrchr(dir, '/');
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    *slash = '\0';
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mkdir_recursive(dir, 0755);
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void handle_generic_device_event(struct uevent *uevent)
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char *base;
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char *name;
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char devpath[DEVPATH_LEN] = {0};
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char **links = NULL;
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    name = parse_device_name(uevent, MAX_DEV_NAME);
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!name)
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct ueventd_subsystem *subsystem =
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ueventd_subsystem_find_by_name(uevent->subsystem);
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (subsystem) {
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const char *devname;
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (subsystem->devname_src) {
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case DEVNAME_UEVENT_DEVNAME:
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            devname = uevent->device_name;
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case DEVNAME_UEVENT_DEVPATH:
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            devname = name;
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOG(ERROR) << uevent->subsystem << " subsystem's devpath option is not set; ignoring event";
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!assemble_devpath(devpath, subsystem->dirname, devname))
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mkdir_recursive_for_devpath(devpath);
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else if (!strncmp(uevent->subsystem, "usb", 3)) {
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         if (!strcmp(uevent->subsystem, "usb")) {
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (uevent->device_name) {
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!assemble_devpath(devpath, "/dev", uevent->device_name))
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return;
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mkdir_recursive_for_devpath(devpath);
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             }
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             else {
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 /* This imitates the file system that would be created
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  * if we were using devfs instead.
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  * Minors are broken up into groups of 128, starting at "001"
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  */
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 int bus_id = uevent->minor / 128 + 1;
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 int device_id = uevent->minor % 128 + 1;
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 /* build directories */
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 make_dir("/dev/bus", 0755);
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 make_dir("/dev/bus/usb", 0755);
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d", bus_id);
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 make_dir(devpath, 0755);
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d/%03d", bus_id, device_id);
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             }
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         } else {
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             /* ignore other USB events */
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             return;
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         }
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     } else if (!strncmp(uevent->subsystem, "graphics", 8)) {
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         base = "/dev/graphics/";
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         make_dir(base, 0755);
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     } else if (!strncmp(uevent->subsystem, "drm", 3)) {
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         base = "/dev/dri/";
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         make_dir(base, 0755);
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) {
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         base = "/dev/oncrpc/";
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         make_dir(base, 0755);
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         base = "/dev/adsp/";
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         make_dir(base, 0755);
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) {
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         base = "/dev/msm_camera/";
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         make_dir(base, 0755);
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     } else if(!strncmp(uevent->subsystem, "input", 5)) {
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         base = "/dev/input/";
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         make_dir(base, 0755);
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         base = "/dev/mtd/";
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         make_dir(base, 0755);
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     } else if(!strncmp(uevent->subsystem, "sound", 5)) {
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         base = "/dev/snd/";
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         make_dir(base, 0755);
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     } else if(!strncmp(uevent->subsystem, "misc", 4) && !strncmp(name, "log_", 4)) {
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         LOG(INFO) << "kernel logger is deprecated";
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         base = "/dev/log/";
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         make_dir(base, 0755);
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         name += 4;
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     } else
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         base = "/dev/";
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     links = get_character_device_symlinks(uevent);
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     if (!devpath[0])
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         snprintf(devpath, sizeof(devpath), "%s%s", base, name);
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     handle_device(uevent->action, devpath, uevent->path, 0,
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             uevent->major, uevent->minor, links);
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void handle_device_event(struct uevent *uevent)
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fixup_sys_perms(uevent->path, uevent->subsystem);
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!strncmp(uevent->subsystem, "block", 5)) {
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        handle_block_device_event(uevent);
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else if (!strncmp(uevent->subsystem, "platform", 8)) {
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        handle_platform_device_event(uevent);
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        handle_generic_device_event(uevent);
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void load_firmware(uevent* uevent, const std::string& root,
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          int fw_fd, size_t fw_size,
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          int loading_fd, int data_fd) {
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Start transfer.
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    android::base::WriteFully(loading_fd, "1", 1);
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Copy the firmware.
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int rc = sendfile(data_fd, fw_fd, nullptr, fw_size);
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (rc == -1) {
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PLOG(ERROR) << "firmware: sendfile failed { '" << root << "', '" << uevent->firmware << "' }";
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Tell the firmware whether to abort or commit.
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char* response = (rc != -1) ? "0" : "-1";
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    android::base::WriteFully(loading_fd, response, strlen(response));
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic int is_booting() {
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return access("/dev/.booting", F_OK) == 0;
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void process_firmware_event(uevent* uevent) {
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int booting = is_booting();
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LOG(INFO) << "firmware: loading '" << uevent->firmware << "' for '" << uevent->path << "'";
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    std::string root = android::base::StringPrintf("/sys%s", uevent->path);
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    std::string loading = root + "/loading";
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    std::string data = root + "/data";
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    android::base::unique_fd loading_fd(open(loading.c_str(), O_WRONLY|O_CLOEXEC));
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (loading_fd == -1) {
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PLOG(ERROR) << "couldn't open firmware loading fd for " << uevent->firmware;
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    android::base::unique_fd data_fd(open(data.c_str(), O_WRONLY|O_CLOEXEC));
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (data_fd == -1) {
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PLOG(ERROR) << "couldn't open firmware data fd for " << uevent->firmware;
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projecttry_loading_again:
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (size_t i = 0; i < arraysize(firmware_dirs); i++) {
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        std::string file = android::base::StringPrintf("%s/%s", firmware_dirs[i], uevent->firmware);
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        android::base::unique_fd fw_fd(open(file.c_str(), O_RDONLY|O_CLOEXEC));
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        struct stat sb;
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fw_fd != -1 && fstat(fw_fd, &sb) != -1) {
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            load_firmware(uevent, root, fw_fd, sb.st_size, loading_fd, data_fd);
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (booting) {
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // If we're not fully booted, we may be missing
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // filesystems needed for firmware, wait and retry.
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        std::this_thread::sleep_for(100ms);
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        booting = is_booting();
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto try_loading_again;
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LOG(ERROR) << "firmware: could not find firmware for " << uevent->firmware;
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Write "-1" as our response to the kernel's firmware request, since we have nothing for it.
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    write(loading_fd, "-1", 2);
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void handle_firmware_event(uevent* uevent) {
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (strcmp(uevent->subsystem, "firmware")) return;
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (strcmp(uevent->action, "add")) return;
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Loading the firmware in a child means we can do that in parallel...
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // (We ignore SIGCHLD rather than wait for our children.)
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pid_t pid = fork();
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (pid == 0) {
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Timer t;
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        process_firmware_event(uevent);
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOG(INFO) << "loading " << uevent->path << " took " << t;
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        _exit(EXIT_SUCCESS);
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else if (pid == -1) {
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PLOG(ERROR) << "could not fork to process firmware event for " << uevent->firmware;
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic bool inline should_stop_coldboot(coldboot_action_t act)
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return (act == COLDBOOT_STOP || act == COLDBOOT_FINISH);
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define UEVENT_MSG_LEN  2048
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic inline coldboot_action_t handle_device_fd_with(
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        std::function<coldboot_action_t(uevent* uevent)> handle_uevent)
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char msg[UEVENT_MSG_LEN+2];
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int n;
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if(n >= UEVENT_MSG_LEN)   /* overflow -- discard */
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            continue;
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        msg[n] = '\0';
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        msg[n+1] = '\0';
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        struct uevent uevent;
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        parse_event(msg, &uevent);
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        coldboot_action_t act = handle_uevent(&uevent);
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (should_stop_coldboot(act))
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return act;
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return COLDBOOT_CONTINUE;
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectcoldboot_action_t handle_device_fd(coldboot_callback fn)
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    coldboot_action_t ret = handle_device_fd_with(
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        [&](uevent* uevent) -> coldboot_action_t {
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (selinux_status_updated() > 0) {
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                struct selabel_handle *sehandle2;
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sehandle2 = selinux_android_file_context_handle();
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (sehandle2) {
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    selabel_close(sehandle);
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sehandle = sehandle2;
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // default is to always create the devices
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            coldboot_action_t act = COLDBOOT_CREATE;
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (fn) {
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                act = fn(uevent);
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (act == COLDBOOT_CREATE || act == COLDBOOT_STOP) {
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handle_device_event(uevent);
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handle_firmware_event(uevent);
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return act;
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        });
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return ret;
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* Coldboot walks parts of the /sys tree and pokes the uevent files
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** to cause the kernel to regenerate device add events that happened
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** before init's device manager was started
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project**
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** We drain any pending events from the netlink socket every time
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** we poke another uevent file to make sure we don't overrun the
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** socket's buffer.
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project*/
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic coldboot_action_t do_coldboot(DIR *d, coldboot_callback fn)
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct dirent *de;
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int dfd, fd;
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    coldboot_action_t act = COLDBOOT_CONTINUE;
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    dfd = dirfd(d);
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fd = openat(dfd, "uevent", O_WRONLY);
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fd >= 0) {
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        write(fd, "add\n", 4);
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        close(fd);
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        act = handle_device_fd(fn);
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (should_stop_coldboot(act))
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return act;
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while (!should_stop_coldboot(act) && (de = readdir(d))) {
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        DIR *d2;
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if(de->d_type != DT_DIR || de->d_name[0] == '.')
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            continue;
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if(fd < 0)
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            continue;
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        d2 = fdopendir(fd);
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if(d2 == 0)
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            close(fd);
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else {
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            act = do_coldboot(d2, fn);
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            closedir(d2);
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // default is always to continue looking for uevents
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return act;
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic coldboot_action_t coldboot(const char *path, coldboot_callback fn)
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path), closedir);
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (d) {
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return do_coldboot(d.get(), fn);
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return COLDBOOT_CONTINUE;
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid device_init(const char* path, coldboot_callback fn) {
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sehandle = selinux_android_file_context_handle();
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    selinux_status_open(true);
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* is 256K enough? udev uses 16MB! */
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    device_fd.reset(uevent_open_socket(256*1024, true));
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (device_fd == -1) {
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fcntl(device_fd, F_SETFL, O_NONBLOCK);
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (access(COLDBOOT_DONE, F_OK) == 0) {
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOG(VERBOSE) << "Skipping coldboot, already done!";
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Timer t;
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    coldboot_action_t act;
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!path) {
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        act = coldboot("/sys/class", fn);
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!should_stop_coldboot(act)) {
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            act = coldboot("/sys/block", fn);
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!should_stop_coldboot(act)) {
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                act = coldboot("/sys/devices", fn);
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        act = coldboot(path, fn);
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1031fc01794f33057862a361a0d0113630c58befc21bKenny Root    // If we have a callback, then do as it says. If no, then the default is
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // to always create COLDBOOT_DONE file.
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!fn || (act == COLDBOOT_FINISH)) {
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LOG(INFO) << "Coldboot took " << t;
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1040fc01794f33057862a361a0d0113630c58befc21bKenny Rootvoid device_close() {
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    destroy_platform_devices();
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    device_fd.reset();
1043fc01794f33057862a361a0d0113630c58befc21bKenny Root}
1044fc01794f33057862a361a0d0113630c58befc21bKenny Root
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint get_device_fd() {
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return device_fd;
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project