• 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 "list.h"
31 #include "property_service.h"
32 #include "util.h"
33 
34 #include <cutils/iosched_policy.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 static void *parse_service(struct parse_state *state, int nargs, char **args);
44 static void parse_line_service(struct parse_state *state, int nargs, char **args);
45 
46 static void *parse_action(struct parse_state *state, int nargs, char **args);
47 static void parse_line_action(struct parse_state *state, int nargs, char **args);
48 
49 #define SECTION 0x01
50 #define COMMAND 0x02
51 #define OPTION  0x04
52 
53 #include "keywords.h"
54 
55 #define KEYWORD(symbol, flags, nargs, func) \
56     [ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
57 
58 struct {
59     const char *name;
60     int (*func)(int nargs, char **args);
61     unsigned char nargs;
62     unsigned char flags;
63 } keyword_info[KEYWORD_COUNT] = {
64     [ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
65 #include "keywords.h"
66 };
67 #undef KEYWORD
68 
69 #define kw_is(kw, type) (keyword_info[kw].flags & (type))
70 #define kw_name(kw) (keyword_info[kw].name)
71 #define kw_func(kw) (keyword_info[kw].func)
72 #define kw_nargs(kw) (keyword_info[kw].nargs)
73 
lookup_keyword(const char * s)74 int lookup_keyword(const char *s)
75 {
76     switch (*s++) {
77     case 'c':
78     if (!strcmp(s, "opy")) return K_copy;
79         if (!strcmp(s, "apability")) return K_capability;
80         if (!strcmp(s, "hdir")) return K_chdir;
81         if (!strcmp(s, "hroot")) return K_chroot;
82         if (!strcmp(s, "lass")) return K_class;
83         if (!strcmp(s, "lass_start")) return K_class_start;
84         if (!strcmp(s, "lass_stop")) return K_class_stop;
85         if (!strcmp(s, "onsole")) return K_console;
86         if (!strcmp(s, "hown")) return K_chown;
87         if (!strcmp(s, "hmod")) return K_chmod;
88         if (!strcmp(s, "ritical")) return K_critical;
89         break;
90     case 'd':
91         if (!strcmp(s, "isabled")) return K_disabled;
92         if (!strcmp(s, "omainname")) return K_domainname;
93         break;
94     case 'e':
95         if (!strcmp(s, "xec")) return K_exec;
96         if (!strcmp(s, "xport")) return K_export;
97         break;
98     case 'g':
99         if (!strcmp(s, "roup")) return K_group;
100         break;
101     case 'h':
102         if (!strcmp(s, "ostname")) return K_hostname;
103         break;
104     case 'i':
105         if (!strcmp(s, "oprio")) return K_ioprio;
106         if (!strcmp(s, "fup")) return K_ifup;
107         if (!strcmp(s, "nsmod")) return K_insmod;
108         if (!strcmp(s, "mport")) return K_import;
109         break;
110     case 'k':
111         if (!strcmp(s, "eycodes")) return K_keycodes;
112         break;
113     case 'l':
114         if (!strcmp(s, "oglevel")) return K_loglevel;
115         break;
116     case 'm':
117         if (!strcmp(s, "kdir")) return K_mkdir;
118         if (!strcmp(s, "ount")) return K_mount;
119         break;
120     case 'o':
121         if (!strcmp(s, "n")) return K_on;
122         if (!strcmp(s, "neshot")) return K_oneshot;
123         if (!strcmp(s, "nrestart")) return K_onrestart;
124         break;
125     case 'r':
126         if (!strcmp(s, "estart")) return K_restart;
127         break;
128     case 's':
129         if (!strcmp(s, "ervice")) return K_service;
130         if (!strcmp(s, "etenv")) return K_setenv;
131         if (!strcmp(s, "etkey")) return K_setkey;
132         if (!strcmp(s, "etprop")) return K_setprop;
133         if (!strcmp(s, "etrlimit")) return K_setrlimit;
134         if (!strcmp(s, "ocket")) return K_socket;
135         if (!strcmp(s, "tart")) return K_start;
136         if (!strcmp(s, "top")) return K_stop;
137         if (!strcmp(s, "ymlink")) return K_symlink;
138         if (!strcmp(s, "ysclktz")) return K_sysclktz;
139         break;
140     case 't':
141         if (!strcmp(s, "rigger")) return K_trigger;
142         break;
143     case 'u':
144         if (!strcmp(s, "ser")) return K_user;
145         break;
146     case 'w':
147         if (!strcmp(s, "rite")) return K_write;
148         if (!strcmp(s, "ait")) return K_wait;
149         break;
150     }
151     return K_UNKNOWN;
152 }
153 
parse_line_no_op(struct parse_state * state,int nargs,char ** args)154 void parse_line_no_op(struct parse_state *state, int nargs, char **args)
155 {
156 }
157 
parse_new_section(struct parse_state * state,int kw,int nargs,char ** args)158 void parse_new_section(struct parse_state *state, int kw,
159                        int nargs, char **args)
160 {
161     printf("[ %s %s ]\n", args[0],
162            nargs > 1 ? args[1] : "");
163     switch(kw) {
164     case K_service:
165         state->context = parse_service(state, nargs, args);
166         if (state->context) {
167             state->parse_line = parse_line_service;
168             return;
169         }
170         break;
171     case K_on:
172         state->context = parse_action(state, nargs, args);
173         if (state->context) {
174             state->parse_line = parse_line_action;
175             return;
176         }
177         break;
178     }
179     state->parse_line = parse_line_no_op;
180 }
181 
parse_config(const char * fn,char * s)182 static void parse_config(const char *fn, char *s)
183 {
184     struct parse_state state;
185     char *args[INIT_PARSER_MAXARGS];
186     int nargs;
187 
188     nargs = 0;
189     state.filename = fn;
190     state.line = 1;
191     state.ptr = s;
192     state.nexttoken = 0;
193     state.parse_line = parse_line_no_op;
194     for (;;) {
195         switch (next_token(&state)) {
196         case T_EOF:
197             state.parse_line(&state, 0, 0);
198             return;
199         case T_NEWLINE:
200             if (nargs) {
201                 int kw = lookup_keyword(args[0]);
202                 if (kw_is(kw, SECTION)) {
203                     state.parse_line(&state, 0, 0);
204                     parse_new_section(&state, kw, nargs, args);
205                 } else {
206                     state.parse_line(&state, nargs, args);
207                 }
208                 nargs = 0;
209             }
210             break;
211         case T_TEXT:
212             if (nargs < INIT_PARSER_MAXARGS) {
213                 args[nargs++] = state.text;
214             }
215             break;
216         }
217     }
218 }
219 
init_parse_config_file(const char * fn)220 int init_parse_config_file(const char *fn)
221 {
222     char *data;
223     data = read_file(fn, 0);
224     if (!data) return -1;
225 
226     parse_config(fn, data);
227     DUMP();
228     return 0;
229 }
230 
valid_name(const char * name)231 static int valid_name(const char *name)
232 {
233     if (strlen(name) > 16) {
234         return 0;
235     }
236     while (*name) {
237         if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
238             return 0;
239         }
240         name++;
241     }
242     return 1;
243 }
244 
service_find_by_name(const char * name)245 struct service *service_find_by_name(const char *name)
246 {
247     struct listnode *node;
248     struct service *svc;
249     list_for_each(node, &service_list) {
250         svc = node_to_item(node, struct service, slist);
251         if (!strcmp(svc->name, name)) {
252             return svc;
253         }
254     }
255     return 0;
256 }
257 
service_find_by_pid(pid_t pid)258 struct service *service_find_by_pid(pid_t pid)
259 {
260     struct listnode *node;
261     struct service *svc;
262     list_for_each(node, &service_list) {
263         svc = node_to_item(node, struct service, slist);
264         if (svc->pid == pid) {
265             return svc;
266         }
267     }
268     return 0;
269 }
270 
service_find_by_keychord(int keychord_id)271 struct service *service_find_by_keychord(int keychord_id)
272 {
273     struct listnode *node;
274     struct service *svc;
275     list_for_each(node, &service_list) {
276         svc = node_to_item(node, struct service, slist);
277         if (svc->keychord_id == keychord_id) {
278             return svc;
279         }
280     }
281     return 0;
282 }
283 
service_for_each(void (* func)(struct service * svc))284 void service_for_each(void (*func)(struct service *svc))
285 {
286     struct listnode *node;
287     struct service *svc;
288     list_for_each(node, &service_list) {
289         svc = node_to_item(node, struct service, slist);
290         func(svc);
291     }
292 }
293 
service_for_each_class(const char * classname,void (* func)(struct service * svc))294 void service_for_each_class(const char *classname,
295                             void (*func)(struct service *svc))
296 {
297     struct listnode *node;
298     struct service *svc;
299     list_for_each(node, &service_list) {
300         svc = node_to_item(node, struct service, slist);
301         if (!strcmp(svc->classname, classname)) {
302             func(svc);
303         }
304     }
305 }
306 
service_for_each_flags(unsigned matchflags,void (* func)(struct service * svc))307 void service_for_each_flags(unsigned matchflags,
308                             void (*func)(struct service *svc))
309 {
310     struct listnode *node;
311     struct service *svc;
312     list_for_each(node, &service_list) {
313         svc = node_to_item(node, struct service, slist);
314         if (svc->flags & matchflags) {
315             func(svc);
316         }
317     }
318 }
319 
action_for_each_trigger(const char * trigger,void (* func)(struct action * act))320 void action_for_each_trigger(const char *trigger,
321                              void (*func)(struct action *act))
322 {
323     struct listnode *node;
324     struct action *act;
325     list_for_each(node, &action_list) {
326         act = node_to_item(node, struct action, alist);
327         if (!strcmp(act->name, trigger)) {
328             func(act);
329         }
330     }
331 }
332 
queue_property_triggers(const char * name,const char * value)333 void queue_property_triggers(const char *name, const char *value)
334 {
335     struct listnode *node;
336     struct action *act;
337     list_for_each(node, &action_list) {
338         act = node_to_item(node, struct action, alist);
339         if (!strncmp(act->name, "property:", strlen("property:"))) {
340             const char *test = act->name + strlen("property:");
341             int name_length = strlen(name);
342 
343             if (!strncmp(name, test, name_length) &&
344                     test[name_length] == '=' &&
345                     !strcmp(test + name_length + 1, value)) {
346                 action_add_queue_tail(act);
347             }
348         }
349     }
350 }
351 
queue_all_property_triggers()352 void queue_all_property_triggers()
353 {
354     struct listnode *node;
355     struct action *act;
356     list_for_each(node, &action_list) {
357         act = node_to_item(node, struct action, alist);
358         if (!strncmp(act->name, "property:", strlen("property:"))) {
359             /* parse property name and value
360                syntax is property:<name>=<value> */
361             const char* name = act->name + strlen("property:");
362             const char* equals = strchr(name, '=');
363             if (equals) {
364                 char prop_name[PROP_NAME_MAX + 1];
365                 const char* value;
366                 int length = equals - name;
367                 if (length > PROP_NAME_MAX) {
368                     ERROR("property name too long in trigger %s", act->name);
369                 } else {
370                     memcpy(prop_name, name, length);
371                     prop_name[length] = 0;
372 
373                     /* does the property exist, and match the trigger value? */
374                     value = property_get(prop_name);
375                     if (value && !strcmp(equals + 1, value)) {
376                         action_add_queue_tail(act);
377                     }
378                 }
379             }
380         }
381     }
382 }
383 
queue_builtin_action(int (* func)(int nargs,char ** args),char * name)384 void queue_builtin_action(int (*func)(int nargs, char **args), char *name)
385 {
386     struct action *act;
387     struct command *cmd;
388 
389     act = calloc(1, sizeof(*act));
390     act->name = name;
391     list_init(&act->commands);
392 
393     cmd = calloc(1, sizeof(*cmd));
394     cmd->func = func;
395     cmd->args[0] = name;
396     list_add_tail(&act->commands, &cmd->clist);
397 
398     list_add_tail(&action_list, &act->alist);
399     action_add_queue_tail(act);
400 }
401 
action_add_queue_tail(struct action * act)402 void action_add_queue_tail(struct action *act)
403 {
404     list_add_tail(&action_queue, &act->qlist);
405 }
406 
action_remove_queue_head(void)407 struct action *action_remove_queue_head(void)
408 {
409     if (list_empty(&action_queue)) {
410         return 0;
411     } else {
412         struct listnode *node = list_head(&action_queue);
413         struct action *act = node_to_item(node, struct action, qlist);
414         list_remove(node);
415         return act;
416     }
417 }
418 
action_queue_empty()419 int action_queue_empty()
420 {
421     return list_empty(&action_queue);
422 }
423 
parse_service(struct parse_state * state,int nargs,char ** args)424 static void *parse_service(struct parse_state *state, int nargs, char **args)
425 {
426     struct service *svc;
427     if (nargs < 3) {
428         parse_error(state, "services must have a name and a program\n");
429         return 0;
430     }
431     if (!valid_name(args[1])) {
432         parse_error(state, "invalid service name '%s'\n", args[1]);
433         return 0;
434     }
435 
436     svc = service_find_by_name(args[1]);
437     if (svc) {
438         parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
439         return 0;
440     }
441 
442     nargs -= 2;
443     svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
444     if (!svc) {
445         parse_error(state, "out of memory\n");
446         return 0;
447     }
448     svc->name = args[1];
449     svc->classname = "default";
450     memcpy(svc->args, args + 2, sizeof(char*) * nargs);
451     svc->args[nargs] = 0;
452     svc->nargs = nargs;
453     svc->onrestart.name = "onrestart";
454     list_init(&svc->onrestart.commands);
455     list_add_tail(&service_list, &svc->slist);
456     return svc;
457 }
458 
parse_line_service(struct parse_state * state,int nargs,char ** args)459 static void parse_line_service(struct parse_state *state, int nargs, char **args)
460 {
461     struct service *svc = state->context;
462     struct command *cmd;
463     int i, kw, kw_nargs;
464 
465     if (nargs == 0) {
466         return;
467     }
468 
469     svc->ioprio_class = IoSchedClass_NONE;
470 
471     kw = lookup_keyword(args[0]);
472     switch (kw) {
473     case K_capability:
474         break;
475     case K_class:
476         if (nargs != 2) {
477             parse_error(state, "class option requires a classname\n");
478         } else {
479             svc->classname = args[1];
480         }
481         break;
482     case K_console:
483         svc->flags |= SVC_CONSOLE;
484         break;
485     case K_disabled:
486         svc->flags |= SVC_DISABLED;
487         break;
488     case K_ioprio:
489         if (nargs != 3) {
490             parse_error(state, "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n");
491         } else {
492             svc->ioprio_pri = strtoul(args[2], 0, 8);
493 
494             if (svc->ioprio_pri < 0 || svc->ioprio_pri > 7) {
495                 parse_error(state, "priority value must be range 0 - 7\n");
496                 break;
497             }
498 
499             if (!strcmp(args[1], "rt")) {
500                 svc->ioprio_class = IoSchedClass_RT;
501             } else if (!strcmp(args[1], "be")) {
502                 svc->ioprio_class = IoSchedClass_BE;
503             } else if (!strcmp(args[1], "idle")) {
504                 svc->ioprio_class = IoSchedClass_IDLE;
505             } else {
506                 parse_error(state, "ioprio option usage: ioprio <rt|be|idle> <0-7>\n");
507             }
508         }
509         break;
510     case K_group:
511         if (nargs < 2) {
512             parse_error(state, "group option requires a group id\n");
513         } else if (nargs > NR_SVC_SUPP_GIDS + 2) {
514             parse_error(state, "group option accepts at most %d supp. groups\n",
515                         NR_SVC_SUPP_GIDS);
516         } else {
517             int n;
518             svc->gid = decode_uid(args[1]);
519             for (n = 2; n < nargs; n++) {
520                 svc->supp_gids[n-2] = decode_uid(args[n]);
521             }
522             svc->nr_supp_gids = n - 2;
523         }
524         break;
525     case K_keycodes:
526         if (nargs < 2) {
527             parse_error(state, "keycodes option requires atleast one keycode\n");
528         } else {
529             svc->keycodes = malloc((nargs - 1) * sizeof(svc->keycodes[0]));
530             if (!svc->keycodes) {
531                 parse_error(state, "could not allocate keycodes\n");
532             } else {
533                 svc->nkeycodes = nargs - 1;
534                 for (i = 1; i < nargs; i++) {
535                     svc->keycodes[i - 1] = atoi(args[i]);
536                 }
537             }
538         }
539         break;
540     case K_oneshot:
541         svc->flags |= SVC_ONESHOT;
542         break;
543     case K_onrestart:
544         nargs--;
545         args++;
546         kw = lookup_keyword(args[0]);
547         if (!kw_is(kw, COMMAND)) {
548             parse_error(state, "invalid command '%s'\n", args[0]);
549             break;
550         }
551         kw_nargs = kw_nargs(kw);
552         if (nargs < kw_nargs) {
553             parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
554                 kw_nargs > 2 ? "arguments" : "argument");
555             break;
556         }
557 
558         cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
559         cmd->func = kw_func(kw);
560         cmd->nargs = nargs;
561         memcpy(cmd->args, args, sizeof(char*) * nargs);
562         list_add_tail(&svc->onrestart.commands, &cmd->clist);
563         break;
564     case K_critical:
565         svc->flags |= SVC_CRITICAL;
566         break;
567     case K_setenv: { /* name value */
568         struct svcenvinfo *ei;
569         if (nargs < 2) {
570             parse_error(state, "setenv option requires name and value arguments\n");
571             break;
572         }
573         ei = calloc(1, sizeof(*ei));
574         if (!ei) {
575             parse_error(state, "out of memory\n");
576             break;
577         }
578         ei->name = args[1];
579         ei->value = args[2];
580         ei->next = svc->envvars;
581         svc->envvars = ei;
582         break;
583     }
584     case K_socket: {/* name type perm [ uid gid ] */
585         struct socketinfo *si;
586         if (nargs < 4) {
587             parse_error(state, "socket option requires name, type, perm arguments\n");
588             break;
589         }
590         if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")
591                 && strcmp(args[2],"seqpacket")) {
592             parse_error(state, "socket type must be 'dgram', 'stream' or 'seqpacket'\n");
593             break;
594         }
595         si = calloc(1, sizeof(*si));
596         if (!si) {
597             parse_error(state, "out of memory\n");
598             break;
599         }
600         si->name = args[1];
601         si->type = args[2];
602         si->perm = strtoul(args[3], 0, 8);
603         if (nargs > 4)
604             si->uid = decode_uid(args[4]);
605         if (nargs > 5)
606             si->gid = decode_uid(args[5]);
607         si->next = svc->sockets;
608         svc->sockets = si;
609         break;
610     }
611     case K_user:
612         if (nargs != 2) {
613             parse_error(state, "user option requires a user id\n");
614         } else {
615             svc->uid = decode_uid(args[1]);
616         }
617         break;
618     default:
619         parse_error(state, "invalid option '%s'\n", args[0]);
620     }
621 }
622 
parse_action(struct parse_state * state,int nargs,char ** args)623 static void *parse_action(struct parse_state *state, int nargs, char **args)
624 {
625     struct action *act;
626     if (nargs < 2) {
627         parse_error(state, "actions must have a trigger\n");
628         return 0;
629     }
630     if (nargs > 2) {
631         parse_error(state, "actions may not have extra parameters\n");
632         return 0;
633     }
634     act = calloc(1, sizeof(*act));
635     act->name = args[1];
636     list_init(&act->commands);
637     list_add_tail(&action_list, &act->alist);
638         /* XXX add to hash */
639     return act;
640 }
641 
parse_line_action(struct parse_state * state,int nargs,char ** args)642 static void parse_line_action(struct parse_state* state, int nargs, char **args)
643 {
644     struct command *cmd;
645     struct action *act = state->context;
646     int (*func)(int nargs, char **args);
647     int kw, n;
648 
649     if (nargs == 0) {
650         return;
651     }
652 
653     kw = lookup_keyword(args[0]);
654     if (!kw_is(kw, COMMAND)) {
655         parse_error(state, "invalid command '%s'\n", args[0]);
656         return;
657     }
658 
659     n = kw_nargs(kw);
660     if (nargs < n) {
661         parse_error(state, "%s requires %d %s\n", args[0], n - 1,
662             n > 2 ? "arguments" : "argument");
663         return;
664     }
665     cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
666     cmd->func = kw_func(kw);
667     cmd->nargs = nargs;
668     memcpy(cmd->args, args, sizeof(char*) * nargs);
669     list_add_tail(&act->commands, &cmd->clist);
670 }
671