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

Commit 5ebd8e43 authored by Greg Hackmann's avatar Greg Hackmann Committed by Android Git Automerger
Browse files

am b2406973: Merge changes I727d9135,I3bd1b59d,I0d05aa28

* commit 'b2406973':
  rootdir: add ueventd.rc rule for adf subsystem
  init: add subsystem rules to ueventd.rc
  init: handle ueventd path truncation better
parents 675c9966 b2406973
Loading
Loading
Loading
Loading
+63 −20
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@
#include <cutils/uevent.h>

#include "devices.h"
#include "ueventd_parser.h"
#include "util.h"
#include "log.h"

@@ -530,8 +531,11 @@ static const char *parse_device_name(struct uevent *uevent, unsigned int len)
    name++;

    /* too-long names would overrun our buffer */
    if(strlen(name) > len)
    if(strlen(name) > len) {
        ERROR("DEVPATH=%s exceeds %u-character limit on filename; ignoring event\n",
                name, len);
        return NULL;
    }

    return name;
}
@@ -557,37 +561,76 @@ static void handle_block_device_event(struct uevent *uevent)
            uevent->major, uevent->minor, links);
}

#define DEVPATH_LEN 96

static bool assemble_devpath(char *devpath, const char *dirname,
        const char *devname)
{
    int s = snprintf(devpath, DEVPATH_LEN, "%s/%s", dirname, devname);
    if (s < 0) {
        ERROR("failed to assemble device path (%s); ignoring event\n",
                strerror(errno));
        return false;
    } else if (s >= DEVPATH_LEN) {
        ERROR("%s/%s exceeds %u-character limit on path; ignoring event\n",
                dirname, devname, DEVPATH_LEN);
        return false;
    }
    return true;
}

static void mkdir_recursive_for_devpath(const char *devpath)
{
    char dir[DEVPATH_LEN];
    char *slash;

    strcpy(dir, devpath);
    slash = strrchr(dir, '/');
    *slash = '\0';
    mkdir_recursive(dir, 0755);
}

