2 #-------------------------------------------------------------------------
4 # initdb creates (initializes) a PostgreSQL database cluster (site,
5 # instance, installation, whatever). A database cluster is a
6 # collection of PostgreSQL databases all managed by the same postmaster.
8 # To create the database cluster, we create the directory that contains
9 # all its data, create the files that hold the global tables, create
10 # a few other control files for it, and create two databases: the
11 # template0 and template1 databases.
13 # The template databases are ordinary PostgreSQL databases. template0
14 # is never supposed to change after initdb, whereas template1 can be
15 # changed to add site-local standard data. Either one can be copied
16 # to produce a new database.
18 # To create template1, we run the postgres (backend) program and
19 # feed it data from the bki files that were installed. template0 is
20 # made just by copying the completed template1.
23 # Copyright (c) 1994, Regents of the University of California
25 # $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.120 2001/01/20 22:09:24 tgl Exp $
27 #-------------------------------------------------------------------------
30 ##########################################################################
35 stty echo > /dev/null 2>&1
37 echo "$CMDNAME failed." 1>&2
38 if [ "$noclean" != yes ]; then
39 if [ "$made_new_pgdata" = yes ]; then
40 echo "Removing $PGDATA." 1>&2
41 rm -rf "$PGDATA" || echo "Failed." 1>&2
43 echo "Removing temp file $TEMPFILE." 1>&2
44 rm -rf "$TEMPFILE" || echo "Failed." 1>&2
46 echo "Data directory $PGDATA will not be removed at user's request." 1>&2
54 # Placed here during build
57 # Note that "datadir" is not the directory we're initializing, it's
58 # merely how Autoconf names PREFIX/share.
60 # as set by configure --enable-multibyte[=XXX].
61 MULTIBYTE='@MULTIBYTE@'
63 if [ "$TMPDIR" ]; then
64 TEMPFILE="$TMPDIR/initdb.$$"
66 TEMPFILE="/tmp/initdb.$$"
70 # Check for echo -n vs echo \c
71 if echo '\c' | grep -s c >/dev/null 2>&1
82 # Find out where we're located
84 if echo "$0" | grep '/' > /dev/null 2>&1
86 # explicit dir name given
87 self_path=`echo $0 | sed 's,/[^/]*$,,'` # (dirname command is not portable)
89 # look for it in PATH ('which' command is not portable)
90 for dir in `echo "$PATH" | sed 's/:/ /g'`
92 # empty entry in path means current dir
93 [ -z "$dir" ] && dir='.'
94 if [ -f "$dir/$CMDNAME" ]
103 # Check for right version of backend. First we check for an
104 # executable in the same directory is this initdb script (presuming
105 # the above code worked). Then we fall back to the hard-wired bindir.
106 # We do it in this order because during upgrades users might move
107 # their trees to backup places, so $bindir might be inaccurate.
109 if [ x"$self_path" != x"" ] \
110 && [ -x "$self_path/postgres" ] \
111 && [ x"`$self_path/postgres -V 2>/dev/null`" = x"postgres (PostgreSQL) $VERSION" ]
114 elif [ -x "$bindir/postgres" ]; then
115 if [ x"`$bindir/postgres -V 2>/dev/null`" = x"postgres (PostgreSQL) $VERSION" ]
119 echo "The program '$bindir/postgres' needed by $CMDNAME does not belong to" 1>&2
120 echo "PostgreSQL version $VERSION. Check your installation." 1>&2
124 echo "The program 'postgres' is needed by $CMDNAME but was not found in" 1>&2
125 echo "the directory '$bindir'. Check your installation." 1>&2
130 # Now we can assume that 'pg_id' belongs to the same version as the
131 # verified 'postgres' in the same directory.
132 if [ ! -x "$PGPATH/pg_id" ]; then
133 echo "The program 'pg_id' is needed by $CMDNAME but was not found in" 1>&2
134 echo "the directory '$PGPATH'. Check your installation." 1>&2
139 EffectiveUser=`$PGPATH/pg_id -n -u`
140 if [ -z "$EffectiveUser" ]; then
141 echo "$CMDNAME: could not determine current user name" 1>&2
145 if [ `$PGPATH/pg_id -u` -eq 0 ]
147 echo "You cannot run $CMDNAME as root. Please log in (using, e.g., 'su')" 1>&2
148 echo "as the (unprivileged) user that will own the server process." 1>&2
153 short_version=`echo $VERSION | sed -e 's!^\([0-9][0-9]*\.[0-9][0-9]*\).*!\1!'`
154 if [ x"$short_version" = x"" ] ; then
155 echo "$CMDNAME: bug: version number has wrong format" 1>&2
160 ##########################################################################
162 # COMMAND LINE OPTIONS
164 # 0 is the default (non-)encoding
172 # Note: There is a single compelling reason that the name of the database
173 # superuser be the same as the Unix user owning the server process:
174 # The single user postgres backend will only connect as the database
175 # user with the same name as the Unix user running it. That's
176 # a security measure.
177 POSTGRES_SUPERUSERNAME="$EffectiveUser"
178 POSTGRES_SUPERUSERID=`$PGPATH/pg_id -u`
188 echo "initdb (PostgreSQL) $VERSION"
193 echo "Running with debug mode on."
200 echo "Running with noclean mode on. Mistakes will not be cleaned up."
202 # The sysid of the database superuser. Can be freely changed.
204 POSTGRES_SUPERUSERID="$2"
207 POSTGRES_SUPERUSERID=`echo $1 | sed 's/^--sysid=//'`
210 POSTGRES_SUPERUSERID=`echo $1 | sed 's/^-i//'`
212 # The default password of the database superuser.
213 # Make initdb prompt for the default password of the database superuser.
217 # Directory where to install the data. No default, unless the environment
218 # variable PGDATA is set.
223 PGDATA=`echo $1 | sed 's/^--pgdata=//'`
226 PGDATA=`echo $1 | sed 's/^-D//'`
228 # The directory where the .bki input files are stored. Normally
229 # they are in PREFIX/share and this option should be unnecessary.
234 datadir=`echo $1 | sed 's/^-L//'`
236 # The encoding of the template1 database. Defaults to what you chose
237 # at configure time. (see above)
242 MULTIBYTE=`echo $1 | sed 's/^--encoding=//'`
245 MULTIBYTE=`echo $1 | sed 's/^-E//'`
248 echo "$CMDNAME: invalid option: $1"
249 echo "Try '$CMDNAME --help' for more information."
259 if [ "$usage" ]; then
260 echo "$CMDNAME initializes a PostgreSQL database cluster."
263 echo " $CMDNAME [options] datadir"
266 echo " [-D, --pgdata] DATADIR Location for this database cluster"
267 echo " -W, --pwprompt Prompt for a password for the new superuser"
268 if [ -n "$MULTIBYTE" ] ; then
269 echo " -E, --encoding ENCODING Set the default multibyte encoding for new databases"
271 echo " -i, --sysid SYSID Database sysid for the superuser"
272 echo "Less commonly used options: "
273 echo " -L DIRECTORY Where to find the input files"
274 echo " -d, --debug Generate lots of debugging output"
275 echo " -n, --noclean Do not clean up after errors"
277 echo "Report bugs to <pgsql-bugs@postgresql.org>."
281 #-------------------------------------------------------------------------
282 # Resolve the multibyte encoding name
283 #-------------------------------------------------------------------------
287 MULTIBYTEID=`$PGPATH/pg_encoding $MULTIBYTE`
291 echo "$CMDNAME: pg_encoding failed"
293 echo "Perhaps you did not configure PostgreSQL for multibyte support or"
294 echo "the program was not successfully installed."
298 if [ -z "$MULTIBYTEID" ]
300 echo "$CMDNAME: $MULTIBYTE is not a valid encoding name" 1>&2
306 #-------------------------------------------------------------------------
307 # Make sure he told us where to build the database system
308 #-------------------------------------------------------------------------
313 echo "$CMDNAME: You must identify where the the data for this database"
314 echo "system will reside. Do this with either a -D invocation"
315 echo "option or a PGDATA environment variable."
321 #-------------------------------------------------------------------------
322 # Find the input files
323 #-------------------------------------------------------------------------
325 TEMPLATE1_BKI="$datadir"/template1.bki
326 GLOBAL_BKI="$datadir"/global.bki
328 TEMPLATE1_DESCR="$datadir"/template1.description
329 GLOBAL_DESCR="$datadir"/global.description
331 PG_HBA_SAMPLE="$datadir"/pg_hba.conf.sample
332 PG_IDENT_SAMPLE="$datadir"/pg_ident.conf.sample
333 POSTGRESQL_CONF_SAMPLE="$datadir"/postgresql.conf.sample
335 if [ "$show_setting" = yes ] || [ "$debug" = yes ]
338 echo "Initdb variables:"
339 for var in PGDATA datadir PGPATH TEMPFILE MULTIBYTE MULTIBYTEID \
340 POSTGRES_SUPERUSERNAME POSTGRES_SUPERUSERID TEMPLATE1_BKI GLOBAL_BKI \
341 TEMPLATE1_DESCR GLOBAL_DESCR POSTGRESQL_CONF_SAMPLE \
342 PG_HBA_SAMPLE PG_IDENT_SAMPLE ; do
343 eval "echo ' '$var=\$$var"
347 if [ "$show_setting" = yes ] ; then
351 for PREREQ_FILE in "$TEMPLATE1_BKI" "$GLOBAL_BKI" "$PG_HBA_SAMPLE" \
354 if [ ! -f "$PREREQ_FILE" ] ; then
356 echo "$CMDNAME does not find the file '$PREREQ_FILE'."
357 echo "This means you have a corrupted installation or identified the"
358 echo "wrong directory with the -L invocation option."
364 for file in "$TEMPLATE1_BKI" "$GLOBAL_BKI"; do
365 if [ x"`sed 1q $file`" != x"# PostgreSQL $short_version" ]; then
367 echo "The input file '$file' needed by $CMDNAME does not"
368 echo "belong to PostgreSQL $VERSION. Check your installation or specify the"
369 echo "correct path using the -L option."
376 trap 'echo "Caught signal." ; exit_nicely' 1 2 3 15
379 echo "This database system will be initialized with username \"$POSTGRES_SUPERUSERNAME\"."
380 echo "This user will own all the data files and must also own the server process."
384 ##########################################################################
386 # CREATE DATABASE DIRECTORY
388 # umask must disallow access to group, other for files and dirs
391 # find out if directory is empty
392 pgdata_contents=`ls -A "$PGDATA" 2>/dev/null`
393 if [ x"$pgdata_contents" != x ]
396 echo "$CMDNAME: The directory $PGDATA exists but is not empty."
397 echo "If you want to create a new database system, either remove or empty"
398 echo "the directory $PGDATA or run initdb with"
399 echo "an argument other than $PGDATA."
403 if [ ! -d "$PGDATA" ]; then
404 echo "Creating directory $PGDATA"
405 mkdir -p "$PGDATA" >/dev/null 2>&1 || mkdir "$PGDATA" || exit_nicely
408 echo "Fixing permissions on existing directory $PGDATA"
409 chmod go-rwx "$PGDATA" || exit_nicely
412 if [ ! -d "$PGDATA"/base ]
414 echo "Creating directory $PGDATA/base"
415 mkdir "$PGDATA"/base || exit_nicely
417 if [ ! -d "$PGDATA"/global ]
419 echo "Creating directory $PGDATA/global"
420 mkdir "$PGDATA"/global || exit_nicely
422 if [ ! -d "$PGDATA"/pg_xlog ]
424 echo "Creating directory $PGDATA/pg_xlog"
425 mkdir "$PGDATA"/pg_xlog || exit_nicely
430 ##########################################################################
432 # CREATE TEMPLATE1 DATABASE
434 rm -rf "$PGDATA"/base/1 || exit_nicely
435 mkdir "$PGDATA"/base/1 || exit_nicely
437 if [ "$debug" = yes ]
439 BACKEND_TALK_ARG="-d"
441 BACKEND_TALK_ARG="-Q"
444 BACKENDARGS="-boot -C -F -D$PGDATA $BACKEND_TALK_ARG"
445 FIRSTRUN="-boot -x1 -C -F -D$PGDATA $BACKEND_TALK_ARG"
447 echo "Creating template1 database in $PGDATA/base/1"
448 [ "$debug" = yes ] && echo "Running: $PGPATH/postgres $FIRSTRUN template1"
450 cat "$TEMPLATE1_BKI" \
451 | sed -e "s/PGUID/$POSTGRES_SUPERUSERID/g" \
452 | "$PGPATH"/postgres $FIRSTRUN template1 \
455 echo $short_version > "$PGDATA"/base/1/PG_VERSION || exit_nicely
458 ##########################################################################
460 # CREATE GLOBAL TABLES
463 echo "Creating global relations in $PGDATA/global"
465 [ "$debug" = yes ] && echo "Running: $PGPATH/postgres $BACKENDARGS template1"
468 | sed -e "s/POSTGRES/$POSTGRES_SUPERUSERNAME/g" \
469 -e "s/PGUID/$POSTGRES_SUPERUSERID/g" \
470 -e "s/ENCODING/$MULTIBYTEID/g" \
471 | "$PGPATH"/postgres $BACKENDARGS template1 \
474 echo $short_version > "$PGDATA/PG_VERSION" || exit_nicely
476 cp "$PG_HBA_SAMPLE" "$PGDATA"/pg_hba.conf || exit_nicely
477 cp "$PG_IDENT_SAMPLE" "$PGDATA"/pg_ident.conf || exit_nicely
478 cp "$POSTGRESQL_CONF_SAMPLE" "$PGDATA"/postgresql.conf || exit_nicely
479 chmod 0600 "$PGDATA"/pg_hba.conf "$PGDATA"/pg_ident.conf \
480 "$PGDATA"/postgresql.conf
483 ##########################################################################
485 # CREATE VIEWS and other things
487 echo "Initializing pg_shadow."
489 PGSQL_OPT="-o /dev/null -O -F -D$PGDATA"
491 # Create a trigger so that direct updates to pg_shadow will be written
492 # to the flat password file pg_pwd
493 echo "CREATE TRIGGER pg_sync_pg_pwd AFTER INSERT OR UPDATE OR DELETE ON pg_shadow" \
494 "FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd()" \
495 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
497 # needs to be done before alter user
498 echo "REVOKE ALL on pg_shadow FROM public" \
499 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
502 if [ "$PwPrompt" ]; then
503 $ECHO_N "Enter new superuser password: "$ECHO_C
504 stty -echo > /dev/null 2>&1
506 stty echo > /dev/null 2>&1
508 $ECHO_N "Enter it again: "$ECHO_C
509 stty -echo > /dev/null 2>&1
511 stty echo > /dev/null 2>&1
513 if [ "$FirstPw" != "$SecondPw" ]; then
514 echo "Passwords didn't match." 1>&2
517 echo "ALTER USER \"$POSTGRES_SUPERUSERNAME\" WITH PASSWORD '$FirstPw'" \
518 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
519 if [ ! -f $PGDATA/global/pg_pwd ]; then
520 echo "The password file wasn't generated. Please report this problem." 1>&2
523 echo "Setting password"
527 echo "Enabling unlimited row width for system tables."
529 echo "ALTER TABLE pg_attrdef CREATE TOAST TABLE" \
530 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
531 echo "ALTER TABLE pg_description CREATE TOAST TABLE" \
532 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
533 echo "ALTER TABLE pg_proc CREATE TOAST TABLE" \
534 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
535 echo "ALTER TABLE pg_relcheck CREATE TOAST TABLE" \
536 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
537 echo "ALTER TABLE pg_rewrite CREATE TOAST TABLE" \
538 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
539 echo "ALTER TABLE pg_statistic CREATE TOAST TABLE" \
540 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
543 echo "Creating system views."
545 echo "CREATE VIEW pg_user AS \
553 '********'::text as passwd, \
556 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
558 echo "CREATE VIEW pg_rules AS \
560 C.relname AS tablename, \
561 R.rulename AS rulename, \
562 pg_get_ruledef(R.rulename) AS definition \
563 FROM pg_rewrite R, pg_class C \
564 WHERE R.rulename !~ '^_RET' \
565 AND C.oid = R.ev_class;" \
566 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
568 echo "CREATE VIEW pg_views AS \
570 C.relname AS viewname, \
571 pg_get_userbyid(C.relowner) AS viewowner, \
572 pg_get_viewdef(C.relname) AS definition \
574 WHERE C.relkind = 'v';" \
575 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
577 # XXX why does pg_tables include sequences?
579 echo "CREATE VIEW pg_tables AS \
581 C.relname AS tablename, \
582 pg_get_userbyid(C.relowner) AS tableowner, \
583 C.relhasindex AS hasindexes, \
584 C.relhasrules AS hasrules, \
585 (C.reltriggers > 0) AS hastriggers \
587 WHERE C.relkind IN ('r', 's');" \
588 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
590 echo "CREATE VIEW pg_indexes AS \
592 C.relname AS tablename, \
593 I.relname AS indexname, \
594 pg_get_indexdef(X.indexrelid) AS indexdef \
595 FROM pg_index X, pg_class C, pg_class I \
596 WHERE C.relkind = 'r' AND I.relkind = 'i' \
597 AND C.oid = X.indrelid \
598 AND I.oid = X.indexrelid;" \
599 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
601 echo "Loading pg_description."
602 echo "COPY pg_description FROM STDIN" > $TEMPFILE
603 cat "$TEMPLATE1_DESCR" >> $TEMPFILE
604 cat "$GLOBAL_DESCR" >> $TEMPFILE
607 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
608 rm -f "$TEMPFILE" || exit_nicely
610 echo "Setting lastsysoid."
611 echo "UPDATE pg_database SET \
612 datistemplate = 't', \
613 datlastsysoid = (SELECT max(oid) FROM pg_description) \
614 WHERE datname = 'template1'" \
615 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
617 echo "Vacuuming database."
618 echo "VACUUM ANALYZE" \
619 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
621 echo "Copying template1 to template0."
622 echo "CREATE DATABASE template0" \
623 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
624 echo "UPDATE pg_database SET \
625 datistemplate = 't', \
627 WHERE datname = 'template0'" \
628 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
629 echo "VACUUM pg_database" \
630 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
633 ##########################################################################
638 echo "Success. You can now start the database server using:"
640 echo " $PGPATH/postmaster -D $PGDATA"
642 echo " $PGPATH/pg_ctl -D $PGDATA start"