• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 * state,int nargs,char ** args)70 static void parse_line_no_op(struct parse_state *state __attribute__((unused)),
71         int nargs __attribute__((unused)), char **args  __attribute__((unused)))
72 {
73 }
74 
valid_name(const char * name)75 static 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 
ueventd_subsystem_find_by_name(const char * name)86 struct 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 
parse_subsystem(struct parse_state * state,int nargs,char ** args)100 static 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 
parse_line_subsystem(struct parse_state * state,int nargs,char ** args)128 static 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 
parse_new_section(struct parse_state * state,int kw,int nargs,char ** args)162 static 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 
parse_line(struct parse_state * state,char ** args,int nargs)180 static 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 
parse_config(const char * fn,char * s)200 static 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;
210     state.parse_line = parse_line_no_op;
211     for (;;) {
212         int token = next_token(&state);
213         switch (token) {
214         case T_EOF:
215             parse_line(&state, args, nargs);
216             return;
217         case T_NEWLINE:
218             if (nargs) {
219                 parse_line(&state, args, nargs);
220                 nargs = 0;
221             }
222             state.line++;
223             break;
224         case T_TEXT:
225             if (nargs < UEVENTD_PARSER_MAXARGS) {
226                 args[nargs++] = state.text;
227             }
228             break;
229         }
230     }
231 }
232 
ueventd_parse_config_file(const char * fn)233 int 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 
parse_line_device(struct parse_state * state,int nargs,char ** args)244 static void parse_line_device(struct parse_state *state __attribute__((unused)),
245         int nargs, char **args)
246 {
247     set_device_permission(nargs, args);
248 }
249