static void handle_generic_device_event(struct uevent *uevent)
{
    char *base;
    const char *name;
    char devpath[96] = {0};
    char devpath[DEVPATH_LEN] = {0};
    char **links = NULL;

    name = parse_device_name(uevent, 64);
    if (!name)
        return;

    if (!strncmp(uevent->subsystem, "usb", 3)) {
    struct ueventd_subsystem *subsystem =
            ueventd_subsystem_find_by_name(uevent->subsystem);

    if (subsystem) {
        const char *devname;

        switch (subsystem->devname_src) {
        case DEVNAME_UEVENT_DEVNAME:
            devname = uevent->device_name;
            break;

        case DEVNAME_UEVENT_DEVPATH:
            devname = name;
            break;

        default:
            ERROR("%s subsystem's devpath option is not set; ignoring event\n",
                    uevent->subsystem);
            return;
        }

        if (!assemble_devpath(devpath, subsystem->dirname, devname))
            return;
        mkdir_recursive_for_devpath(devpath);
    } else if (!strncmp(uevent->subsystem, "usb", 3)) {
         if (!strcmp(uevent->subsystem, "usb")) {
            if (uevent->device_name) {
                /*
                 * create device node provided by kernel if present
                 * see drivers/base/core.c
                 */
                char *p = devpath;
                snprintf(devpath, sizeof(devpath), "/dev/%s", uevent->device_name);
                /* skip leading /dev/ */
                p += 5;
                /* build directories */
                while (*p) {
                    if (*p == '/') {
                        *p = 0;
                        make_dir(devpath, 0755);
                        *p = '/';
                    }
                    p++;
                }
                if (!assemble_devpath(devpath, "/dev", uevent->device_name))
                    return;
                mkdir_recursive_for_devpath(devpath);
             }
             else {
                 /* This imitates the file system that would be created
+15 −0
Original line number Diff line number Diff line
@@ -17,6 +17,21 @@
#ifndef _INIT_UEVENTD_H_
#define _INIT_UEVENTD_H_

#include <cutils/list.h>
#include <sys/types.h>

struct ueventd_subsystem {
    struct listnode slist;

    const char *name;
    enum {
        DEVNAME_UNKNOWN = 0,
        DEVNAME_UEVENT_DEVNAME,
        DEVNAME_UEVENT_DEVPATH,
    } devname_src;
    const char *dirname;
};

int ueventd_main(int argc, char **argv);

#endif
+15 −0
Original line number Diff line number Diff line
#ifndef KEYWORD
#define __MAKE_KEYWORD_ENUM__
#define KEYWORD(symbol, flags, nargs) K_##symbol,
enum {
    K_UNKNOWN,
#endif
    KEYWORD(subsystem,      SECTION,    1)
    KEYWORD(devname,        OPTION,     1)
    KEYWORD(dirname,        OPTION,     1)
#ifdef __MAKE_KEYWORD_ENUM__
    KEYWORD_COUNT,
};
#undef __MAKE_KEYWORD_ENUM__
#undef KEYWORD
#endif
+177 −4
Original line number Diff line number Diff line
@@ -14,18 +14,189 @@
 * limitations under the License.
 */

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

#include "ueventd.h"
#include "ueventd_parser.h"
#include "parser.h"
#include "log.h"
#include "util.h"

static list_declare(subsystem_list);

static void parse_line_device(struct parse_state *state, int nargs, char **args);

#define SECTION 0x01
#define OPTION  0x02

#include "ueventd_keywords.h"

#define KEYWORD(symbol, flags, nargs) \
    [ K_##symbol ] = { #symbol, nargs + 1, flags, },

static struct {
    const char *name;
    unsigned char nargs;
    unsigned char flags;
} keyword_info[KEYWORD_COUNT] = {
    [ K_UNKNOWN ] = { "unknown", 0, 0 },
#include "ueventd_keywords.h"
};
#undef KEYWORD

#define kw_is(kw, type) (keyword_info[kw].flags & (type))
#define kw_nargs(kw) (keyword_info[kw].nargs)

static int lookup_keyword(const char *s)
{
    switch (*s++) {
    case 'd':
        if (!strcmp(s, "evname")) return K_devname;
        if (!strcmp(s, "irname")) return K_dirname;
        break;
    case 's':
        if (!strcmp(s, "ubsystem")) return K_subsystem;
        break;
    }
    return K_UNKNOWN;
}

static void parse_line_no_op(struct parse_state *state __attribute__((unused)),
        int nargs __attribute__((unused)), char **args  __attribute__((unused)))
{
}

static int valid_name(const char *name)
{
    while (*name) {
        if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
            return 0;
        }
        name++;
    }
    return 1;
}

struct ueventd_subsystem *ueventd_subsystem_find_by_name(const char *name)
{
    struct listnode *node;
    struct ueventd_subsystem *s;

    list_for_each(node, &subsystem_list) {
        s = node_to_item(node, struct ueventd_subsystem, slist);
        if (!strcmp(s->name, name)) {
            return s;
        }
    }
    return 0;
}

static void *parse_subsystem(struct parse_state *state,
        int nargs __attribute__((unused)), char **args)
{
    struct ueventd_subsystem *s;

    if (!valid_name(args[1])) {
        parse_error(state, "invalid subsystem name '%s'\n", args[1]);
        return 0;
    }

    s = ueventd_subsystem_find_by_name(args[1]);
    if (s) {
        parse_error(state, "ignored duplicate definition of subsystem '%s'\n",
                args[1]);
        return 0;
    }

    s = calloc(1, sizeof(*s));
    if (!s) {
        parse_error(state, "out of memory\n");
        return 0;
    }
    s->name = args[1];
    s->dirname = "/dev";
    list_add_tail(&subsystem_list, &s->slist);
    return s;
}

static void parse_line_subsystem(struct parse_state *state, int nargs,
        char **args)
{
    struct ueventd_subsystem *s = state->context;
    int kw;

    if (nargs == 0) {
        return;
    }

    kw = lookup_keyword(args[0]);
    switch (kw) {
    case K_devname:
        if (!strcmp(args[1], "uevent_devname"))
            s->devname_src = DEVNAME_UEVENT_DEVNAME;
        else if (!strcmp(args[1], "uevent_devpath"))
            s->devname_src = DEVNAME_UEVENT_DEVPATH;
        else
            parse_error(state, "invalid devname '%s'\n", args[1]);
        break;

    case K_dirname:
        if (args[1][0] == '/')
            s->dirname = args[1];
        else
            parse_error(state, "dirname '%s' does not start with '/'\n",
                    args[1]);
        break;

    default:
        parse_error(state, "invalid option '%s'\n", args[0]);
    }
}

static void parse_new_section(struct parse_state *state, int kw,
                       int nargs, char **args)
{
    printf("[ %s %s ]\n", args[0],
           nargs > 1 ? args[1] : "");

    switch(kw) {
    case K_subsystem:
        state->context = parse_subsystem(state, nargs, args);
        if (state->context) {
            state->parse_line = parse_line_subsystem;
            return;
        }
        break;
    }
    state->parse_line = parse_line_no_op;
}

static void parse_line(struct parse_state *state, char **args, int nargs)
{
    int kw = lookup_keyword(args[0]);
    int kw_nargs = kw_nargs(kw);

    if (nargs < kw_nargs) {
        parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
            kw_nargs > 2 ? "arguments" : "argument");
        return;
    }

    if (kw_is(kw, SECTION)) {
        parse_new_section(state, kw, nargs, args);
    } else if (kw_is(kw, OPTION)) {
        state->parse_line(state, nargs, args);
    } else {
        parse_line_device(state, nargs, args);
    }
}

static void parse_config(const char *fn, char *s)
{
    struct parse_state state;
@@ -36,18 +207,19 @@ static void parse_config(const char *fn, char *s)
    state.line = 1;
    state.ptr = s;
    state.nexttoken = 0;
    state.parse_line = parse_line_device;
    state.parse_line = parse_line_no_op;
    for (;;) {
        int token = next_token(&state);
        switch (token) {
        case T_EOF:
            state.parse_line(&state, 0, 0);
            parse_line(&state, args, nargs);
            return;
        case T_NEWLINE:
            if (nargs) {
                state.parse_line(&state, nargs, args);
                parse_line(&state, args, nargs);
                nargs = 0;
            }
            state.line++;
            break;
        case T_TEXT:
            if (nargs < UEVENTD_PARSER_MAXARGS) {
@@ -69,7 +241,8 @@ int ueventd_parse_config_file(const char *fn)
    return 0;
}

static void parse_line_device(struct parse_state* state, int nargs, char **args)
static void parse_line_device(struct parse_state *state __attribute__((unused)),
        int nargs, char **args)
{
    set_device_permission(nargs, args);
}
+3 −0
Original line number Diff line number Diff line
@@ -17,9 +17,12 @@
#ifndef _INIT_UEVENTD_PARSER_H_
#define _INIT_UEVENTD_PARSER_H_

#include "ueventd.h"

#define UEVENTD_PARSER_MAXARGS 5

int ueventd_parse_config_file(const char *fn);
void set_device_permission(int nargs, char **args);
struct ueventd_subsystem *ueventd_subsystem_find_by_name(const char *name);

#endif
Loading