Loading init/devices.c +63 −20 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ #include <cutils/uevent.h> #include "devices.h" #include "ueventd_parser.h" #include "util.h" #include "log.h" Loading Loading @@ -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; } Loading @@ -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 Loading init/ueventd.h +15 −0 Original line number Diff line number Diff line Loading @@ -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 init/ueventd_keywords.h 0 → 100644 +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 init/ueventd_parser.c +177 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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) { Loading @@ -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); } init/ueventd_parser.h +3 −0 Original line number Diff line number Diff line Loading @@ -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
init/devices.c +63 −20 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ #include <cutils/uevent.h> #include "devices.h" #include "ueventd_parser.h" #include "util.h" #include "log.h" Loading Loading @@ -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; } Loading @@ -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 Loading
init/ueventd.h +15 −0 Original line number Diff line number Diff line Loading @@ -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
init/ueventd_keywords.h 0 → 100644 +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
init/ueventd_parser.c +177 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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) { Loading @@ -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); }
init/ueventd_parser.h +3 −0 Original line number Diff line number Diff line Loading @@ -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