boa.c 续
书接上回。
main函数的调用到了 fixup_server_root()
- static void fixup_server_root()
- {
- char *dirbuf;
-
- if (!server_root) {
- #ifdef SERVER_ROOT
- server_root = strdup(SERVER_ROOT);
- if (!server_root) {
- perror("strdup (SERVER_ROOT)");
- exit(1);
- }
- #else
- fputs("boa: don't know where server root is. Please #define "
- "SERVER_ROOT in boa.h\n"
- "and recompile, or use the -c command line option to "
- "specify it.\n", stderr);
- exit(1);
- #endif
- }
-
- if (chdir(server_root) == -1) {
- fprintf(stderr, "Could not chdir to \"%s\": aborting\n",
- server_root);
- exit(1);
- }
-
- dirbuf = normalize_path(server_root);
- free(server_root);
- server_root = dirbuf;
- }
该函数的功能主要是由程序运行时的选项和defines.h里的宏定义确定server_root。
如果参数没有指定server_root,那么就由宏指定,如果宏没指定,就报错。
该函数最后调用的normalize_path(),定义在util.c里。功能是,如果给出的是绝对路径,不转化。如果是相对路径转化为绝对路径。
该函数不贴了,用到了getcwd()
#include <unistd.h>
char *getcwd(char *buf, size_t size);
char *getwd(char *buf);
getcwd函数返回当前程序的工作目录。因此,如果相对路径不是"."的话,还需要将两个字符串连接起来。细节上的处理大家有兴趣的话可以看一下。
fixup_server_root()调用完毕,程序运行到这儿,应该已经有了规范的工作目录了。
main函数继续执行到read_config_files();
程序的注释说,Description: Reads config files via yyparse, then makes sure that all required variables were set properly.
这个函数解析配置文件,保证所有的全局变量正确初始化。
- void read_config_files(void)
- {
- char *temp;
- current_uid = getuid();
- yyin = fopen("boa.conf", "r");
-
- if (!yyin) {
- fputs("Could not open boa.conf for reading.\n", stderr);
- exit(1);
- }
- if (yyparse()) {
- fputs("Error parsing config files, exiting\n", stderr);
- exit(1);
- }
-
- if (!server_name) {
- struct hostent *he;
- char temp_name[100];
-
- if (gethostname(temp_name, 100) == -1) {
- perror("gethostname:");
- exit(1);
- }
-
- he = gethostbyname(temp_name);
- if (he == NULL) {
- perror("gethostbyname:");
- exit(1);
- }
-
- server_name = strdup(he->h_name);
- if (server_name == NULL) {
- perror("strdup:");
- exit(1);
- }
- }
- tempdir = getenv("TMP");
- if (tempdir == NULL)
- tempdir = "/tmp";
-
- if (single_post_limit < 0) {
- fprintf(stderr, "Invalid value for single_post_limit: %d\n",
- single_post_limit);
- exit(1);
- }
-
- if (document_root) {
- temp = normalize_path(document_root);
- free(document_root);
- document_root = temp;
- }
-
- if (error_log_name) {
- temp = normalize_path(error_log_name);
- free(error_log_name);
- error_log_name = temp;
- }
-
- if (access_log_name) {
- temp = normalize_path(access_log_name);
- free(access_log_name);
- access_log_name = temp;
- }
-
- if (cgi_log_name) {
- temp = normalize_path(cgi_log_name);
- free(cgi_log_name);
- cgi_log_name = temp;
- }
-
- if (dirmaker) {
- temp = normalize_path(dirmaker);
- free(dirmaker);
- dirmaker = temp;
- }
-
- #if 0
- if (mime_types) {
- temp = normalize_path(mime_types);
- free(mime_types);
- mime_types = temp;
- }
- #endif
- }
首先打开boa.conf文件,yyin被赋值。然后就可以调用yyparse()进行解析了。
关于flex和bison学习,推荐oreilly的flex&bison。
现在把bison和flex部分研究一下吧
boa_grammar.y
- %{
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- /* #include "boa.h" */
- #include "parse.h"
- # yyerror的实现在boa_lexer.l里
- int yyerror(char * msg);
-
- /* yydebug = 1; */
-
- #ifdef DEBUG
- #define DBG(x) x
- #else
- #define DBG(x)
- #endif
- # 之后可以看到arg1hold用于临时保存TOKEN的参数内容,mime_type也是临时用于存储mime的名。
- char *arg1hold;
- char mime_type[256]; /* global to inherit */
-
- %}
-
- %union {
- char * sval;
- int ival;
- struct ccommand * cval;
- };
-
- /* boa.conf tokens */
- %token <cval> STMT_NO_ARGS STMT_ONE_ARG STMT_TWO_ARGS
-
- /* mime.type tokens */
- %token <sval> MIMETYPE
- %token <sval> STRING
- %token <ival> INTEGER
-
- %start ConfigFiles
-
- %%
-
- ConfigFiles: BoaConfigStmts MimeTypeStmts
- ;
-
- BoaConfigStmts: BoaConfigStmts BoaConfigStmt
- | /* empty */
- ;
-
- BoaConfigStmt:
- StmtNoArgs
- | StmtOneArg
- | StmtTwoArgs
- ;
-
- StmtNoArgs: STMT_NO_ARGS
- { if ($1->action) {
- DBG(printf("StmtNoArgs: %s\n",$1->name);)
- $1->action(NULL,NULL,$1->object);
- }
- }
- ;
-
- StmtOneArg: STMT_ONE_ARG STRING
- { if ($1->action) {
- DBG(printf("StmtOneArg: %s %s\n",$1->name,$2);)
- $1->action($2,NULL,$1->object);
- }
- }
- ;
-
- StmtTwoArgs: STMT_TWO_ARGS STRING
- { arg1hold = strdup($2); }
- STRING
- { if ($1->action) {
- DBG(printf("StmtTwoArgs: '%s' '%s' '%s'\n",
- $1->name,arg1hold,$4);)
- $1->action($4,arg1hold,$1->object);
- }
- free(arg1hold);
- }
- ;
-
-
- /******************* mime.types **********************/
-
- MimeTypeStmts: MimeTypeStmts MimeTypeStmt
- | /* empty */
- ;
-
- MimeTypeStmt: MIMETYPE
- { strcpy(mime_type, $1); }
- ExtensionList
- ;
-
- ExtensionList: ExtensionList Extension
- | /* empty */
- ;
-
- Extension: STRING
- { add_mime_type($1, mime_type); }
- ;
-
- %%
先说说这个宏,DBG(x)
#ifdef DEBUG
#define DBG(x) x
#else
#define DBG(x)
#endif
学了一招!
up主之前用#define DEBUG,然后每一处需要调试时调用的函数前后加上#ifdef DEBUG ...... #endif的方法来达到同样效果,太累。
这里只要在需要调试的函数前后加上DBG()就行了。
将boa.conf文件和mime.types文件的语法规则写在一起,简单的先后关系:ConfigFiles: BoaConfigStmts MimeTypeStmts;
BoaConfigStmts
boa config stmt分三种,无参的,一个参数的,两个参数的。
实际的配置如下:
AccessLog /var/log/boa/access_log
Alias /doc /usr/doc
词法分析得到一条stmt后,调用action函数进行操作。
每一个stmt是struct ccommand *类型,声明如下
struct ccommand{
char *name;
int type;
void (*action) (char *, char *, void *);
void *object;
};
所有的struct ccommand以数组方式存储
- struct ccommand clist[] = {
- {"Port", S1A, c_set_int, &server_port},
- ......
- {"CGIPath", S1A, c_set_string, &cgi_path},
- {"MaxConnections", S1A, c_set_int, &max_connections},
- };
词法分析yylex每次找到一个stmt就根据名字从这个数组中查找对应项返回给yyparse,再从yyparse中调用action,完成各自的初始化。
MimeTypeStmts
mimetype的形式类似于 MIMETYPE STRING STRING STRING...
每次解析到一个MIMETYPE,先暂时存储于mime_type字符数组。解析STRING时,就调用add_mime_type($1, mime_type);
这个函数的作用就是将type-extension添加到一个哈系表中,type为key,可以有很多extension,索引方式存储。
语法分析规则boa_grammar.y就到这儿,词法分析规则boa_lexer.l就不说了。
大体功能和yywrap()、yyerror()在前一篇已经提到,具体的词法规则就太细节了。
好了,回到我们的read_config_files(),大家不会忘了这个函数还没完呢吧?^ ^
其实也没什么了,把一些路径转化为绝对路径,host_name什么的验证一下,也就完了。
最后有个#if 0 ...... #endif
我是第一次到见这个用法,查了一下就是相当于多行注释。有的文章推荐这样用。
好了,up主累了,看会儿动画去,下次更新依然不定期。。。 ^ ^