init: create symlinks to block device nodes

eMMC block device names may change based on the detection order of
the eMMC device and any other SD bus devices, such as a removable SD
card.

This patch adds support to init for:
  * Symlinks to block devices.  When a block device uevent is
    processed, if it starts with "/devices/platform", the platform
    driver name is parsed out, and symlinks to the block device are
    created in /dev/block/platform/<platform driver>/
  * Symlinks based on partition name and number.  If the uevent for
    a block device contains information on the partition name or
    number, symlinks are created under
    /dev/block/platform/<platform driver>/by-num/p<partition>
    and
    /dev/block/platform/<platform driver>/by-name/<partition name>

init.rc can then use a device path like the following to mount an
eMMC device:
/dev/block/platform/<platform>/by-name/system /system ro

Change-Id: Id11bb7cdf1e2ada7752a5bd671cbf87237b34ae2
diff --git a/init/util.c b/init/util.c
index 6f9a12e..a56ba0d 100644
--- a/init/util.c
+++ b/init/util.c
@@ -299,3 +299,81 @@
 
     return ts.tv_sec;
 }
+
+int mkdir_recursive(const char *pathname, mode_t mode)
+{
+    char buf[128];
+    const char *slash;
+    const char *p = pathname;
+    int width;
+    int ret;
+    struct stat info;
+
+    while ((slash = strchr(p, '/')) != NULL) {
+        width = slash - pathname;
+        p = slash + 1;
+        if (width < 0)
+            break;
+        if (width == 0)
+            continue;
+        if ((unsigned int)width > sizeof(buf) - 1) {
+            ERROR("path too long for mkdir_recursive\n");
+            return -1;
+        }
+        memcpy(buf, pathname, width);
+        buf[width] = 0;
+        if (stat(buf, &info) != 0) {
+            ret = mkdir(buf, mode);
+            if (ret && errno != EEXIST)
+                return ret;
+        }
+    }
+    ret = mkdir(pathname, mode);
+    if (ret && errno != EEXIST)
+        return ret;
+    return 0;
+}
+
+void sanitize(char *s)
+{
+    if (!s)
+        return;
+    while (isalnum(*s))
+        s++;
+    *s = 0;
+}
+void make_link(const char *oldpath, const char *newpath)
+{
+    int ret;
+    char buf[256];
+    char *slash;
+    int width;
+
+    slash = strrchr(newpath, '/');
+    if (!slash)
+        return;
+    width = slash - newpath;
+    if (width <= 0 || width > (int)sizeof(buf) - 1)
+        return;
+    memcpy(buf, newpath, width);
+    buf[width] = 0;
+    ret = mkdir_recursive(buf, 0755);
+    if (ret)
+        ERROR("Failed to create directory %s: %s (%d)\n", buf, strerror(errno), errno);
+
+    ret = symlink(oldpath, newpath);
+    if (ret && errno != EEXIST)
+        ERROR("Failed to symlink %s to %s: %s (%d)\n", oldpath, newpath, strerror(errno), errno);
+}
+
+void remove_link(const char *oldpath, const char *newpath)
+{
+    char path[256];
+    ssize_t ret;
+    ret = readlink(newpath, path, sizeof(path) - 1);
+    if (ret <= 0)
+        return;
+    path[ret] = 0;
+    if (!strcmp(path, oldpath))
+        unlink(newpath);
+}