blob: e447006e58db2549c91ace802a31c33701f7210e [file] [log] [blame]
Colin Cross44b65d02010-04-20 14:32:50 -07001/*
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
Greg Hackmann3312aa82013-11-18 15:24:40 -080017#include <ctype.h>
18#include <errno.h>
Colin Cross44b65d02010-04-20 14:32:50 -070019#include <stdio.h>
20#include <unistd.h>
21#include <stdarg.h>
Greg Hackmann3312aa82013-11-18 15:24:40 -080022#include <stdlib.h>
Colin Cross44b65d02010-04-20 14:32:50 -070023#include <string.h>
24
Greg Hackmann3312aa82013-11-18 15:24:40 -080025#include "ueventd.h"
Colin Cross44b65d02010-04-20 14:32:50 -070026#include "ueventd_parser.h"
27#include "parser.h"
28#include "log.h"
Colin Cross44b65d02010-04-20 14:32:50 -070029#include "util.h"
30
Greg Hackmann3312aa82013-11-18 15:24:40 -080031static list_declare(subsystem_list);
32
Colin Cross44b65d02010-04-20 14:32:50 -070033static void parse_line_device(struct parse_state *state, int nargs, char **args);
34
Greg Hackmann3312aa82013-11-18 15:24:40 -080035#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
43static 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
56static 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
70static void parse_line_no_op(struct parse_state *state __attribute__((unused)),
71 int nargs __attribute__((unused)), char **args __attribute__((unused)))
72{
73}
74
75static 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
86struct 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
100static 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
128static 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
162static 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
180static 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
Colin Cross44b65d02010-04-20 14:32:50 -0700200static 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;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800210 state.parse_line = parse_line_no_op;
Colin Cross44b65d02010-04-20 14:32:50 -0700211 for (;;) {
212 int token = next_token(&state);
213 switch (token) {
214 case T_EOF:
Greg Hackmann3312aa82013-11-18 15:24:40 -0800215 parse_line(&state, args, nargs);
Colin Cross44b65d02010-04-20 14:32:50 -0700216 return;
217 case T_NEWLINE:
218 if (nargs) {
Greg Hackmann3312aa82013-11-18 15:24:40 -0800219 parse_line(&state, args, nargs);
Colin Cross44b65d02010-04-20 14:32:50 -0700220 nargs = 0;
221 }
Greg Hackmann3312aa82013-11-18 15:24:40 -0800222 state.line++;
Colin Cross44b65d02010-04-20 14:32:50 -0700223 break;
224 case T_TEXT:
225 if (nargs < UEVENTD_PARSER_MAXARGS) {
226 args[nargs++] = state.text;
227 }
228 break;
229 }
230 }
231}
232
233int 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
Greg Hackmann3312aa82013-11-18 15:24:40 -0800244static void parse_line_device(struct parse_state *state __attribute__((unused)),
245 int nargs, char **args)
Colin Cross44b65d02010-04-20 14:32:50 -0700246{
247 set_device_permission(nargs, args);
248}