init: Add ueventd.rc parsing to ueventd

Change-Id: Iea53050d6c10e8cabf563e5d80e84eaf78873695
diff --git a/init/Android.mk b/init/Android.mk
index 9259fb0..9d8ca9c 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -14,7 +14,8 @@
 	keychords.c \
 	signal_handler.c \
 	init_parser.c \
-	ueventd.c
+	ueventd.c \
+	ueventd_parser.c
 
 ifeq ($(strip $(INIT_BOOTCHART)),true)
 LOCAL_SRC_FILES += bootchart.c
diff --git a/init/devices.c b/init/devices.c
index 3e1c524..fa96f7c 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -37,10 +37,8 @@
 #include "log.h"
 #include "list.h"
 
-#define CMDLINE_PREFIX  "/dev"
 #define SYSFS_PREFIX    "/sys"
 #define FIRMWARE_DIR    "/etc/firmware"
-#define MAX_QEMU_PERM 6
 
 static int device_fd = -1;
 
@@ -87,102 +85,21 @@
     unsigned int gid;
     unsigned short prefix;
 };
-static struct perms_ devperms[] = {
-    { "/dev/null",          0666,   AID_ROOT,       AID_ROOT,       0 },
-    { "/dev/zero",          0666,   AID_ROOT,       AID_ROOT,       0 },
-    { "/dev/full",          0666,   AID_ROOT,       AID_ROOT,       0 },
-    { "/dev/ptmx",          0666,   AID_ROOT,       AID_ROOT,       0 },
-    { "/dev/tty",           0666,   AID_ROOT,       AID_ROOT,       0 },
-    { "/dev/random",        0666,   AID_ROOT,       AID_ROOT,       0 },
-    { "/dev/urandom",       0666,   AID_ROOT,       AID_ROOT,       0 },
-    { "/dev/ashmem",        0666,   AID_ROOT,       AID_ROOT,       0 },
-    { "/dev/binder",        0666,   AID_ROOT,       AID_ROOT,       0 },
 
-	    /* logger should be world writable (for logging) but not readable */
-    { "/dev/log/",          0662,   AID_ROOT,       AID_LOG,        1 },
-
-    /* the msm hw3d client device node is world writable/readable. */
-    { "/dev/msm_hw3dc",     0666,   AID_ROOT,       AID_ROOT,       0 },
-
-    /* gpu driver for adreno200 is globally accessible */
-    { "/dev/kgsl",          0666,   AID_ROOT,       AID_ROOT,       0 },
-
-        /* these should not be world writable */
-    { "/dev/diag",          0660,   AID_RADIO,      AID_RADIO,        0 },
-    { "/dev/diag_arm9",     0660,   AID_RADIO,      AID_RADIO,        0 },
-    { "/dev/android_adb",   0660,   AID_ADB,        AID_ADB,        0 },
-    { "/dev/android_adb_enable",   0660,   AID_ADB,        AID_ADB,        0 },
-    { "/dev/ttyMSM0",       0600,   AID_BLUETOOTH,  AID_BLUETOOTH,  0 },
-    { "/dev/ttyHS0",        0600,   AID_BLUETOOTH,  AID_BLUETOOTH,  0 },
-    { "/dev/uinput",        0660,   AID_SYSTEM,     AID_BLUETOOTH,  0 },
-    { "/dev/alarm",         0664,   AID_SYSTEM,     AID_RADIO,      0 },
-    { "/dev/tty0",          0660,   AID_ROOT,       AID_SYSTEM,     0 },
-    { "/dev/graphics/",     0660,   AID_ROOT,       AID_GRAPHICS,   1 },
-    { "/dev/msm_hw3dm",     0660,   AID_SYSTEM,     AID_GRAPHICS,   0 },
-    { "/dev/input/",        0660,   AID_ROOT,       AID_INPUT,      1 },
-    { "/dev/eac",           0660,   AID_ROOT,       AID_AUDIO,      0 },
-    { "/dev/cam",           0660,   AID_ROOT,       AID_CAMERA,     0 },
-    { "/dev/pmem",          0660,   AID_SYSTEM,     AID_GRAPHICS,   0 },
-    { "/dev/pmem_adsp",     0660,   AID_SYSTEM,     AID_AUDIO,      1 },
-    { "/dev/pmem_camera",   0660,   AID_SYSTEM,     AID_CAMERA,     1 },
-    { "/dev/oncrpc/",       0660,   AID_ROOT,       AID_SYSTEM,     1 },
-    { "/dev/adsp/",         0660,   AID_SYSTEM,     AID_AUDIO,      1 },
-    { "/dev/snd/",          0660,   AID_SYSTEM,     AID_AUDIO,      1 },
-    { "/dev/mt9t013",       0660,   AID_SYSTEM,     AID_SYSTEM,     0 },
-    { "/dev/msm_camera/",   0660,   AID_SYSTEM,     AID_SYSTEM,     1 },
-    { "/dev/akm8976_daemon",0640,   AID_COMPASS,    AID_SYSTEM,     0 },
-    { "/dev/akm8976_aot",   0640,   AID_COMPASS,    AID_SYSTEM,     0 },
-    { "/dev/akm8973_daemon",0640,   AID_COMPASS,    AID_SYSTEM,     0 },
-    { "/dev/akm8973_aot",   0640,   AID_COMPASS,    AID_SYSTEM,     0 },
-    { "/dev/bma150",        0640,   AID_COMPASS,    AID_SYSTEM,     0 },
-    { "/dev/cm3602",        0640,   AID_COMPASS,    AID_SYSTEM,     0 },
-    { "/dev/akm8976_pffd",  0640,   AID_COMPASS,    AID_SYSTEM,     0 },
-    { "/dev/lightsensor",   0640,   AID_SYSTEM,     AID_SYSTEM,     0 },
-    { "/dev/msm_pcm_out",   0660,   AID_SYSTEM,     AID_AUDIO,      1 },
-    { "/dev/msm_pcm_in",    0660,   AID_SYSTEM,     AID_AUDIO,      1 },
-    { "/dev/msm_pcm_ctl",   0660,   AID_SYSTEM,     AID_AUDIO,      1 },
-    { "/dev/msm_snd",       0660,   AID_SYSTEM,     AID_AUDIO,      1 },
-    { "/dev/msm_mp3",       0660,   AID_SYSTEM,     AID_AUDIO,      1 },
-    { "/dev/audience_a1026", 0660,   AID_SYSTEM,     AID_AUDIO,      1 },
-    { "/dev/tpa2018d1",     0660,   AID_SYSTEM,     AID_AUDIO,      1 },
-    { "/dev/msm_audpre",    0660,   AID_SYSTEM,     AID_AUDIO,      0 },
-    { "/dev/msm_audio_ctl", 0660,   AID_SYSTEM,     AID_AUDIO,      0 },
-    { "/dev/htc-acoustic",  0660,   AID_SYSTEM,     AID_AUDIO,      0 },
-    { "/dev/vdec",          0660,   AID_SYSTEM,     AID_AUDIO,      0 },
-    { "/dev/q6venc",        0660,   AID_SYSTEM,     AID_AUDIO,      0 },
-    { "/dev/snd/dsp",       0660,   AID_SYSTEM,     AID_AUDIO,      0 },
-    { "/dev/snd/dsp1",      0660,   AID_SYSTEM,     AID_AUDIO,      0 },
-    { "/dev/snd/mixer",     0660,   AID_SYSTEM,     AID_AUDIO,      0 },
-    { "/dev/smd0",          0640,   AID_RADIO,      AID_RADIO,      0 },
-    { "/dev/qemu_trace",    0666,   AID_SYSTEM,     AID_SYSTEM,     0 },
-    { "/dev/qmi",           0640,   AID_RADIO,      AID_RADIO,      0 },
-    { "/dev/qmi0",          0640,   AID_RADIO,      AID_RADIO,      0 },
-    { "/dev/qmi1",          0640,   AID_RADIO,      AID_RADIO,      0 },
-    { "/dev/qmi2",          0640,   AID_RADIO,      AID_RADIO,      0 },
-        /* CDMA radio interface MUX */
-    { "/dev/ts0710mux",     0640,   AID_RADIO,      AID_RADIO,      1 },
-    { "/dev/ppp",           0660,   AID_RADIO,      AID_VPN,        0 },
-    { "/dev/tun",           0640,   AID_VPN,        AID_VPN,        0 },
-    { NULL, 0, 0, 0, 0 },
-};
-
-/* devperms_partners list and perm_node are for hardware specific /dev entries */
 struct perm_node {
     struct perms_ dp;
     struct listnode plist;
 };
