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 # Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
24 # Portions Copyright (c) 1994, Regents of the University of California
26 # $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.121 2001/02/18 18:33:59 momjian Exp $
28 #-------------------------------------------------------------------------
31 ##########################################################################
36 stty echo > /dev/null 2>&1
38 echo "$CMDNAME failed." 1>&2
39 if [ "$noclean" != yes ]; then
40 if [ "$made_new_pgdata" = yes ]; then
41 echo "Removing $PGDATA." 1>&2
42 rm -rf "$PGDATA" || echo "Failed." 1>&2
44 echo "Removing temp file $TEMPFILE." 1>&2
45 rm -rf "$TEMPFILE" || echo "Failed." 1>&2
47 echo "Data directory $PGDATA will not be removed at user's request." 1>&2
55 # Placed here during build
58 # Note that "datadir" is not the directory we're initializing, it's
59 # merely how Autoconf names PREFIX/share.
61 # as set by configure --enable-multibyte[=XXX].
62 MULTIBYTE='@MULTIBYTE@'
64 if [ "$TMPDIR" ]; then
65 TEMPFILE="$TMPDIR/initdb.$$"
67 TEMPFILE="/tmp/initdb.$$"
71 # Check for echo -n vs echo \c
72 if echo '\c' | grep -s c >/dev/null 2>&1
83 # Find out where we're located
85 if echo "$0" | grep '/' > /dev/null 2>&1
87 # explicit dir name given
88 self_path=`echo $0 | sed 's,/[^/]*$,,'` # (dirname command is not portable)
90 # look for it in PATH ('which' command is not portable)
91 for dir in `echo "$PATH" | sed 's/:/ /g'`
93 # empty entry in path means current dir
94 [ -z "$dir" ] && dir='.'
95 if [ -f "$dir/$CMDNAME" ]
104 # Check for right version of backend. First we check for an
105 # executable in the same directory is this initdb script (presuming
106 # the above code worked). Then we fall back to the hard-wired bindir.
107 # We do it in this order because during upgrades users might move
108 # their trees to backup places, so $bindir might be inaccurate.
110 if [ x"$self_path" != x"" ] \
111 && [ -x "$self_path/postgres" ] \
112 && [ x"`$self_path/postgres -V 2>/dev/null`" = x"postgres (PostgreSQL) $VERSION" ]
115 elif [ -x "$bindir/postgres" ]; then
116 if [ x"`$bindir/postgres -V 2>/dev/null`" = x"postgres (PostgreSQL) $VERSION" ]
120 echo "The program '$bindir/postgres' needed by $CMDNAME does not belong to" 1>&2
121 echo "PostgreSQL version $VERSION. Check your installation." 1>&2
125 echo "The program 'postgres' is needed by $CMDNAME but was not found in" 1>&2
126 echo "the directory '$bindir'. Check your installation." 1>&2
131 # Now we can assume that 'pg_id' belongs to the same version as the
132 # verified 'postgres' in the same directory.
133 if [ ! -x "$PGPATH/pg_id" ]; then
134 echo "The program 'pg_id' is needed by $CMDNAME but was not found in" 1>&2
135 echo "the directory '$PGPATH'. Check your installation." 1>&2
140 EffectiveUser=`$PGPATH/pg_id -n -u`
141 if [ -z "$EffectiveUser" ]; then
142 echo "$CMDNAME: could not determine current user name" 1>&2
146 if [ `$PGPATH/pg_id -u` -eq 0 ]
148 echo "You cannot run $CMDNAME as root. Please log in (using, e.g., 'su')" 1>&2
149 echo "as the (unprivileged) user that will own the server process." 1>&2
154 short_version=`echo $VERSION | sed -e 's!^\([0-9][0-9]*\.[0-9][0-9]*\).*!\1!'`
155 if [ x"$short_version" = x"" ] ; then
156 echo "$CMDNAME: bug: version number has wrong format" 1>&2
161 ##########################################################################
163 # COMMAND LINE OPTIONS
165 # 0 is the default (non-)encoding
173 # Note: There is a single compelling reason that the name of the database
174 # superuser be the same as the Unix user owning the server process:
175 # The single user postgres backend will only connect as the database
176 # user with the same name as the Unix user running it. That's
177 # a security measure.
178 POSTGRES_SUPERUSERNAME="$EffectiveUser"
179 POSTGRES_SUPERUSERID=`$PGPATH/pg_id -u`
189 echo "initdb (PostgreSQL) $VERSION"
194 echo "Running with debug mode on."
201 echo "Running with noclean mode on. Mistakes will not be cleaned up."
203 # The sysid of the database superuser. Can be freely changed.
205 POSTGRES_SUPERUSERID="$2"
208 POSTGRES_SUPERUSERID=`echo $1 | sed 's/^--sysid=//'`
211 POSTGRES_SUPERUSERID=`echo $1 | sed 's/^-i//'`
213 # The default password of the database superuser.
214 # Make initdb prompt for the default password of the database superuser.
218 # Directory where to install the data. No default, unless the environment
219 # variable PGDATA is set.
224 PGDATA=`echo $1 | sed 's/^--pgdata=//'`
227 PGDATA=`echo $1 | sed 's/^-D//'`
229 # The directory where the .bki input files are stored. Normally
230 # they are in PREFIX/share and this option should be unnecessary.
235 datadir=`echo $1 | sed 's/^-L//'`
237 # The encoding of the template1 database. Defaults to what you chose
238 # at configure time. (see above)
243 MULTIBYTE=`echo $1 | sed 's/^--encoding=//'`
246 MULTIBYTE=`echo $1 | sed 's/^-E//'`
249 echo "$CMDNAME: invalid option: $1"
250 echo "Try '$CMDNAME --help' for more information."
260 if [ "$usage" ]; then
261 echo "$CMDNAME initializes a PostgreSQL database cluster."
264 echo " $CMDNAME [options] datadir"
267 echo " [-D, --pgdata] DATADIR Location for this database cluster"
268 echo " -W, --pwprompt Prompt for a password for the new superuser"
269 if [ -n "$MULTIBYTE" ] ; then
270 echo " -E, --encoding ENCODING Set the default multibyte encoding for new databases"
272 echo " -i, --sysid SYSID Database sysid for the superuser"
273 echo "Less commonly used options: "
274 echo " -L DIRECTORY Where to find the input files"
275 echo " -d, --debug Generate lots of debugging output"
276 echo " -n, --noclean Do not clean up after errors"
278 echo "Report bugs to <pgsql-bugs@postgresql.org>."
282 #-------------------------------------------------------------------------
283 # Resolve the multibyte encoding name
284 #-------------------------------------------------------------------------
288 MULTIBYTEID=`$PGPATH/pg_encoding $MULTIBYTE`
292 echo "$CMDNAME: pg_encoding failed"
294 echo "Perhaps you did not configure PostgreSQL for multibyte support or"
295 echo "the program was not successfully installed."
299 if [ -z "$MULTIBYTEID" ]
301 echo "$CMDNAME: $MULTIBYTE is not a valid encoding name" 1>&2
307 #-------------------------------------------------------------------------
308 # Make sure he told us where to build the database system
309 #-------------------------------------------------------------------------
314 echo "$CMDNAME: You must identify where the the data for this database"
315 echo "system will reside. Do this with either a -D invocation"
316 echo "option or a PGDATA environment variable."
322 #-------------------------------------------------------------------------
323 # Find the input files
324 #-------------------------------------------------------------------------
326 TEMPLATE1_BKI="$datadir"/template1.bki
327 GLOBAL_BKI="$datadir"/global.bki
329 TEMPLATE1_DESCR="$datadir"/template1.description
330 GLOBAL_DESCR="$datadir"/global.description
332 PG_HBA_SAMPLE="$datadir"/pg_hba.conf.sample
333 PG_IDENT_SAMPLE="$datadir"/pg_ident.conf.sample
334 POSTGRESQL_CONF_SAMPLE="$datadir"/postgresql.conf.sample
336 if [ "$show_setting" = yes ] || [ "$debug" = yes ]
339 echo "Initdb variables:"
340 for var in PGDATA datadir PGPATH TEMPFILE MULTIBYTE MULTIBYTEID \
341 POSTGRES_SUPERUSERNAME POSTGRES_SUPERUSERID TEMPLATE1_BKI GLOBAL_BKI \
342 TEMPLATE1_DESCR GLOBAL_DESCR POSTGRESQL_CONF_SAMPLE \
343 PG_HBA_SAMPLE PG_IDENT_SAMPLE ; do
344 eval "echo ' '$var=\$$var"
348 if [ "$show_setting" = yes ] ; then
352 for PREREQ_FILE in "$TEMPLATE1_BKI" "$GLOBAL_BKI" "$PG_HBA_SAMPLE" \
355 if [ ! -f "$PREREQ_FILE" ] ; then
357 echo "$CMDNAME does not find the file '$PREREQ_FILE'."
358 echo "This means you have a corrupted installation or identified the"
359 echo "wrong directory with the -L invocation option."
365 for file in "$TEMPLATE1_BKI" "$GLOBAL_BKI"; do
366 if [ x"`sed 1q $file`" != x"# PostgreSQL $short_version" ]; then
368 echo "The input file '$file' needed by $CMDNAME does not"
369 echo "belong to PostgreSQL $VERSION. Check your installation or specify the"
370 echo "correct path using the -L option."
377 trap 'echo "Caught signal." ; exit_nicely' 1 2 3 15
380 echo "This database system will be initialized with username \"$POSTGRES_SUPERUSERNAME\"."
381 echo "This user will own all the data files and must also own the server process."
385 ##########################################################################
387 # CREATE DATABASE DIRECTORY
389 # umask must disallow access to group, other for files and dirs
392 # find out if directory is empty
393 pgdata_contents=`ls -A "$PGDATA" 2>/dev/null`
394 if [ x"$pgdata_contents" != x ]
397 echo "$CMDNAME: The directory $PGDATA exists but is not empty."
398 echo "If you want to create a new database system, either remove or empty"
399 echo "the directory $PGDATA or run initdb with"
400 echo "an argument other than $PGDATA."
404 if [ ! -d "$PGDATA" ]; then
405 echo "Creating directory $PGDATA"
406 mkdir -p "$PGDATA" >/dev/null 2>&1 || mkdir "$PGDATA" || exit_nicely
409 echo "Fixing permissions on existing directory $PGDATA"
410 chmod go-rwx "$PGDATA" || exit_nicely
413 if [ ! -d "$PGDATA"/base ]
415 echo "Creating directory $PGDATA/base"
416 mkdir "$PGDATA"/base || exit_nicely
418 if [ ! -d "$PGDATA"/global ]
420 echo "Creating directory $PGDATA/global"
421 mkdir "$PGDATA"/global || exit_nicely
423 if [ ! -d "$PGDATA"/pg_xlog ]
425 echo "Creating directory $PGDATA/pg_xlog"
426 mkdir "$PGDATA"/pg_xlog || exit_nicely
431 ##########################################################################
433 # CREATE TEMPLATE1 DATABASE
435 rm -rf "$PGDATA"/base/1 || exit_nicely
436 mkdir "$PGDATA"/base/1 || exit_nicely
438 if [ "$debug" = yes ]
440 BACKEND_TALK_ARG="-d"
442 BACKEND_TALK_ARG="-Q"
445 BACKENDARGS="-boot -C -F -D$PGDATA $BACKEND_TALK_ARG"
446 FIRSTRUN="-boot -x1 -C -F -D$PGDATA $BACKEND_TALK_ARG"
448 echo "Creating template1 database in $PGDATA/base/1"
449 [ "$debug" = yes ] && echo "Running: $PGPATH/postgres $FIRSTRUN template1"
451 cat "$TEMPLATE1_BKI" \
452 | sed -e "s/PGUID/$POSTGRES_SUPERUSERID/g" \
453 | "$PGPATH"/postgres $FIRSTRUN template1 \
456 echo $short_version > "$PGDATA"/base/1/PG_VERSION || exit_nicely
459 ##########################################################################
461 # CREATE GLOBAL TABLES
464 echo "Creating global relations in $PGDATA/global"
466 [ "$debug" = yes ] && echo "Running: $PGPATH/postgres $BACKENDARGS template1"
469 | sed -e "s/POSTGRES/$POSTGRES_SUPERUSERNAME/g" \
470 -e "s/PGUID/$POSTGRES_SUPERUSERID/g" \
471 -e "s/ENCODING/$MULTIBYTEID/g" \
472 | "$PGPATH"/postgres $BACKENDARGS template1 \
475 echo $short_version > "$PGDATA/PG_VERSION" || exit_nicely
477 cp "$PG_HBA_SAMPLE" "$PGDATA"/pg_hba.conf || exit_nicely
478 cp "$PG_IDENT_SAMPLE" "$PGDATA"/pg_ident.conf || exit_nicely
479 cp "$POSTGRESQL_CONF_SAMPLE" "$PGDATA"/postgresql.conf || exit_nicely
480 chmod 0600 "$PGDATA"/pg_hba.conf "$PGDATA"/pg_ident.conf \
481 "$PGDATA"/postgresql.conf
484 ##########################################################################
486 # CREATE VIEWS and other things
488 echo "Initializing pg_shadow."
490 PGSQL_OPT="-o /dev/null -O -F -D$PGDATA"
492 # Create a trigger so that direct updates to pg_shadow will be written
493 # to the flat password file pg_pwd
494 echo "CREATE TRIGGER pg_sync_pg_pwd AFTER INSERT OR UPDATE OR DELETE ON pg_shadow" \
495 "FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd()" \
496 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
498 # needs to be done before alter user
499 echo "REVOKE ALL on pg_shadow FROM public" \
500 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
503 if [ "$PwPrompt" ]; then
504 $ECHO_N "Enter new superuser password: "$ECHO_C
505 stty -echo > /dev/null 2>&1
507 stty echo > /dev/null 2>&1
509 $ECHO_N "Enter it again: "$ECHO_C
510 stty -echo > /dev/null 2>&1
512 stty echo > /dev/null 2>&1
514 if [ "$FirstPw" != "$SecondPw" ]; then
515 echo "Passwords didn't match." 1>&2
518 echo "ALTER USER \"$POSTGRES_SUPERUSERNAME\" WITH PASSWORD '$FirstPw'" \
519 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
520 if [ ! -f $PGDATA/global/pg_pwd ]; then
521 echo "The password file wasn't generated. Please report this problem." 1>&2
524 echo "Setting password"
528 echo "Enabling unlimited row width for system tables."
530 echo "ALTER TABLE pg_attrdef CREATE TOAST TABLE" \
531 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
532 echo "ALTER TABLE pg_description CREATE TOAST TABLE" \
533 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
534 echo "ALTER TABLE pg_proc CREATE TOAST TABLE" \
535 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
536 echo "ALTER TABLE pg_relcheck CREATE TOAST TABLE" \
537 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
538 echo "ALTER TABLE pg_rewrite CREATE TOAST TABLE" \
539 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
540 echo "ALTER TABLE pg_statistic CREATE TOAST TABLE" \
541 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
544 echo "Creating system views."
546 echo "CREATE VIEW pg_user AS \
554 '********'::text as passwd, \
557 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
559 echo "CREATE VIEW pg_rules AS \
561 C.relname AS tablename, \
562 R.rulename AS rulename, \
563 pg_get_ruledef(R.rulename) AS definition \
564 FROM pg_rewrite R, pg_class C \
565 WHERE R.rulename !~ '^_RET' \
566 AND C.oid = R.ev_class;" \
567 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
569 echo "CREATE VIEW pg_views AS \
571 C.relname AS viewname, \
572 pg_get_userbyid(C.relowner) AS viewowner, \
573 pg_get_viewdef(C.relname) AS definition \
575 WHERE C.relkind = 'v';" \
576 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
578 # XXX why does pg_tables include sequences?
580 echo "CREATE VIEW pg_tables AS \
582 C.relname AS tablename, \
583 pg_get_userbyid(C.relowner) AS tableowner, \
584 C.relhasindex AS hasindexes, \
585 C.relhasrules AS hasrules, \
586 (C.reltriggers > 0) AS hastriggers \
588 WHERE C.relkind IN ('r', 's');" \
589 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
591 echo "CREATE VIEW pg_indexes AS \
593 C.relname AS tablename, \
594 I.relname AS indexname, \
595 pg_get_indexdef(X.indexrelid) AS indexdef \
596 FROM pg_index X, pg_class C, pg_class I \
597 WHERE C.relkind = 'r' AND I.relkind = 'i' \
598 AND C.oid = X.indrelid \
599 AND I.oid = X.indexrelid;" \
600 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
602 echo "Loading pg_description."
603 echo "COPY pg_description FROM STDIN" > $TEMPFILE
604 cat "$TEMPLATE1_DESCR" >> $TEMPFILE
605 cat "$GLOBAL_DESCR" >> $TEMPFILE
608 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
609 rm -f "$TEMPFILE" || exit_nicely
611 echo "Setting lastsysoid."
612 echo "UPDATE pg_database SET \
613 datistemplate = 't', \
614 datlastsysoid = (SELECT max(oid) FROM pg_description) \
615 WHERE datname = 'template1'" \
616 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
618 echo "Vacuuming database."
619 echo "VACUUM ANALYZE" \
620 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
622 echo "Copying template1 to template0."
623 echo "CREATE DATABASE template0" \
624 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
625 echo "UPDATE pg_database SET \
626 datistemplate = 't', \
628 WHERE datname = 'template0'" \
629 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
630 echo "VACUUM pg_database" \
631 | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
634 ##########################################################################
639 echo "Success. You can now start the database server using:"
641 echo " $PGPATH/postmaster -D $PGDATA"
643 echo " $PGPATH/pg_ctl -D $PGDATA start"