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
lookup_keyword(const char * s)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
parse_line_no_op(struct parse_state *,int,char **)70 static void parse_line_no_op(struct parse_state*, int, char**) {
71 }
72
valid_name(const char * name)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
ueventd_subsystem_find_by_name(const char * name)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
parse_subsystem(parse_state * state,int,char ** args)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
parse_line_subsystem(struct parse_state * state,int nargs,char ** args)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
parse_new_section(struct parse_state * state,int kw,int nargs,char ** args)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
parse_line(struct parse_state * state,char ** args,int nargs)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
parse_config(const char * fn,const std::string & data)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
ueventd_parse_config_file(const char * fn)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 dump_parser_state();
237 return 0;
238 }
239
parse_line_device(parse_state *,int nargs,char ** args)240 static void parse_line_device(parse_state*, int nargs, char** args) {
241 set_device_permission(nargs, args);
242 }
243