• 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 <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_system_props")) return K_load_system_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, "etusercryptopolicies")) return K_setusercryptopolicies;
191         if (!strcmp(s, "ocket")) return K_socket;
192         if (!strcmp(s, "tart")) return K_start;
193         if (!strcmp(s, "top")) return K_stop;
194         if (!strcmp(s, "wapon_all")) return K_swapon_all;
195         if (!strcmp(s, "ymlink")) return K_symlink;
196         if (!strcmp(s, "ysclktz")) return K_sysclktz;
197         break;
198     case 't':
199         if (!strcmp(s, "rigger")) return K_trigger;
200         break;
201     case 'u':
202         if (!strcmp(s, "ser")) return K_user;
203         break;
204     case 'v':
205         if (!strcmp(s, "erity_load_state")) return K_verity_load_state;
206         if (!strcmp(s, "erity_update_state")) return K_verity_update_state;
207         break;
208     case 'w':
209         if (!strcmp(s, "rite")) return K_write;
210         if (!strcmp(s, "ritepid")) return K_writepid;
211         if (!strcmp(s, "ait")) return K_wait;
212         break;
213     }
214     return K_UNKNOWN;
215 }
216 
parse_line_no_op(struct parse_state *,int,char **)217 static void parse_line_no_op(struct parse_state*, int, char**) {
218 }
219 
push_chars(char ** dst,int * len,const char * chars,int cnt)220 static int push_chars(char **dst, int *len, const char *chars, int cnt)
221 {
222     if (cnt > *len)
223         return -1;
224 
225     memcpy(*dst, chars, cnt);
226     *dst += cnt;
227     *len -= cnt;
228 
229     return 0;
230 }
231 
expand_props(char * dst,const char * src,int dst_size)232 int expand_props(char *dst, const char *src, int dst_size)
233 {
234     char *dst_ptr = dst;
235     const char *src_ptr = src;
236     int ret = 0;
237     int left = dst_size - 1;
238 
239     if (!src || !dst || dst_size == 0)
240         return -1;
241 
242     /* - variables can either be $x.y or ${x.y}, in case they are only part
243      *   of the string.
244      * - will accept $$ as a literal $.
245      * - no nested property expansion, i.e. ${foo.${bar}} is not supported,
246      *   bad things will happen
247      */
248     while (*src_ptr && left > 0) {
249         char *c;
250         char prop[PROP_NAME_MAX + 1];
251         char prop_val[PROP_VALUE_MAX];
252         int prop_len = 0;
253         int prop_val_len;
254 
255         c = strchr(src_ptr, '$');
256         if (!c) {
257             while (left-- > 0 && *src_ptr)
258                 *(dst_ptr++) = *(src_ptr++);
259             break;
260         }
261 
262         memset(prop, 0, sizeof(prop));
263 
264         ret = push_chars(&dst_ptr, &left, src_ptr, c - src_ptr);
265         if (ret < 0)
266             goto err_nospace;
267         c++;
268 
269         if (*c == '$') {
270             *(dst_ptr++) = *(c++);
271             src_ptr = c;
272             left--;
273             continue;
274         } else if (*c == '\0') {
275             break;
276         }
277 
278         if (*c == '{') {
279             c++;
280             while (*c && *c != '}' && prop_len < PROP_NAME_MAX)
281                 prop[prop_len++] = *(c++);
282             if (*c != '}') {
283                 /* failed to find closing brace, abort. */
284                 if (prop_len == PROP_NAME_MAX)
285                     ERROR("prop name too long during expansion of '%s'\n",
286                           src);
287                 else if (*c == '\0')
288                     ERROR("unexpected end of string in '%s', looking for }\n",
289                           src);
290                 goto err;
291             }
292             prop[prop_len] = '\0';
293             c++;
294         } else if (*c) {
295             while (*c && prop_len < PROP_NAME_MAX)
296                 prop[prop_len++] = *(c++);
297             if (prop_len == PROP_NAME_MAX && *c != '\0') {
298                 ERROR("prop name too long in '%s'\n", src);
299                 goto err;
300             }
301             prop[prop_len] = '\0';
302             ERROR("using deprecated syntax for specifying property '%s', use ${name} instead\n",
303                   prop);
304         }
305 
306         if (prop_len == 0) {
307             ERROR("invalid zero-length prop name in '%s'\n", src);
308             goto err;
309         }
310 
311         prop_val_len = property_get(prop, prop_val);
312         if (!prop_val_len) {
313             ERROR("property '%s' doesn't exist while expanding '%s'\n",
314                   prop, src);
315             goto err;
316         }
317 
318         ret = push_chars(&dst_ptr, &left, prop_val, prop_val_len);
319         if (ret < 0)
320             goto err_nospace;
321         src_ptr = c;
322         continue;
323     }
324 
325     *dst_ptr = '\0';
326     return 0;
327 
328 err_nospace:
329     ERROR("destination buffer overflow while expanding '%s'\n", src);
330 err:
331     return -1;
332 }
333 
parse_import(struct parse_state * state,int nargs,char ** args)334 static void parse_import(struct parse_state *state, int nargs, char **args)
335 {
336     struct listnode *import_list = (listnode*) state->priv;
337     char conf_file[PATH_MAX];
338     int ret;
339 
340     if (nargs != 2) {
341         ERROR("single argument needed for import\n");
342         return;
343     }
344 
345     ret = expand_props(conf_file, args[1], sizeof(conf_file));
346     if (ret) {
347         ERROR("error while handling import on line '%d' in '%s'\n",
348               state->line, state->filename);
349         return;
350     }
351 
352     struct import* import = (struct import*) calloc(1, sizeof(struct import));
353     import->filename = strdup(conf_file);
354     list_add_tail(import_list, &import->list);
355     INFO("Added '%s' to import list\n", import->filename);
356 }
357 
parse_new_section(struct parse_state * state,int kw,int nargs,char ** args)358 static void parse_new_section(struct parse_state *state, int kw,
359                        int nargs, char **args)
360 {
361     printf("[ %s %s ]\n", args[0],
362            nargs > 1 ? args[1] : "");
363     switch(kw) {
364     case K_service:
365         state->context = parse_service(state, nargs, args);
366         if (state->context) {
367             state->parse_line = parse_line_service;
368             return;
369         }
370         break;
371     case K_on:
372         state->context = parse_action(state, nargs, args);
373         if (state->context) {
374             state->parse_line = parse_line_action;
375             return;
376         }
377         break;
378     case K_import:
379         parse_import(state, nargs, args);
380         break;
381     }
382     state->parse_line = parse_line_no_op;
383 }
384 
parse_config(const char * fn,const std::string & data)385 static void parse_config(const char *fn, const std::string& data)
386 {
387     struct listnode import_list;
388     struct listnode *node;
389     char *args[INIT_PARSER_MAXARGS];
390 
391     int nargs = 0;
392 
393     parse_state state;
394     state.filename = fn;
395     state.line = 0;
396     state.ptr = strdup(data.c_str());  // TODO: fix this code!
397     state.nexttoken = 0;
398     state.parse_line = parse_line_no_op;
399 
400     list_init(&import_list);
401     state.priv = &import_list;
402 
403     for (;;) {
404         switch (next_token(&state)) {
405         case T_EOF:
406             state.parse_line(&state, 0, 0);
407             goto parser_done;
408         case T_NEWLINE:
409             state.line++;
410             if (nargs) {
411                 int kw = lookup_keyword(args[0]);
412                 if (kw_is(kw, SECTION)) {
413                     state.parse_line(&state, 0, 0);
414                     parse_new_section(&state, kw, nargs, args);
415                 } else {
416                     state.parse_line(&state, nargs, args);
417                 }
418                 nargs = 0;
419             }
420             break;
421         case T_TEXT:
422             if (nargs < INIT_PARSER_MAXARGS) {
423                 args[nargs++] = state.text;
424             }
425             break;
426         }
427     }
428 
429 parser_done:
430     list_for_each(node, &import_list) {
431          struct import *import = node_to_item(node, struct import, list);
432          int ret;
433 
434          ret = init_parse_config_file(import->filename);
435          if (ret)
436              ERROR("could not import file '%s' from '%s'\n",
437                    import->filename, fn);
438     }
439 }
440 
init_parse_config_file(const char * path)441 int init_parse_config_file(const char* path) {
442     INFO("Parsing %s...\n", path);
443     Timer t;
444     std::string data;
445     if (!read_file(path, &data)) {
446         return -1;
447     }
448 
449     data.push_back('\n'); // TODO: fix parse_config.
450     parse_config(path, data);
451     dump_parser_state();
452 
453     NOTICE("(Parsing %s took %.2fs.)\n", path, t.duration());
454     return 0;
455 }
456 
valid_name(const char * name)457 static int valid_name(const char *name)
458 {
459     if (strlen(name) > 16) {
460         return 0;
461     }
462     while (*name) {
463         if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
464             return 0;
465         }
466         name++;
467     }
468     return 1;
469 }
470 
service_find_by_name(const char * name)471 struct service *service_find_by_name(const char *name)
472 {
473     struct listnode *node;
474     struct service *svc;
475     list_for_each(node, &service_list) {
476         svc = node_to_item(node, struct service, slist);
477         if (!strcmp(svc->name, name)) {
478             return svc;
479         }
480     }
481     return 0;
482 }
483 
service_find_by_pid(pid_t pid)484 struct service *service_find_by_pid(pid_t pid)
485 {
486     struct listnode *node;
487     struct service *svc;
488     list_for_each(node, &service_list) {
489         svc = node_to_item(node, struct service, slist);
490         if (svc->pid == pid) {
491             return svc;
492         }
493     }
494     return 0;
495 }
496 
service_find_by_keychord(int keychord_id)497 struct service *service_find_by_keychord(int keychord_id)
498 {
499     struct listnode *node;
500     struct service *svc;
501     list_for_each(node, &service_list) {
502         svc = node_to_item(node, struct service, slist);
503         if (svc->keychord_id == keychord_id) {
504             return svc;
505         }
506     }
507     return 0;
508 }
509 
service_for_each(void (* func)(struct service * svc))510 void service_for_each(void (*func)(struct service *svc))
511 {
512     struct listnode *node;
513     struct service *svc;
514     list_for_each(node, &service_list) {
515         svc = node_to_item(node, struct service, slist);
516         func(svc);
517     }
518 }
519 
service_for_each_class(const char * classname,void (* func)(struct service * svc))520 void service_for_each_class(const char *classname,
521                             void (*func)(struct service *svc))
522 {
523     struct listnode *node;
524     struct service *svc;
525     list_for_each(node, &service_list) {
526         svc = node_to_item(node, struct service, slist);
527         if (!strcmp(svc->classname, classname)) {
528             func(svc);
529         }
530     }
531 }
532 
service_for_each_flags(unsigned matchflags,void (* func)(struct service * svc))533 void service_for_each_flags(unsigned matchflags,
534                             void (*func)(struct service *svc))
535 {
536     struct listnode *node;
537     struct service *svc;
538     list_for_each(node, &service_list) {
539         svc = node_to_item(node, struct service, slist);
540         if (svc->flags & matchflags) {
541             func(svc);
542         }
543     }
544 }
545 
action_for_each_trigger(const char * trigger,void (* func)(struct action * act))546 void action_for_each_trigger(const char *trigger,
547                              void (*func)(struct action *act))
548 {
549     struct listnode *node, *node2;
550     struct action *act;
551     struct trigger *cur_trigger;
552 
553     list_for_each(node, &action_list) {
554         act = node_to_item(node, struct action, alist);
555         list_for_each(node2, &act->triggers) {
556             cur_trigger = node_to_item(node2, struct trigger, nlist);
557             if (!strcmp(cur_trigger->name, trigger)) {
558                 func(act);
559             }
560         }
561     }
562 }
563 
564 
queue_property_triggers(const char * name,const char * value)565 void queue_property_triggers(const char *name, const char *value)
566 {
567     struct listnode *node, *node2;
568     struct action *act;
569     struct trigger *cur_trigger;
570     bool match;
571     int name_length;
572 
573     list_for_each(node, &action_list) {
574         act = node_to_item(node, struct action, alist);
575         match = !name;
576         list_for_each(node2, &act->triggers) {
577             cur_trigger = node_to_item(node2, struct trigger, nlist);
578             if (!strncmp(cur_trigger->name, "property:", strlen("property:"))) {
579                 const char *test = cur_trigger->name + strlen("property:");
580                 if (!match) {
581                     name_length = strlen(name);
582                     if (!strncmp(name, test, name_length) &&
583                         test[name_length] == '=' &&
584                         (!strcmp(test + name_length + 1, value) ||
585                         !strcmp(test + name_length + 1, "*"))) {
586                         match = true;
587                         continue;
588                     }
589                 }
590                 const char* equals = strchr(test, '=');
591                 if (equals) {
592                     char prop_name[PROP_NAME_MAX + 1];
593                     char value[PROP_VALUE_MAX];
594                     int length = equals - test;
595                     if (length <= PROP_NAME_MAX) {
596                         int ret;
597                         memcpy(prop_name, test, length);
598                         prop_name[length] = 0;
599 
600                         /* does the property exist, and match the trigger value? */
601                         ret = property_get(prop_name, value);
602                         if (ret > 0 && (!strcmp(equals + 1, value) ||
603                                         !strcmp(equals + 1, "*"))) {
604                             continue;
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