⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 initdb.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/*------------------------------------------------------------------------- * * initdb --- initialize a PostgreSQL installation * * initdb creates (initializes) a PostgreSQL database cluster (site, * instance, installation, whatever).  A database cluster is a * collection of PostgreSQL databases all managed by the same postmaster. * * To create the database cluster, we create the directory that contains * all its data, create the files that hold the global tables, create * a few other control files for it, and create three databases: the * template databases "template0" and "template1", and a default user * database "postgres". * * The template databases are ordinary PostgreSQL databases.  template0 * is never supposed to change after initdb, whereas template1 can be * changed to add site-local standard data.  Either one can be copied * to produce a new database. * * For largely-historical reasons, the template1 database is the one built * by the basic bootstrap process.	After it is complete, template0 and * the default database, postgres, are made just by copying template1. * * To create template1, we run the postgres (backend) program in bootstrap * mode and feed it data from the postgres.bki library file.  After this * initial bootstrap phase, some additional stuff is created by normal * SQL commands fed to a standalone backend.  Some of those commands are * just embedded into this program (yeah, it's ugly), but larger chunks * are taken from script files. * * * Note: *	 The program has some memory leakage - it isn't worth cleaning it up. * * This is a C implementation of the previous shell script for setting up a * PostgreSQL cluster location, and should be highly compatible with it. * author of C translation: Andrew Dunstan	   mailto:andrew@dunslane.net * * This code is released under the terms of the PostgreSQL License. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * Portions taken from FreeBSD. * * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.99.2.2 2006/02/24 00:55:27 adunstan Exp $ * *------------------------------------------------------------------------- */#include "postgres_fe.h"#include <dirent.h>#include <sys/stat.h>#include <unistd.h>#include <locale.h>#include <signal.h>#ifdef HAVE_LANGINFO_H#include <langinfo.h>#endif#include "libpq/pqsignal.h"#include "mb/pg_wchar.h"#include "getaddrinfo.h"#include "getopt_long.h"#ifndef HAVE_INT_OPTRESETint			optreset;#endif/* version string we expect back from postgres */#define PG_VERSIONSTR "postgres (PostgreSQL) " PG_VERSION "\n"/* * these values are passed in by makefile defines */static char *share_path = NULL;/* values to be obtained from arguments */static char *pg_data = "";static char *encoding = "";static char *locale = "";static char *lc_collate = "";static char *lc_ctype = "";static char *lc_monetary = "";static char *lc_numeric = "";static char *lc_time = "";static char *lc_messages = "";static char *username = "";static bool pwprompt = false;static char *pwfilename = NULL;static char *authmethod = "";static bool debug = false;static bool noclean = false;static bool show_setting = false;/* internal vars */static const char *progname;static char *encodingid = "0";static char *bki_file;static char *desc_file;static char *hba_file;static char *ident_file;static char *conf_file;static char *conversion_file;static char *info_schema_file;static char *features_file;static char *system_views_file;static bool made_new_pgdata = false;static bool found_existing_pgdata = false;static char infoversion[100];static bool caught_signal = false;static bool output_failed = false;static int	output_errno = 0;/* defaults */static int	n_connections = 10;static int	n_buffers = 50;/* * Warning messages for authentication methods */#define AUTHTRUST_WARNING \"# CAUTION: Configuring the system for local \"trust\" authentication allows\n" \"# any local user to connect as any PostgreSQL user, including the database\n" \"# superuser. If you do not trust all your local users, use another\n" \"# authentication method.\n"static char *authwarning = NULL;/* * Centralized knowledge of switches to pass to backend * * Note: in the shell-script version, we also passed PGDATA as a -D switch, * but here it is more convenient to pass it as an environment variable * (no quoting to worry about). */static const char *boot_options = "-F";static const char *backend_options = "-F -O -c search_path=pg_catalog -c exit_on_error=true";/* path to 'initdb' binary directory */static char bin_path[MAXPGPATH];static char backend_exec[MAXPGPATH];static void *pg_malloc(size_t size);static char *xstrdup(const char *s);static char **replace_token(char **lines,			  const char *token, const char *replacement);#ifndef HAVE_UNIX_SOCKETSstatic char **filter_lines_with_token(char **lines, const char *token);#endifstatic char **readfile(char *path);static void writefile(char *path, char **lines);static FILE *popen_check(const char *command, const char *mode);static int	mkdir_p(char *path, mode_t omode);static void exit_nicely(void);static char *get_id(void);static char *get_encoding_id(char *encoding_name);static char *get_short_version(void);static int	check_data_dir(void);static bool mkdatadir(const char *subdir);static void set_input(char **dest, char *filename);static void check_input(char *path);static void set_short_version(char *short_version, char *extrapath);static void set_null_conf(void);static void test_connections(void);static void test_buffers(void);static void setup_config(void);static void bootstrap_template1(char *short_version);static void setup_auth(void);static void get_set_pwd(void);static void unlimit_systables(void);static void setup_depend(void);static void setup_sysviews(void);static void setup_description(void);static void setup_conversion(void);static void setup_privileges(void);static void set_info_version(void);static void setup_schema(void);static void vacuum_db(void);static void make_template0(void);static void make_postgres(void);static void trapsig(int signum);static void check_ok(void);static char *escape_quotes(const char *src);static bool chklocale(const char *locale);static void setlocales(void);static void usage(const char *progname);/* * macros for running pipes to postgres */#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_CLOSE \do { \	if (pclose_check(cmdfd)) \		exit_nicely(); /* message already printed by pclose_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_PRINTF1(fmt, arg1) \do { \	if (fprintf(cmdfd, fmt, arg1) < 0 || fflush(cmdfd) < 0) \		output_failed = true, output_errno = errno; \} while (0)#define PG_CMD_PRINTF2(fmt, arg1, arg2) \do { \	if (fprintf(cmdfd, fmt, arg1, arg2) < 0 || fflush(cmdfd) < 0) \		output_failed = true, output_errno = errno; \} while (0)#ifndef WIN32#define QUOTE_PATH	""#define DIR_SEP "/"#else#define QUOTE_PATH	"\""#define DIR_SEP "\\"#endif/* * routines to check mem allocations and fail noisily. * * Note that we can't call exit_nicely() on a memory failure, as it calls * rmtree() which needs memory allocation. So we just exit with a bang. */static void *pg_malloc(size_t size){	void	   *result;	result = malloc(size);	if (!result)	{		fprintf(stderr, _("%s: out of memory\n"), progname);		exit(1);	}	return result;}static char *xstrdup(const char *s){	char	   *result;	result = strdup(s);	if (!result)	{		fprintf(stderr, _("%s: out of memory\n"), progname);		exit(1);	}	return result;}/* * make a copy of the array of lines, with token replaced by replacement * the first time it occurs on each line. * * This does most of what sed was used for in the shell script, but * doesn't need any regexp stuff. */static char **replace_token(char **lines, const char *token, const char *replacement){	int			numlines = 1;	int			i;	char	  **result;	int			toklen,				replen,				diff;	for (i = 0; lines[i]; i++)		numlines++;	result = (char **) pg_malloc(numlines * sizeof(char *));	toklen = strlen(token);	replen = strlen(replacement);	diff = replen - toklen;	for (i = 0; i < numlines; i++)	{		char	   *where;		char	   *newline;		int			pre;		/* just copy pointer if NULL or no change needed */		if (lines[i] == NULL || (where = strstr(lines[i], token)) == NULL)		{			result[i] = lines[i];			continue;		}		/* if we get here a change is needed - set up new line */		newline = (char *) pg_malloc(strlen(lines[i]) + diff + 1);		pre = where - lines[i];		strncpy(newline, lines[i], pre);		strcpy(newline + pre, replacement);		strcpy(newline + pre + replen, lines[i] + pre + toklen);		result[i] = newline;	}	return result;}/* * make a copy of lines without any that contain the token * * a sort of poor man's grep -v */#ifndef HAVE_UNIX_SOCKETSstatic char **filter_lines_with_token(char **lines, const char *token){	int			numlines = 1;	int			i,				src,				dst;	char	  **result;	for (i = 0; lines[i]; i++)		numlines++;	result = (char **) pg_malloc(numlines * sizeof(char *));	for (src = 0, dst = 0; src < numlines; src++)	{		if (lines[src] == NULL || strstr(lines[src], token) == NULL)			result[dst++] = lines[src];	}	return result;}#endif/* * get the lines from a text file */static char **readfile(char *path){	FILE	   *infile;	int			maxlength = 0,				linelen = 0;	int			nlines = 0;	char	  **result;	char	   *buffer;	int			c;	if ((infile = fopen(path, "r")) == NULL)	{		fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),				progname, path, strerror(errno));		exit_nicely();	}	/* pass over the file twice - the first time to size the result */	while ((c = fgetc(infile)) != EOF)	{		linelen++;		if (c == '\n')		{			nlines++;			if (linelen > maxlength)				maxlength = linelen;			linelen = 0;		}	}	/* handle last line without a terminating newline (yuck) */	if (linelen)		nlines++;	if (linelen > maxlength)		maxlength = linelen;	/* set up the result and the line buffer */	result = (char **) pg_malloc((nlines + 2) * sizeof(char *));	buffer = (char *) pg_malloc(maxlength + 2);	/* now reprocess the file and store the lines */	rewind(infile);	nlines = 0;	while (fgets(buffer, maxlength + 1, infile) != NULL)	{		result[nlines] = xstrdup(buffer);		nlines++;	}	fclose(infile);	result[nlines] = NULL;	return result;}/* * write an array of lines to a file * * This is only used to write text files.  Use fopen "w" not PG_BINARY_W * so that the resulting configuration files are nicely editable on Windows. */static voidwritefile(char *path, char **lines){	FILE	   *out_file;	char	  **line;	if ((out_file = fopen(path, "w")) == NULL)	{		fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),				progname, path, strerror(errno));		exit_nicely();	}	for (line = lines; *line != NULL; line++)	{		if (fputs(*line, out_file) < 0)		{			fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),					progname, path, strerror(errno));			exit_nicely();		}		free(*line);	}	if (fclose(out_file))	{		fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),				progname, path, strerror(errno));		exit_nicely();	}}/* * Open a subcommand with suitable error messaging */static FILE *popen_check(const char *command, const char *mode){	FILE	   *cmdfd;	fflush(stdout);	fflush(stderr);	errno = 0;	cmdfd = popen(command, mode);	if (cmdfd == NULL)		fprintf(stderr, _("%s: could not execute command \"%s\": %s\n"),				progname, command, strerror(errno));	return cmdfd;}/* source stolen from FreeBSD /src/bin/mkdir/mkdir.c and adapted *//* * this tries to build all the elements of a path to a directory a la mkdir -p * we assume the path is in canonical form, i.e. uses / as the separator * we also assume it isn't null. * * note that on failure, the path arg has been modified to show the particular * directory level we had problems with. */static intmkdir_p(char *path, mode_t omode){	struct stat sb;	mode_t		numask,				oumask;	int			first,				last,				retval;	char	   *p;	p = path;	oumask = 0;	retval = 0;#ifdef WIN32	/* skip network and drive specifiers for win32 */	if (strlen(p) >= 2)	{		if (p[0] == '/' && p[1] == '/')		{			/* network drive */			p = strstr(p + 2, "/");			if (p == NULL)				return 1;		}		else if (p[1] == ':' &&				 ((p[0] >= 'a' && p[0] <= 'z') ||				  (p[0] >= 'A' && p[0] <= 'Z')))		{			/* local drive */			p += 2;		}	}#endif	if (p[0] == '/')			/* Skip leading '/'. */		++p;	for (first = 1, last = 0; !last; ++p)	{		if (p[0] == '\0')			last = 1;		else if (p[0] != '/')			continue;		*p = '\0';		if (!last && p[1] == '\0')			last = 1;		if (first)		{			/*			 * POSIX 1003.2: For each dir operand that does not name an			 * existing directory, effects equivalent to those caused by the			 * following command shall occcur:			 *			 * mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode]			 * dir			 *			 * We change the user's umask and then restore it, instead of			 * doing chmod's.			 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -