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 <fcntl.h>
20 #include <inttypes.h>
21 #include <stdarg.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #include "init.h"
29 #include "parser.h"
30 #include "init_parser.h"
31 #include "log.h"
32 #include "property_service.h"
33 #include "util.h"
34 
35 #include <cutils/iosched_policy.h>
36 #include <cutils/list.h>
37 
38 static list_declare(service_list);
39 static list_declare(action_list);
40 static list_declare(action_queue);
41 
42 struct import {
43     struct listnode list;
44     const char *filename;
45 };
46 
47 static void *parse_service(struct parse_state *state, int nargs, char **args);
48 static void parse_line_service(struct parse_state *state, int nargs, char **args);
49 
50 static void *parse_action(struct parse_state *state, int nargs, char **args);
51 static void parse_line_action(struct parse_state *state, int nargs, char **args);
52 
53 #define SECTION 0x01
54 #define COMMAND 0x02
55 #define OPTION  0x04
56 
57 #include "keywords.h"
58 
59 #define KEYWORD(symbol, flags, nargs, func) \
60     [ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
61 
62 static struct {
63     const char *name;
64     int (*func)(int nargs, char **args);
65     unsigned char nargs;
66     unsigned char flags;
67 } keyword_info[KEYWORD_COUNT] = {
68     [ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
69 #include "keywords.h"
70 };
71 #undef KEYWORD
72 
73 #define kw_is(kw, type) (keyword_info[kw].flags & (type))
74 #define kw_name(kw) (keyword_info[kw].name)
75 #define kw_func(kw) (keyword_info[kw].func)
76 #define kw_nargs(kw) (keyword_info[kw].nargs)
77 
dump_parser_state()78 void dump_parser_state() {
79     if (false) {
80         struct listnode* node;
81         list_for_each(node, &service_list) {
82             service* svc = node_to_item(node, struct service, slist);
83             INFO("service %s\n", svc->name);
84             INFO("  class '%s'\n", svc->classname);
85             INFO("  exec");
86             for (int n = 0; n < svc->nargs; n++) {
87                 INFO(" '%s'", svc->args[n]);
88             }
89             INFO("\n");
90             for (socketinfo* si = svc->sockets; si; si = si->next) {
91                 INFO("  socket %s %s 0%o\n", si->name, si->type, si->perm);
92             }
93         }
94 
95         list_for_each(node, &action_list) {
96             action* act = node_to_item(node, struct action, alist);
97             INFO("on ");
98             char name_str[256] = "";
99             build_triggers_string(name_str, sizeof(name_str), act);
100             INFO("%s", name_str);
101             INFO("\n");
102 
103             struct listnode* node2;
104             list_for_each(node2, &act->commands) {
105                 command* cmd = node_to_item(node2, struct command, clist);
106                 INFO("  %p", cmd->func);
107                 for (int n = 0; n < cmd->nargs; n++) {
108                     INFO(" %s", cmd->args[n]);
109                 }
110                 INFO("\n");
111             }
112             INFO("\n");
113         }
114     }
115 }
116 
lookup_keyword(const char * s)117 static int lookup_keyword(const char *s)
118 {
119     switch (*s++) {
120     case 'b':
121         if (!strcmp(s, "ootchart_init")) return K_bootchart_init;
122         break;
123     case 'c':
124         if (!strcmp(s, "opy")) return K_copy;
125         if (!strcmp(s, "lass")) return K_class;
126         if (!strcmp(s, "lass_start")) return K_class_start;
127         if (!strcmp(s, "lass_stop")) return K_class_stop;
128         if (!strcmp(s, "lass_reset")) return K_class_reset;
129         if (!strcmp(s, "onsole")) return K_console;
130         if (!strcmp(s, "hown")) return K_chown;
131         if (!strcmp(s, "hmod")) return K_chmod;
132         if (!strcmp(s, "ritical")) return K_critical;
133         break;
134     case 'd':
135         if (!strcmp(s, "isabled")) return K_disabled;
136         if (!strcmp(s, "omainname")) return K_domainname;
137         break;
138     case 'e':
139         if (!strcmp(s, "nable")) return K_enable;
140         if (!strcmp(s, "xec")) return K_exec;
141         if (!strcmp(s, "xport")) return K_export;
142         break;
143     case 'g':
144         if (!strcmp(s, "roup")) return K_group;
145         break;
146     case 'h':
147         if (!strcmp(s, "ostname")) return K_hostname;
148         break;
149     case 'i':
150         if (!strcmp(s, "oprio")) return K_ioprio;
151         if (!strcmp(s, "fup")) return K_ifup;
152         if (!strcmp(s, "nsmod")) return K_insmod;
153         if (!strcmp(s, "mport")) return K_import;
154         if (!strcmp(s, "nstallkey")) return K_installkey;
155         break;
156     case 'k':
157         if (!strcmp(s, "eycodes")) return K_keycodes;
158         break;
159     case 'l':
160         if (!strcmp(s, "oglevel")) return K_loglevel;
161         if (!strcmp(s, "oad_persist_props")) return K_load_persist_props;
162         if (!strcmp(s, "oad_all_props")) return K_load_all_props;
163         break;
164     case 'm':
165         if (!strcmp(s, "kdir")) return K_mkdir;
166         if (!strcmp(s, "ount_all")) return K_mount_all;
167         if (!strcmp(s, "ount")) return K_mount;
168         break;
169     case 'o':
170         if (!strcmp(s, "n")) return K_on;
171         if (!strcmp(s, "neshot")) return K_oneshot;
172         if (!strcmp(s, "nrestart")) return K_onrestart;
173         break;
174     case 'p':
175         if (!strcmp(s, "owerctl")) return K_powerctl;
176         break;
177     case 'r':
178         if (!strcmp(s, "estart")) return K_restart;
179         if (!strcmp(s, "estorecon")) return K_restorecon;
180         if (!strcmp(s, "estorecon_recursive")) return K_restorecon_recursive;
181         if (!strcmp(s, "mdir")) return K_rmdir;
182         if (!strcmp(s, "m")) return K_rm;
183         break;
184     case 's':
185         if (!strcmp(s, "eclabel")) return K_seclabel;
186         if (!strcmp(s, "ervice")) return K_service;
187         if (!strcmp(s, "etenv")) return K_setenv;
188         if (!strcmp(s, "etprop")) return K_setprop;
189         if (!strcmp(s, "etrlimit")) return K_setrlimit;
190         if (!strcmp(s, "ocket")) return K_socket;
191         if (!strcmp(s, "tart")) return K_start;
192         if (!strcmp(s, "top")) return K_stop;
193         if (!strcmp(s, "wapon_all")) return K_swapon_all;
194         if (!strcmp(s, "ymlink")) return K_symlink;
195         if (!strcmp(s, "ysclktz")) return K_sysclktz;
196         break;
197     case 't':
198         if (!strcmp(s, "rigger")) return K_trigger;
199         break;
200     case 'u':
201         if (!strcmp(s, "ser")) return K_user;
202         break;
203     case 'v':
204         if (!strcmp(s, "erity_load_state")) return K_verity_load_state;
205         if (!strcmp(s, "erity_update_state")) return K_verity_update_state;
206         break;
207     case 'w':
208         if (!strcmp(s, "rite")) return K_write;
209         if (!strcmp(s, "ritepid")) return K_writepid;
210         if (!strcmp(s, "ait")) return K_wait;
211         break;
212     }
213     return K_UNKNOWN;
214 }
215 
parse_line_no_op(struct parse_state *,int,char **)216 static void parse_line_no_op(struct parse_state*, int, char**) {
217 }
218 
push_chars(char ** dst,int * len,const char * chars,int cnt)219 static int push_chars(char **dst, int *len, const char *chars, int cnt)
220 {
221     if (cnt > *len)
222         return -1;
223 
224     memcpy(*dst, chars, cnt);
225     *dst += cnt;
226     *len -= cnt;
227 
228     return 0;
229 }
230 
expand_props(char * dst,const char * src,int dst_size)231 int expand_props(char *dst, const char *src, int dst_size)
232 {
233     char *dst_ptr = dst;
234     const char *src_ptr = src;
235     int ret = 0;
236     int left = dst_size - 1;
237 
238     if (!src || !dst || dst_size == 0)
239         return -1;
240 
241     /* - variables can either be $x.y or ${x.y}, in case they are only part
242      *   of the string.
243      * - will accept $$ as a literal $.
244      * - no nested property expansion, i.e. ${foo.${bar}} is not supported,
245      *   bad things will happen
246      */
247     while (*src_ptr && left > 0) {
248         char *c;
249         char prop[PROP_NAME_MAX + 1];
250         char prop_val[PROP_VALUE_MAX];
251         int prop_len = 0;
252         int prop_val_len;
253 
254         c = strchr(src_ptr, '$');
255         if (!c) {
256             while (left-- > 0 && *src_ptr)
257                 *(dst_ptr++) = *(src_ptr++);
258             break;
259         }
260 
261         memset(prop, 0, sizeof(prop));
262 
263         ret = push_chars(&dst_ptr, &left, src_ptr, c - src_ptr);
264         if (ret < 0)
265             goto err_nospace;
266         c++;
267 
268         if (*c == '$') {
269             *(dst_ptr++) = *(c++);
270             src_ptr = c;
271             left--;
272             continue;
273         } else if (*c == '\0') {
274             break;
275         }
276 
277         if (*c == '{') {
278             c++;
279             while (*c && *c != '}' && prop_len < PROP_NAME_MAX)
280                 prop[prop_len++] = *(c++);
281             if (*c != '}') {
282                 /* failed to find closing brace, abort. */
283                 if (prop_len == PROP_NAME_MAX)
284                     ERROR("prop name too long during expansion of '%s'\n",
285                           src);
286                 else if (*c == '\0')
287                     ERROR("unexpected end of string in '%s', looking for }\n",
288                           src);
289                 goto err;
290             }
291             prop[prop_len] = '\0';
292             c++;
293         } else if (*c) {
294             while (*c && prop_len < PROP_NAME_MAX)
295                 prop[prop_len++] = *(c++);
296             if (prop_len == PROP_NAME_MAX && *c != '\0') {
297                 ERROR("prop name too long in '%s'\n", src);
298                 goto err;
299             }
300             prop[prop_len] = '\0';
301             ERROR("using deprecated syntax for specifying property '%s', use ${name} instead\n",
302                   prop);
303         }
304 
305         if (prop_len == 0) {
306             ERROR("invalid zero-length prop name in '%s'\n", src);
307             goto err;
308         }
309 
310         prop_val_len = property_get(prop, prop_val);
311         if (!prop_val_len) {
312             ERROR("property '%s' doesn't exist while expanding '%s'\n",
313                   prop, src);
314             goto err;
315         }
316 
317         ret = push_chars(&dst_ptr, &left, prop_val, prop_val_len);
318         if (ret < 0)
319             goto err_nospace;
320         src_ptr = c;
321         continue;
322     }
323 
324     *dst_ptr = '\0';
325     return 0;
326 
327 err_nospace:
328     ERROR("destination buffer overflow while expanding '%s'\n", src);
329 err:
330     return -1;
331 }
332 
parse_import(struct parse_state * state,int nargs,char ** args)333 static void parse_import(struct parse_state *state, int nargs, char **args)
334 {
335     struct listnode *import_list = (listnode*) state->priv;
336     char conf_file[PATH_MAX];
337     int ret;
338 
339     if (nargs != 2) {
340         ERROR("single argument needed for import\n");
341         return;
342     }
343 
344     ret = expand_props(conf_file, args[1], sizeof(conf_file));
345     if (ret) {
346         ERROR("error while handling import on line '%d' in '%s'\n",
347               state->line, state->filename);
348         return;
349     }
350 
351     struct import* import = (struct import*) calloc(1, sizeof(struct import));
352     import->filename = strdup(conf_file);
353     list_add_tail(import_list, &import->list);
354     INFO("Added '%s' to import list\n", import->filename);
355 }
356 
parse_new_section(struct parse_state * state,int kw,int nargs,char ** args)357 static void parse_new_section(struct parse_state *state, int kw,
358                        int nargs, char **args)
359 {
360     printf("[ %s %s ]\n", args[0],
361            nargs > 1 ? args[1] : "");
362     switch(kw) {
363     case K_service:
364         state->context = parse_service(state, nargs, args);
365         if (state->context) {
366             state->parse_line = parse_line_service;
367             return;
368         }
369         break;
370     case K_on:
371         state->context = parse_action(state, nargs, args);
372         if (state->context) {
373             state->parse_line = parse_line_action;
374             return;
375         }
376         break;
377     case K_import:
378         parse_import(state, nargs, args);
379         break;
380     }
381     state->parse_line = parse_line_no_op;
382 }
383 
parse_config(const char * fn,const std::string & data)384 static void parse_config(const char *fn, const std::string& data)
385 {
386     struct listnode import_list;
387     struct listnode *node;
388     char *args[INIT_PARSER_MAXARGS];
389 
390     int nargs = 0;
391 
392     parse_state state;
393     state.filename = fn;
394     state.line = 0;
395     state.ptr = strdup(data.c_str());  // TODO: fix this code!
396     state.nexttoken = 0;
397     state.parse_line = parse_line_no_op;
398 
399     list_init(&import_list);
400     state.priv = &import_list;
401 
402     for (;;) {
403         switch (next_token(&state)) {
404         case T_EOF:
405             state.parse_line(&state, 0, 0);
406             goto parser_done;
407         case T_NEWLINE:
408             state.line++;
409             if (nargs) {
410                 int kw = lookup_keyword(args[0]);
411                 if (kw_is(kw, SECTION)) {
412                     state.parse_line(&state, 0, 0);
413                     parse_new_section(&state, kw, nargs, args);
414                 } else {
415                     state.parse_line(&state, nargs, args);
416                 }
417                 nargs = 0;
418             }
419             break;
420         case T_TEXT:
421             if (nargs < INIT_PARSER_MAXARGS) {
422                 args[nargs++] = state.text;
423             }
424             break;
425         }
426     }
427 
428 parser_done:
429     list_for_each(node, &import_list) {
430          struct import *import = node_to_item(node, struct import, list);
431          int ret;
432 
433          ret = init_parse_config_file(import->filename);
434          if (ret)
435              ERROR("could not import file '%s' from '%s'\n",
436                    import->filename, fn);
437     }
438 }
439 
init_parse_config_file(const char * path)440 int init_parse_config_file(const char* path) {
441     INFO("Parsing %s...\n", path);
442     Timer t;
443     std::string data;
444     if (!read_file(path, &data)) {
445         return -1;
446     }
447 
448     data.push_back('\n'); // TODO: fix parse_config.
449     parse_config(path, data);
450     dump_parser_state();
451 
452     NOTICE("(Parsing %s took %.2fs.)\n", path, t.duration());
453     return 0;
454 }
455 
valid_name(const char * name)456 static int valid_name(const char *name)
457 {
458     if (strlen(name) > 16) {
459         return 0;
460     }
461     while (*name) {
462         if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
463             return 0;
464         }
465         name++;
466     }
467     return 1;
468 }
469 
service_find_by_name(const char * name)470 struct service *service_find_by_name(const char *name)
471 {
472     struct listnode *node;
473     struct service *svc;
474     list_for_each(node, &service_list) {
475         svc = node_to_item(node, struct service, slist);
476         if (!strcmp(svc->name, name)) {
477             return svc;
478         }
479     }
480     return 0;
481 }
482 
service_find_by_pid(pid_t pid)483 struct service *service_find_by_pid(pid_t pid)
484 {
485     struct listnode *node;
486     struct service *svc;
487     list_for_each(node, &service_list) {
488         svc = node_to_item(node, struct service, slist);
489         if (svc->pid == pid) {
490             return svc;
491         }
492     }
493     return 0;
494 }
495 
service_find_by_keychord(int keychord_id)496 struct service *service_find_by_keychord(int keychord_id)
497 {
498     struct listnode *node;
499     struct service *svc;
500     list_for_each(node, &service_list) {
501         svc = node_to_item(node, struct service, slist);
502         if (svc->keychord_id == keychord_id) {
503             return svc;
504         }
505     }
506     return 0;
507 }
508 
service_for_each(void (* func)(struct service * svc))509 void service_for_each(void (*func)(struct service *svc))
510 {
511     struct listnode *node;
512     struct service *svc;
513     list_for_each(node, &service_list) {
514         svc = node_to_item(node, struct service, slist);
515         func(svc);
516     }
517 }
518 
service_for_each_class(const char * classname,void (* func)(struct service * svc))519 void service_for_each_class(const char *classname,
520                             void (*func)(struct service *svc))
521 {
522     struct listnode *node;
523     struct service *svc;
524     list_for_each(node, &service_list) {
525         svc = node_to_item(node, struct service, slist);
526         if (!strcmp(svc->classname, classname)) {
527             func(svc);
528         }
529     }
530 }
531 
service_for_each_flags(unsigned matchflags,void (* func)(struct service * svc))532 void service_for_each_flags(unsigned matchflags,
533                             void (*func)(struct service *svc))
534 {
535     struct listnode *node;
536     struct service *svc;
537     list_for_each(node, &service_list) {
538         svc = node_to_item(node, struct service, slist);
539         if (svc->flags & matchflags) {
540             func(svc);
541         }
542     }
543 }
544 
action_for_each_trigger(const char * trigger,void (* func)(struct action * act))545 void action_for_each_trigger(const char *trigger,
546                              void (*func)(struct action *act))
547 {
548     struct listnode *node, *node2;
549     struct action *act;
550     struct trigger *cur_trigger;
551 
552     list_for_each(node, &action_list) {
553         act = node_to_item(node, struct action, alist);
554         list_for_each(node2, &act->triggers) {
555             cur_trigger = node_to_item(node2, struct trigger, nlist);
556             if (!strcmp(cur_trigger->name, trigger)) {
557                 func(act);
558             }
559         }
560     }
561 }
562 
563 
queue_property_triggers(const char * name,const char * value)564 void queue_property_triggers(const char *name, const char *value)
565 {
566     struct listnode *node, *node2;
567     struct action *act;
568     struct trigger *cur_trigger;
569     bool match;
570     int name_length;
571 
572     list_for_each(node, &action_list) {
573         act = node_to_item(node, struct action, alist);
574             match = !name;
575         list_for_each(node2, &act->triggers) {
576             cur_trigger = node_to_item(node2, struct trigger, nlist);
577             if (!strncmp(cur_trigger->name, "property:", strlen("property:"))) {
578                 const char *test = cur_trigger->name + strlen("property:");
579                 if (!match) {
580                     name_length = strlen(name);
581                     if (!strncmp(name, test, name_length) &&
582                         test[name_length] == '=' &&
583                         (!strcmp(test + name_length + 1, value) ||
584                         !strcmp(test + name_length + 1, "*"))) {
585                         match = true;
586                         continue;
587                     }
588                 } else {
589                      const char* equals = strchr(test, '=');
590                      if (equals) {
591                          char prop_name[PROP_NAME_MAX + 1];
592                          char value[PROP_VALUE_MAX];
593                          int length = equals - test;
594                          if (length <= PROP_NAME_MAX) {
595                              int ret;
596                              memcpy(prop_name, test, length);
597                              prop_name[length] = 0;
598 
599                              /* does the property exist, and match the trigger value? */
600                              ret = property_get(prop_name, value);
601                              if (ret > 0 && (!strcmp(equals + 1, value) ||
602                                 !strcmp(equals + 1, "*"))) {
603                                  continue;
604                              }
605                          }
606                      }
607                  }
608              }
609              match = false;
610              break;
611         }
612         if (match) {
613             action_add_queue_tail(act);
614         }
615     }
616 }
617 
queue_all_property_triggers()618 void queue_all_property_triggers()
619 {
620     queue_property_triggers(NULL, NULL);
621 }
622 
queue_builtin_action(int (* func)(int nargs,char ** args),const char * name)623 void queue_builtin_action(int (*func)(int nargs, char **args), const char *name)
624 {
625     action* act = (action*) calloc(1, sizeof(*act));
626     trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
627     cur_trigger->name = name;
628     list_init(&act->triggers);
629     list_add_tail(&act->triggers, &cur_trigger->nlist);
630     list_init(&act->commands);
631     list_init(&act->qlist);
632 
633     command* cmd = (command*) calloc(1, sizeof(*cmd));
634     cmd->func = func;
635     cmd->args[0] = const_cast<char*>(name);
636     cmd->nargs = 1;
637     list_add_tail(&act->commands, &cmd->clist);
638 
639     list_add_tail(&action_list, &act->alist);
640     action_add_queue_tail(act);
641 }
642 
action_add_queue_tail(struct action * act)643 void action_add_queue_tail(struct action *act)
644 {
645     if (list_empty(&act->qlist)) {
646         list_add_tail(&action_queue, &act->qlist);
647     }
648 }
649 
action_remove_queue_head(void)650 struct action *action_remove_queue_head(void)
651 {
652     if (list_empty(&action_queue)) {
653         return 0;
654     } else {
655         struct listnode *node = list_head(&action_queue);
656         struct action *act = node_to_item(node, struct action, qlist);
657         list_remove(node);
658         list_init(node);
659         return act;
660     }
661 }
662 
action_queue_empty()663 int action_queue_empty()
664 {
665     return list_empty(&action_queue);
666 }
667 
make_exec_oneshot_service(int nargs,char ** args)668 service* make_exec_oneshot_service(int nargs, char** args) {
669     // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
670     // SECLABEL can be a - to denote default
671     int command_arg = 1;
672     for (int i = 1; i < nargs; ++i) {
673         if (strcmp(args[i], "--") == 0) {
674             command_arg = i + 1;
675             break;
676         }
677     }
678     if (command_arg > 4 + NR_SVC_SUPP_GIDS) {
679         ERROR("exec called with too many supplementary group ids\n");
680         return NULL;
681     }
682 
683     int argc = nargs - command_arg;
684     char** argv = (args + command_arg);
685     if (argc < 1) {
686         ERROR("exec called without command\n");
687         return NULL;
688     }
689 
690     service* svc = (service*) calloc(1, sizeof(*svc) + sizeof(char*) * argc);
691     if (svc == NULL) {
692         ERROR("Couldn't allocate service for exec of '%s': %s", argv[0], strerror(errno));
693         return NULL;
694     }
695 
696     if ((command_arg > 2) && strcmp(args[1], "-")) {
697         svc->seclabel = args[1];
698     }
699     if (command_arg > 3) {
700         svc->uid = decode_uid(args[2]);
701     }
702     if (command_arg > 4) {
703         svc->gid = decode_uid(args[3]);
704         svc->nr_supp_gids = command_arg - 1 /* -- */ - 4 /* exec SECLABEL UID GID */;
705         for (size_t i = 0; i < svc->nr_supp_gids; ++i) {
706             svc->supp_gids[i] = decode_uid(args[4 + i]);
707         }
708     }
709 
710     static int exec_count; // Every service needs a unique name.
711     char* name = NULL;
712     asprintf(&name, "exec %d (%s)", exec_count++, argv[0]);
713     if (name == NULL) {
714         ERROR("Couldn't allocate name for exec service '%s'\n", argv[0]);
715         free(svc);
716         return NULL;
717     }
718     svc->name = name;
719     svc->classname = "default";
720     svc->flags = SVC_EXEC | SVC_ONESHOT;
721     svc->nargs = argc;
722     memcpy(svc->args, argv, sizeof(char*) * svc->nargs);
723     svc->args[argc] = NULL;
724     list_add_tail(&service_list, &svc->slist);
725     return svc;
726 }
727 
parse_service(struct parse_state * state,int nargs,char ** args)728 static void *parse_service(struct parse_state *state, int nargs, char **args)
729 {
730     if (nargs < 3) {
731         parse_error(state, "services must have a name and a program\n");
732         return 0;
733     }
734     if (!valid_name(args[1])) {
735         parse_error(state, "invalid service name '%s'\n", args[1]);
736         return 0;
737     }
738 
739     service* svc = (service*) service_find_by_name(args[1]);
740     if (svc) {
741         parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
742         return 0;
743     }
744 
745     nargs -= 2;
746     svc = (service*) calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
747     if (!svc) {
748         parse_error(state, "out of memory\n");
749         return 0;
750     }
751     svc->name = strdup(args[1]);
752     svc->classname = "default";
753     memcpy(svc->args, args + 2, sizeof(char*) * nargs);
754     trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
755     svc->args[nargs] = 0;
756     svc->nargs = nargs;
757     list_init(&svc->onrestart.triggers);
758     cur_trigger->name = "onrestart";
759     list_add_tail(&svc->onrestart.triggers, &cur_trigger->nlist);
760     list_init(&svc->onrestart.commands);
761     list_add_tail(&service_list, &svc->slist);
762     return svc;
763 }
764 
parse_line_service(struct parse_state * state,int nargs,char ** args)765 static void parse_line_service(struct parse_state *state, int nargs, char **args)
766 {
767     struct service *svc = (service*) state->context;
768     struct command *cmd;
769     int i, kw, kw_nargs;
770 
771     if (nargs == 0) {
772         return;
773     }
774 
775     svc->ioprio_class = IoSchedClass_NONE;
776 
777     kw = lookup_keyword(args[0]);
778     switch (kw) {
779     case K_class:
780         if (nargs != 2) {
781             parse_error(state, "class option requires a classname\n");
782         } else {
783             svc->classname = args[1];
784         }
785         break;
786     case K_console:
787         svc->flags |= SVC_CONSOLE;
788         break;
789     case K_disabled:
790         svc->flags |= SVC_DISABLED;
791         svc->flags |= SVC_RC_DISABLED;
792         break;
793     case K_ioprio:
794         if (nargs != 3) {
795             parse_error(state, "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n");
796         } else {
797             svc->ioprio_pri = strtoul(args[2], 0, 8);
798 
799             if (svc->ioprio_pri < 0 || svc->ioprio_pri > 7) {
800                 parse_error(state, "priority value must be range 0 - 7\n");
801                 break;
802             }
803 
804             if (!strcmp(args[1], "rt")) {
805                 svc->ioprio_class = IoSchedClass_RT;
806             } else if (!strcmp(args[1], "be")) {
807                 svc->ioprio_class = IoSchedClass_BE;
808             } else if (!strcmp(args[1], "idle")) {
809                 svc->ioprio_class = IoSchedClass_IDLE;
810             } else {
811                 parse_error(state, "ioprio option usage: ioprio <rt|be|idle> <0-7>\n");
812             }
813         }
814         break;
815     case K_group:
816         if (nargs < 2) {
817             parse_error(state, "group option requires a group id\n");
818         } else if (nargs > NR_SVC_SUPP_GIDS + 2) {
819             parse_error(state, "group option accepts at most %d supp. groups\n",
820                         NR_SVC_SUPP_GIDS);
821         } else {
822             int n;
823             svc->gid = decode_uid(args[1]);
824             for (n = 2; n < nargs; n++) {
825                 svc->supp_gids[n-2] = decode_uid(args[n]);
826             }
827             svc->nr_supp_gids = n - 2;
828         }
829         break;
830     case K_keycodes:
831         if (nargs < 2) {
832             parse_error(state, "keycodes option requires atleast one keycode\n");
833         } else {
834             svc->keycodes = (int*) malloc((nargs - 1) * sizeof(svc->keycodes[0]));
835             if (!svc->keycodes) {
836                 parse_error(state, "could not allocate keycodes\n");
837             } else {
838                 svc->nkeycodes = nargs - 1;
839                 for (i = 1; i < nargs; i++) {
840                     svc->keycodes[i - 1] = atoi(args[i]);
841                 }
842             }
843         }
844         break;
845     case K_oneshot:
846         svc->flags |= SVC_ONESHOT;
847         break;
848     case K_onrestart:
849         nargs--;
850         args++;
851         kw = lookup_keyword(args[0]);
852         if (!kw_is(kw, COMMAND)) {
853             parse_error(state, "invalid command '%s'\n", args[0]);
854             break;
855         }
856         kw_nargs = kw_nargs(kw);
857         if (nargs < kw_nargs) {
858             parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
859                 kw_nargs > 2 ? "arguments" : "argument");
860             break;
861         }
862 
863         cmd = (command*) malloc(sizeof(*cmd) + sizeof(char*) * nargs);
864         cmd->func = kw_func(kw);
865         cmd->nargs = nargs;
866         memcpy(cmd->args, args, sizeof(char*) * nargs);
867         list_add_tail(&svc->onrestart.commands, &cmd->clist);
868         break;
869     case K_critical:
870         svc->flags |= SVC_CRITICAL;
871         break;
872     case K_setenv: { /* name value */
873         if (nargs < 3) {
874             parse_error(state, "setenv option requires name and value arguments\n");
875             break;
876         }
877         svcenvinfo* ei = (svcenvinfo*) calloc(1, sizeof(*ei));
878         if (!ei) {
879             parse_error(state, "out of memory\n");
880             break;
881         }
882         ei->name = args[1];
883         ei->value = args[2];
884         ei->next = svc->envvars;
885         svc->envvars = ei;
886         break;
887     }
888     case K_socket: {/* name type perm [ uid gid context ] */
889         if (nargs < 4) {
890             parse_error(state, "socket option requires name, type, perm arguments\n");
891             break;
892         }
893         if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")
894                 && strcmp(args[2],"seqpacket")) {
895             parse_error(state, "socket type must be 'dgram', 'stream' or 'seqpacket'\n");
896             break;
897         }
898         socketinfo* si = (socketinfo*) calloc(1, sizeof(*si));
899         if (!si) {
900             parse_error(state, "out of memory\n");
901             break;
902         }
903         si->name = args[1];
904         si->type = args[2];
905         si->perm = strtoul(args[3], 0, 8);
906         if (nargs > 4)
907             si->uid = decode_uid(args[4]);
908         if (nargs > 5)
909             si->gid = decode_uid(args[5]);
910         if (nargs > 6)
911             si->socketcon = args[6];
912         si->next = svc->sockets;
913         svc->sockets = si;
914         break;
915     }
916     case K_user:
917         if (nargs != 2) {
918             parse_error(state, "user option requires a user id\n");
919         } else {
920             svc->uid = decode_uid(args[1]);
921         }
922         break;
923     case K_seclabel:
924         if (nargs != 2) {
925             parse_error(state, "seclabel option requires a label string\n");
926         } else {
927             svc->seclabel = args[1];
928         }
929         break;
930     case K_writepid:
931         if (nargs < 2) {
932             parse_error(state, "writepid option requires at least one filename\n");
933             break;
934         }
935         svc->writepid_files_ = new std::vector<std::string>;
936         for (int i = 1; i < nargs; ++i) {
937             svc->writepid_files_->push_back(args[i]);
938         }
939         break;
940 
941     default:
942         parse_error(state, "invalid option '%s'\n", args[0]);
943     }
944 }
945 
parse_action(struct parse_state * state,int nargs,char ** args)946 static void *parse_action(struct parse_state *state, int nargs, char **args)
947 {
948     struct trigger *cur_trigger;
949     int i;
950     if (nargs < 2) {
951         parse_error(state, "actions must have a trigger\n");
952         return 0;
953     }
954 
955     action* act = (action*) calloc(1, sizeof(*act));
956     list_init(&act->triggers);
957 
958     for (i = 1; i < nargs; i++) {
959         if (!(i % 2)) {
960             if (strcmp(args[i], "&&")) {
961                 struct listnode *node;
962                 struct listnode *node2;
963                 parse_error(state, "& is the only symbol allowed to concatenate actions\n");
964                 list_for_each_safe(node, node2, &act->triggers) {
965                     struct trigger *trigger = node_to_item(node, struct trigger, nlist);
966                     free(trigger);
967                 }
968                 free(act);
969                 return 0;
970             } else
971                 continue;
972         }
973         cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
974         cur_trigger->name = args[i];
975         list_add_tail(&act->triggers, &cur_trigger->nlist);
976     }
977 
978     list_init(&act->commands);
979     list_init(&act->qlist);
980     list_add_tail(&action_list, &act->alist);
981         /* XXX add to hash */
982     return act;
983 }
984 
parse_line_action(struct parse_state * state,int nargs,char ** args)985 static void parse_line_action(struct parse_state* state, int nargs, char **args)
986 {
987     struct action *act = (action*) state->context;
988     int kw, n;
989 
990     if (nargs == 0) {
991         return;
992     }
993 
994     kw = lookup_keyword(args[0]);
995     if (!kw_is(kw, COMMAND)) {
996         parse_error(state, "invalid command '%s'\n", args[0]);
997         return;
998     }
999 
1000     n = kw_nargs(kw);
1001     if (nargs < n) {
1002         parse_error(state, "%s requires %d %s\n", args[0], n - 1,
1003             n > 2 ? "arguments" : "argument");
1004         return;
1005     }
1006     command* cmd = (command*) malloc(sizeof(*cmd) + sizeof(char*) * nargs);
1007     cmd->func = kw_func(kw);
1008     cmd->line = state->line;
1009     cmd->filename = state->filename;
1010     cmd->nargs = nargs;
1011     memcpy(cmd->args, args, sizeof(char*) * nargs);
1012     list_add_tail(&act->commands, &cmd->clist);
1013 }
1014