-list_declare(devperms_partners);
+static list_declare(dev_perms);
 
 /*
  * Permission override when in emulator mode, must be parsed before
  * system properties is initalized.
  */
-static int qemu_perm_count;
-static struct perms_ qemu_perms[MAX_QEMU_PERM + 1];
-
-int add_devperms_partners(const char *name, mode_t perm, unsigned int uid,
-                        unsigned int gid, unsigned short prefix) {
+int add_dev_perms(const char *name, mode_t perm, unsigned int uid,
+                  unsigned int gid, unsigned short prefix) {
     int size;
+    char *tmp = 0;
     struct perm_node *node = malloc(sizeof (struct perm_node));
     if (!node)
         return -ENOMEM;
@@ -197,51 +114,10 @@
     node->dp.gid = gid;
     node->dp.prefix = prefix;
 
-    list_add_tail(&devperms_partners, &node->plist);
+    list_add_tail(&dev_perms, &node->plist);
     return 0;
 }
 
-void qemu_init(void) {
-    qemu_perm_count = 0;
-    memset(&qemu_perms, 0, sizeof(qemu_perms));
-}
-
-static int qemu_perm(const char* name, mode_t perm, unsigned int uid,
-                         unsigned int gid, unsigned short prefix)
-{
-    char *buf;
-    if (qemu_perm_count == MAX_QEMU_PERM)
-        return -ENOSPC;
-
-    buf = malloc(strlen(name) + 1);
-    if (!buf)
-        return -errno;
-
-    strlcpy(buf, name, strlen(name) + 1);
-    qemu_perms[qemu_perm_count].name = buf;
-    qemu_perms[qemu_perm_count].perm = perm;
-    qemu_perms[qemu_perm_count].uid = uid;
-    qemu_perms[qemu_perm_count].gid = gid;
-    qemu_perms[qemu_perm_count].prefix = prefix;
-
-    qemu_perm_count++;
-    return 0;
-}
-
-/* Permission overrides for emulator that are parsed from /proc/cmdline. */
-void qemu_cmdline(const char* name, const char *value)
-{
-    char *buf;
-    if (!strcmp(name, "android.ril")) {
-        /* cmd line params currently assume /dev/ prefix */
-        if (asprintf(&buf, CMDLINE_PREFIX"/%s", value) == -1) {
-            return;
-        }
-        INFO("nani- buf:: %s\n", buf);
-        qemu_perm(buf, 0660, AID_RADIO, AID_ROOT, 0);
-    }
-}
-
 static int get_device_perm_inner(struct perms_ *perms, const char *path,
                                     unsigned *uid, unsigned *gid, mode_t *perm)
 {
@@ -267,38 +143,32 @@
 static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid)
 {
     mode_t perm;
+    struct listnode *node;
+    struct perm_node *perm_node;
+    struct perms_ *dp;
 
-    if (get_device_perm_inner(qemu_perms, path, uid, gid, &perm) == 0) {
-        return perm;
-    } else if (get_device_perm_inner(devperms, path, uid, gid, &perm) == 0) {
-        return perm;
-    } else {
-        struct listnode *node;
-        struct perm_node *perm_node;
-        struct perms_ *dp;
+    /* search the perms list in reverse so that ueventd.$hardware can
+     * override ueventd.rc
+     */
+    list_for_each_reverse(node, &dev_perms) {
+        perm_node = node_to_item(node, struct perm_node, plist);
+        dp = &perm_node->dp;
 
-        /* Check partners list. */
-        list_for_each(node, &devperms_partners) {
-            perm_node = node_to_item(node, struct perm_node, plist);
-            dp = &perm_node->dp;
-
-            if (dp->prefix) {
-                if (strncmp(path, dp->name, strlen(dp->name)))
-                    continue;
-            } else {
-                if (strcmp(path, dp->name))
-                    continue;
-            }
-            /* Found perm in partner list. */
-            *uid = dp->uid;
-            *gid = dp->gid;
-            return dp->perm;
+        if (dp->prefix) {
+            if (strncmp(path, dp->name, strlen(dp->name)))
+                continue;
+        } else {
+            if (strcmp(path, dp->name))
+                continue;
         }
-        /* Default if nothing found. */
-        *uid = 0;
-        *gid = 0;
-        return 0600;
+        *uid = dp->uid;
+        *gid = dp->gid;
+        return dp->perm;
     }
+    /* Default if nothing found. */
+    *uid = 0;
+    *gid = 0;
+    return 0600;
 }
 
 static void make_device(const char *path, int block, int major, int minor)
diff --git a/init/list.h b/init/list.h
index 04cb0d3..0a7b28c 100644
--- a/init/list.h
+++ b/init/list.h
@@ -35,6 +35,9 @@
 #define list_for_each(node, list) \
     for (node = (list)->next; node != (list); node = node->next)
 
+#define list_for_each_reverse(node, list) \
+    for (node = (list)->prev; node != (list); node = node->prev)
+
 void list_init(struct listnode *list);
 void list_add_tail(struct listnode *list, struct listnode *item);
 void list_remove(struct listnode *item);
diff --git a/init/ueventd.c b/init/ueventd.c
index 5a2222a..d51ffde 100644
--- a/init/ueventd.c
+++ b/init/ueventd.c
@@ -15,22 +15,40 @@
  */
 
 #include <poll.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <private/android_filesystem_config.h>
 
 #include "ueventd.h"
 #include "log.h"
 #include "util.h"
 #include "devices.h"
+#include "ueventd_parser.h"
+
+static char hardware[32];
+static unsigned revision = 0;
 
 int ueventd_main(int argc, char **argv)
 {
     struct pollfd ufd;
     int nr;
+    char tmp[32];
 
     open_devnull_stdio();
     log_init();
 
     INFO("starting ueventd\n");
 
+    get_hardware_name(hardware, &revision);
+
+    ueventd_parse_config_file("/ueventd.rc");
+
+    snprintf(tmp, sizeof(tmp), "/ueventd.%s.rc", hardware);
+    ueventd_parse_config_file(tmp);
+
     device_init();
 
     ufd.events = POLLIN;
@@ -45,3 +63,76 @@
                handle_device_fd();
     }
 }
+
+static int get_android_id(const char *id)
+{
+    unsigned int i;
+    for (i = 0; i < ARRAY_SIZE(android_ids); i++)
+        if (!strcmp(id, android_ids[i].name))
+            return android_ids[i].aid;
+    return 0;
+}
+
+void set_device_permission(int nargs, char **args)
+{
+    char *name;
+    mode_t perm;
+    uid_t uid;
+    gid_t gid;
+    int prefix = 0;
+    char *endptr;
+    int ret;
+    char *tmp = 0;
+
+    if (nargs == 0)
+        return;
+
+    if (args[0][0] == '#')
+        return;
+
+    if (nargs != 4) {
+        ERROR("invalid line ueventd.rc line for '%s'\n", args[0]);
+        return;
+    }
+
+    name = args[0];
+    /* If path starts with mtd@ lookup the mount number. */
+    if (!strncmp(name, "mtd@", 4)) {
+        int n = mtd_name_to_number(name + 4);
+        if (n >= 0)
+            asprintf(&tmp, "/dev/mtd/mtd%d", n);
+        name = tmp;
+    } else {
+        int len = strlen(name);
+        if (name[len - 1] == '*') {
+            prefix = 1;
+            name[len - 1] = '\0';
+        }
+    }
+
+    perm = strtol(args[1], &endptr, 8);
+    if (!endptr || *endptr != '\0') {
+        ERROR("invalid mode '%s'\n", args[1]);
+        free(tmp);
+        return;
+    }
+
+    ret = get_android_id(args[2]);
+    if (ret < 0) {
+        ERROR("invalid uid '%s'\n", args[2]);
+        free(tmp);
+        return;
+    }
+    uid = ret;
+
+    ret = get_android_id(args[3]);
+    if (ret < 0) {
+        ERROR("invalid gid '%s'\n", args[3]);
+        free(tmp);
+        return;
+    }
+    gid = ret;
+
+    add_dev_perms(name, perm, uid, gid, prefix);
+    free(tmp);
+}
diff --git a/init/ueventd_parser.c b/init/ueventd_parser.c
new file mode 100644
index 0000000..0dd8b4d
--- /dev/null
+++ b/init/ueventd_parser.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "ueventd_parser.h"
+#include "parser.h"
+#include "log.h"
+#include "list.h"
+#include "util.h"
+
+static void parse_line_device(struct parse_state *state, int nargs, char **args);
+
+static void parse_config(const char *fn, char *s)
+{
+    struct parse_state state;
+    char *args[UEVENTD_PARSER_MAXARGS];
+    int nargs;
+    nargs = 0;
+    state.filename = fn;
+    state.line = 1;
+    state.ptr = s;
+    state.nexttoken = 0;
+    state.parse_line = parse_line_device;
+    for (;;) {
+        int token = next_token(&state);
+        switch (token) {
+        case T_EOF:
+            state.parse_line(&state, 0, 0);
+            return;
+        case T_NEWLINE:
+            if (nargs) {
+                state.parse_line(&state, nargs, args);
+                nargs = 0;
+            }
+            break;
+        case T_TEXT:
+            if (nargs < UEVENTD_PARSER_MAXARGS) {
+                args[nargs++] = state.text;
+            }
+            break;
+        }
+    }
+}
+
+int ueventd_parse_config_file(const char *fn)
+{
+    char *data;
+    data = read_file(fn, 0);
+    if (!data) return -1;
+
+    parse_config(fn, data);
+    DUMP();
+    return 0;
+}
+
+static void parse_line_device(struct parse_state* state, int nargs, char **args)
+{
+    set_device_permission(nargs, args);
+}
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
new file mode 100644
index 0000000..48f9bb8
--- /dev/null
+++ b/init/ueventd_parser.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_UEVENTD_PARSER_H_
+#define _INIT_UEVENTD_PARSER_H_
+
+#define UEVENTD_PARSER_MAXARGS 4
+
+int ueventd_parse_config_file(const char *fn);
+void set_device_permission(int nargs, char **args);
+
+#endif
diff --git a/init/util.h b/init/util.h
index 5fcd2ec..2e47369 100644
--- a/init/util.h
+++ b/init/util.h
@@ -20,6 +20,8 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
 static const char *coldboot_done = "/dev/.coldboot_done";
 
 int mtd_name_to_number(const char *name);
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index ed13060..329be7f 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -40,6 +40,12 @@
 $(INSTALLED_RAMDISK_TARGET): $(file)
 endif
 
+file := $(TARGET_ROOT_OUT)/ueventd.rc
+$(file) : $(LOCAL_PATH)/ueventd.rc | $(ACP)
+	$(transform-prebuilt-to-target)
+ALL_PREBUILT += $(file)
+$(INSTALLED_RAMDISK_TARGET): $(file)
+
 # Just like /system/etc/init.goldfish.sh, the /init.godlfish.rc is here
 # to allow -user builds to properly run the dex pre-optimization pass in
 # the emulator.
@@ -47,6 +53,13 @@
 $(file) : $(LOCAL_PATH)/etc/init.goldfish.rc | $(ACP)
 	$(transform-prebuilt-to-target)
 ALL_PREBUILT += $(file)
+$(INSTALLED_RAMDISK_TARGET): $(file)
+
+file := $(TARGET_ROOT_OUT)/ueventd.goldfish.rc
+$(file) : $(LOCAL_PATH)/etc/ueventd.goldfish.rc | $(ACP)
+	$(transform-prebuilt-to-target)
+ALL_PREBUILT += $(file)
+$(INSTALLED_RAMDISK_TARGET): $(file)
 
 # create some directories (some are mount points)
 DIRS := $(addprefix $(TARGET_ROOT_OUT)/, \
diff --git a/rootdir/etc/ueventd.goldfish.rc b/rootdir/etc/ueventd.goldfish.rc
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/rootdir/etc/ueventd.goldfish.rc
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
new file mode 100644
index 0000000..46f640f
--- /dev/null
+++ b/rootdir/ueventd.rc
@@ -0,0 +1,76 @@
+/dev/null                 0666   root       root
+/dev/zero                 0666   root       root
+/dev/full                 0666   root       root
+/dev/ptmx                 0666   root       root
+/dev/tty                  0666   root       root
+/dev/random               0666   root       root
+/dev/urandom              0666   root       root
+/dev/ashmem               0666   root       root
+/dev/binder               0666   root       root
+
+# logger should be world writable (for logging) but not readable
+/dev/log/*                0662   root       log
+
+# the msm hw3d client device node is world writable/readable.
+/dev/msm_hw3dc            0666   root       root
+
+# gpu driver for adreno200 is globally accessible
+/dev/kgsl                 0666   root       root
+
+# these should not be world writable
+/dev/diag                 0660   radio      radio
+/dev/diag_arm9            0660   radio      radio
+/dev/android_adb          0660   adb        adb
+/dev/android_adb_enable   0660   adb        adb
+/dev/ttyMSM0              0600   bluetooth  bluetooth
+/dev/ttyHS0               0600   bluetooth  bluetooth
+/dev/uinput               0660   system     bluetooth
+/dev/alarm                0664   system     radio
+/dev/tty0                 0660   root       system
+/dev/graphics/*           0660   root       graphics
+/dev/msm_hw3dm            0660   system     graphics
+/dev/input/*              0660   root       input
+/dev/eac                  0660   root       audio
+/dev/cam                  0660   root       camera
+/dev/pmem                 0660   system     graphics
+/dev/pmem_adsp*           0660   system     audio
+/dev/pmem_camera*         0660   system     camera
+/dev/oncrpc/*             0660   root       system
+/dev/adsp/*               0660   system     audio
+/dev/snd/*                0660   system     audio
+/dev/mt9t013              0660   system     system
+/dev/msm_camera/*         0660   system     system
+/dev/akm8976_daemon       0640   compass    system
+/dev/akm8976_aot          0640   compass    system
+/dev/akm8973_daemon       0640   compass    system
+/dev/akm8973_aot          0640   compass    system
+/dev/bma150               0640   compass    system
+/dev/cm3602               0640   compass    system
+/dev/akm8976_pffd         0640   compass    system
+/dev/lightsensor          0640   system     system
+/dev/msm_pcm_out*         0660   system     audio
+/dev/msm_pcm_in*          0660   system     audio
+/dev/msm_pcm_ctl*         0660   system     audio
+/dev/msm_snd*             0660   system     audio
+/dev/msm_mp3*             0660   system     audio
+/dev/audience_a1026*      0660   system     audio
+/dev/tpa2018d1*           0660   system     audio
+/dev/msm_audpre           0660   system     audio
+/dev/msm_audio_ctl        0660   system     audio
+/dev/htc-acoustic         0660   system     audio
+/dev/vdec                 0660   system     audio
+/dev/q6venc               0660   system     audio
+/dev/snd/dsp              0660   system     audio
+/dev/snd/dsp1             0660   system     audio
+/dev/snd/mixer            0660   system     audio
+/dev/smd0                 0640   radio      radio
+/dev/qemu_trace           0666   system     system
+/dev/qmi                  0640   radio      radio
+/dev/qmi0                 0640   radio      radio
+/dev/qmi1                 0640   radio      radio
+/dev/qmi2                 0640   radio      radio
+
+# CDMA radio interface MUX
+/dev/ts0710mux*           0640   radio      radio
+/dev/ppp                  0660   radio      vpn
+/dev/tun                  0640   vpn        vpn