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