blob: f54a90ba04228ecbf8c21fdec6e92a0c65d6001e [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{
Greg Hackmann3312aa82013-11-18 15:24:40 -0800103 if (!valid_name(args[1])) {
104 parse_error(state, "invalid subsystem name '%s'\n", args[1]);
105 return 0;
106 }
107
Elliott Hughesf3cf4382015-02-03 17:12:07 -0800108 ueventd_subsystem* s = ueventd_subsystem_find_by_name(args[1]);
Greg Hackmann3312aa82013-11-18 15:24:40 -0800109 if (s) {
110 parse_error(state, "ignored duplicate definition of subsystem '%s'\n",
111 args[1]);
112 return 0;
113 }
114
Elliott Hughesf3cf4382015-02-03 17:12:07 -0800115 s = (ueventd_subsystem*) calloc(1, sizeof(*s));
Greg Hackmann3312aa82013-11-18 15:24:40 -0800116 if (!s) {
117 parse_error(state, "out of memory\n");
118 return 0;
119 }
120 s->name = args[1];
121 s->dirname = "/dev";
122 list_add_tail(&subsystem_list, &s->slist);
123 return s;
124}
125
126static void parse_line_subsystem(struct parse_state *state, int nargs,
127 char **args)
128{
Elliott Hughesf3cf4382015-02-03 17:12:07 -0800129 struct ueventd_subsystem *s = (ueventd_subsystem*) state->context;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800130 int kw;
131
132 if (nargs == 0) {
133 return;
134 }
135
136 kw = lookup_keyword(args[0]);
137 switch (kw) {
138 case K_devname:
139 if (!strcmp(args[1], "uevent_devname"))
140 s->devname_src = DEVNAME_UEVENT_DEVNAME;
141 else if (!strcmp(args[1], "uevent_devpath"))
142 s->devname_src = DEVNAME_UEVENT_DEVPATH;
143 else
144 parse_error(state, "invalid devname '%s'\n", args[1]);
145 break;
146
147 case K_dirname:
148 if (args[1][0] == '/')
149 s->dirname = args[1];
150 else
151 parse_error(state, "dirname '%s' does not start with '/'\n",
152 args[1]);
153 break;
154
155 default:
156 parse_error(state, "invalid option '%s'\n", args[0]);
157 }
158}
159
160static void parse_new_section(struct parse_state *state, int kw,
161 int nargs, char **args)
162{
163 printf("[ %s %s ]\n", args[0],
164 nargs > 1 ? args[1] : "");
165
166 switch(kw) {
167 case K_subsystem:
168 state->context = parse_subsystem(state, nargs, args);
169 if (state->context) {
170 state->parse_line = parse_line_subsystem;
171 return;
172 }
173 break;
174 }
175 state->parse_line = parse_line_no_op;
176}
177
178static void parse_line(struct parse_state *state, char **args, int nargs)
179{
180 int kw = lookup_keyword(args[0]);
181 int kw_nargs = kw_nargs(kw);
182
183 if (nargs < kw_nargs) {
184 parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
185 kw_nargs > 2 ? "arguments" : "argument");
186 return;
187 }
188
189 if (kw_is(kw, SECTION)) {
190 parse_new_section(state, kw, nargs, args);
191 } else if (kw_is(kw, OPTION)) {
192 state->parse_line(state, nargs, args);
193 } else {
194 parse_line_device(state, nargs, args);
195 }
196}
197
Colin Cross44b65d02010-04-20 14:32:50 -0700198static void parse_config(const char *fn, char *s)
199{
200 struct parse_state state;
201 char *args[UEVENTD_PARSER_MAXARGS];
202 int nargs;
203 nargs = 0;
204 state.filename = fn;
205 state.line = 1;
206 state.ptr = s;
207 state.nexttoken = 0;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800208 state.parse_line = parse_line_no_op;
Colin Cross44b65d02010-04-20 14:32:50 -0700209 for (;;) {
210 int token = next_token(&state);
211 switch (token) {
212 case T_EOF:
Greg Hackmann3312aa82013-11-18 15:24:40 -0800213 parse_line(&state, args, nargs);
Colin Cross44b65d02010-04-20 14:32:50 -0700214 return;
215 case T_NEWLINE:
216 if (nargs) {
Greg Hackmann3312aa82013-11-18 15:24:40 -0800217 parse_line(&state, args, nargs);
Colin Cross44b65d02010-04-20 14:32:50 -0700218 nargs = 0;
219 }
Greg Hackmann3312aa82013-11-18 15:24:40 -0800220 state.line++;
Colin Cross44b65d02010-04-20 14:32:50 -0700221 break;
222 case T_TEXT:
223 if (nargs < UEVENTD_PARSER_MAXARGS) {
224 args[nargs++] = state.text;
225 }
226 break;
227 }
228 }
229}
230
231int ueventd_parse_config_file(const char *fn)
232{
233 char *data;
234 data = read_file(fn, 0);
235 if (!data) return -1;
236
237 parse_config(fn, data);
238 DUMP();
239 return 0;
240}
241
Greg Hackmann3312aa82013-11-18 15:24:40 -0800242static void parse_line_device(struct parse_state *state __attribute__((unused)),
243 int nargs, char **args)
Colin Cross44b65d02010-04-20 14:32:50 -0700244{
245 set_device_permission(nargs, args);
246}