devices.c revision 27b8b3a1aab015ed8673ffd03bbf57f63adb85f0
1e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy/*
2e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * Copyright (C) 2007 The Android Open Source Project
3e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *
4e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * you may not use this file except in compliance with the License.
6e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * You may obtain a copy of the License at
7e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *
8e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *      http://www.apache.org/licenses/LICENSE-2.0
9e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *
10e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * Unless required by applicable law or agreed to in writing, software
11e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * See the License for the specific language governing permissions and
14e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * limitations under the License.
15e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy */
16e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1785bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy#include <errno.h>
18e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include <stdio.h>
19e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include <stdlib.h>
20e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include <sys/stat.h>
21e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include <sys/types.h>
22e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
23bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy#include <fcntl.h>
2403d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy#include <dirent.h>
25694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy#include <unistd.h>
265cbbce535744b89df5ecea95de21ee3733298260Romain Guy#include <string.h>
275cbbce535744b89df5ecea95de21ee3733298260Romain Guy
28e2d345ea67e2960b37bfdc0fc8626d1bfa747404Romain Guy#include <sys/socket.h>
2985bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy#include <sys/un.h>
3008aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy#include <linux/netlink.h>
3108aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy#include <private/android_filesystem_config.h>
325b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy#include <sys/time.h>
335b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy#include <asm/page.h>
3485bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy
350fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy#include "init.h"
36710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#include "devices.h"
37a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy
38e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#define CMDLINE_PREFIX  "/dev"
39e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#define SYSFS_PREFIX    "/sys"
409d5316e3f56d138504565ff311145ac01621dff4Romain Guy#define FIRMWARE_DIR    "/etc/firmware"
419d5316e3f56d138504565ff311145ac01621dff4Romain Guy#define MAX_QEMU_PERM 6
429d5316e3f56d138504565ff311145ac01621dff4Romain Guy
439d5316e3f56d138504565ff311145ac01621dff4Romain Guystruct uevent {
449d5316e3f56d138504565ff311145ac01621dff4Romain Guy    const char *action;
459d5316e3f56d138504565ff311145ac01621dff4Romain Guy    const char *path;
46759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy    const char *subsystem;
47759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy    const char *firmware;
48759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy    int major;
49f877308f77f7c6f3edd91618a092207dd3be9077Romain Guy    int minor;
50dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy};
51d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guy
52d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guystatic int open_uevent_socket(void)
539d5316e3f56d138504565ff311145ac01621dff4Romain Guy{
549d5316e3f56d138504565ff311145ac01621dff4Romain Guy    struct sockaddr_nl addr;
559d5316e3f56d138504565ff311145ac01621dff4Romain Guy    int sz = 64*1024; // XXX larger? udev uses 16MB!
569d5316e3f56d138504565ff311145ac01621dff4Romain Guy    int s;
57889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy
58889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    memset(&addr, 0, sizeof(addr));
59889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    addr.nl_family = AF_NETLINK;
60889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    addr.nl_pid = getpid();
61889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    addr.nl_groups = 0xffffffff;
62889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy
63889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
64889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    if(s < 0)
65889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy        return -1;
66026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy
67026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy    setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
68026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy
692ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
702ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy        close(s);
712ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy        return -1;
722ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    }
732ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy
742ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    return s;
752ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy}
762ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy
772ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guystruct perms_ {
782ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    char *name;
792ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    mode_t perm;
802ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    unsigned int uid;
812ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    unsigned int gid;
822ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    unsigned short prefix;
832ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy};
84026c5e16704e817cac7d9c382914c947e34f87e0Romain Guystatic struct perms_ devperms[] = {
85e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    { "/dev/null",          0666,   AID_ROOT,       AID_ROOT,       0 },
8687a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy    { "/dev/zero",          0666,   AID_ROOT,       AID_ROOT,       0 },
8787a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy    { "/dev/full",          0666,   AID_ROOT,       AID_ROOT,       0 },
8887a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy    { "/dev/ptmx",          0666,   AID_ROOT,       AID_ROOT,       0 },
89f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    { "/dev/tty",           0666,   AID_ROOT,       AID_ROOT,       0 },
902ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    { "/dev/random",        0666,   AID_ROOT,       AID_ROOT,       0 },
912ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    { "/dev/urandom",       0666,   AID_ROOT,       AID_ROOT,       0 },
922ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    { "/dev/ashmem",        0666,   AID_ROOT,       AID_ROOT,       0 },
932ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    { "/dev/binder",        0666,   AID_ROOT,       AID_ROOT,       0 },
942ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy
952ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy	    /* logger should be world writable (for logging) but not readable */
962ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    { "/dev/log/",          0662,   AID_ROOT,       AID_LOG,        1 },
972ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy
982ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    /* the msm hw3d client device node is world writable/readable. */
992ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    { "/dev/msm_hw3dc",     0666,   AID_ROOT,       AID_ROOT,       0 },
1002ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy
1012ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    /* gpu driver for adreno200 is globally accessible */
1022ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    { "/dev/kgsl",          0666,   AID_ROOT,       AID_ROOT,       0 },
1032ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy
1042ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy    /* STOPSHIP: temporarily make this be writable by all. We need to
105f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy     * remove this entirely before we ship. */
106f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    { "/dev/pmem_gpu",      0666,   AID_ROOT,       AID_ROOT,       1 },
107f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
108f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        /* these should not be world writable */
109f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    { "/dev/diag",          0660,   AID_RADIO,      AID_RADIO,        0 },
110f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    { "/dev/diag_arm9",     0660,   AID_RADIO,      AID_RADIO,        0 },
111fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    { "/dev/android_adb",   0660,   AID_ADB,        AID_ADB,        0 },
11206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    { "/dev/android_adb_enable",   0660,   AID_ADB,        AID_ADB,        0 },
113db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    { "/dev/ttyMSM0",       0600,   AID_BLUETOOTH,  AID_BLUETOOTH,  0 },
1141e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    { "/dev/ttyHS0",        0600,   AID_BLUETOOTH,  AID_BLUETOOTH,  0 },
1155ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy    { "/dev/uinput",        0660,   AID_SYSTEM,     AID_BLUETOOTH,  0 },
116026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy    { "/dev/alarm",         0664,   AID_SYSTEM,     AID_RADIO,      0 },
117ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy    { "/dev/tty0",          0660,   AID_ROOT,       AID_SYSTEM,     0 },
118ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy    { "/dev/graphics/",     0660,   AID_ROOT,       AID_GRAPHICS,   1 },
119ae5575b3421c8fbe590ab046d7d5f2b36ecfd821Romain Guy    { "/dev/msm_hw3dm",     0660,   AID_SYSTEM,     AID_GRAPHICS,   0 },
120e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    { "/dev/input/",        0660,   AID_ROOT,       AID_INPUT,      1 },
121e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    { "/dev/eac",           0660,   AID_ROOT,       AID_AUDIO,      0 },
12285bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy    { "/dev/cam",           0660,   AID_ROOT,       AID_CAMERA,     0 },
12329d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy    { "/dev/pmem",          0660,   AID_SYSTEM,     AID_GRAPHICS,   0 },
12429d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy    { "/dev/pmem_adsp",     0660,   AID_SYSTEM,     AID_AUDIO,      1 },
125e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    { "/dev/pmem_camera",   0660,   AID_SYSTEM,     AID_CAMERA,     1 },
126e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    { "/dev/oncrpc/",       0660,   AID_ROOT,       AID_SYSTEM,     1 },
127f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    { "/dev/adsp/",         0660,   AID_SYSTEM,     AID_AUDIO,      1 },
12813631f3da855f200a151e7837ed9f6b079622b58Romain Guy    { "/dev/mt9t013",       0660,   AID_SYSTEM,     AID_SYSTEM,     0 },
12913631f3da855f200a151e7837ed9f6b079622b58Romain Guy    { "/dev/msm_camera/",   0660,   AID_SYSTEM,     AID_SYSTEM,     1 },
13013631f3da855f200a151e7837ed9f6b079622b58Romain Guy    { "/dev/akm8976_daemon",0640,   AID_COMPASS,    AID_SYSTEM,     0 },
13113631f3da855f200a151e7837ed9f6b079622b58Romain Guy    { "/dev/akm8976_aot",   0640,   AID_COMPASS,    AID_SYSTEM,     0 },
13213631f3da855f200a151e7837ed9f6b079622b58Romain Guy    { "/dev/akm8973_daemon",0640,   AID_COMPASS,    AID_SYSTEM,     0 },
13313631f3da855f200a151e7837ed9f6b079622b58Romain Guy    { "/dev/akm8973_aot",   0640,   AID_COMPASS,    AID_SYSTEM,     0 },
13413631f3da855f200a151e7837ed9f6b079622b58Romain Guy    { "/dev/bma150",        0640,   AID_COMPASS,    AID_SYSTEM,     0 },
13513631f3da855f200a151e7837ed9f6b079622b58Romain Guy    { "/dev/cm3602",        0640,   AID_COMPASS,    AID_SYSTEM,     0 },
13613631f3da855f200a151e7837ed9f6b079622b58Romain Guy    { "/dev/akm8976_pffd",  0640,   AID_COMPASS,    AID_SYSTEM,     0 },
13713631f3da855f200a151e7837ed9f6b079622b58Romain Guy    { "/dev/lightsensor",   0640,   AID_SYSTEM,     AID_SYSTEM,     0 },
13813631f3da855f200a151e7837ed9f6b079622b58Romain Guy    { "/dev/msm_pcm_out",   0660,   AID_SYSTEM,     AID_AUDIO,      1 },
13913631f3da855f200a151e7837ed9f6b079622b58Romain Guy    { "/dev/msm_pcm_in",    0660,   AID_SYSTEM,     AID_AUDIO,      1 },
140f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    { "/dev/msm_pcm_ctl",   0660,   AID_SYSTEM,     AID_AUDIO,      1 },
141f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    { "/dev/msm_snd",       0660,   AID_SYSTEM,     AID_AUDIO,      1 },
142f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    { "/dev/msm_mp3",       0660,   AID_SYSTEM,     AID_AUDIO,      1 },
14349c5fc0b9e850497233e189ff9dcc71a78ebe6e7Romain Guy    { "/dev/audience_a1026", 0660,   AID_SYSTEM,     AID_AUDIO,      1 },
14449c5fc0b9e850497233e189ff9dcc71a78ebe6e7Romain Guy    { "/dev/msm_audpre",    0660,   AID_SYSTEM,     AID_AUDIO,      0 },
14549c5fc0b9e850497233e189ff9dcc71a78ebe6e7Romain Guy    { "/dev/msm_audio_ctl", 0660,   AID_SYSTEM,     AID_AUDIO,      0 },
14649c5fc0b9e850497233e189ff9dcc71a78ebe6e7Romain Guy    { "/dev/htc-acoustic",  0660,   AID_SYSTEM,     AID_AUDIO,      0 },
14785bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy    { "/dev/vdec",          0660,   AID_SYSTEM,     AID_AUDIO,      0 },
14835643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    { "/dev/snd/dsp",       0660,   AID_SYSTEM,     AID_AUDIO,      0 },
14935643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    { "/dev/snd/dsp1",      0660,   AID_SYSTEM,     AID_AUDIO,      0 },
15035643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    { "/dev/snd/mixer",     0660,   AID_SYSTEM,     AID_AUDIO,      0 },
15135643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    { "/dev/smd0",          0640,   AID_RADIO,      AID_RADIO,      0 },
15235643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    { "/dev/qemu_trace",    0666,   AID_SYSTEM,     AID_SYSTEM,     0 },
15335643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    { "/dev/qmi",           0640,   AID_RADIO,      AID_RADIO,      0 },
15435643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    { "/dev/qmi0",          0640,   AID_RADIO,      AID_RADIO,      0 },
15535643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    { "/dev/qmi1",          0640,   AID_RADIO,      AID_RADIO,      0 },
15635643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    { "/dev/qmi2",          0640,   AID_RADIO,      AID_RADIO,      0 },
157260e102162322958cf17dbd895cd6bd30dc87e32Romain Guy        /* CDMA radio interface MUX */
158bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    { "/dev/ts0710mux",     0640,   AID_RADIO,      AID_RADIO,      1 },
159bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    { "/dev/ppp",           0660,   AID_RADIO,      AID_VPN,        0 },
160bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    { "/dev/tun",           0640,   AID_VPN,        AID_VPN,        0 },
161eb99356a0548684a501766e6a524529ab93304c8Romain Guy    { NULL, 0, 0, 0, 0 },
162eb99356a0548684a501766e6a524529ab93304c8Romain Guy};
163eb99356a0548684a501766e6a524529ab93304c8Romain Guy
164e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy/* devperms_partners list and perm_node are for hardware specific /dev entries */
165e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guystruct perm_node {
16644b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase    struct perms_ dp;
16744b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase    struct listnode plist;
1687d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy};
1697d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guylist_declare(devperms_partners);
17044b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase
171fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy/*
172fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy * Permission override when in emulator mode, must be parsed before
1738aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy * system properties is initalized.
1748aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy */
17584962f2fe6ce779c583cc54b11a9de2b6a568117Romain Guystatic int qemu_perm_count;
1768fb954263dd2f918ad339045cc6d82e346515599Romain Guystatic struct perms_ qemu_perms[MAX_QEMU_PERM + 1];
177f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
1787d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guyint add_devperms_partners(const char *name, mode_t perm, unsigned int uid,
1792b7028eabac80cec170572bc0e945a1d4224e595Romain Guy                        unsigned int gid, unsigned short prefix) {
180ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy    int size;
18145e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy    struct perm_node *node = malloc(sizeof (struct perm_node));
18245e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy    if (!node)
18345e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy        return -ENOMEM;
18445e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy
18545e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy    size = strlen(name) + 1;
18645e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy    if ((node->dp.name = malloc(size)) == NULL)
18745e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy        return -ENOMEM;
18845e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy
18945e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy    memcpy(node->dp.name, name, size);
190ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy    node->dp.perm = perm;
1917d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    node->dp.uid = uid;
1922b7028eabac80cec170572bc0e945a1d4224e595Romain Guy    node->dp.gid = gid;
1932b7028eabac80cec170572bc0e945a1d4224e595Romain Guy    node->dp.prefix = prefix;
1942b7028eabac80cec170572bc0e945a1d4224e595Romain Guy
1956b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy    list_add_tail(&devperms_partners, &node->plist);
196586cae3ac69c0c667fbf8a954edbd399f620a717Romain Guy    return 0;
197ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy}
1986b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy
19944b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haasevoid qemu_init(void) {
200ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy    qemu_perm_count = 0;
201ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy    memset(&qemu_perms, 0, sizeof(qemu_perms));
202ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy}
20344b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase
20444b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haasestatic int qemu_perm(const char* name, mode_t perm, unsigned int uid,
205ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy                         unsigned int gid, unsigned short prefix)
206ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy{
207ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy    char *buf;
208ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy    if (qemu_perm_count == MAX_QEMU_PERM)
209ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy        return -ENOSPC;
210ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy
211ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy    buf = malloc(strlen(name) + 1);
212ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy    if (!buf)
213ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy        return -errno;
2146b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy
215bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    strlcpy(buf, name, strlen(name) + 1);
216bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    qemu_perms[qemu_perm_count].name = buf;
2172b7028eabac80cec170572bc0e945a1d4224e595Romain Guy    qemu_perms[qemu_perm_count].perm = perm;
2182b7028eabac80cec170572bc0e945a1d4224e595Romain Guy    qemu_perms[qemu_perm_count].uid = uid;
2192b7028eabac80cec170572bc0e945a1d4224e595Romain Guy    qemu_perms[qemu_perm_count].gid = gid;
2202b7028eabac80cec170572bc0e945a1d4224e595Romain Guy    qemu_perms[qemu_perm_count].prefix = prefix;
2212b7028eabac80cec170572bc0e945a1d4224e595Romain Guy
2222b7028eabac80cec170572bc0e945a1d4224e595Romain Guy    qemu_perm_count++;
2232b7028eabac80cec170572bc0e945a1d4224e595Romain Guy    return 0;
2242b7028eabac80cec170572bc0e945a1d4224e595Romain Guy}
2252b7028eabac80cec170572bc0e945a1d4224e595Romain Guy
2262b7028eabac80cec170572bc0e945a1d4224e595Romain Guy/* Permission overrides for emulator that are parsed from /proc/cmdline. */
2272b7028eabac80cec170572bc0e945a1d4224e595Romain Guyvoid qemu_cmdline(const char* name, const char *value)
2282b7028eabac80cec170572bc0e945a1d4224e595Romain Guy{
2292b7028eabac80cec170572bc0e945a1d4224e595Romain Guy    char *buf;
2302b7028eabac80cec170572bc0e945a1d4224e595Romain Guy    if (!strcmp(name, "android.ril")) {
2312b7028eabac80cec170572bc0e945a1d4224e595Romain Guy        /* cmd line params currently assume /dev/ prefix */
2322b7028eabac80cec170572bc0e945a1d4224e595Romain Guy        if (asprintf(&buf, CMDLINE_PREFIX"/%s", value) == -1) {
2332b7028eabac80cec170572bc0e945a1d4224e595Romain Guy            return;
2342b7028eabac80cec170572bc0e945a1d4224e595Romain Guy        }
2352b7028eabac80cec170572bc0e945a1d4224e595Romain Guy        INFO("nani- buf:: %s\n", buf);
2362b7028eabac80cec170572bc0e945a1d4224e595Romain Guy        qemu_perm(buf, 0660, AID_RADIO, AID_ROOT, 0);
2372b7028eabac80cec170572bc0e945a1d4224e595Romain Guy    }
238b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy}
2392b7028eabac80cec170572bc0e945a1d4224e595Romain Guy
2402b7028eabac80cec170572bc0e945a1d4224e595Romain Guystatic int get_device_perm_inner(struct perms_ *perms, const char *path,
241b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy                                    unsigned *uid, unsigned *gid, mode_t *perm)
242b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy{
243b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy    int i;
2445baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    for(i = 0; perms[i].name; i++) {
245a07105b7d2a27e6d69407bf96ddb773bddb5e553Romain Guy
246a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy        if(perms[i].prefix) {
247a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy            if(strncmp(path, perms[i].name, strlen(perms[i].name)))
248a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy                continue;
249a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy        } else {
250a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy            if(strcmp(path, perms[i].name))
251a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy                continue;
252a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy        }
253a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy        *uid = perms[i].uid;
254a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy        *gid = perms[i].gid;
255a07105b7d2a27e6d69407bf96ddb773bddb5e553Romain Guy        *perm = perms[i].perm;
256a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy        return 0;
257a07105b7d2a27e6d69407bf96ddb773bddb5e553Romain Guy    }
258a07105b7d2a27e6d69407bf96ddb773bddb5e553Romain Guy    return -1;
259b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy}
260b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy
261c15008e72ec00ca20a271c3006dac649fd07533bRomain Guy/* First checks for emulator specific permissions specified in /proc/cmdline. */
262c15008e72ec00ca20a271c3006dac649fd07533bRomain Guystatic mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid)
263e190aa69756aecfaffabdd4c6d32cb6b3220d842Romain Guy{
264e190aa69756aecfaffabdd4c6d32cb6b3220d842Romain Guy    mode_t perm;
265e190aa69756aecfaffabdd4c6d32cb6b3220d842Romain Guy
266e190aa69756aecfaffabdd4c6d32cb6b3220d842Romain Guy    if (get_device_perm_inner(qemu_perms, path, uid, gid, &perm) == 0) {
267c15008e72ec00ca20a271c3006dac649fd07533bRomain Guy        return perm;
268b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy    } else if (get_device_perm_inner(devperms, path, uid, gid, &perm) == 0) {
269b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        return perm;
2706c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    } else {
271da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        struct listnode *node;
272da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        struct perm_node *perm_node;
273da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        struct perms_ *dp;
274da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy
275da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        /* Check partners list. */
276da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        list_for_each(node, &devperms_partners) {
27750c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy            perm_node = node_to_item(node, struct perm_node, plist);
27815bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy            dp = &perm_node->dp;
279f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy
28015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy            if (dp->prefix) {
281da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy                if (strncmp(path, dp->name, strlen(dp->name)))
282da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy                    continue;
2836c319ca1275c8db892c39b48fc54864c949f9171Romain Guy            } else {
28408837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase                if (strcmp(path, dp->name))
28508837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase                    continue;
28635643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy            }
28735643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy            /* Found perm in partner list. */
2883e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy            *uid = dp->uid;
2893e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy            *gid = dp->gid;
2908025061c594e5171e1bf370d8fdd77e0e9a02b47Chet Haase            return dp->perm;
291586cae3ac69c0c667fbf8a954edbd399f620a717Romain Guy        }
29282bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy        /* Default if nothing found. */
293746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy        *uid = 0;
294da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        *gid = 0;
295a1d3c91afbd52c7e8b01f4a9060c5459f02ae7a5Romain Guy        return 0600;
29650c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy    }
29750c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy}
29850c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy
29950c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guystatic void make_device(const char *path, int block, int major, int minor)
30050c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy{
301da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    unsigned uid;
302da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    unsigned gid;
30335643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    mode_t mode;
30435643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    dev_t dev;
30535643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy
30635643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    if(major > 255 || minor > 255)
30735643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy        return;
30835643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy
30935643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
31035643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    dev = (major << 8) | minor;
31135643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    mknod(path, mode, dev);
312ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    chown(path, uid, gid);
313932b7f6765968bd526c03512f3805fbc3924dc29Chris Craik}
314ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
3158f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy#if LOG_UEVENTS
316ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
317ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guystatic inline suseconds_t get_usecs(void)
318ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy{
3198f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy    struct timeval tv;
320ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    gettimeofday(&tv, 0);
321ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    return tv.tv_sec * (suseconds_t) 1000000 + tv.tv_usec;
3223d745c03ace18ee59c539e1b7f1df13f22beb57dRomain Guy}
3238f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy
324ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy#define log_event_print(x...) INFO(x)
325ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
326ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy#else
327ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
328ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy#define log_event_print(fmt, args...)   do { } while (0)
329ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy#define get_usecs()                     0
330ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
331ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy#endif
332ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
333ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guystatic void parse_event(const char *msg, struct uevent *uevent)
334ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy{
335ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    uevent->action = "";
336ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    uevent->path = "";
337ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    uevent->subsystem = "";
338ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    uevent->firmware = "";
339ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    uevent->major = -1;
340ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    uevent->minor = -1;
341ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
342c2c9543c135ffc4e18c7db0e817112ac03e3e97aChris Craik        /* currently ignoring SEQNUM */
343ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    while(*msg) {
344ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy        if(!strncmp(msg, "ACTION=", 7)) {
345c2c9543c135ffc4e18c7db0e817112ac03e3e97aChris Craik            msg += 7;
346ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy            uevent->action = msg;
347c2c9543c135ffc4e18c7db0e817112ac03e3e97aChris Craik        } else if(!strncmp(msg, "DEVPATH=", 8)) {
348c2c9543c135ffc4e18c7db0e817112ac03e3e97aChris Craik            msg += 8;
3498f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy            uevent->path = msg;
3508f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy        } else if(!strncmp(msg, "SUBSYSTEM=", 10)) {
351beb8bd0db28d8c5cad2a258f2ba2f3b8b76cf037Chet Haase            msg += 10;
352beb8bd0db28d8c5cad2a258f2ba2f3b8b76cf037Chet Haase            uevent->subsystem = msg;
353beb8bd0db28d8c5cad2a258f2ba2f3b8b76cf037Chet Haase        } else if(!strncmp(msg, "FIRMWARE=", 9)) {
354beb8bd0db28d8c5cad2a258f2ba2f3b8b76cf037Chet Haase            msg += 9;
3558f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy            uevent->firmware = msg;
3568f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy        } else if(!strncmp(msg, "MAJOR=", 6)) {
3578f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy            msg += 6;
3588f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy            uevent->major = atoi(msg);
3598f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy        } else if(!strncmp(msg, "MINOR=", 6)) {
3608f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy            msg += 6;
361daf98e941e140e8739458126640183b9f296a2abChet Haase            uevent->minor = atoi(msg);
362932b7f6765968bd526c03512f3805fbc3924dc29Chris Craik        }
363c8538ade8df2c2f013f8b93094912057ee1cc417Chris Craik
3648a4ac610e1aaf04931ac1af54b146a7fc8e66114Romain Guy            /* advance to after the next \0 */
365f90f8171e6acb56f9f87093c01fd586f2140697aRomain Guy        while(*msg++)
366f90f8171e6acb56f9f87093c01fd586f2140697aRomain Guy            ;
367f90f8171e6acb56f9f87093c01fd586f2140697aRomain Guy    }
368d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy
36980911b851764b073310fd0bffdf4a7db0d8fdd0bRomain Guy    log_event_print("event { '%s', '%s', '%s', '%s', %d, %d }\n",
37080911b851764b073310fd0bffdf4a7db0d8fdd0bRomain Guy                    uevent->action, uevent->path, uevent->subsystem,
37180911b851764b073310fd0bffdf4a7db0d8fdd0bRomain Guy                    uevent->firmware, uevent->major, uevent->minor);
372d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy}
373d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy
374d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guystatic void handle_device_event(struct uevent *uevent)
375d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy{
376d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy    char devpath[96];
377d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy    char *base, *name;
37808aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy    int block;
37908aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy
38008aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy        /* if it's not a /dev device, nothing to do */
38108aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy    if((uevent->major < 0) || (uevent->minor < 0))
38208aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy        return;
38308aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy
3847b6a75872bd2df96a23453d31c2e2e7fcc373554Chet Haase        /* do we have a name? */
3857b6a75872bd2df96a23453d31c2e2e7fcc373554Chet Haase    name = strrchr(uevent->path, '/');
38608aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy    if(!name)
38780911b851764b073310fd0bffdf4a7db0d8fdd0bRomain Guy        return;
388486590963e2207d68eebd6944fec70d50d41116aChet Haase    name++;
389cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy
3908f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy        /* too-long names would overrun our buffer */
39108aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy    if(strlen(name) > 64)
392cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy        return;
3938f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy
39465924a3e56c2e7ac863f8e25e9f9a58b9db7d513Chris Craik        /* are we block or char? where should we live? */
395ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    if(!strncmp(uevent->subsystem, "block", 5)) {
3968f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy        block = 1;
397cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy        base = "/dev/block/";
398cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy        mkdir(base, 0755);
399daf98e941e140e8739458126640183b9f296a2abChet Haase    } else {
4006554943a1dd6854c0f4976900956e556767b49e1Romain Guy        block = 0;
401daf98e941e140e8739458126640183b9f296a2abChet Haase            /* this should probably be configurable somehow */
402daf98e941e140e8739458126640183b9f296a2abChet Haase        if(!strncmp(uevent->subsystem, "graphics", 8)) {
403f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy            base = "/dev/graphics/";
404f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy            mkdir(base, 0755);
405f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) {
406f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy            base = "/dev/oncrpc/";
407bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy            mkdir(base, 0755);
4087ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy        } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
409bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy            base = "/dev/adsp/";
410bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy            mkdir(base, 0755);
411bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) {
4128aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy            base = "/dev/msm_camera/";
413bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy            mkdir(base, 0755);
414bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        } else if(!strncmp(uevent->subsystem, "input", 5)) {
415bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy            base = "/dev/input/";
4162542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy            mkdir(base, 0755);
4172542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy        } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
4187ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy            base = "/dev/mtd/";
419bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy            mkdir(base, 0755);
420bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        } else if(!strncmp(uevent->subsystem, "sound", 5)) {
421bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy            base = "/dev/snd/";
4228fb954263dd2f918ad339045cc6d82e346515599Romain Guy            mkdir(base, 0755);
423bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        } else if(!strncmp(uevent->subsystem, "misc", 4) &&
4248fb954263dd2f918ad339045cc6d82e346515599Romain Guy                    !strncmp(name, "log_", 4)) {
4252542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy            base = "/dev/log/";
4267ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy            mkdir(base, 0755);
427bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy            name += 4;
428bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        } else
4298aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy            base = "/dev/";
4308aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    }
4318fb954263dd2f918ad339045cc6d82e346515599Romain Guy
432bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    snprintf(devpath, sizeof(devpath), "%s%s", base, name);
433bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
434bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    if(!strcmp(uevent->action, "add")) {
4357ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy        make_device(devpath, block, uevent->major, uevent->minor);
436bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        return;
437eb99356a0548684a501766e6a524529ab93304c8Romain Guy    }
438bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
439bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    if(!strcmp(uevent->action, "remove")) {
4407ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy        unlink(devpath);
441bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        return;
442eb99356a0548684a501766e6a524529ab93304c8Romain Guy    }
443eb99356a0548684a501766e6a524529ab93304c8Romain Guy}
444eb99356a0548684a501766e6a524529ab93304c8Romain Guy
445eb99356a0548684a501766e6a524529ab93304c8Romain Guystatic int load_firmware(int fw_fd, int loading_fd, int data_fd)
446eb99356a0548684a501766e6a524529ab93304c8Romain Guy{
447eb99356a0548684a501766e6a524529ab93304c8Romain Guy    struct stat st;
4488b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    long len_to_copy;
4498b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    int ret = 0;
4508b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy
4512542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy    if(fstat(fw_fd, &st) < 0)
452746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy        return -1;
4538fb954263dd2f918ad339045cc6d82e346515599Romain Guy    len_to_copy = st.st_size;
4542542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy
4555ec9924d24495822b589f1a17996655d66273b30Romain Guy    write(loading_fd, "1", 1);  /* start transfer */
4565ec9924d24495822b589f1a17996655d66273b30Romain Guy
4575ec9924d24495822b589f1a17996655d66273b30Romain Guy    while (len_to_copy > 0) {
4585ec9924d24495822b589f1a17996655d66273b30Romain Guy        char buf[PAGE_SIZE];
4592542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy        ssize_t nr;
460d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy
4615cbbce535744b89df5ecea95de21ee3733298260Romain Guy        nr = read(fw_fd, buf, sizeof(buf));
462f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        if(!nr)
463bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy            break;
464bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        if(nr < 0) {
465bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy            ret = -1;
466bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy            break;
4675c13d89c1332fcc499379b9064b891187b75ca32Chet Haase        }
468eb99356a0548684a501766e6a524529ab93304c8Romain Guy
469eb99356a0548684a501766e6a524529ab93304c8Romain Guy        len_to_copy -= nr;
470d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy        while (nr > 0) {
471af636ebf5feb2837683fbfe965040cb706b32ec1Romain Guy            ssize_t nw = 0;
472e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy
473e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy            nw = write(data_fd, buf + nw, nr);
474e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy            if(nw <= 0) {
475e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy                ret = -1;
476e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy                goto out;
477710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik            }
478a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            nr -= nw;
479e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy        }
480d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy    }
481d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy
482d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haaseout:
483dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    if(!ret)
484d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy        write(loading_fd, "0", 1);  /* successful end of transfer */
485d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy    else
486bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        write(loading_fd, "-1", 2); /* abort transfer */
487bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
488bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    return ret;
489bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy}
490f877308f77f7c6f3edd91618a092207dd3be9077Romain Guy
4918aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guystatic void process_firmware_event(struct uevent *uevent)
4928b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy{
4938aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    char *root, *loading, *data, *file;
4948aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    int l, loading_fd, data_fd, fw_fd;
4958aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy
4968b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    log_event_print("firmware event { '%s', '%s' }\n",
497d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy                    uevent->path, uevent->firmware);
498bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
4991c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);
5001c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    if (l == -1)
5011c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        return;
5021c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy
5031c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    l = asprintf(&loading, "%sloading", root);
5041c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    if (l == -1)
5051c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        goto root_free_out;
5061c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy
5071c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    l = asprintf(&data, "%sdata", root);
5081c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    if (l == -1)
5091c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        goto loading_free_out;
5101c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy
5111c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    l = asprintf(&file, FIRMWARE_DIR"/%s", uevent->firmware);
5121c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    if (l == -1)
5131c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        goto data_free_out;
5141c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy
5151c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    loading_fd = open(loading, O_WRONLY);
5166b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy    if(loading_fd < 0)
5176b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy        goto file_free_out;
5186b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy
5196b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy    data_fd = open(data, O_WRONLY);
5201c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    if(data_fd < 0)
5211c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        goto loading_close_out;
5221c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy
5231c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    fw_fd = open(file, O_RDONLY);
52487a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy    if(fw_fd < 0)
5251c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        goto data_close_out;
5261c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy
5271c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    if(!load_firmware(fw_fd, loading_fd, data_fd))
5281c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        log_event_print("firmware copy success { '%s', '%s' }\n", root, file);
5291c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    else
5301c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        log_event_print("firmware copy failure { '%s', '%s' }\n", root, file);
5311c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy
5321c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    close(fw_fd);
5331c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guydata_close_out:
5341c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    close(data_fd);
5351c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guyloading_close_out:
5361c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    close(loading_fd);
5371c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guyfile_free_out:
5381c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    free(file);
5391c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guydata_free_out:
5401c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    free(data);
5411c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guyloading_free_out:
5421c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    free(loading);
5431c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guyroot_free_out:
54487a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy    free(root);
54587a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy}
54687a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy
54787a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guystatic void handle_firmware_event(struct uevent *uevent)
54887a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy{
5491c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    pid_t pid;
550d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase
551d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    if(strcmp(uevent->subsystem, "firmware"))
552eb99356a0548684a501766e6a524529ab93304c8Romain Guy        return;
553fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
554dda570201ac851dd85af3861f7e575721d3345daRomain Guy    if(strcmp(uevent->action, "add"))
555eb99356a0548684a501766e6a524529ab93304c8Romain Guy        return;
556eb99356a0548684a501766e6a524529ab93304c8Romain Guy
557f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    /* we fork, to avoid making large memory allocations in init proper */
558d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    pid = fork();
5598aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    if (!pid) {
560d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase        process_firmware_event(uevent);
561d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase        exit(EXIT_SUCCESS);
562d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    }
563d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase}
564d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase
565d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase#define UEVENT_MSG_LEN  1024
566d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haasevoid handle_device_fd(int fd)
567d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase{
568d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    char msg[UEVENT_MSG_LEN+2];
569d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    int n;
570d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase
571d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    while((n = recv(fd, msg, UEVENT_MSG_LEN, 0)) > 0) {
572ad37cd3b5d3de9dd0858af04fbccd102e8ff4b0eRomain Guy        struct uevent uevent;
573d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase
574d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase        if(n == UEVENT_MSG_LEN)   /* overflow -- discard */
575d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase            continue;
576d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase
577d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase        msg[n] = '\0';
578d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase        msg[n+1] = '\0';
579d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase
580d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase        parse_event(msg, &uevent);
581d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase
582d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase        handle_device_event(&uevent);
583d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase        handle_firmware_event(&uevent);
584d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    }
585ad37cd3b5d3de9dd0858af04fbccd102e8ff4b0eRomain Guy}
586d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase
587d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase/* Coldboot walks parts of the /sys tree and pokes the uevent files
588eb99356a0548684a501766e6a524529ab93304c8Romain Guy** to cause the kernel to regenerate device add events that happened
589bf434114cbf55b216fdc76fc8d65a75e84c9dab5Romain Guy** before init's device manager was started
590746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy**
591d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase** We drain any pending events from the netlink socket every time
592d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase** we poke another uevent file to make sure we don't overrun the
593d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase** socket's buffer.
594dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy*/
595d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase
596dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guystatic void do_coldboot(int event_fd, DIR *d)
597dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy{
598dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    struct dirent *de;
599d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    int dfd, fd;
600b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy
601b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy    dfd = dirfd(d);
602dda570201ac851dd85af3861f7e575721d3345daRomain Guy
603a1d3c91afbd52c7e8b01f4a9060c5459f02ae7a5Romain Guy    fd = openat(dfd, "uevent", O_WRONLY);
6048550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    if(fd >= 0) {
605f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        write(fd, "add\n", 4);
606f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        close(fd);
607bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        handle_device_fd(event_fd);
608bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    }
6099ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy
6108aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    while((de = readdir(d))) {
6119ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        DIR *d2;
6129ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy
6139ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        if(de->d_type != DT_DIR || de->d_name[0] == '.')
614a23eed808a1ae4ec0d818c0a9238385e797fd056Chet Haase            continue;
615dda570201ac851dd85af3861f7e575721d3345daRomain Guy
6168fb954263dd2f918ad339045cc6d82e346515599Romain Guy        fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
617d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase        if(fd < 0)
618d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase            continue;
6191d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy
620eb99356a0548684a501766e6a524529ab93304c8Romain Guy        d2 = fdopendir(fd);
621d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase        if(d2 == 0)
622eb99356a0548684a501766e6a524529ab93304c8Romain Guy            close(fd);
623eb99356a0548684a501766e6a524529ab93304c8Romain Guy        else {
6249ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            do_coldboot(event_fd, d2);
625514fb18827186591d66973c2362c859b64b63556Romain Guy            closedir(d2);
6269ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        }
6279ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    }
628d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase}
6299ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy
6309ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guystatic void coldboot(int event_fd, const char *path)
631514fb18827186591d66973c2362c859b64b63556Romain Guy{
632514fb18827186591d66973c2362c859b64b63556Romain Guy    DIR *d = opendir(path);
633d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    if(d) {
634514fb18827186591d66973c2362c859b64b63556Romain Guy        do_coldboot(event_fd, d);
6357b5b6abf852c039983eded25ebe43a70fef5a4abRomain Guy        closedir(d);
63654be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy    }
63754be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy}
638ae88e5e8e9cb6c9539314c4360c5b20f8ec1fefcRomain Guy
639eb99356a0548684a501766e6a524529ab93304c8Romain Guyint device_init(void)
640f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy{
641d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy    suseconds_t t0, t1;
642bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    int fd;
643bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
644d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    fd = open_uevent_socket();
6459ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    if(fd < 0)
6465b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        return -1;
647d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase
648d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    fcntl(fd, F_SETFD, FD_CLOEXEC);
649d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    fcntl(fd, F_SETFL, O_NONBLOCK);
650d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase
651d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    t0 = get_usecs();
652d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    coldboot(fd, "/sys/class");
653d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    coldboot(fd, "/sys/block");
654d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    coldboot(fd, "/sys/devices");
655d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    t1 = get_usecs();
656d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase
657d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    log_event_print("coldboot %ld uS\n", ((long) (t1 - t0)));
6585b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
6592b7028eabac80cec170572bc0e945a1d4224e595Romain Guy    return fd;
6605b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy}
6619ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy