首页 > 系统服务 > 详细

init进程解析rc文件语法的相关函数分析

时间:2015-10-20 17:48:46      阅读:345      评论:0      收藏:0      [点我收藏+]

init进程的源码文件位于system/core/init,其中解析rc文件语法的代码放在五个函数中, init_parse_config_file (init_parser.c), read_file (util.c), parse_config (init_parser.c), next_token (parser.c), lookup_keyword (init_parser.c)。下面一个一个看这几个函数的具体实现。

首先是 init_parser_config_file 函数在init的main函数中被调用

1 init_parse_config_file("/init.rc");

可以看到直接解析init.rc文件,其会import其他rc文件

函数内容如下

 1 int init_parse_config_file(const char *fn)
 2 {
 3     char *data;
 4     data = read_file(fn, 0);
 5     if (!data) return -1;
 6 
 7     parse_config(fn, data);
 8     DUMP();
 9     return 0;
10 }

可以看到非常简单,先把rc文件读到内存里,再调用 parse_config 函数解析读到内存中的文件内容,最后把接触出来的数据结构dump出来。

先看读取文件内容部分

 1 /* reads a file, making sure it is terminated with \n \0 */
 2 void *read_file(const char *fn, unsigned *_sz)
 3 {
 4     char *data;
 5     int sz;
 6     int fd;
 7     struct stat sb;
 8 
 9     data = 0;
10     fd = open(fn, O_RDONLY);
11     if(fd < 0) return 0;
12 
13     // for security reasons, disallow world-writable
14     // or group-writable files
15     if (fstat(fd, &sb) < 0) {
16         ERROR("fstat failed for ‘%s‘\n", fn);
17         goto oops;
18     }
19     if ((sb.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
20         ERROR("skipping insecure file ‘%s‘\n", fn);
21         goto oops;
22     }
23 
24     sz = lseek(fd, 0, SEEK_END);
25     if(sz < 0) goto oops;
26 
27     if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
28 
29     data = (char*) malloc(sz + 2);
30     if(data == 0) goto oops;
31 
32     if(read(fd, data, sz) != sz) goto oops;
33     close(fd);
34     data[sz] = \n;
35     data[sz+1] = 0;
36     if(_sz) *_sz = sz;
37     return data;
38 
39 oops:
40     close(fd);
41     if(data != 0) free(data);
42     return 0;
43 }

内容很简单,要注意两点,一是权限问题,对于可以对其他用户随意写(S_IWOTH)以及组内可写的文件,不会读取其内容;二是读出来的数据在比文件附加了两个字节,一个是换行 \n ,一个是NULL \0

把文件内容读到内存之后就可以用函数 parse_config 解析了,其内容如下

 1 static void parse_config(const char *fn, char *s)
 2 {
 3     struct parse_state state;
 4     struct listnode import_list;
 5     struct listnode *node;
 6     char *args[INIT_PARSER_MAXARGS];
 7     int nargs;
 8 
 9 #ifdef MTK_INIT
10     NOTICE("<<Parsing %s>>\n", fn);
11 #endif
12 
13     nargs = 0;
14     state.filename = fn;
15     state.line = 0;
16     state.ptr = s;
17     state.nexttoken = 0;
18     state.parse_line = parse_line_no_op;
19 
20     list_init(&import_list);
21     state.priv = &import_list;
22 
23     for (;;) {
24         switch (next_token(&state)) {
25         case T_EOF:
26             state.parse_line(&state, 0, 0);
27             goto parser_done;
28         case T_NEWLINE:
29             state.line++;
30             if (nargs) {
31                 int kw = lookup_keyword(args[0]);
32                 if (kw_is(kw, SECTION)) {
33                     state.parse_line(&state, 0, 0);
34                     parse_new_section(&state, kw, nargs, args);
35                 } else {
36                     state.parse_line(&state, nargs, args);
37                 }
38                 nargs = 0;
39             }
40             break;
41         case T_TEXT:
42             if (nargs < INIT_PARSER_MAXARGS) {
43                 args[nargs++] = state.text;
44             }
45             break;
46         }
47     }
48 
49 parser_done:
50     list_for_each(node, &import_list) {
51          struct import *import = node_to_item(node, struct import, list);
52          int ret;
53 
54          INFO("importing ‘%s‘", import->filename);
55          ret = init_parse_config_file(import->filename);
56          if (ret)
57              ERROR("could not import file ‘%s‘ from ‘%s‘\n",
58                    import->filename, fn);
59     }
60 }

做语法解析一般分两步,一是进行词法分析,二是进行语法分析。词法分析会把一个一个字符聚合成词法单元,随后将一组按语法规则分割好的词法单元送给语法分析部分。这里做词法分析的是 next_token 函数。rc文件是以一行为单位分割词法单元,所以解析到新行( \n )词法单元后,之前已经聚合好的词法单元会被解析语义,即 case T_NEWLINE 内的部分,生成内部相依的数据结构,比如action,service等。在此之前会把收集到的一个个词法单元放进 args字符数组里。若是检测到文件结束,则该文件解析结束,进入 parse_done标签部分,递归解析被import进来的其他rc文件。

记录解析状态的结构体是 parse_state ,其定义与parser.h文件中,内容如下

 1 struct parse_state
 2 {
 3     char *ptr;
 4     char *text;
 5     int line;
 6     int nexttoken;
 7     void *context;
 8     void (*parse_line)(struct parse_state *state, int nargs, char **args);
 9     const char *filename;
10     void *priv;
11 };

记录解析到的词法单元的性质的三个宏也定义与parser.h文件中,如下

1 #define T_EOF 0
2 #define T_TEXT 1
3 #define T_NEWLINE 2

语法分析部分会根据返回的词法单元的性质,做不同的动作,或者解析结束,或者继续聚合词法单元,或者进行语法解析,映射相依内容到内部表示的数据结构。

 

init进程解析rc文件语法的相关函数分析

原文:http://www.cnblogs.com/cascle/p/4895457.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!