blob: 3ed1d585bc375bc2ba512c76b0c7ec50edfcf92b [file] [log] [blame]
Colin Cross6310a822010-04-20 14:29:05 -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
Elliott Hughesda40c002015-03-27 23:20:44 -070017#include <ctype.h>
Lee Campbellf13b1b32015-07-24 16:57:14 -070018#include <dirent.h>
Elliott Hughes8d82ea02015-02-06 20:15:18 -080019#include <errno.h>
Elliott Hughesda40c002015-03-27 23:20:44 -070020#include <fcntl.h>
21#include <inttypes.h>
22#include <stdarg.h>
23#include <stddef.h>
Colin Cross6310a822010-04-20 14:29:05 -070024#include <stdio.h>
25#include <stdlib.h>
Colin Cross6310a822010-04-20 14:29:05 -070026#include <string.h>
Elliott Hughesda40c002015-03-27 23:20:44 -070027#include <unistd.h>
Colin Cross6310a822010-04-20 14:29:05 -070028
Tom Cherryfa0c21c2015-07-23 17:53:11 -070029#include "action.h"
Colin Cross6310a822010-04-20 14:29:05 -070030#include "init.h"
Colin Cross6310a822010-04-20 14:29:05 -070031#include "init_parser.h"
32#include "log.h"
Tom Cherrybac32992015-07-31 12:45:25 -070033#include "parser.h"
Colin Cross6310a822010-04-20 14:29:05 -070034#include "property_service.h"
Tom Cherrybac32992015-07-31 12:45:25 -070035#include "service.h"
Colin Cross6310a822010-04-20 14:29:05 -070036#include "util.h"
37
Lee Campbellf13b1b32015-07-24 16:57:14 -070038#include <base/stringprintf.h>
Colin Cross6310a822010-04-20 14:29:05 -070039#include <cutils/iosched_policy.h>
Dima Zavinda04c522011-09-01 17:09:44 -070040#include <cutils/list.h>
Colin Cross6310a822010-04-20 14:29:05 -070041
Colin Cross6310a822010-04-20 14:29:05 -070042static list_declare(service_list);
Colin Cross6310a822010-04-20 14:29:05 -070043
Dima Zavin78a1b1f2011-12-20 12:53:48 -080044struct import {
45 struct listnode list;
46 const char *filename;
47};
48
Colin Cross6310a822010-04-20 14:29:05 -070049static void *parse_service(struct parse_state *state, int nargs, char **args);
50static void parse_line_service(struct parse_state *state, int nargs, char **args);
51
52static void *parse_action(struct parse_state *state, int nargs, char **args);
53static void parse_line_action(struct parse_state *state, int nargs, char **args);
54
55#define SECTION 0x01
56#define COMMAND 0x02
57#define OPTION 0x04
58
59#include "keywords.h"
60
61#define KEYWORD(symbol, flags, nargs, func) \
62 [ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
63
Greg Hackmannd68db712013-11-18 09:44:20 -080064static struct {
Colin Cross6310a822010-04-20 14:29:05 -070065 const char *name;
Tom Cherry96f67312015-07-30 13:52:55 -070066 int (*func)(const std::vector<std::string>& args);
Tom Cherrybac32992015-07-31 12:45:25 -070067 size_t nargs;
Colin Cross6310a822010-04-20 14:29:05 -070068 unsigned char flags;
69} keyword_info[KEYWORD_COUNT] = {
70 [ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
71#include "keywords.h"
72};
73#undef KEYWORD
74
75#define kw_is(kw, type) (keyword_info[kw].flags & (type))
76#define kw_name(kw) (keyword_info[kw].name)
77#define kw_func(kw) (keyword_info[kw].func)
78#define kw_nargs(kw) (keyword_info[kw].nargs)
79
Elliott Hughesc0e919c2015-02-04 14:46:36 -080080void dump_parser_state() {
Tom Cherrybac32992015-07-31 12:45:25 -070081 ServiceManager::GetInstance().DumpState();
82 ActionManager::GetInstance().DumpState();
Elliott Hughesc0e919c2015-02-04 14:46:36 -080083}
84
Greg Hackmannd68db712013-11-18 09:44:20 -080085static int lookup_keyword(const char *s)
Colin Cross6310a822010-04-20 14:29:05 -070086{
87 switch (*s++) {
Yongqin Liua197ff12014-12-05 13:45:02 +080088 case 'b':
89 if (!strcmp(s, "ootchart_init")) return K_bootchart_init;
Mark Salyzyn7a3d66c2015-03-24 07:29:22 -070090 break;
Colin Cross6310a822010-04-20 14:29:05 -070091 case 'c':
Elliott Hughesf682b472015-02-06 12:19:48 -080092 if (!strcmp(s, "opy")) return K_copy;
Colin Cross6310a822010-04-20 14:29:05 -070093 if (!strcmp(s, "lass")) return K_class;
94 if (!strcmp(s, "lass_start")) return K_class_start;
95 if (!strcmp(s, "lass_stop")) return K_class_stop;
Ken Sumrall752923c2010-12-03 16:33:31 -080096 if (!strcmp(s, "lass_reset")) return K_class_reset;
Colin Cross6310a822010-04-20 14:29:05 -070097 if (!strcmp(s, "onsole")) return K_console;
98 if (!strcmp(s, "hown")) return K_chown;
99 if (!strcmp(s, "hmod")) return K_chmod;
100 if (!strcmp(s, "ritical")) return K_critical;
101 break;
102 case 'd':
103 if (!strcmp(s, "isabled")) return K_disabled;
104 if (!strcmp(s, "omainname")) return K_domainname;
105 break;
106 case 'e':
JP Abgrall3beec7e2014-05-02 21:14:29 -0700107 if (!strcmp(s, "nable")) return K_enable;
Colin Cross6310a822010-04-20 14:29:05 -0700108 if (!strcmp(s, "xec")) return K_exec;
109 if (!strcmp(s, "xport")) return K_export;
110 break;
111 case 'g':
112 if (!strcmp(s, "roup")) return K_group;
113 break;
114 case 'h':
115 if (!strcmp(s, "ostname")) return K_hostname;
116 break;
117 case 'i':
118 if (!strcmp(s, "oprio")) return K_ioprio;
119 if (!strcmp(s, "fup")) return K_ifup;
120 if (!strcmp(s, "nsmod")) return K_insmod;
121 if (!strcmp(s, "mport")) return K_import;
Paul Lawrenceb8c9d272015-03-26 15:49:42 +0000122 if (!strcmp(s, "nstallkey")) return K_installkey;
Colin Cross6310a822010-04-20 14:29:05 -0700123 break;
124 case 'k':
125 if (!strcmp(s, "eycodes")) return K_keycodes;
126 break;
127 case 'l':
128 if (!strcmp(s, "oglevel")) return K_loglevel;
Ken Sumrallc5c51032011-03-08 17:01:29 -0800129 if (!strcmp(s, "oad_persist_props")) return K_load_persist_props;
Riley Andrewse4b7b292014-06-16 15:06:21 -0700130 if (!strcmp(s, "oad_all_props")) return K_load_all_props;
Colin Cross6310a822010-04-20 14:29:05 -0700131 break;
132 case 'm':
133 if (!strcmp(s, "kdir")) return K_mkdir;
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700134 if (!strcmp(s, "ount_all")) return K_mount_all;
Colin Cross6310a822010-04-20 14:29:05 -0700135 if (!strcmp(s, "ount")) return K_mount;
136 break;
137 case 'o':
138 if (!strcmp(s, "n")) return K_on;
139 if (!strcmp(s, "neshot")) return K_oneshot;
140 if (!strcmp(s, "nrestart")) return K_onrestart;
141 break;
Nick Kralevichca8e66a2013-04-18 12:20:02 -0700142 case 'p':
143 if (!strcmp(s, "owerctl")) return K_powerctl;
Elliott Hughesf682b472015-02-06 12:19:48 -0800144 break;
Colin Cross6310a822010-04-20 14:29:05 -0700145 case 'r':
146 if (!strcmp(s, "estart")) return K_restart;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500147 if (!strcmp(s, "estorecon")) return K_restorecon;
Stephen Smalley726e8f72013-10-09 16:02:09 -0400148 if (!strcmp(s, "estorecon_recursive")) return K_restorecon_recursive;
Ken Sumrall203bad52011-01-18 17:37:41 -0800149 if (!strcmp(s, "mdir")) return K_rmdir;
150 if (!strcmp(s, "m")) return K_rm;
Colin Cross6310a822010-04-20 14:29:05 -0700151 break;
152 case 's':
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500153 if (!strcmp(s, "eclabel")) return K_seclabel;
Colin Cross6310a822010-04-20 14:29:05 -0700154 if (!strcmp(s, "ervice")) return K_service;
155 if (!strcmp(s, "etenv")) return K_setenv;
Colin Cross6310a822010-04-20 14:29:05 -0700156 if (!strcmp(s, "etprop")) return K_setprop;
157 if (!strcmp(s, "etrlimit")) return K_setrlimit;
158 if (!strcmp(s, "ocket")) return K_socket;
159 if (!strcmp(s, "tart")) return K_start;
160 if (!strcmp(s, "top")) return K_stop;
Ken Sumralla76baaa2013-07-09 18:42:09 -0700161 if (!strcmp(s, "wapon_all")) return K_swapon_all;
Colin Cross6310a822010-04-20 14:29:05 -0700162 if (!strcmp(s, "ymlink")) return K_symlink;
163 if (!strcmp(s, "ysclktz")) return K_sysclktz;
164 break;
165 case 't':
166 if (!strcmp(s, "rigger")) return K_trigger;
167 break;
168 case 'u':
169 if (!strcmp(s, "ser")) return K_user;
170 break;
Sami Tolvanen8ff01902015-02-16 11:03:34 +0000171 case 'v':
172 if (!strcmp(s, "erity_load_state")) return K_verity_load_state;
Sami Tolvanenacbf9be2015-03-19 10:00:34 +0000173 if (!strcmp(s, "erity_update_state")) return K_verity_update_state;
Sami Tolvanen8ff01902015-02-16 11:03:34 +0000174 break;
Colin Cross6310a822010-04-20 14:29:05 -0700175 case 'w':
176 if (!strcmp(s, "rite")) return K_write;
Elliott Hughesd62f0602015-06-12 18:02:20 -0700177 if (!strcmp(s, "ritepid")) return K_writepid;
Colin Cross6310a822010-04-20 14:29:05 -0700178 if (!strcmp(s, "ait")) return K_wait;
179 break;
180 }
181 return K_UNKNOWN;
182}
183
Elliott Hughesf682b472015-02-06 12:19:48 -0800184static void parse_line_no_op(struct parse_state*, int, char**) {
Colin Cross6310a822010-04-20 14:29:05 -0700185}
186
Tom Cherryfa0c21c2015-07-23 17:53:11 -0700187int expand_props(const std::string& src, std::string* dst) {
188 const char *src_ptr = src.c_str();
Dima Zavina6235ea2011-12-16 14:20:12 -0800189
Tom Cherryfa0c21c2015-07-23 17:53:11 -0700190 if (!dst) {
Dima Zavina6235ea2011-12-16 14:20:12 -0800191 return -1;
Yabin Cui00ede7d2015-07-24 13:26:04 -0700192 }
Dima Zavina6235ea2011-12-16 14:20:12 -0800193
Dima Zavina6235ea2011-12-16 14:20:12 -0800194 /* - variables can either be $x.y or ${x.y}, in case they are only part
195 * of the string.
196 * - will accept $$ as a literal $.
197 * - no nested property expansion, i.e. ${foo.${bar}} is not supported,
198 * bad things will happen
199 */
Yabin Cui00ede7d2015-07-24 13:26:04 -0700200 while (*src_ptr) {
201 const char *c;
Dima Zavina6235ea2011-12-16 14:20:12 -0800202
203 c = strchr(src_ptr, '$');
204 if (!c) {
Yabin Cui00ede7d2015-07-24 13:26:04 -0700205 dst->append(src_ptr);
Dima Zavina6235ea2011-12-16 14:20:12 -0800206 break;
207 }
208
Yabin Cui00ede7d2015-07-24 13:26:04 -0700209 dst->append(src_ptr, c);
Dima Zavina6235ea2011-12-16 14:20:12 -0800210 c++;
211
212 if (*c == '$') {
Yabin Cui00ede7d2015-07-24 13:26:04 -0700213 dst->push_back(*(c++));
Dima Zavina6235ea2011-12-16 14:20:12 -0800214 src_ptr = c;
Dima Zavina6235ea2011-12-16 14:20:12 -0800215 continue;
216 } else if (*c == '\0') {
217 break;
218 }
219
Yabin Cui00ede7d2015-07-24 13:26:04 -0700220 std::string prop_name;
Dima Zavina6235ea2011-12-16 14:20:12 -0800221 if (*c == '{') {
222 c++;
Yabin Cui00ede7d2015-07-24 13:26:04 -0700223 const char* end = strchr(c, '}');
224 if (!end) {
225 // failed to find closing brace, abort.
Tom Cherryfa0c21c2015-07-23 17:53:11 -0700226 ERROR("unexpected end of string in '%s', looking for }\n", src.c_str());
Dima Zavina6235ea2011-12-16 14:20:12 -0800227 goto err;
228 }
Yabin Cui00ede7d2015-07-24 13:26:04 -0700229 prop_name = std::string(c, end);
230 c = end + 1;
231 } else {
232 prop_name = c;
Dima Zavina6235ea2011-12-16 14:20:12 -0800233 ERROR("using deprecated syntax for specifying property '%s', use ${name} instead\n",
Yabin Cui00ede7d2015-07-24 13:26:04 -0700234 c);
235 c += prop_name.size();
Dima Zavina6235ea2011-12-16 14:20:12 -0800236 }
237
Yabin Cui00ede7d2015-07-24 13:26:04 -0700238 if (prop_name.empty()) {
Tom Cherryfa0c21c2015-07-23 17:53:11 -0700239 ERROR("invalid zero-length prop name in '%s'\n", src.c_str());
Dima Zavina6235ea2011-12-16 14:20:12 -0800240 goto err;
241 }
242
Yabin Cui00ede7d2015-07-24 13:26:04 -0700243 std::string prop_val = property_get(prop_name.c_str());
Yabin Cui74edcea2015-07-24 10:11:05 -0700244 if (prop_val.empty()) {
Dima Zavina6235ea2011-12-16 14:20:12 -0800245 ERROR("property '%s' doesn't exist while expanding '%s'\n",
Tom Cherryfa0c21c2015-07-23 17:53:11 -0700246 prop_name.c_str(), src.c_str());
Dima Zavina6235ea2011-12-16 14:20:12 -0800247 goto err;
248 }
249
Yabin Cui00ede7d2015-07-24 13:26:04 -0700250 dst->append(prop_val);
Dima Zavina6235ea2011-12-16 14:20:12 -0800251 src_ptr = c;
252 continue;
253 }
254
Dima Zavina6235ea2011-12-16 14:20:12 -0800255 return 0;
Dima Zavina6235ea2011-12-16 14:20:12 -0800256err:
257 return -1;
258}
259
Greg Hackmannd68db712013-11-18 09:44:20 -0800260static void parse_import(struct parse_state *state, int nargs, char **args)
Dima Zavin78a1b1f2011-12-20 12:53:48 -0800261{
Dima Zavin78a1b1f2011-12-20 12:53:48 -0800262 if (nargs != 2) {
263 ERROR("single argument needed for import\n");
264 return;
265 }
266
Yabin Cui00ede7d2015-07-24 13:26:04 -0700267 std::string conf_file;
268 int ret = expand_props(args[1], &conf_file);
Dima Zavin78a1b1f2011-12-20 12:53:48 -0800269 if (ret) {
270 ERROR("error while handling import on line '%d' in '%s'\n",
271 state->line, state->filename);
272 return;
273 }
274
Elliott Hughesf3cf4382015-02-03 17:12:07 -0800275 struct import* import = (struct import*) calloc(1, sizeof(struct import));
Yabin Cui00ede7d2015-07-24 13:26:04 -0700276 import->filename = strdup(conf_file.c_str());
277
278 struct listnode *import_list = (listnode*) state->priv;
Dima Zavin78a1b1f2011-12-20 12:53:48 -0800279 list_add_tail(import_list, &import->list);
Elliott Hughesda40c002015-03-27 23:20:44 -0700280 INFO("Added '%s' to import list\n", import->filename);
Dima Zavin78a1b1f2011-12-20 12:53:48 -0800281}
282
Greg Hackmannd68db712013-11-18 09:44:20 -0800283static void parse_new_section(struct parse_state *state, int kw,
Colin Cross6310a822010-04-20 14:29:05 -0700284 int nargs, char **args)
285{
286 printf("[ %s %s ]\n", args[0],
287 nargs > 1 ? args[1] : "");
288 switch(kw) {
289 case K_service:
290 state->context = parse_service(state, nargs, args);
291 if (state->context) {
292 state->parse_line = parse_line_service;
293 return;
294 }
295 break;
296 case K_on:
297 state->context = parse_action(state, nargs, args);
298 if (state->context) {
299 state->parse_line = parse_line_action;
300 return;
301 }
302 break;
Mike Lockwoodf5cb5b22011-06-07 20:08:40 -0700303 case K_import:
Dima Zavin78a1b1f2011-12-20 12:53:48 -0800304 parse_import(state, nargs, args);
Dima Zavina6235ea2011-12-16 14:20:12 -0800305 break;
Colin Cross6310a822010-04-20 14:29:05 -0700306 }
307 state->parse_line = parse_line_no_op;
308}
309
Elliott Hughesf682b472015-02-06 12:19:48 -0800310static void parse_config(const char *fn, const std::string& data)
Colin Cross6310a822010-04-20 14:29:05 -0700311{
Dima Zavin78a1b1f2011-12-20 12:53:48 -0800312 struct listnode import_list;
313 struct listnode *node;
Colin Cross6310a822010-04-20 14:29:05 -0700314 char *args[INIT_PARSER_MAXARGS];
Colin Cross6310a822010-04-20 14:29:05 -0700315
Tom Cherryeaa3b4e2015-05-12 13:54:41 -0700316 int nargs = 0;
317
318 parse_state state;
Colin Cross6310a822010-04-20 14:29:05 -0700319 state.filename = fn;
Bruce Beare1be69682010-12-26 09:55:10 -0800320 state.line = 0;
Elliott Hughesf682b472015-02-06 12:19:48 -0800321 state.ptr = strdup(data.c_str()); // TODO: fix this code!
Colin Cross6310a822010-04-20 14:29:05 -0700322 state.nexttoken = 0;
323 state.parse_line = parse_line_no_op;
Dima Zavin78a1b1f2011-12-20 12:53:48 -0800324
325 list_init(&import_list);
326 state.priv = &import_list;
327
Colin Cross6310a822010-04-20 14:29:05 -0700328 for (;;) {
329 switch (next_token(&state)) {
330 case T_EOF:
331 state.parse_line(&state, 0, 0);
Dima Zavin78a1b1f2011-12-20 12:53:48 -0800332 goto parser_done;
Colin Cross6310a822010-04-20 14:29:05 -0700333 case T_NEWLINE:
Bruce Beare1be69682010-12-26 09:55:10 -0800334 state.line++;
Colin Cross6310a822010-04-20 14:29:05 -0700335 if (nargs) {
336 int kw = lookup_keyword(args[0]);
337 if (kw_is(kw, SECTION)) {
338 state.parse_line(&state, 0, 0);
339 parse_new_section(&state, kw, nargs, args);
340 } else {
341 state.parse_line(&state, nargs, args);
342 }
343 nargs = 0;
344 }
345 break;
346 case T_TEXT:
347 if (nargs < INIT_PARSER_MAXARGS) {
348 args[nargs++] = state.text;
349 }
350 break;
351 }
352 }
Dima Zavin78a1b1f2011-12-20 12:53:48 -0800353
354parser_done:
355 list_for_each(node, &import_list) {
Elliott Hughese5ce30f2015-05-06 19:19:24 -0700356 struct import* import = node_to_item(node, struct import, list);
Lee Campbellf13b1b32015-07-24 16:57:14 -0700357 if (!init_parse_config(import->filename)) {
Elliott Hughese5ce30f2015-05-06 19:19:24 -0700358 ERROR("could not import file '%s' from '%s': %s\n",
359 import->filename, fn, strerror(errno));
360 }
Dima Zavin78a1b1f2011-12-20 12:53:48 -0800361 }
Colin Cross6310a822010-04-20 14:29:05 -0700362}
363
Lee Campbellf13b1b32015-07-24 16:57:14 -0700364static bool init_parse_config_file(const char* path) {
365 INFO("Parsing file %s...\n", path);
Elliott Hughesda40c002015-03-27 23:20:44 -0700366 Timer t;
Elliott Hughesf682b472015-02-06 12:19:48 -0800367 std::string data;
368 if (!read_file(path, &data)) {
Elliott Hughese5ce30f2015-05-06 19:19:24 -0700369 return false;
Elliott Hughesf682b472015-02-06 12:19:48 -0800370 }
Colin Cross6310a822010-04-20 14:29:05 -0700371
Tom Cherryeaa3b4e2015-05-12 13:54:41 -0700372 data.push_back('\n'); // TODO: fix parse_config.
Elliott Hughesf682b472015-02-06 12:19:48 -0800373 parse_config(path, data);
Elliott Hughesc0e919c2015-02-04 14:46:36 -0800374 dump_parser_state();
Elliott Hughesda40c002015-03-27 23:20:44 -0700375
376 NOTICE("(Parsing %s took %.2fs.)\n", path, t.duration());
Elliott Hughese5ce30f2015-05-06 19:19:24 -0700377 return true;
Colin Cross6310a822010-04-20 14:29:05 -0700378}
379
Lee Campbellf13b1b32015-07-24 16:57:14 -0700380static bool init_parse_config_dir(const char* path) {
381 INFO("Parsing directory %s...\n", path);
382 std::unique_ptr<DIR, int(*)(DIR*)> config_dir(opendir(path), closedir);
383 if (!config_dir) {
384 ERROR("Could not import directory '%s'\n", path);
385 return false;
386 }
387 dirent* current_file;
388 while ((current_file = readdir(config_dir.get()))) {
389 std::string current_path =
390 android::base::StringPrintf("%s/%s", path, current_file->d_name);
391 // Ignore directories and only process regular files.
392 if (current_file->d_type == DT_REG) {
393 if (!init_parse_config_file(current_path.c_str())) {
394 ERROR("could not import file '%s'\n", current_path.c_str());
395 }
396 }
397 }
398 return true;
399}
400
401bool init_parse_config(const char* path) {
402 if (is_dir(path)) {
403 return init_parse_config_dir(path);
404 }
405 return init_parse_config_file(path);
406}
407
Colin Cross6310a822010-04-20 14:29:05 -0700408static void *parse_service(struct parse_state *state, int nargs, char **args)
409{
Colin Cross6310a822010-04-20 14:29:05 -0700410 if (nargs < 3) {
411 parse_error(state, "services must have a name and a program\n");
Tom Cherrybac32992015-07-31 12:45:25 -0700412 return nullptr;
Colin Cross6310a822010-04-20 14:29:05 -0700413 }
Tom Cherrybac32992015-07-31 12:45:25 -0700414 std::vector<std::string> str_args(args + 2, args + nargs);
415 std::string ret_err;
416 Service* svc = ServiceManager::GetInstance().AddNewService(args[1], "default",
417 str_args, &ret_err);
Colin Cross6310a822010-04-20 14:29:05 -0700418
Colin Cross6310a822010-04-20 14:29:05 -0700419 if (!svc) {
Tom Cherrybac32992015-07-31 12:45:25 -0700420 parse_error(state, "%s\n", ret_err.c_str());
Colin Cross6310a822010-04-20 14:29:05 -0700421 }
Tom Cherrybac32992015-07-31 12:45:25 -0700422
Colin Cross6310a822010-04-20 14:29:05 -0700423 return svc;
424}
425
426static void parse_line_service(struct parse_state *state, int nargs, char **args)
427{
Colin Cross6310a822010-04-20 14:29:05 -0700428 if (nargs == 0) {
429 return;
430 }
431
Tom Cherrybac32992015-07-31 12:45:25 -0700432 Service* svc = static_cast<Service*>(state->context);
433 int kw = lookup_keyword(args[0]);
434 std::vector<std::string> str_args(args, args + nargs);
435 std::string ret_err;
436 bool ret = svc->HandleLine(kw, str_args, &ret_err);
Colin Cross6310a822010-04-20 14:29:05 -0700437
Tom Cherrybac32992015-07-31 12:45:25 -0700438 if (!ret) {
439 parse_error(state, "%s\n", ret_err.c_str());
Colin Cross6310a822010-04-20 14:29:05 -0700440 }
441}
442
Tom Cherryfa0c21c2015-07-23 17:53:11 -0700443static void *parse_action(struct parse_state* state, int nargs, char **args)
Colin Cross6310a822010-04-20 14:29:05 -0700444{
Tom Cherryfa0c21c2015-07-23 17:53:11 -0700445 std::string ret_err;
446 std::vector<std::string> triggers(args + 1, args + nargs);
447 Action* ret = ActionManager::GetInstance().AddNewAction(triggers, &ret_err);
448
449 if (!ret) {
450 parse_error(state, "%s\n", ret_err.c_str());
Colin Cross6310a822010-04-20 14:29:05 -0700451 }
Badhri Jagan Sridharan0b415122014-10-10 23:19:06 -0700452
Tom Cherryfa0c21c2015-07-23 17:53:11 -0700453 return ret;
Colin Cross6310a822010-04-20 14:29:05 -0700454}
455
Tom Cherrybac32992015-07-31 12:45:25 -0700456bool add_command_to_action(Action* action, const std::vector<std::string>& args,
457 const std::string& filename, int line, std::string* err)
458{
459 int kw;
460 size_t n;
461
462 kw = lookup_keyword(args[0].c_str());
463 if (!kw_is(kw, COMMAND)) {
464 *err = android::base::StringPrintf("invalid command '%s'\n", args[0].c_str());
465 return false;
466 }
467
468 n = kw_nargs(kw);
469 if (args.size() < n) {
470 *err = android::base::StringPrintf("%s requires %zu %s\n",
471 args[0].c_str(), n - 1,
472 n > 2 ? "arguments" : "argument");
473 return false;
474 }
475
476 action->AddCommand(kw_func(kw), args, filename, line);
477 return true;
478}
479
Colin Cross6310a822010-04-20 14:29:05 -0700480static void parse_line_action(struct parse_state* state, int nargs, char **args)
481{
Colin Cross6310a822010-04-20 14:29:05 -0700482 if (nargs == 0) {
483 return;
484 }
485
Tom Cherrybac32992015-07-31 12:45:25 -0700486 Action* action = static_cast<Action*>(state->context);
Tom Cherryfa0c21c2015-07-23 17:53:11 -0700487 std::vector<std::string> str_args(args, args + nargs);
Tom Cherrybac32992015-07-31 12:45:25 -0700488 std::string ret_err;
489 bool ret = add_command_to_action(action, str_args, state->filename,
490 state->line, &ret_err);
491 if (!ret) {
492 parse_error(state, "%s\n", ret_err.c_str());
493 }
Colin Cross6310a822010-04-20 14:29:05 -0700494}