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