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