PostgreSQL数据库集簇初始化——initdb初始化数据库(数据库template1)
在bootstrap模式下创建数据库template1,存储在数据目录的子目录base/1/中。
1 /* Bootstrap template1 */ 2 bootstrap_template1(short_version); 3 /* Make the per-database PG_VERSION for template1 only after init'ing it */ 4 set_short_version(short_version, "base/1");
headerline数组中存储的内容为# PostgreSQL short_version\n,用于和*bki_lines中的内容进行对比,确保读取的bki是正确的。下一步对bki进行读取,并根据之前配置的内容对bki_lines中的内容进行替换。cmd的内容为"backend_exec" --boot -x1 boot_options talkargs。
#define PG_CMD_DECL char cmd[MAXPGPATH]; FILE *cmdfd
#define PG_CMD_OPEN \
do { \
cmdfd = popen_check(cmd, "w"); \
if (cmdfd == NULL) \
exit_nicely(); /* message already printed by popen_check */ \
} while (0)
#define PG_CMD_PUTS(line) \
do { \
if (fputs(line, cmdfd) < 0 || fflush(cmdfd) < 0) \
output_failed = true, output_errno = errno; \
} while (0)
#define PG_CMD_CLOSE \
do { \
if (pclose_check(cmdfd)) \
exit_nicely(); /* message already printed by pclose_check */ \
} while (0)
1 /* run the BKI script in bootstrap mode to create template1 */ 2 static void bootstrap_template1(char *short_version) { 3 PG_CMD_DECL; 4 char **line; 5 char *talkargs = ""; 6 char **bki_lines; 7 char headerline[MAXPGPATH]; 8 char buf[64]; 9 printf(_("creating template1 database in %s/base/1 ... "), pg_data); 10 fflush(stdout); 11 if (debug) 12 talkargs = "-d 5"; 13 bki_lines = readfile(bki_file); 14 /* Check that bki file appears to be of the right version */ 15 snprintf(headerline, sizeof(headerline), "# PostgreSQL %s\n",short_version); 16 if (strcmp(headerline, *bki_lines) != 0){ 17 fprintf(stderr,_("%s: input file \"%s\" does not belong to PostgreSQL %s\n" "Check your installation or specify the correct path " "using the option -L.\n"), progname, bki_file, PG_VERSION); 18 exit_nicely(); 19 } 20 21 /* Substitute for various symbols used in the BKI file */ 22 sprintf(buf, "%d", NAMEDATALEN); 23 bki_lines = replace_token(bki_lines, "NAMEDATALEN", buf); 24 sprintf(buf, "%d", (int) sizeof(Pointer)); 25 bki_lines = replace_token(bki_lines, "SIZEOF_POINTER", buf); 26 bki_lines = replace_token(bki_lines, "ALIGNOF_POINTER", (sizeof(Pointer) == 4) ? "i" : "d"); 27 bki_lines = replace_token(bki_lines, "FLOAT4PASSBYVAL",FLOAT4PASSBYVAL ? "true" : "false"); 28 bki_lines = replace_token(bki_lines, "FLOAT8PASSBYVAL", FLOAT8PASSBYVAL ? "true" : "false"); 29 bki_lines = replace_token(bki_lines, "POSTGRES",username); 30 bki_lines = replace_token(bki_lines, "ENCODING",encodingid); 31 bki_lines = replace_token(bki_lines, "LC_COLLATE",lc_collate); 32 bki_lines = replace_token(bki_lines, "LC_CTYPE", lc_ctype); 33 34 /* Pass correct LC_xxx environment to bootstrap. The shell script arranged to restore the LC settings afterwards, but there doesn't seem to be any compelling reason to do that. */ 35 snprintf(cmd, sizeof(cmd), "LC_COLLATE=%s", lc_collate); 36 putenv(xstrdup(cmd)); 37 snprintf(cmd, sizeof(cmd), "LC_CTYPE=%s", lc_ctype); 38 putenv(xstrdup(cmd)); 39 unsetenv("LC_ALL"); 40 41 /* Also ensure backend isn't confused by this environment var: */ 42 unsetenv("PGCLIENTENCODING"); 43 snprintf(cmd, sizeof(cmd), "\"%s\" --boot -x1 %s %s", backend_exec, boot_options, talkargs); 44 45 PG_CMD_OPEN; 46 for (line = bki_lines; *line != NULL; line++){ 47 PG_CMD_PUTS(*line); 48 free(*line); 49 } 50 PG_CMD_CLOSE; 51 free(bki_lines); 52 check_ok(); 53 }
popen_check使用了popen,popen()函数通过创建一个管道,调用fork()产生一个子进程,执行一个shell以运行命令来开启一个进程。这个管道必须由pclose()函数关闭,而不是fclose()函数。pclose()函数关闭标准I/O流,等待命令执行结束,然后返回shell的终止状态。如果shell不能被执行,则pclose()返回的终止状态与shell已执行exit一样。故使用popen产生子进程去执行comamnd中的命令。
1 /* Open a subcommand with suitable error messaging */ 2 static FILE * popen_check(const char *command, const char *mode){ 3 FILE *cmdfd; 4 fflush(stdout); 5 fflush(stderr); 6 errno = 0; 7 cmdfd = popen(command, mode); 8 if (cmdfd == NULL) 9 fprintf(stderr, _("%s: could not execute command \"%s\": %s\n"), progname, command, strerror(errno)); 10 return cmdfd; 11 }