Home | History | Annotate | Download | only in init
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <ctype.h>
     18 #include <errno.h>
     19 #include <stdio.h>
     20 #include <unistd.h>
     21 #include <stdarg.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 
     25 #include "ueventd.h"
     26 #include "ueventd_parser.h"
     27 #include "parser.h"
     28 #include "log.h"
     29 #include "util.h"
     30 
     31 static list_declare(subsystem_list);
     32 
     33 static void parse_line_device(struct parse_state *state, int nargs, char **args);
     34 
     35 #define SECTION 0x01
     36 #define OPTION  0x02
     37 
     38 #include "ueventd_keywords.h"
     39 
     40 #define KEYWORD(symbol, flags, nargs) \
     41     [ K_##symbol ] = { #symbol, nargs + 1, flags, },
     42 
     43 static struct {
     44     const char *name;
     45     unsigned char nargs;
     46     unsigned char flags;
     47 } keyword_info[KEYWORD_COUNT] = {
     48     [ K_UNKNOWN ] = { "unknown", 0, 0 },
     49 #include "ueventd_keywords.h"
     50 };
     51 #undef KEYWORD
     52 
     53 #define kw_is(kw, type) (keyword_info[kw].flags & (type))
     54 #define kw_nargs(kw) (keyword_info[kw].nargs)
     55 
     56 static int lookup_keyword(const char *s)
     57 {
     58     switch (*s++) {
     59     case 'd':
     60         if (!strcmp(s, "evname")) return K_devname;
     61         if (!strcmp(s, "irname")) return K_dirname;
     62         break;
     63     case 's':
     64         if (!strcmp(s, "ubsystem")) return K_subsystem;
     65         break;
     66     }
     67     return K_UNKNOWN;
     68 }
     69 
     70 static void parse_line_no_op(struct parse_state *state __attribute__((unused)),
     71         int nargs __attribute__((unused)), char **args  __attribute__((unused)))
     72 {
     73 }
     74 
     75 static int valid_name(const char *name)
     76 {
     77     while (*name) {
     78         if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
     79             return 0;
     80         }
     81         name++;
     82     }
     83     return 1;
     84 }
     85 
     86 struct ueventd_subsystem *ueventd_subsystem_find_by_name(const char *name)
     87 {
     88     struct listnode *node;
     89     struct ueventd_subsystem *s;
     90 
     91     list_for_each(node, &subsystem_list) {
     92         s = node_to_item(node, struct ueventd_subsystem, slist);
     93         if (!strcmp(s->name, name)) {
     94             return s;
     95         }
     96     }
     97     return 0;
     98 }
     99 
    100 static void *parse_subsystem(struct parse_state *state,
    101         int nargs __attribute__((unused)), char **args)
    102 {
    103     struct ueventd_subsystem *s;
    104 
    105     if (!valid_name(args[1])) {
    106         parse_error(state, "invalid subsystem name '%s'\n", args[1]);
    107         return 0;
    108     }
    109 
    110     s = ueventd_subsystem_find_by_name(args[1]);
    111     if (s) {
    112         parse_error(state, "ignored duplicate definition of subsystem '%s'\n",
    113                 args[1]);
    114         return 0;
    115     }
    116 
    117     s = calloc(1, sizeof(*s));
    118     if (!s) {
    119         parse_error(state, "out of memory\n");
    120         return 0;
    121     }
    122     s->name = args[1];
    123     s->dirname = "/dev";
    124     list_add_tail(&subsystem_list, &s->slist);
    125     return s;
    126 }
    127 
    128 static void parse_line_subsystem(struct parse_state *state, int nargs,
    129         char **args)
    130 {
    131     struct ueventd_subsystem *s = state->context;
    132     int kw;
    133 
    134     if (nargs == 0) {
    135         return;
    136     }
    137 
    138     kw = lookup_keyword(args[0]);
    139     switch (kw) {
    140     case K_devname:
    141         if (!strcmp(args[1], "uevent_devname"))
    142             s->devname_src = DEVNAME_UEVENT_DEVNAME;
    143         else if (!strcmp(args[1], "uevent_devpath"))
    144             s->devname_src = DEVNAME_UEVENT_DEVPATH;
    145         else
    146             parse_error(state, "invalid devname '%s'\n", args[1]);
    147         break;
    148 
    149     case K_dirname:
    150         if (args[1][0] == '/')
    151             s->dirname = args[1];
    152         else
    153             parse_error(state, "dirname '%s' does not start with '/'\n",
    154                     args[1]);
    155         break;
    156 
    157     default:
    158         parse_error(state, "invalid option '%s'\n", args[0]);
    159     }
    160 }
    161 
    162 static void parse_new_section(struct parse_state *state, int kw,
    163                        int nargs, char **args)
    164 {
    165     printf("[ %s %s ]\n", args[0],
    166            nargs > 1 ? args[1] : "");
    167 
    168     switch(kw) {
    169     case K_subsystem:
    170         state->context = parse_subsystem(state, nargs, args);
    171         if (state->context) {
    172             state->parse_line = parse_line_subsystem;
    173             return;
    174         }
    175         break;
    176     }
    177     state->parse_line = parse_line_no_op;
    178 }
    179 
    180 static void parse_line(struct parse_state *state, char **args, int nargs)
    181 {
    182     int kw = lookup_keyword(args[0]);
    183     int kw_nargs = kw_nargs(kw);
    184 
    185     if (nargs < kw_nargs) {
    186         parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
    187             kw_nargs > 2 ? "arguments" : "argument");
    188         return;
    189     }
    190 
    191     if (kw_is(kw, SECTION)) {
    192         parse_new_section(state, kw, nargs, args);
    193     } else if (kw_is(kw, OPTION)) {
    194         state->parse_line(state, nargs, args);
    195     } else {
    196         parse_line_device(state, nargs, args);
    197     }
    198 }
    199 
    200 static void parse_config(const char *fn, char *s)
    201 {
    202     struct parse_state state;
    203     char *args[UEVENTD_PARSER_MAXARGS];
    204     int nargs;
    205     nargs = 0;
    206     state.filename = fn;
    207     state.line = 1;
    208     state.ptr = s;
    209     state.nexttoken = 0;
    210     state.parse_line = parse_line_no_op;
    211     for (;;) {
    212         int token = next_token(&state);
    213         switch (token) {
    214         case T_EOF:
    215             parse_line(&state, args, nargs);
    216             return;
    217         case T_NEWLINE:
    218             if (nargs) {
    219                 parse_line(&state, args, nargs);
    220                 nargs = 0;
    221             }
    222             state.line++;
    223             break;
    224         case T_TEXT:
    225             if (nargs < UEVENTD_PARSER_MAXARGS) {
    226                 args[nargs++] = state.text;
    227             }
    228             break;
    229         }
    230     }
    231 }
    232 
    233 int ueventd_parse_config_file(const char *fn)
    234 {
    235     char *data;
    236     data = read_file(fn, 0);
    237     if (!data) return -1;
    238 
    239     parse_config(fn, data);
    240     DUMP();
    241     return 0;
    242 }
    243 
    244 static void parse_line_device(struct parse_state *state __attribute__((unused)),
    245         int nargs, char **args)
    246 {
    247     set_device_permission(nargs, args);
    248 }
    249