blob: baff58c3642066d5fbfbcf3b6e72def733e53ab5 [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) \
Chih-Hung Hsiehc713bce2016-05-18 15:59:37 -070041 [ K_##symbol ] = { #symbol, (nargs) + 1, flags, },
Greg Hackmann3312aa82013-11-18 15:24:40 -080042
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
Elliott Hughesf682b472015-02-06 12:19:48 -080070static void parse_line_no_op(struct parse_state*, int, char**) {
Greg Hackmann3312aa82013-11-18 15:24:40 -080071}
72
73static 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
84struct 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
Elliott Hughesf682b472015-02-06 12:19:48 -080098static void *parse_subsystem(parse_state* state, int /*nargs*/, char** args) {
Greg Hackmann3312aa82013-11-18 15:24:40 -080099 if (!valid_name(args[1])) {
100 parse_error(state, "invalid subsystem name '%s'\n", args[1]);
101 return 0;
102 }
103
Elliott Hughesf3cf4382015-02-03 17:12:07 -0800104 ueventd_subsystem* s = ueventd_subsystem_find_by_name(args[1]);
Greg Hackmann3312aa82013-11-18 15:24:40 -0800105 if (s) {
106 parse_error(state, "ignored duplicate definition of subsystem '%s'\n",
107 args[1]);
108 return 0;
109 }
110
Elliott Hughesf3cf4382015-02-03 17:12:07 -0800111 s = (ueventd_subsystem*) calloc(1, sizeof(*s));
Greg Hackmann3312aa82013-11-18 15:24:40 -0800112 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
122static void parse_line_subsystem(struct parse_state *state, int nargs,
123 char **args)
124{
Elliott Hughesf3cf4382015-02-03 17:12:07 -0800125 struct ueventd_subsystem *s = (ueventd_subsystem*) state->context;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800126 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
156static 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
174static 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
Elliott Hughesf682b472015-02-06 12:19:48 -0800194static void parse_config(const char *fn, const std::string& data)
Colin Cross44b65d02010-04-20 14:32:50 -0700195{
Colin Cross44b65d02010-04-20 14:32:50 -0700196 char *args[UEVENTD_PARSER_MAXARGS];
Tom Cherryeaa3b4e2015-05-12 13:54:41 -0700197
198 int nargs = 0;
199 parse_state state;
Colin Cross44b65d02010-04-20 14:32:50 -0700200 state.filename = fn;
201 state.line = 1;
Elliott Hughesf682b472015-02-06 12:19:48 -0800202 state.ptr = strdup(data.c_str()); // TODO: fix this code!
Colin Cross44b65d02010-04-20 14:32:50 -0700203 state.nexttoken = 0;
Greg Hackmann3312aa82013-11-18 15:24:40 -0800204 state.parse_line = parse_line_no_op;
Colin Cross44b65d02010-04-20 14:32:50 -0700205 for (;;) {
206 int token = next_token(&state);
207 switch (token) {
208 case T_EOF:
Greg Hackmann3312aa82013-11-18 15:24:40 -0800209 parse_line(&state, args, nargs);
Colin Cross44b65d02010-04-20 14:32:50 -0700210 return;
211 case T_NEWLINE:
212 if (nargs) {
Greg Hackmann3312aa82013-11-18 15:24:40 -0800213 parse_line(&state, args, nargs);
Colin Cross44b65d02010-04-20 14:32:50 -0700214 nargs = 0;
215 }
Greg Hackmann3312aa82013-11-18 15:24:40 -0800216 state.line++;
Colin Cross44b65d02010-04-20 14:32:50 -0700217 break;
218 case T_TEXT:
219 if (nargs < UEVENTD_PARSER_MAXARGS) {
220 args[nargs++] = state.text;
221 }
222 break;
223 }
224 }
225}
226
227int ueventd_parse_config_file(const char *fn)
228{
Elliott Hughesf682b472015-02-06 12:19:48 -0800229 std::string data;
230 if (!read_file(fn, &data)) {
231 return -1;
232 }
Colin Cross44b65d02010-04-20 14:32:50 -0700233
Tom Cherryeaa3b4e2015-05-12 13:54:41 -0700234 data.push_back('\n'); // TODO: fix parse_config.
Colin Cross44b65d02010-04-20 14:32:50 -0700235 parse_config(fn, data);
Colin Cross44b65d02010-04-20 14:32:50 -0700236 return 0;
237}
238
Elliott Hughesf682b472015-02-06 12:19:48 -0800239static void parse_line_device(parse_state*, int nargs, char** args) {
Colin Cross44b65d02010-04-20 14:32:50 -0700240 set_device_permission(nargs, args);
241}