本节分析一下ngx_get_options()
函数,这个函数的做用就是解析nginx
的启动命令传递的参数,好比/usr/local/nginx/sbin/nginx -s reload
, /usr/local/nginx/sbin/nginx -t
等。html
http://nginx.org/en/docs/switches.html
nginx supports the following command-line parameters:
-? | -h — print help for command-line parameters.
-c file — use an alternative configuration file instead of a default file.
-g directives — set global configuration directives, for example,
nginx -g "pid /var/run/nginx.pid; worker_processes `sysctl -n hw.ncpu`;"
-p prefix — set nginx path prefix, i.e. a directory that will keep server files (default value is /usr/local/nginx).
-q — suppress non-error messages during configuration testing.不输出error级别下的信息,配合-t参数使用
-s signal — send a signal to the master process. The argument signal can be one of:
stop — shut down quickly
quit — shut down gracefully
reload — reload configuration, start the new worker process with a new configuration, gracefully shut down old worker processes.
reopen — reopen log files
-t — test the configuration file: nginx checks the configuration for correct syntax, and then tries to open files referred in the configuration.
-T — same as -t, but additionally dump configuration files to standard output (1.9.2).
-v — print nginx version.
-V — print nginx version, compiler version, and configure parameters.
复制代码
咱们先看一下ngx_get_options
的源码,以下:nginx
static ngx_int_t
ngx_get_options(int argc, char *const *argv)
{
u_char *p;
ngx_int_t i;
// 第0个参数是nginx自己,因此从第一个参数进行解析
for (i = 1; i < argc; i++) {
p = (u_char *) argv[i];
// 参数必须以短横线开头
if (*p++ != '-') {
ngx_log_stderr(0, "invalid option: \"%s\"", argv[i]);
return NGX_ERROR;
}
while (*p) {
switch (*p++) {
case '?':
case 'h':
ngx_show_version = 1;
ngx_show_help = 1;
break;
case 'v':
ngx_show_version = 1;
break;
case 'V':
ngx_show_version = 1;
ngx_show_configure = 1;
break;
case 't':
ngx_test_config = 1;
break;
case 'T':
ngx_test_config = 1;
ngx_dump_config = 1;
break;
case 'q':
ngx_quiet_mode = 1;
break;
case 'p':
if (*p) {
ngx_prefix = p;
goto next;
}
if (argv[++i]) {
ngx_prefix = (u_char *) argv[i];
goto next;
}
ngx_log_stderr(0, "option \"-p\" requires directory name");
return NGX_ERROR;
case 'c':
if (*p) {
ngx_conf_file = p;
goto next;
}
if (argv[++i]) {
ngx_conf_file = (u_char *) argv[i];
goto next;
}
ngx_log_stderr(0, "option \"-c\" requires file name");
return NGX_ERROR;
case 'g':
if (*p) {
ngx_conf_params = p;
goto next;
}
if (argv[++i]) {
ngx_conf_params = (u_char *) argv[i];
goto next;
}
ngx_log_stderr(0, "option \"-g\" requires parameter");
return NGX_ERROR;
case 's':
if (*p) {
ngx_signal = (char *) p;
} else if (argv[++i]) {
ngx_signal = argv[i];
} else {
ngx_log_stderr(0, "option \"-s\" requires parameter");
return NGX_ERROR;
}
if (ngx_strcmp(ngx_signal, "stop") == 0
|| ngx_strcmp(ngx_signal, "quit") == 0
|| ngx_strcmp(ngx_signal, "reopen") == 0
|| ngx_strcmp(ngx_signal, "reload") == 0)
{
ngx_process = NGX_PROCESS_SIGNALLER;
goto next;
}
ngx_log_stderr(0, "invalid option: \"-s %s\"", ngx_signal);
return NGX_ERROR;
default:
ngx_log_stderr(0, "invalid option: \"%c\"", *(p - 1));
return NGX_ERROR;
}
}
next:
continue;
}
return NGX_OK;
}
复制代码
Q1:
为何有一个while
循环?A1:
一个减号后面能够带有多个参数。好比-thv
等。web
Q2:
为何处理-p
的时候要先判断一下if(*p)
呢?sql
// 为何要先判断一次 *p, 而后再判断argv[++i]呢?
if (*p) {
ngx_prefix = p;
goto next;
}
if (argv[++i]) {
ngx_prefix = (u_char *) argv[i];
goto next;
}
ngx_log_stderr(0, "option \"-p\" requires directory name");
return NGX_ERROR;
复制代码
A2:
由于nginx
的-p
的参数既能够紧跟着p
,也能够和-p
中间隔若干个空格。
好比/usr/local/nginx/sbin/nginx -p/usr/local/nginx/html/
,也能够/usr/local/nginx/sbin/nginx -p /usr/local/nginx/html/
,因此这里有两种处理方式了。if(*p)
是处理第一种中间没有空格的状况。数组
要知道,argv[]
是一个字符串指针数组,每一个元素都是以\0
结尾的,而且数组的最后一个元素是NULL
。因此若是*p != NULL
,那么就说明-p
的参数是紧挨着-p
的。app
从这里咱们也能够看出来,处理完-p
指令以后执行了goto next
,而不是break
,这里也说明:若是-p
指令和其余指令一块儿使用的时候,-p
必须放到最后,好比/usr/local/nginx/sbin/nginx -tp /usr/local/nginx/html/
, 而不能是/usr/local/nginx/sbin/nginx -pt /usr/local/nginx/html/
。(注意p
和t
的顺序)函数
对于每种参数的解析都是相似的,会设置一个变量。
好比,若是是-v
,那么就会设置ngx_show_version = 1
等。源码分析
TODO: 此处缺乏一张归纳图ui
本文就先简单的分析一下启动过程当中的解析命令行参数的函数。若是喜欢本文,能够关注公众号Nginx源码分析
.spa