/*-------------------------------------------------------------------------
*
- * initdb
+ * initdb --- initialize a PostgreSQL installation
*
- * author: Andrew Dunstan mailto:andrew@dunslane.net
+ * 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.
*
- * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
+ * 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 two databases: the
+ * template0 and template1 databases.
*
- * This code is released under the terms of the PostgreSQL License.
+ * 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.
*
- * This is a C implementation of the previous shell script for setting up a
- * PostgreSQL cluster location, and should be highly compatible with it.
+ * 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.
+ *
+ * template0 is made just by copying the completed template1.
*
- * $Header: /cvsroot/pgsql/src/bin/initdb/initdb.c,v 1.6 2003/11/13 20:12:47 momjian Exp $
*
* TODO:
* - clean up find_postgres code and return values
*
* Note:
* The program has some memory leakage - it isn't worth cleaning it up.
- * Even before the code was put in to free most of the dynamic memory
- * used it ran around 500Kb used + malloc overhead. It should now use
- * far less than that (around 240Kb - the size of the BKI file).
- * If we can't load this much data into memory how will we ever run
- * postgres anyway?
+ *
+ *
+ * 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-2003, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $Header: /cvsroot/pgsql/src/bin/initdb/initdb.c,v 1.7 2003/11/13 23:46:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* version string we expect back from postgres */
#define PG_VERSIONSTR "postgres (PostgreSQL) " PG_VERSION "\n"
-/* values passed in by makefile define */
-
+/*
+ * these values are passed in by makefile defines
+ *
+ * Note that "datadir" is not the directory we're going to initialize,
+ * it's merely how Autoconf names PREFIX/share.
+ */
char *bindir = PGBINDIR;
char *datadir = PGDATADIR;
int n_connections = 10;
int n_buffers = 50;
+/*
+ * 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";
+
/* platform specific path stuff */
#if defined(__CYGWIN__) || defined(WIN32)
static bool rmtree(char *, bool);
static void exit_nicely(void);
static void canonicalize_path(char *);
-
#ifdef WIN32
static char *expanded_path(char *);
-
#else
#define expanded_path(x) (x)
#endif
-
static char **readfile(char *);
static void writefile(char *, char **);
static char *get_id(void);
#define PG_CMD_CLOSE \
do { \
- if(pclose(pg) >> 8 & 0xff) \
+ if ((pclose(pg) >> 8) & 0xff) \
exit_nicely(); \
} while (0)
/*
* 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 *
xmalloc(size_t size)
* assumes path points to a valid directory
* deletes everything under path
* if rmtopdir is true deletes the directory too
- *
*/
static bool
rmtree(char *path, bool rmtopdir)
/*
* make all paths look like unix, with forward slashes
* also strip any trailing slash.
+ *
* The Windows command processor will accept suitably quoted paths
* with forward slashes, but barfs badly with mixed forward and back
* slashes. Removing the trailing slash on a path means we never get
- * ugly double slashes.
+ * ugly double slashes. Don't remove a leading slash, though.
*/
static void
canonicalize_path(char *path)
*p = '/';
#endif
}
- if (p != path && *--p == '/')
+ if (p > path+1 && *--p == '/')
*p = '\0';
}
/*
* 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.
*/
/*
* get the lines from a text file
- *
*/
static char **
readfile(char *path)
/*
* write an array of lines to a file
- *
*/
static void
writefile(char *path, char **lines)
* 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.
- *
*/
static int
mkdir_p(char *path, mode_t omode)
/*
* clean up any files we created on failure
* if we created the data directory remove it too
- *
*/
static void
exit_nicely(void)
fprintf(stderr, "%s: failed\n", progname);
}
}
+ else
+ {
+ fprintf(stderr,
+ "%s: data directory \"%s\" not removed at user's request\n",
+ progname, pg_data);
+ }
exit(1);
}
/*
* find the current user using code lifted from pg_id.c
- * on unix make sure it isn't really root
*
+ * on unix make sure it isn't really root
*/
static char *
get_id(void)
{
fprintf(stderr,
"%s: cannot be run as root\n"
- "Please log in (using, e.g., \"su\") as the (unprivileged) "
- "user that will\n" "own the server process.\n",
+ "Please log in (using, e.g., \"su\") as the "
+ "(unprivileged) user that will\n"
+ "own the server process.\n",
progname);
exit(1);
}
/*
* get the encoding id for a given encoding name
- *
*/
static char *
get_encoding_id(char *encoding_name)
/*
* get short version of VERSION
- *
*/
static char *
get_short_version(void)
/*
* make sure the data directory either doesn't exist or is empty
- *
*/
static bool
check_data_dir(void)
/*
* make the data directory (or one of its subdirectories if subdir is not NULL)
- *
*/
static bool
mkdatadir(char *subdir)
/*
* set name of given input file variable under data directory
- *
*/
static void
set_input(char **dest, char *filename)
/*
* check that given input file exists
- *
*/
static void
check_input(char *path)
/*
* TODO - clean this up and handle the errors properly
* don't overkill
- *
*/
#define FIND_SUCCESS 0
#define FIND_NOT_FOUND 1
/*
* see if there is a postgres executable in the given path, and giving the
* right version number
- *
*/
static int
find_postgres(char *path)
FILE *pgver;
int plen = strlen(path);
- if (path[plen - 1] != '/')
- snprintf(fn, MAXPGPATH, "%s/postgres%s", path, EXE);
+ if (plen > 0 && path[plen - 1] != '/')
+ snprintf(fn, sizeof(fn), "%s/postgres%s", path, EXE);
else
- snprintf(fn, MAXPGPATH, "%spostgres%s", path, EXE);
+ snprintf(fn, sizeof(fn), "%spostgres%s", path, EXE);
if (stat(fn, &statbuf) != 0)
{
return FIND_BAD_PERM;
#endif
- snprintf(cmd, MAXPGPATH, "\"%s/postgres\" -V 2>%s", path, DEVNULL);
+ snprintf(cmd, sizeof(cmd), "\"%s/postgres\" -V 2>%s", path, DEVNULL);
if ((pgver = popen(cmd, "r")) == NULL)
return FIND_EXEC_ERR;
/*
* Windows doesn't like relative paths to executables (other things work fine)
* so we call its builtin function to expand them. Elsewhere this is a NOOP
- *
*/
#ifdef WIN32
static char *
{
char abspath[MAXPGPATH];
- if (_fullpath(abspath, path, MAXPGPATH) == NULL)
+ if (_fullpath(abspath, path, sizeof(abspath)) == NULL)
{
perror("expanded path");
return path;
/*
* set the paths pointing to postgres
+ *
* look for it in the same place we found this program, or in the environment
* path, or in the configured bindir.
+ * We do it in this order because during upgrades users might move
+ * their trees to backup places, so the hard-wired bindir might be inaccurate.
*
+ * XXX this needs work, as its error handling is vastly inferior to the
+ * shell-script version, in particular the case where a postgres executable
+ * is failing
*/
static int
set_paths(void)
{
if (testpath && !self_path)
{
-
char *path,
*cursor;
int pathlen,
for (i = 0; i < pathsegs; i++)
{
- snprintf(buf, MAXPGPATH, "%s/%s%s", pathbits[i], progname, EXE);
+ snprintf(buf, sizeof(buf), "%s/%s%s", pathbits[i], progname, EXE);
if (stat(buf, &statbuf) == 0 && S_ISREG(statbuf.st_mode))
{
self_path = pathbits[i];
/*
* write out the PG_VERSION file in the data dir, or its subdirectory
* if extrapath is not NULL
- *
*/
static void
set_short_version(char *short_version, char *extrapath)
/*
* set up an empty config file so we can check buffers and connections
- *
*/
static void
set_null_conf(void)
/*
* check how many connections we can sustain
- *
*/
static void
test_connections(void)
{
- char *format =
- "\"%s/postgres\" -boot -x 0 -F "
- "-c shared_buffers=%d -c max_connections=%d template1 <%s >%s 2>&1";
char cmd[MAXPGPATH];
- int conns[] = {100, 50, 40, 30, 20, 10};
- int len = sizeof(conns) / sizeof(int);
+ static const int conns[] = {100, 50, 40, 30, 20, 10};
+ static const int len = sizeof(conns) / sizeof(int);
int i,
status;
for (i = 0; i < len; i++)
{
- snprintf(cmd, sizeof(cmd), format,
- pgpath, conns[i] * 5, conns[i], DEVNULL, DEVNULL);
+ snprintf(cmd, sizeof(cmd),
+ "\"%s/postgres\" -boot -x0 %s "
+ "-c shared_buffers=%d -c max_connections=%d template1 "
+ "<%s >%s 2>&1",
+ pgpath, boot_options,
+ conns[i] * 5, conns[i],
+ DEVNULL, DEVNULL);
status = system(cmd);
if (status == 0)
break;
/*
* check how many buffers we can run with
- *
*/
static void
test_buffers(void)
{
- char *format =
- "\"%s/postgres\" -boot -x 0 -F "
- "-c shared_buffers=%d -c max_connections=%d template1 <%s >%s 2>&1";
char cmd[MAXPGPATH];
- int bufs[] = {1000, 900, 800, 700, 600, 500, 400, 300, 200, 100, 50};
- int len = sizeof(bufs) / sizeof(int);
+ static const int bufs[] = {1000, 900, 800, 700, 600, 500,
+ 400, 300, 200, 100, 50};
+ static const int len = sizeof(bufs) / sizeof(int);
int i,
status;
for (i = 0; i < len; i++)
{
- snprintf(cmd, sizeof(cmd), format, pgpath, bufs[i], n_connections,
+ snprintf(cmd, sizeof(cmd),
+ "\"%s/postgres\" -boot -x0 %s "
+ "-c shared_buffers=%d -c max_connections=%d template1 "
+ "<%s >%s 2>&1",
+ pgpath, boot_options,
+ bufs[i], n_connections,
DEVNULL, DEVNULL);
status = system(cmd);
if (status == 0)
/*
* set up all the config files
- *
*/
static void
setup_config(void)
{
-
char **conflines;
char repltok[100];
char path[MAXPGPATH];
snprintf(repltok, sizeof(repltok), "lc_time = '%s'", lc_time);
conflines = replace_token(conflines, "#lc_time = 'C'", repltok);
- snprintf(path, MAXPGPATH, "%s/postgresql.conf", pg_data);
+ snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data);
writefile(path, conflines);
chmod(path, 0600);
"#host all all ::1");
#endif
- snprintf(path, MAXPGPATH, "%s/pg_hba.conf", pg_data);
+ snprintf(path, sizeof(path), "%s/pg_hba.conf", pg_data);
writefile(path, conflines);
chmod(path, 0600);
conflines = readfile(ident_file);
- snprintf(path, MAXPGPATH, "%s/pg_ident.conf", pg_data);
+ snprintf(path, sizeof(path), "%s/pg_ident.conf", pg_data);
writefile(path, conflines);
chmod(path, 0600);
/*
- * run the bootstrap code
- *
+ * run the BKI script in bootstrap mode to create template1
*/
static void
bootstrap_template1(char *short_version)
bki_lines = readfile(bki_file);
- snprintf(headerline, MAXPGPATH, "# PostgreSQL %s\n", short_version);
+ /* Check that bki file appears to be of the right version */
+
+ snprintf(headerline, sizeof(headerline), "# PostgreSQL %s\n",
+ short_version);
if (strcmp(headerline, *bki_lines) != 0)
{
bki_lines = replace_token(bki_lines, "ENCODING", encodingid);
/*
- * we could save the old environment here, and restore it afterwards,
- * but there doesn't seem to be any point, especially as we have
- * already called setlocale().
+ * 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.
*/
- snprintf(cmd, MAXPGPATH, "LC_COLLATE=%s", lc_collate);
+ snprintf(cmd, sizeof(cmd), "LC_COLLATE=%s", lc_collate);
putenv(xstrdup(cmd));
- snprintf(cmd, MAXPGPATH, "LC_CTYPE=%s", lc_ctype);
+ snprintf(cmd, sizeof(cmd), "LC_CTYPE=%s", lc_ctype);
putenv(xstrdup(cmd));
putenv("LC_ALL");
- snprintf(cmd, MAXPGPATH,
- " \"%s/postgres\" -boot -x1 -F %s template1", pgpath, talkargs);
+ snprintf(cmd, sizeof(cmd),
+ "\"%s/postgres\" -boot -x1 %s %s template1",
+ pgpath, boot_options, talkargs);
PG_CMD_OPEN;
/*
* set up the shadow password table
- *
*/
static void
setup_shadow(void)
{
-
char *pg_shadow_setup[] = {
/*
* Create a trigger so that direct updates to pg_shadow will be
fputs("initializing pg_shadow ... ", stdout);
fflush(stdout);
- snprintf(cmd, MAXPGPATH,
- "\"%s/postgres\" -F -O -c search_path=pg_catalog "
- "-c exit_on_error=true template1 >%s",
- pgpath, DEVNULL);
+ snprintf(cmd, sizeof(cmd),
+ "\"%s/postgres\" %s template1 >%s",
+ pgpath, backend_options,
+ DEVNULL);
PG_CMD_OPEN;
/*
* get the superuser password if required, and call postgres to set it
- *
*/
static void
get_set_pwd(void)
}
free(pwd2);
- printf("storing the password ... ");
+ printf("setting password ... ");
fflush(stdout);
- snprintf(cmd, MAXPGPATH,
- "\"%s/postgres\" -F -O -c search_path=pg_catalog "
- "-c exit_on_error=true template1 >%s", pgpath, DEVNULL);
+ snprintf(cmd, sizeof(cmd),
+ "\"%s/postgres\" %s template1 >%s",
+ pgpath, backend_options,
+ DEVNULL);
PG_CMD_OPEN;
PG_CMD_CLOSE;
- snprintf(pwdpath, MAXPGPATH, "%s/global/pg_pwd", pg_data);
+ snprintf(pwdpath, sizeof(pwdpath), "%s/global/pg_pwd", pg_data);
if (stat(pwdpath, &statbuf) != 0 || !S_ISREG(statbuf.st_mode))
{
fprintf(stderr,
- "%s: The password file was not generated - "
- "please report this problem\n",
+ "%s: The password file was not generated. "
+ "Please report this problem.\n",
progname);
exit_nicely();
}
/*
* toast sys tables
- *
*/
static void
unlimit_systables(void)
fputs("enabling unlimited row size for system tables ... ", stdout);
fflush(stdout);
- snprintf(cmd, MAXPGPATH,
- "\"%s/postgres\" -F -O -c search_path=pg_catalog "
- "-c exit_on_error=true template1 >%s", pgpath, DEVNULL);
+ snprintf(cmd, sizeof(cmd),
+ "\"%s/postgres\" %s template1 >%s",
+ pgpath, backend_options,
+ DEVNULL);
PG_CMD_OPEN;
/*
* set up pg_depend
- *
*/
static void
setup_depend(void)
* the tables that the dependency code handles. This is overkill
* (the system doesn't really depend on having every last weird
* datatype, for instance) but generating only the minimum
- * required set of dependencies seems hard. Note that we
- * deliberately do not pin the system views. First delete any
- * already-made entries; PINs override all else, and must be the
- * only entries for their objects.
+ * required set of dependencies seems hard.
+ *
+ * Note that we deliberately do not pin the system views, which
+ * haven't been created yet.
+ *
+ * First delete any already-made entries; PINs override all else, and
+ * must be the only entries for their objects.
*/
"DELETE FROM pg_depend;\n",
"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
fputs("initializing pg_depend ... ", stdout);
fflush(stdout);
- snprintf(cmd, MAXPGPATH,
- "\"%s/postgres\" -F -O -c search_path=pg_catalog "
- "-c exit_on_error=true template1 >%s",
- pgpath, DEVNULL);
+ snprintf(cmd, sizeof(cmd),
+ "\"%s/postgres\" %s template1 >%s",
+ pgpath, backend_options,
+ DEVNULL);
PG_CMD_OPEN;
/*
* set up system views
- *
*/
static void
setup_sysviews(void)
sysviews_setup = readfile(system_views_file);
- snprintf(cmd, MAXPGPATH,
- "\"%s/postgres\" -F -N -O -c search_path=pg_catalog "
- "-c exit_on_error=true template1 >%s",
- pgpath, DEVNULL);
+ /*
+ * We use -N here to avoid backslashing stuff in system_views.sql
+ */
+ snprintf(cmd, sizeof(cmd),
+ "\"%s/postgres\" %s -N template1 >%s",
+ pgpath, backend_options,
+ DEVNULL);
PG_CMD_OPEN;
/*
* load description data
- *
*/
static void
setup_description(void)
{
- char *pg_description_setup1[] = {
- "CREATE TEMP TABLE tmp_pg_description ( "
- " objoid oid, "
- " classname name, "
- " objsubid int4, "
- " description text) WITHOUT OIDS;\n",
- "COPY tmp_pg_description FROM STDIN;\n",
- NULL
- };
-
- char *pg_description_setup2[] = {
- "\\.\n",
- "INSERT INTO pg_description "
- " SELECT t.objoid, c.oid, t.objsubid, t.description "
- " FROM tmp_pg_description t, pg_class c "
- " WHERE c.relname = t.classname;\n",
- NULL
- };
-
-
- PG_CMD_DECL;
-
- char **desc_lines;
+ PG_CMD_DECL_NOLINE;
+ int fres;
fputs("loading pg_description ... ", stdout);
fflush(stdout);
- snprintf(cmd, MAXPGPATH,
- "\"%s/postgres\" -F -O -c search_path=pg_catalog "
- "-c exit_on_error=true template1 >%s",
- pgpath, DEVNULL);
+ snprintf(cmd, sizeof(cmd),
+ "\"%s/postgres\" %s template1 >%s",
+ pgpath, backend_options,
+ DEVNULL);
PG_CMD_OPEN;
- for (line = pg_description_setup1; *line != NULL; line++)
- PG_CMD_PUTLINE;
-
- desc_lines = readfile(desc_file);
- for (line = desc_lines; *line != NULL; line++)
- {
- PG_CMD_PUTLINE;
- free(*line);
- }
-
- free(desc_lines);
+ fres = fprintf(pg,
+ "CREATE TEMP TABLE tmp_pg_description ( "
+ " objoid oid, "
+ " classname name, "
+ " objsubid int4, "
+ " description text) WITHOUT OIDS;\n");
+ if (fres < 0)
+ exit_nicely();
+ fres = fprintf(pg,
+ "COPY tmp_pg_description FROM '%s';\n",
+ desc_file);
+ if (fres < 0)
+ exit_nicely();
- for (line = pg_description_setup2; *line != NULL; line++)
- PG_CMD_PUTLINE;
+ fres = fprintf(pg,
+ "INSERT INTO pg_description "
+ " SELECT t.objoid, c.oid, t.objsubid, t.description "
+ " FROM tmp_pg_description t, pg_class c "
+ " WHERE c.relname = t.classname;\n");
+ if (fres < 0)
+ exit_nicely();
PG_CMD_CLOSE;
/*
* load conversion functions
- *
*/
static void
setup_conversion(void)
fputs("creating conversions ... ", stdout);
fflush(stdout);
- snprintf(cmd, MAXPGPATH,
- "\"%s/postgres\" -F -O -c search_path=pg_catalog "
- "-c exit_on_error=true template1 >%s",
- pgpath, DEVNULL);
+ snprintf(cmd, sizeof(cmd),
+ "\"%s/postgres\" %s template1 >%s",
+ pgpath, backend_options,
+ DEVNULL);
PG_CMD_OPEN;
}
/*
- * run privileges script
+ * Set up privileges
*
+ * We set most system catalogs and built-in functions as world-accessible.
+ * Some objects may require different permissions by default, so we
+ * make sure we don't overwrite privilege sets that have already been
+ * set (NOT NULL).
*/
static void
setup_privileges(void)
fputs("setting privileges on built-in objects ... ", stdout);
fflush(stdout);
- snprintf(cmd, MAXPGPATH,
- "\"%s/postgres\" -F -O -c search_path=pg_catalog "
- "-c exit_on_error=true template1 >%s",
- pgpath, DEVNULL);
+ snprintf(cmd, sizeof(cmd),
+ "\"%s/postgres\" %s template1 >%s",
+ pgpath, backend_options,
+ DEVNULL);
PG_CMD_OPEN;
}
/*
- * extract the strange version of version required for info schema
- *
+ * extract the strange version of version required for information schema
+ * (09.08.0007abc)
*/
static void
set_info_version(void)
/*
* load info schema and populate from features file
- *
*/
static void
setup_schema(void)
{
-
PG_CMD_DECL;
-
char **lines;
int fres;
lines = readfile(info_schema_file);
/*
- * note that here we don't run in single line mode, unlike other
- * places
+ * We use -N here to avoid backslashing stuff in information_schema.sql
*/
- snprintf(cmd, MAXPGPATH,
- "\"%s/postgres\" -F -O -c search_path=pg_catalog "
- "-c exit_on_error=true -N template1 >%s",
- pgpath, DEVNULL);
+ snprintf(cmd, sizeof(cmd),
+ "\"%s/postgres\" %s -N template1 >%s",
+ pgpath, backend_options,
+ DEVNULL);
PG_CMD_OPEN;
PG_CMD_CLOSE;
- lines = readfile(features_file);
-
- /*
- * strip CR before NL this is the only place we do this (following
- * the shell script) - we could do it universally in readfile() if
- * necessary
- *
- */
- lines = replace_token(lines, "\r\n", "\n");
-
- snprintf(cmd, MAXPGPATH,
- "\"%s/postgres\" -F -O -c search_path=pg_catalog "
- "-c exit_on_error=true template1 >%s",
- pgpath, DEVNULL);
+ snprintf(cmd, sizeof(cmd),
+ "\"%s/postgres\" %s template1 >%s",
+ pgpath, backend_options,
+ DEVNULL);
PG_CMD_OPEN;
" SET character_value = '%s' "
" WHERE implementation_info_name = 'DBMS VERSION';\n",
infoversion);
-
if (fres < 0)
exit_nicely();
- fres = fputs("COPY information_schema.sql_features "
- " (feature_id, feature_name, sub_feature_id, "
- " sub_feature_name, is_supported, comments) "
- "FROM STDIN;\n",
- pg);
-
+ fres = fprintf(pg,
+ "COPY information_schema.sql_features "
+ " (feature_id, feature_name, sub_feature_id, "
+ " sub_feature_name, is_supported, comments) "
+ " FROM '%s';\n",
+ features_file);
if (fres < 0)
exit_nicely();
- for (line = lines; *line != NULL; line++)
- {
- PG_CMD_PUTLINE;
- free(*line);
- }
-
- free(lines);
-
- if (fputs("\\.\n", pg) < 0)
- exit_nicely();
- fflush(pg);
-
PG_CMD_CLOSE;
check_ok();
/*
* clean everything up in template1
- *
*/
static void
vacuum_db(void)
fputs("vacuuming database template1 ... ", stdout);
fflush(stdout);
- snprintf(cmd, MAXPGPATH,
- "\"%s/postgres\" -F -O -c search_path=pg_catalog "
- "-c exit_on_error=true template1 >%s",
- pgpath, DEVNULL);
+ snprintf(cmd, sizeof(cmd),
+ "\"%s/postgres\" %s template1 >%s",
+ pgpath, backend_options,
+ DEVNULL);
PG_CMD_OPEN;
- if (fputs("ANALYSE;\nVACUUM FULL FREEZE;\n", pg) < 0)
+ if (fputs("ANALYZE;\nVACUUM FULL FREEZE;\n", pg) < 0)
exit_nicely();
fflush(pg);
PG_CMD_CLOSE;
check_ok();
-
}
/*
* copy template1 to template0
- *
*/
static void
make_template0(void)
/*
* We use the OID of template0 to determine lastsysoid
- *
*/
"UPDATE pg_database SET datlastsysoid = "
" (SELECT oid::int4 - 1 FROM pg_database "
fputs("copying template1 to template0 ... ", stdout);
fflush(stdout);
- snprintf(cmd, MAXPGPATH,
- "\"%s/postgres\" -F -O -c search_path=pg_catalog "
- "-c exit_on_error=true template1 >%s",
- pgpath, DEVNULL);
+ snprintf(cmd, sizeof(cmd),
+ "\"%s/postgres\" %s template1 >%s",
+ pgpath, backend_options,
+ DEVNULL);
PG_CMD_OPEN;
*
* I have no idea how to handle this. (Strange they call UNIX an application!)
* So this will need some testing on Windows.
- *
*/
static void
trapsig(int signum)
/*
* call exit_nicely() if we got a signal, or else output "ok".
- *
*/
static void
check_ok()
{
if (not_ok)
{
- puts("Caught Signal.");
+ printf("Caught Signal.\n");
exit_nicely();
}
else
{
/* no signal caught */
- puts("ok");
+ printf("ok\n");
}
}
/*
- * check if given string is a valid locle specifier
+ * check if given string is a valid locale specifier
* based on some code given to me by Peter Eisentraut
* (but I take responsibility for it :-)
*/
/*
* set up the locale variables
- * assumes we have called setlocale(LC_ALL,"")
*
+ * assumes we have called setlocale(LC_ALL,"")
*/
static void
setlocales(void)
/*
* help text data
*
+ * Note: $CMDNAME is replaced by the right thing in usage()
*/
char *usage_text[] = {
"$CMDNAME initializes a PostgreSQL database cluster.\n",
};
-
/*
* print help text
- *
*/
static void
usage(void)
{
-
int i;
char **newtext;
fputs(newtext[i], stdout); /* faster than printf */
}
+
int
main(int argc, char *argv[])
{
/*
* options with no short version return a low integer, the rest return
* their short version value
- *
*/
static struct option long_options[] = {
{"pgdata", required_argument, NULL, 'D'},
* environment */
char *subdirs[] =
{"global", "pg_xlog", "pg_clog", "base", "base/1"};
-
char *lastsep;
-
- /* parse argv[0] - detect explicit path if there was one */
-
char *carg0;
-
#if defined(__CYGWIN__) || defined(WIN32)
char *exe; /* location of exe suffix in progname */
#endif
setlocale(LC_ALL, "");
+ /* parse argv[0] - detect explicit path if there was one */
carg0 = xstrdup(argv[0]);
canonicalize_path(carg0);
self_path = NULL;
}
- /* process options */
+ /* process command-line options */
while (1)
{
break;
case 'd':
debug = true;
+ printf("Running in debug mode.\n");
break;
case 'n':
noclean = true;
+ printf("Running in noclean mode. Mistakes will not be cleaned up.\n");
break;
case 'L':
datadir = xstrdup(optarg);
}
+ /* Non-option argument specifies data directory */
if (optind < argc)
{
pg_data = xstrdup(argv[optind]);
optind++;
}
- set_info_version();
+ if (optind < argc)
+ show_help = true;
+
+ if (show_version)
+ {
+ /* hard coded name here, in case they rename executable */
+ printf("initdb (PostgreSQL) %s\n", PG_VERSION);
+ exit(0);
+ }
- if (strlen(pg_data) == 0 && !(show_help || show_setting))
+ if (show_help)
+ {
+ usage();
+ exit(0);
+ }
+
+ if (strlen(pg_data) == 0)
{
pgdenv = getenv("PGDATA");
if (pgdenv && strlen(pgdenv))
{
fprintf(stderr,
"%s: no data directory specified\n"
- "You must identify the directory where the data for this "
- "database system\n"
- "will reside. Do this with either the invocation option "
- "-D or the\n" "environment variable PGDATA.\n",
+ "You must identify the directory where the data "
+ "for this database system\n"
+ "will reside. Do this with either the invocation "
+ "option -D or the\n"
+ "environment variable PGDATA.\n",
progname);
+ exit(1);
}
}
* commnd line to avoid dumb quoting problems on Windows, and we would
* expecially need quotes otherwise on Windows because paths there are
* most likely to have embedded spaces.
- *
*/
pgdenv = xmalloc(8 + strlen(pg_data));
sprintf(pgdenv, "PGDATA=%s", pg_data);
putenv(pgdenv);
- if (optind < argc)
- show_help = true;
-
- if (show_version)
- {
- /* hard coded name here, in case they rename executable */
- printf("initdb (PostgreSQL) %s\n", PG_VERSION);
- exit(0);
- }
-
- if (show_help)
- {
- usage();
- exit(0);
- }
-
if (set_paths() != 0)
{
fprintf(stderr,
"the directory \"%s\". Check your installation.\n",
progname, bindir);
exit(1);
-
}
-
if ((short_version = get_short_version()) == NULL)
{
fprintf(stderr, "%s: could not get valid short version\n", progname);
set_input(&features_file, "sql_features.txt");
set_input(&system_views_file, "system_views.sql");
+ set_info_version();
+
if (show_setting || debug)
{
fprintf(stderr,
username, bki_file,
desc_file, conf_file,
hba_file, ident_file);
+ if (show_setting)
+ exit(0);
}
- if (show_setting)
- exit(0);
-
check_input(bki_file);
check_input(desc_file);
check_input(hba_file);
{
fprintf(stderr,
"%s: directory \"%s\" exists but is not empty\n"
- "If you want to create a new database system, either "
- "remove or empty\n"
- "the directory \"$PGDATA\" or run $CMDNAME with an "
- "argument other than\n"
- "\"%s\".\n",
- progname, pg_data, pg_data);
+ "If you want to create a new database system, either remove or empty\n"
+ "the directory \"%s\" or run %s\n"
+ "with an argument other than \"%s\".\n",
+ progname, pg_data, pg_data, progname, pg_data);
exit(1);
}
made_new_pgdata = true;
}
+ /* Create required subdirectories */
+
for (i = 0; i < (sizeof(subdirs) / sizeof(char *)); i++)
{
printf("creating directory %s/%s ... ", pg_data, subdirs[i]);
check_ok();
}
+ /* Top level PG_VERSION is checked by bootstrapper, so make it first */
set_short_version(short_version, NULL);
+ /*
+ * Determine platform-specific config settings
+ *
+ * Use reasonable values if kernel will let us, else scale back. Probe for
+ * max_connections first since it is subject to more constraints than
+ * shared_buffers.
+ */
+
set_null_conf();
- /* test connections first because it has more constraints */
test_connections();
test_buffers();
+ /* Now create all the text config files */
setup_config();
+ /* Bootstrap template1 */
bootstrap_template1(short_version);
+ /* Make the per-database PGVERSION for template1 only after init'ing it */
set_short_version(short_version, "base/1");
+ /* Create the stuff we don't need to use bootstrap mode for */
+
setup_shadow();
if (pwprompt)
get_set_pwd();