diff options
Diffstat (limited to 'init/ueventd_parser.c')
-rw-r--r-- | init/ueventd_parser.c | 181 |
1 files changed, 177 insertions, 4 deletions
diff --git a/init/ueventd_parser.c b/init/ueventd_parser.c index 3e60df5..e447006 100644 --- a/init/ueventd_parser.c +++ b/init/ueventd_parser.c @@ -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); } |