postgresql从入门到菜鸟(九)initdb流程分析-参数解析

上一期说了initdb的大概流程和初期准备,这一期说一说参数解析

首先看一下initdb的入口,main函数

main(int argc, char *argv[])

这里有两个参数,argc和argv[]
argc: 命令行总的参数个数
argv[]:保存命令行参数的字符串指针,其中argv[0]参数是程序的全名

假设我在命令行输入initdb -D pgdata
argc=3
argv[0]=“F:\postgresql-9.6.10\bin\bin\initdb.exe”
argv[1]=“-D“
argv[2]=“pgdata”

首先要解析的是调用程序的实际名称

progname = get_progname(argv[0]);
const char *
get_progname(const char *argv0)
{
	const char *nodir_name;
	char	   *progname;
	
	//这里从F:\postgresql-9.6.10\bin\bin\initdb.exe得到initdb.exe
	nodir_name = last_dir_separator(argv0);
	if (nodir_name)
		nodir_name++;
	else
		nodir_name = skip_drive(argv0);

	/*
	 * Make a copy in case argv[0] is modified by ps_status. Leaks memory, but
	 * called only once.
	 */
	progname = strdup(nodir_name);
	if (progname == NULL)
	{
		fprintf(stderr, "%s: out of memory\n", nodir_name);
		abort();				/* This could exit the postmaster */
	}

#if defined(__CYGWIN__) || defined(WIN32)
	//如果是windows平台,去掉.exe.的后缀
	/* strip ".exe" suffix, regardless of case */
	if (strlen(progname) > sizeof(EXE) - 1 &&
	pg_strcasecmp(progname + strlen(progname) - (sizeof(EXE) - 1), EXE) == 0)
		progname[strlen(progname) - (sizeof(EXE) - 1)] = '\0';
#endif
	//最终返回调用程序的实际名称initdb
	return progname;
}

接下来是解析参数,首先判断参数是否是版本或者帮助信息

//刚刚上面分析过,argc = 3,argv[1] = “-D”,所以不进这个if
if (argc > 1)
	{
		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
		{
			usage(progname);
			exit(0);
		}
		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
		{
			puts("initdb (PostgreSQL) " PG_VERSION);
			exit(0);
		}
	}

接下来就是正儿八经的参数解析了,可解析参数类型很多,完整的参数列表可以看官方手册或者我上一篇的文章,这里用-D举例

while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:", long_options, &option_index)) != -1)
	{
		switch (c)
		{
			……
			case 'D':
				pg_data = pg_strdup(optarg);
				break;
			……
			default:
				/* getopt_long already emitted a complaint */
				fprintf(stderr, _("Try \"%s --help\" for more information.\n"),progname);
				exit(1);
		}

首先看getopt_long这个函数,入参有以下几个
argc:上面分析过,参数个数。
argv:上面分析过,命令行参数的字符串指针。
“dD:E:kL:nNU:WA:sST:X:”:可识别的字符选项。
long_options:参数列表,在上一篇文章中分析过。
&option_index:参数索引,标识当前在第几个参数。

getopt_long函数的返回值只是参数的内部value,方便后续操作识别,参数的值则是通过optarg这个全局变量传出来的。在getopt_long中optarg被赋值为F:\data,然后通过pg_strdup函数赋值给pgdata。其中pg_strdup函数是封装了strdup函数,在赋值前会先判断optarg是否为空。

后续还有一些异常处理,一般在一个参数后面添加多个值才会走到此路径

if (optind < argc)
	{
		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
				progname, argv[optind]);
		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
				progname);
		exit(1);
	}

参数解析到这里就差不多结束了,在环境设定前还有一段代码,这里是数据同步的代码,只有在initdb时加上-S参数才会走到这里,这段代码会安全地把所有数据库文件写入到磁盘并退出。这不会执行任何正常的initdb操作。

/* If we only need to fsync, just do it and exit */
	if (sync_only)
	{
		setup_pgdata();

		/* must check that directory is readable */
		if (pg_check_dir(pg_data) <= 0)
		{
			fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
					progname, pg_data, strerror(errno));
			exit_nicely();
		}

		fsync_pgdata();
		return 0;
	}

你可能感兴趣的:(postgresql)