主要是通过该函数实现解析:在init.c中
init_parse_config_file("/init.rc");
int init_parse_config_file(const char *fn)
{
char *data;
//读取文件的内容
data = read_file(fn, 0);
if (!data) return -1;
//真正解析的函数
parse_config(fn, data);
DUMP();
return 0;
}
static void parse_config(const char *fn, char *s)
{
struct parse_state state;
struct listnode import_list;
struct listnode *node;
char *args[INIT_PARSER_MAXARGS];
int nargs;
nargs = 0;
state.filename = fn;
state.line = 0;
state.ptr = s;
state.nexttoken = 0;
state.parse_line = parse_line_no_op;
list_init(&import_list);
state.priv = &import_list;
for (;;) {
switch (next_token(&state)) {
case T_EOF:
state.parse_line(&state, 0, 0);
goto parser_done;
case T_NEWLINE:
state.line++;
if (nargs) {
int kw = lookup_keyword(args[0]);
if (kw_is(kw, SECTION)) {
state.parse_line(&state, 0, 0);
parse_new_section(&state, kw, nargs, args);
} else {
state.parse_line(&state, nargs, args);
}
nargs = 0;
}
break;
case T_TEXT:
if (nargs < INIT_PARSER_MAXARGS) {
args[nargs++] = state.text;
}
break;
}
}
parser_done:
list_for_each(node, &import_list) {
struct import *import = node_to_item(node, struct import, list);
int ret;
INFO("importing '%s'", import->filename);
ret = init_parse_config_file(import->filename);
if (ret)
ERROR("could not import file '%s' from '%s'\n",
import->filename, fn);
}
}
parse_config()函数,位于init_parser.c,在该文件的开头,对一些关键字进行了一些定义,主要通过keywords.h来完成。第一次include keywords.h的时候,是用来定义枚举类型,和函数(结构体中有一个(*func)的成员,在keywords.h中定义了,那个关键字调用哪个函数,如KEYWORD(enable, COMMAND, 1, do_enable),定义了,enable关键字的func函数是do_eable),第二次include keywords.h的时候,是用来填充 keyword_inof这个结构体数组。
#include "keywords.h"
#define KEYWORD(symbol, flags, nargs, func) \
[ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
static struct {
const char *name;
int (*func)(int nargs, char **args);
unsigned char nargs;
unsigned char flags;
} keyword_info[KEYWORD_COUNT] = {
[ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
#include "keywords.h"
};
#undef KEYWORD
在keywords.h中,将关键字分成了三类,分别是:Section、Command、Option.以init.rc中的一段来看parser_config函数是如何解析的。其中三个关键字被分类为Section:import,on,service
service servicemanager /system/bin/servicemanager
class core
user system
group system
critical
onrestart restart healthd
onrestart restart zygote
onrestart restart media
onrestart restart surfaceflinger
onrestart restart drm
第一次执行next_token()出来,case t_text,此时,nargs = 1, args[0] = service
第二次执行next_token()出来,case t_text,此时, nargs =2, args[0] = service, args[1] = servicemanager,
第三次执行next_token()出来,case t_text,此时, nargs = 3, args[0] = service, args[1] = servicemanager, args[2] = /system/bin/servicemanager
第三次执行next_token()出来,case T_NEWLINE,从keywords.h中我们看到service是一个section,于是会执行parse_new_section
static void parse_new_section(struct parse_state *state, int kw,
int nargs, char **args)
{
printf("[ %s %s ]\n", args[0],
nargs > 1 ? args[1] : "");
switch(kw) {
case K_service:
state->context = parse_service(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_service;
return;
}
break;
case K_on:
state->context = parse_action(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_action;
return;
}
break;
case K_import:
parse_import(state, nargs, args);
break;
}
state->parse_line = parse_line_no_op;
}
对于service和action,其实就是实例化一个service和action的结构体,添加到service的list和action的list里面去,并且将parse_line函数转换成对应的prase_line_action/service函数;对于import,则是将import的路径,以及import的文件名保存到import的list里面去。
对于service,parse_new_section的主要做了两件事:1、实例化一个service添加到service的list中;2、将prase_line函数赋值成prase_line_service.
于是我们继续解析第二行: nargs =2, args[0] = class, args[1] = core.
对于class这种属于Option分类的,是用来补充service的信息的。
case K_class:
if (nargs != 2) {
parse_error(state, "class option requires a classname\n");
} else {
svc->classname = args[1];
}
break;
对于onrestart是属于Option分类,后面接的是Command,用来表示重启要做什么动作。
case K_onrestart:
nargs--;
args++;
//kw是restart
kw = lookup_keyword(args[0]);
if (!kw_is(kw, COMMAND)) {
parse_error(state, "invalid command '%s'\n", args[0]);
break;
}
kw_nargs = kw_nargs(kw);
if (nargs < kw_nargs) {
parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
kw_nargs > 2 ? "arguments" : "argument");
break;
}
cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
cmd->func = kw_func(kw);
cmd->nargs = nargs;
memcpy(cmd->args, args, sizeof(char*) * nargs);
list_add_tail(&svc->onrestart.commands, &cmd->clist);
break;
service有一个Command的list,专门用来保存onrestart要做的操作。
对于Action和Service类型的Section,其解析的流程都是类似的,解析的过程就是讲init.rc中的配置,映射到c++中的对象。
对于import类型的Section,其解析的流程就是将import文件的路径和文件名,保存到import_list
static void parse_import(struct parse_state *state, int nargs, char **args)
{
struct listnode *import_list = state->priv;
struct import *import;
char conf_file[PATH_MAX];
int ret;
if (nargs != 2) {
ERROR("single argument needed for import\n");
return;
}
//展开属性,对于变量(即通过$引用的,找到它实际的值,替换进去,保存对应的路径)
ret = expand_props(conf_file, args[1], sizeof(conf_file));
if (ret) {
ERROR("error while handling import on line '%d' in '%s'\n",
state->line, state->filename);
return;
}
import = calloc(1, sizeof(struct import));
import->filename = strdup(conf_file);
list_add_tail(import_list, &import->list);
INFO("found import '%s', adding to import list", import->filename);
}
本文件解析完成之后,再对import的文件进行同样的解析。
parser_done:
list_for_each(node, &import_list) {
struct import *import = node_to_item(node, struct import, list);
int ret;
INFO("importing '%s'", import->filename);
ret = init_parse_config_file(import->filename);
if (ret)
ERROR("could not import file '%s' from '%s'\n",
import->filename, fn);
}
}