init_parser.c revision d5c8ddfdf3f275226c02dc00ccbe63229acf6786
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, "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
154void parse_line_no_op(struct parse_state *state, int nargs, char **args)
155{
156}
157
158void 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
182static 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
220int 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
231static 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
245struct 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
258struct 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
271struct 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
284void 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
294void 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
307void 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
320void 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
333void 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
352void 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
384void 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
402void action_add_queue_tail(struct action *act)
403{
404    list_add_tail(&action_queue, &act->qlist);
405}
406
407struct 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
419int action_queue_empty()
420{
421    return list_empty(&action_queue);
422}
423
424static 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
459static 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
623static 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
642static 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