• 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     list_init(&act->qlist);
575 
576     cmd = calloc(1, sizeof(*cmd));
577     cmd->func = func;
578     cmd->args[0] = name;
579     list_add_tail(&act->commands, &cmd->clist);
580 
581     list_add_tail(&action_list, &act->alist);
582     action_add_queue_tail(act);
583 }
584 
action_add_queue_tail(struct action * act)585 void action_add_queue_tail(struct action *act)
586 {
587     if (list_empty(&act->qlist)) {
588         list_add_tail(&action_queue, &act->qlist);
589     }
590 }
591 
action_remove_queue_head(void)592 struct action *action_remove_queue_head(void)
593 {
594     if (list_empty(&action_queue)) {
595         return 0;
596     } else {
597         struct listnode *node = list_head(&action_queue);
598         struct action *act = node_to_item(node, struct action, qlist);
599         list_remove(node);
600         list_init(node);
601         return act;
602     }
603 }
604 
action_queue_empty()605 int action_queue_empty()
606 {
607     return list_empty(&action_queue);
608 }
609 
parse_service(struct parse_state * state,int nargs,char ** args)610 static void *parse_service(struct parse_state *state, int nargs, char **args)
611 {
612     struct service *svc;
613     if (nargs < 3) {
614         parse_error(state, "services must have a name and a program\n");
615         return 0;
616     }
617     if (!valid_name(args[1])) {
618         parse_error(state, "invalid service name '%s'\n", args[1]);
619         return 0;
620     }
621 
622     svc = service_find_by_name(args[1]);
623     if (svc) {
624         parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
625         return 0;
626     }
627 
628     nargs -= 2;
629     svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
630     if (!svc) {
631         parse_error(state, "out of memory\n");
632         return 0;
633     }
634     svc->name = args[1];
635     svc->classname = "default";
636     memcpy(svc->args, args + 2, sizeof(char*) * nargs);
637     svc->args[nargs] = 0;
638     svc->nargs = nargs;
639     svc->onrestart.name = "onrestart";
640     list_init(&svc->onrestart.commands);
641     list_add_tail(&service_list, &svc->slist);
642     return svc;
643 }
644 
parse_line_service(struct parse_state * state,int nargs,char ** args)645 static void parse_line_service(struct parse_state *state, int nargs, char **args)
646 {
647     struct service *svc = state->context;
648     struct command *cmd;
649     int i, kw, kw_nargs;
650 
651     if (nargs == 0) {
652         return;
653     }
654 
655     svc->ioprio_class = IoSchedClass_NONE;
656 
657     kw = lookup_keyword(args[0]);
658     switch (kw) {
659     case K_capability:
660         break;
661     case K_class:
662         if (nargs != 2) {
663             parse_error(state, "class option requires a classname\n");
664         } else {
665             svc->classname = args[1];
666         }
667         break;
668     case K_console:
669         svc->flags |= SVC_CONSOLE;
670         break;
671     case K_disabled:
672         svc->flags |= SVC_DISABLED;
673         svc->flags |= SVC_RC_DISABLED;
674         break;
675     case K_ioprio:
676         if (nargs != 3) {
677             parse_error(state, "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n");
678         } else {
679             svc->ioprio_pri = strtoul(args[2], 0, 8);
680 
681             if (svc->ioprio_pri < 0 || svc->ioprio_pri > 7) {
682                 parse_error(state, "priority value must be range 0 - 7\n");
683                 break;
684             }
685 
686             if (!strcmp(args[1], "rt")) {
687                 svc->ioprio_class = IoSchedClass_RT;
688             } else if (!strcmp(args[1], "be")) {
689                 svc->ioprio_class = IoSchedClass_BE;
690             } else if (!strcmp(args[1], "idle")) {
691                 svc->ioprio_class = IoSchedClass_IDLE;
692             } else {
693                 parse_error(state, "ioprio option usage: ioprio <rt|be|idle> <0-7>\n");
694             }
695         }
696         break;
697     case K_group:
698         if (nargs < 2) {
699             parse_error(state, "group option requires a group id\n");
700         } else if (nargs > NR_SVC_SUPP_GIDS + 2) {
701             parse_error(state, "group option accepts at most %d supp. groups\n",
702                         NR_SVC_SUPP_GIDS);
703         } else {
704             int n;
705             svc->gid = decode_uid(args[1]);
706             for (n = 2; n < nargs; n++) {
707                 svc->supp_gids[n-2] = decode_uid(args[n]);
708             }
709             svc->nr_supp_gids = n - 2;
710         }
711         break;
712     case K_keycodes:
713         if (nargs < 2) {
714             parse_error(state, "keycodes option requires atleast one keycode\n");
715         } else {
716             svc->keycodes = malloc((nargs - 1) * sizeof(svc->keycodes[0]));
717             if (!svc->keycodes) {
718                 parse_error(state, "could not allocate keycodes\n");
719             } else {
720                 svc->nkeycodes = nargs - 1;
721                 for (i = 1; i < nargs; i++) {
722                     svc->keycodes[i - 1] = atoi(args[i]);
723                 }
724             }
725         }
726         break;
727     case K_oneshot:
728         svc->flags |= SVC_ONESHOT;
729         break;
730     case K_onrestart:
731         nargs--;
732         args++;
733         kw = lookup_keyword(args[0]);
734         if (!kw_is(kw, COMMAND)) {
735             parse_error(state, "invalid command '%s'\n", args[0]);
736             break;
737         }
738         kw_nargs = kw_nargs(kw);
739         if (nargs < kw_nargs) {
740             parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
741                 kw_nargs > 2 ? "arguments" : "argument");
742             break;
743         }
744 
745         cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
746         cmd->func = kw_func(kw);
747         cmd->nargs = nargs;
748         memcpy(cmd->args, args, sizeof(char*) * nargs);
749         list_add_tail(&svc->onrestart.commands, &cmd->clist);
750         break;
751     case K_critical:
752         svc->flags |= SVC_CRITICAL;
753         break;
754     case K_setenv: { /* name value */
755         struct svcenvinfo *ei;
756         if (nargs < 2) {
757             parse_error(state, "setenv option requires name and value arguments\n");
758             break;
759         }
760         ei = calloc(1, sizeof(*ei));
761         if (!ei) {
762             parse_error(state, "out of memory\n");
763             break;
764         }
765         ei->name = args[1];
766         ei->value = args[2];
767         ei->next = svc->envvars;
768         svc->envvars = ei;
769         break;
770     }
771     case K_socket: {/* name type perm [ uid gid ] */
772         struct socketinfo *si;
773         if (nargs < 4) {
774             parse_error(state, "socket option requires name, type, perm arguments\n");
775             break;
776         }
777         if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")
778                 && strcmp(args[2],"seqpacket")) {
779             parse_error(state, "socket type must be 'dgram', 'stream' or 'seqpacket'\n");
780             break;
781         }
782         si = calloc(1, sizeof(*si));
783         if (!si) {
784             parse_error(state, "out of memory\n");
785             break;
786         }
787         si->name = args[1];
788         si->type = args[2];
789         si->perm = strtoul(args[3], 0, 8);
790         if (nargs > 4)
791             si->uid = decode_uid(args[4]);
792         if (nargs > 5)
793             si->gid = decode_uid(args[5]);
794         si->next = svc->sockets;
795         svc->sockets = si;
796         break;
797     }
798     case K_user:
799         if (nargs != 2) {
800             parse_error(state, "user option requires a user id\n");
801         } else {
802             svc->uid = decode_uid(args[1]);
803         }
804         break;
805     case K_seclabel:
806         if (nargs != 2) {
807             parse_error(state, "seclabel option requires a label string\n");
808         } else {
809             svc->seclabel = args[1];
810         }
811         break;
812 
813     default:
814         parse_error(state, "invalid option '%s'\n", args[0]);
815     }
816 }
817 
parse_action(struct parse_state * state,int nargs,char ** args)818 static void *parse_action(struct parse_state *state, int nargs, char **args)
819 {
820     struct action *act;
821     if (nargs < 2) {
822         parse_error(state, "actions must have a trigger\n");
823         return 0;
824     }
825     if (nargs > 2) {
826         parse_error(state, "actions may not have extra parameters\n");
827         return 0;
828     }
829     act = calloc(1, sizeof(*act));
830     act->name = args[1];
831     list_init(&act->commands);
832     list_init(&act->qlist);
833     list_add_tail(&action_list, &act->alist);
834         /* XXX add to hash */
835     return act;
836 }
837 
parse_line_action(struct parse_state * state,int nargs,char ** args)838 static void parse_line_action(struct parse_state* state, int nargs, char **args)
839 {
840     struct command *cmd;
841     struct action *act = state->context;
842     int (*func)(int nargs, char **args);
843     int kw, n;
844 
845     if (nargs == 0) {
846         return;
847     }
848 
849     kw = lookup_keyword(args[0]);
850     if (!kw_is(kw, COMMAND)) {
851         parse_error(state, "invalid command '%s'\n", args[0]);
852         return;
853     }
854 
855     n = kw_nargs(kw);
856     if (nargs < n) {
857         parse_error(state, "%s requires %d %s\n", args[0], n - 1,
858             n > 2 ? "arguments" : "argument");
859         return;
860     }
861     cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
862     cmd->func = kw_func(kw);
863     cmd->nargs = nargs;
864     memcpy(cmd->args, args, sizeof(char*) * nargs);
865     list_add_tail(&act->commands, &cmd->clist);
866 }
867