Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b0ab94b7 authored by Colin Cross's avatar Colin Cross
Browse files

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
parent ebc6ff10
Loading
Loading
Loading
Loading
+92 −2
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@

#include "init.h"
#include "devices.h"
#include "util.h"

#define CMDLINE_PREFIX  "/dev"
#define SYSFS_PREFIX    "/sys"
@@ -47,6 +48,8 @@ struct uevent {
    const char *path;
    const char *subsystem;
    const char *firmware;
    const char *partition_name;
    int partition_num;
    int major;
    int minor;
};
@@ -346,6 +349,8 @@ static void parse_event(const char *msg, struct uevent *uevent)
    uevent->firmware = "";
    uevent->major = -1;
    uevent->minor = -1;
    uevent->partition_name = NULL;
    uevent->partition_num = -1;

        /* currently ignoring SEQNUM */
    while(*msg) {
@@ -367,6 +372,12 @@ static void parse_event(const char *msg, struct uevent *uevent)
        } else if(!strncmp(msg, "MINOR=", 6)) {
            msg += 6;
            uevent->minor = atoi(msg);
        } else if(!strncmp(msg, "PARTN=", 6)) {
            msg += 6;
            uevent->partition_num = atoi(msg);
        } else if(!strncmp(msg, "PARTNAME=", 9)) {
            msg += 9;
            uevent->partition_name = msg;
        }

            /* advance to after the next \0 */
@@ -379,11 +390,76 @@ static void parse_event(const char *msg, struct uevent *uevent)
                    uevent->firmware, uevent->major, uevent->minor);
}

static char **parse_platform_block_device(struct uevent *uevent)
{
    const char *driver;
    const char *path;
    char *slash;
    int width;
    char buf[256];
    char link_path[256];
    int fd;
    int link_num = 0;
    int ret;
    char *p;
    unsigned int size;
    struct stat info;

    char **links = malloc(sizeof(char *) * 4);
    if (!links)
        return NULL;
    memset(links, 0, sizeof(char *) * 4);

    /* Drop "/devices/platform/" */
    path = uevent->path;
    driver = path + 18;
    slash = strchr(driver, '/');
    if (!slash)
        goto err;
    width = slash - driver;
    if (width <= 0)
        goto err;

    snprintf(link_path, sizeof(link_path), "/dev/block/platform/%.*s",
             width, driver);

    if (uevent->partition_name) {
        p = strdup(uevent->partition_name);
        sanitize(p);
        if (asprintf(&links[link_num], "%s/by-name/%s", link_path, p) > 0)
            link_num++;
        else
            links[link_num] = NULL;
        free(p);
    }

    if (uevent->partition_num >= 0) {
        if (asprintf(&links[link_num], "%s/by-num/p%d", link_path, uevent->partition_num) > 0)
            link_num++;
        else
            links[link_num] = NULL;
    }

    slash = strrchr(path, '/');
    if (asprintf(&links[link_num], "%s/%s", link_path, slash + 1) > 0)
        link_num++;
    else
        links[link_num] = NULL;

    return links;

err:
    free(links);
    return NULL;
}

static void handle_device_event(struct uevent *uevent)
{
    char devpath[96];
    char *base, *name;
    char **links = NULL;
    int block;
    int i;

        /* if it's not a /dev device, nothing to do */
    if((uevent->major < 0) || (uevent->minor < 0))
@@ -404,6 +480,8 @@ static void handle_device_event(struct uevent *uevent)
        block = 1;
        base = "/dev/block/";
        mkdir(base, 0755);
        if (!strncmp(uevent->path, "/devices/platform/", 18))
            links = parse_platform_block_device(uevent);
    } else {
        block = 0;
            /* this should probably be configurable somehow */
@@ -441,12 +519,24 @@ static void handle_device_event(struct uevent *uevent)

    if(!strcmp(uevent->action, "add")) {
        make_device(devpath, block, uevent->major, uevent->minor);
        return;
        if (links) {
            for (i = 0; links[i]; i++)
                make_link(devpath, links[i]);
        }
    }

    if(!strcmp(uevent->action, "remove")) {
        if (links) {
            for (i = 0; links[i]; i++)
                remove_link(devpath, links[i]);
        }
        unlink(devpath);
        return;
    }

    if (links) {
        for (i = 0; links[i]; i++)
            free(links[i]);
        free(links);
    }
}

+78 −0
Original line number Diff line number Diff line
@@ -299,3 +299,81 @@ time_t gettime(void)

    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);
}
+4 −0
Original line number Diff line number Diff line
@@ -24,4 +24,8 @@ void *read_file(const char *fn, unsigned *_sz);
time_t gettime(void);
unsigned int decode_uid(const char *s);

int mkdir_recursive(const char *pathname, mode_t mode);
void sanitize(char *p);
void make_link(const char *oldpath, const char *newpath);
void remove_link(const char *oldpath, const char *newpath);
#endif