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