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*, int, char**) {
     71 }
     72 
     73 static int valid_name(const char *name)
     74 {
     75     while (*name) {
     76         if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
     77             return 0;
     78         }
     79         name++;
     80     }
     81     return 1;
     82 }
     83 
     84 struct ueventd_subsystem *ueventd_subsystem_find_by_name(const char *name)
     85 {
     86     struct listnode *node;
     87     struct ueventd_subsystem *s;
     88 
     89     list_for_each(node, &subsystem_list) {
     90         s = node_to_item(node, struct ueventd_subsystem, slist);
     91         if (!strcmp(s->name, name)) {
     92             return s;
     93         }
     94     }
     95     return 0;
     96 }
     97 
     98 static void *parse_subsystem(parse_state* state, int /*nargs*/, char** args) {
     99     if (!valid_name(args[1])) {
    100         parse_error(state, "invalid subsystem name '%s'\n", args[1]);
    101         return 0;
    102     }
    103 
    104     ueventd_subsystem* s = ueventd_subsystem_find_by_name(args[1]);
    105     if (s) {
    106         parse_error(state, "ignored duplicate definition of subsystem '%s'\n",
    107                 args[1]);
    108         return 0;
    109     }
    110 
    111     s = (ueventd_subsystem*) calloc(1, sizeof(*s));
    112     if (!s) {
    113         parse_error(state, "out of memory\n");
    114         return 0;
    115     }
    116     s->name = args[1];
    117     s->dirname = "/dev";
    118     list_add_tail(&subsystem_list, &s->slist);
    119     return s;
    120 }
    121 
    122 static void parse_line_subsystem(struct parse_state *state, int nargs,
    123         char **args)
    124 {
    125     struct ueventd_subsystem *s = (ueventd_subsystem*) state->context;
    126     int kw;
    127 
    128     if (nargs == 0) {
    129         return;
    130     }
    131 
    132     kw = lookup_keyword(args[0]);
    133     switch (kw) {
    134     case K_devname:
    135         if (!strcmp(args[1], "uevent_devname"))
    136             s->devname_src = DEVNAME_UEVENT_DEVNAME;
    137         else if (!strcmp(args[1], "uevent_devpath"))
    138             s->devname_src = DEVNAME_UEVENT_DEVPATH;
    139         else
    140             parse_error(state, "invalid devname '%s'\n", args[1]);
    141         break;
    142 
    143     case K_dirname:
    144         if (args[1][0] == '/')
    145             s->dirname = args[1];
    146         else
    147             parse_error(state, "dirname '%s' does not start with '/'\n",
    148                     args[1]);
    149         break;
    150 
    151     default:
    152         parse_error(state, "invalid option '%s'\n", args[0]);
    153     }
    154 }
    155 
    156 static void parse_new_section(struct parse_state *state, int kw,
    157                        int nargs, char **args)
    158 {
    159     printf("[ %s %s ]\n", args[0],
    160            nargs > 1 ? args[1] : "");
    161 
    162     switch(kw) {
    163     case K_subsystem:
    164         state->context = parse_subsystem(state, nargs, args);
    165         if (state->context) {
    166             state->parse_line = parse_line_subsystem;
    167             return;
    168         }
    169         break;
    170     }
    171     state->parse_line = parse_line_no_op;
    172 }
    173 
    174 static void parse_line(struct parse_state *state, char **args, int nargs)
    175 {
    176     int kw = lookup_keyword(args[0]);
    177     int kw_nargs = kw_nargs(kw);
    178 
    179     if (nargs < kw_nargs) {
    180         parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
    181             kw_nargs > 2 ? "arguments" : "argument");
    182         return;
    183     }
    184 
    185     if (kw_is(kw, SECTION)) {
    186         parse_new_section(state, kw, nargs, args);
    187     } else if (kw_is(kw, OPTION)) {
    188         state->parse_line(state, nargs, args);
    189     } else {
    190         parse_line_device(state, nargs, args);
    191     }
    192 }
    193 
    194 static void parse_config(const char *fn, const std::string& data)
    195 {
    196     char *args[UEVENTD_PARSER_MAXARGS];
    197 
    198     int nargs = 0;
    199     parse_state state;
    200     state.filename = fn;
    201     state.line = 1;
    202     state.ptr = strdup(data.c_str());  // TODO: fix this code!
    203     state.nexttoken = 0;
    204     state.parse_line = parse_line_no_op;
    205     for (;;) {
    206         int token = next_token(&state);
    207         switch (token) {
    208         case T_EOF:
    209             parse_line(&state, args, nargs);
    210             return;
    211         case T_NEWLINE:
    212             if (nargs) {
    213                 parse_line(&state, args, nargs);
    214                 nargs = 0;
    215             }
    216             state.line++;
    217             break;
    218         case T_TEXT:
    219             if (nargs < UEVENTD_PARSER_MAXARGS) {
    220                 args[nargs++] = state.text;
    221             }
    222             break;
    223         }
    224     }
    225 }
    226 
    227 int ueventd_parse_config_file(const char *fn)
    228 {
    229     std::string data;
    230     if (!read_file(fn, &data)) {
    231         return -1;
    232     }
    233 
    234     data.push_back('\n'); // TODO: fix parse_config.
    235     parse_config(fn, data);
    236     return 0;
    237 }
    238 
    239 static void parse_line_device(parse_state*, int nargs, char** args) {
    240     set_device_permission(nargs, args);
    241 }
    242