1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
#!/bin/sh
#-------------------------------------------------------------------------
#
# initdb.sh--
# Create (initialize) a Postgres database system.
#
# A database system is a collection of Postgres databases all managed
# by the same postmaster.
#
# To create the database system, we create the directory that contains
# all its data, create the files that hold the global classes, create
# a few other control files for it, and create one database: the
# template database.
#
# The template database is an ordinary Postgres database. Its data
# never changes, though. It exists to make it easy for Postgres to
# create other databases -- it just copies.
#
# Optionally, we can skip creating the database system and just create
# (or replace) the template database.
#
# To create all those classes, we run the postgres (backend) program and
# feed it data from bki files that are in the Postgres library directory.
#
# Copyright (c) 1994, Regents of the University of California
#
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.81 2000/01/19 20:08:24 petere Exp $
#
#-------------------------------------------------------------------------
exit_nicely(){
stty echo >& /dev/null
echo
echo "$CMDNAME failed."
if [ "$noclean" -eq 0 ]; then
echo "Removing $PGDATA."
rm -rf "$PGDATA" || echo "Failed."
echo "Removing temp file $TEMPFILE."
rm -rf "$TEMPFILE" || echo "Failed."
else
echo "Data directory $PGDATA will not be removed at user's request."
fi
exit 1
}
CMDNAME=`basename $0`
if [ "$USER" = 'root' -o "$LOGNAME" = 'root' ]
then
echo "You cannot run $CMDNAME as root. Please log in (using, e.g., 'su')"
echo "as the (unprivileged) user that will own the server process."
exit 1
fi
EffectiveUser=`id -n -u 2>/dev/null || whoami 2>/dev/null`
if [ "$TMPDIR" ]; then
TEMPFILE="$TMPDIR/initdb.$$"
else
TEMPFILE="/tmp/initdb.$$"
fi
# Check for echo -n vs echo \c
if echo '\c' | grep -s c >/dev/null 2>&1
then
ECHO_N="echo -n"
ECHO_C=""
else
ECHO_N="echo"
ECHO_C='\c'
fi
#
# Find out where we're located
#
if echo "$0" | grep '/' > /dev/null 2>&1
then
# explicit dir name given
PGPATH=`echo $0 | sed 's,/[^/]*$,,'` # (dirname command is not portable)
else
# look for it in PATH ('which' command is not portable)
for dir in `echo "$PATH" | sed 's/:/ /g'`
do
# empty entry in path means current dir
[ -z "$dir" ] && dir='.'
if [ -f "$dir/$CMDNAME" ]
then
PGPATH="$dir"
break
fi
done
fi
# Check if needed programs actually exist in path
for prog in postgres pg_version
do
if [ ! -x "$PGPATH/$prog" ]
then
echo "The program $prog needed by $CMDNAME could not be found. It was"
echo "expected at:"
echo " $PGPATH/$prog"
echo "If this is not the correct directory, please start $CMDNAME"
echo "with a full search path. Otherwise make sure that the program"
echo "was installed successfully."
exit 1
fi
done
# 0 is the default (non-)encoding
MULTIBYTEID=0
# This is placed here by configure --enable-multibyte[=XXX].
MULTIBYTE=__MULTIBYTE__
# Set defaults:
debug=0
noclean=0
template_only=0
# Note: There is a single compelling reason that the name of the database
# superuser be the same as the Unix user owning the server process:
# The single user postgres backend will only connect as the database
# user with the same name as the Unix user running it. That's
# a security measure. It might change in the future (why?), but for
# now the --username option is only a fallback if both id and whoami
# fail, and in that case the argument _must_ be the name of the effective
# user.
POSTGRES_SUPERUSERNAME="$EffectiveUser"
POSTGRES_SUPERUSERID="`id -u 2>/dev/null || echo 0`"
while [ "$#" -gt 0 ]
do
case "$1" in
--help|-\?)
usage=t
break
;;
--debug|-d)
debug=1
echo "Running with debug mode on."
;;
--noclean|-n)
noclean=1
echo "Running with noclean mode on. Mistakes will not be cleaned up."
;;
--template|-t)
template_only=1
echo "Updating template1 database only."
;;
# The database superuser. See comments above.
--username|-u)
POSTGRES_SUPERUSERNAME="$2"
shift;;
--username=*)
POSTGRES_SUPERUSERNAME=`echo $1 | sed 's/^--username=//'`
;;
-u*)
POSTGRES_SUPERUSERNAME=`echo $1 | sed 's/^-u//'`
;;
# The sysid of the database superuser. See comments above.
--sysid|-i)
POSTGRES_SUPERUSERID="$2"
shift;;
--sysid=*)
POSTGRES_SUPERUSERID=`echo $1 | sed 's/^--sysid=//'`
;;
-i*)
POSTGRES_SUPERUSERID=`echo $1 | sed 's/^-i//'`
;;
# The default password of the database superuser.
# Make initdb prompt for the default password of the database superuser.
--pwprompt|-W)
PwPrompt=1
;;
# Directory where to install the data. No default, unless the environment
# variable PGDATA is set.
--pgdata|-D)
PGDATA="$2"
shift;;
--pgdata=*)
PGDATA=`echo $1 | sed 's/^--pgdata=//'`
;;
-D*)
PGDATA=`echo $1 | sed 's/^-D//'`
;;
# The directory where the database templates are stored (traditionally in
# $prefix/lib). This is now autodetected for the most common layouts.
--pglib|-L)
PGLIB="$2"
shift;;
--pglib=*)
PGLIB=`echo $1 | sed 's/^--pglib=//'`
;;
-L*)
PGLIB=`echo $1 | sed 's/^-L//'`
;;
# The encoding of the template1 database. Defaults to what you chose
# at configure time. (see above)
--encoding|-E)
MULTIBYTE="$2"
shift;;
--encoding=*)
MULTIBYTE=`echo $1 | sed 's/^--encoding=//'`
;;
-E*)
MULTIBYTE=`echo $1 | sed 's/^-E//'`
;;
*)
PGDATA=$1
;;
esac
shift
done
if [ "$usage" ]; then
echo "initdb initialized a PostgreSQL database."
echo
echo "Usage:"
echo " $CMDNAME [options] datadir"
echo
echo "Options:"
echo " [-D, --pgdata] <datadir> Location for this database"
echo " -W, --pwprompt Prompt for a password for the new superuser's"
if [ -n "$MULTIBYTE" ]
then
echo " -e, --encoding <encoding> Set the default multibyte encoding for new databases"
fi
echo " -i, --sysid <sysid> Database sysid for the superuser"
echo "Less commonly used options: "
echo " -L, --pglib <libdir> Where to find the input files (should happend automatically"
echo " -t, --template Re-initialize template database only"
echo " -d, --debug Generate lots of debugging output"
echo " -n, --noclean Do not clean up after errors"
echo
echo "Report bugs to <pgsql-bugs@postgresql.org>."
exit 0
fi
#-------------------------------------------------------------------------
# Resolve the multibyte encoding name
#-------------------------------------------------------------------------
if [ "$MULTIBYTE" ]
then
MULTIBYTEID=`$PGPATH/pg_encoding $MULTIBYTE 2> /dev/null`
if [ "$?" -ne 0 ]
then
echo "$CMDNAME: pg_encoding failed"
echo
echo "Perhaps you did not configure PostgreSQL for multibyte support or"
echo "the program was not successfully installed."
exit 1
fi
if [ -z "$MULTIBYTEID" ]
then
echo "$CMDNAME: $MULTIBYTE is not a valid encoding name"
exit 1
fi
fi
#-------------------------------------------------------------------------
# Make sure he told us where to build the database system
#-------------------------------------------------------------------------
if [ -z "$PGDATA" ]
then
echo "$CMDNAME: You must identify where the the data for this database"
echo "system will reside. Do this with either a --pgdata invocation"
echo "option or a PGDATA environment variable."
echo
exit 1
fi
# The data path must be absolute, because the backend doesn't like
# '.' and '..' stuff. (Should perhaps be fixed there.)
if ! echo "$PGDATA" | grep '^/' > /dev/null 2>&1
then
echo "$CMDNAME: data path must be specified as an absolute path"
exit 1
fi
#---------------------------------------------------------------------------
# Figure out who the Postgres superuser for the new database system will be.
#---------------------------------------------------------------------------
# This means they have neither 'id' nor 'whoami'!
if [ -z "$POSTGRES_SUPERUSERNAME" ]
then
echo "$CMDNAME: Could not the determine current username. Please use the -u option."
exit 1
fi
echo "This database system will be initialized with username \"$POSTGRES_SUPERUSERNAME\"."
echo "This user will own all the data files and must also own the server process."
echo
#-------------------------------------------------------------------------
# Find the input files
#-------------------------------------------------------------------------
if [ -z "$PGLIB" ]
then
for dir in "$PGPATH/../lib" "$PGPATH/../lib/pgsql"
do
if [ -f "$dir/global1.bki.source" ]
then
PGLIB="$dir"
break
fi
done
fi
if [ -z "$PGLIB" ]
then
echo "$CMDNAME: Could not find the \"lib\" directory, that contains"
echo "the files needed by initdb. Please specify it with the"
echo "--pglib option."
exit 1
fi
TEMPLATE="$PGLIB"/local1_template1.bki.source
GLOBAL="$PGLIB"/global1.bki.source
PG_HBA_SAMPLE="$PGLIB"/pg_hba.conf.sample
TEMPLATE_DESCR="$PGLIB"/local1_template1.description
GLOBAL_DESCR="$PGLIB"/global1.description
PG_GEQO_SAMPLE="$PGLIB"/pg_geqo.sample
PG_POSTMASTER_OPTS_DEFAULT_SAMPLE="$PGLIB"/postmaster.opts.default.sample
for PREREQ_FILE in "$TEMPLATE" "$GLOBAL" "$PG_HBA_SAMPLE"
do
if [ ! -f "$PREREQ_FILE" ]
then
echo "$CMDNAME does not find the file '$PREREQ_FILE'."
echo "This means you have a corrupted installation or identified the"
echo "wrong directory with the --pglib invocation option."
exit 1
fi
done
[ "$debug" -ne 0 ] && echo "$CMDNAME: Using $TEMPLATE as input to create the template database."
if [ "$template_only" -eq 0 ]
then
[ "$debug" -ne 0 ] && echo "$CMDNAME: Using $GLOBAL as input to create the global classes."
[ "$debug" -ne 0 ] && echo "$CMDNAME: Using $PG_HBA_SAMPLE as default authentication control file."
fi
trap 'echo "Caught signal." ; exit_nicely' 1 2 3 15
# -----------------------------------------------------------------------
# Create the data directory if necessary
# -----------------------------------------------------------------------
# umask must disallow access to group, other for files and dirs
umask 077
if [ -f "$PGDATA"/PG_VERSION ]
then
if [ "$template_only" -eq 0 ]
then
echo "$CMDNAME: The file $PGDATA/PG_VERSION already exists."
echo "This probably means initdb has already been run and the"
echo "database system already exists."
echo
echo "If you want to create a new database system, either remove"
echo "the directory $PGDATA or run initdb with a --pgdata argument"
echo "other than $PGDATA."
exit 1
fi
else
if [ ! -d "$PGDATA" ]
then
echo "Creating database system directory $PGDATA"
mkdir "$PGDATA" || exit_nicely
else
echo "Fixing permissions on pre-existing data directory $PGDATA"
chmod go-rwx "$PGDATA" || exit_nicely
fi
if [ ! -d "$PGDATA"/base ]
then
echo "Creating database system directory $PGDATA/base"
mkdir "$PGDATA"/base || exit_nicely
fi
if [ ! -d "$PGDATA"/pg_xlog ]
then
echo "Creating database XLOG directory $PGDATA/pg_xlog"
mkdir "$PGDATA"/pg_xlog || exit_nicely
fi
fi
#----------------------------------------------------------------------------
# Create the template1 database
#----------------------------------------------------------------------------
rm -rf "$PGDATA"/base/template1 || exit_nicely
mkdir "$PGDATA"/base/template1 || exit_nicely
if [ "$debug" -eq 1 ]
then
BACKEND_TALK_ARG="-d"
else
BACKEND_TALK_ARG="-Q"
fi
BACKENDARGS="-boot -C -F -D$PGDATA $BACKEND_TALK_ARG"
FIRSTRUN="-boot -x -C -F -D$PGDATA $BACKEND_TALK_ARG"
echo "Creating template database in $PGDATA/base/template1"
[ "$debug" -ne 0 ] && echo "Running: $PGPATH/postgres $FIRSTRUN template1"
cat "$TEMPLATE" \
| sed -e "s/PGUID/$POSTGRES_SUPERUSERID/g" \
| "$PGPATH"/postgres $FIRSTRUN template1 \
|| exit_nicely
"$PGPATH"/pg_version "$PGDATA"/base/template1 || exit_nicely
#----------------------------------------------------------------------------
# Create the global classes, if requested.
#----------------------------------------------------------------------------
if [ "$template_only" -eq 0 ]
then
echo "Creating global relations in $PGDATA/base"
[ "$debug" -ne 0 ] && echo "Running: $PGPATH/postgres $BACKENDARGS template1"
cat "$GLOBAL" \
| sed -e "s/POSTGRES/$POSTGRES_SUPERUSERNAME/g" \
-e "s/PGUID/$POSTGRES_SUPERUSERID/g" \
| "$PGPATH"/postgres $BACKENDARGS template1 \
|| exit_nicely
"$PGPATH"/pg_version "$PGDATA" || exit_nicely
cp "$PG_HBA_SAMPLE" "$PGDATA"/pg_hba.conf || exit_nicely
cp "$PG_GEQO_SAMPLE" "$PGDATA"/pg_geqo.sample || exit_nicely
cp "$PG_POSTMASTER_OPTS_DEFAULT_SAMPLE" "$PGDATA"/postmaster.opts.default || exit_nicely
echo "Adding template1 database to pg_database"
echo "open pg_database" > "$TEMPFILE"
echo "insert (template1 $POSTGRES_SUPERUSERID $MULTIBYTEID template1)" >> $TEMPFILE
#echo "show" >> "$TEMPFILE"
echo "close pg_database" >> "$TEMPFILE"
[ "$debug" -ne 0 ] && echo "Running: $PGPATH/postgres $BACKENDARGS template1 < $TEMPFILE"
"$PGPATH"/postgres $BACKENDARGS template1 < "$TEMPFILE"
# Gotta remove that temp file before exiting on error.
retval="$?"
if [ "$noclean" -eq 0 ]
then
rm -f "$TEMPFILE" || exit_nicely
fi
[ "$retval" -ne 0 ] && exit_nicely
fi
echo
PGSQL_OPT="-o /dev/null -O -F -Q -D$PGDATA"
# Create a trigger so that direct updates to pg_shadow will be written
# to the flat password file pg_pwd
echo "CREATE TRIGGER pg_sync_pg_pwd AFTER INSERT OR UPDATE OR DELETE ON pg_shadow" \
"FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd()" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
# needs to be done before alter user
echo "REVOKE ALL on pg_shadow FROM public" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
# set up password
if [ "$PwPrompt" ]; then
$ECHO_N "Enter new superuser password: "$ECHO_C
stty -echo >& /dev/null
read FirstPw
stty echo >& /dev/null
echo
$ECHO_N "Enter it again: "$ECHO_C
stty -echo >& /dev/null
read SecondPw
stty echo >& /dev/null
echo
if [ "$FirstPw" != "$SecondPw" ]; then
echo "Passwords didn't match."
exit_nicely
fi
echo "ALTER USER \"$POSTGRES_SUPERUSERNAME\" WITH PASSWORD '$FirstPw'" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
if [ ! -f $PGDATA/pg_pwd ]; then
echo "The password file wasn't generated. Please report this problem."
exit_nicely
fi
echo "Setting password"
fi
echo "Creating view pg_user."
echo "CREATE VIEW pg_user AS \
SELECT \
usename, \
usesysid, \
usecreatedb, \
usetrace, \
usesuper, \
usecatupd, \
'********'::text as passwd, \
valuntil \
FROM pg_shadow" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo "Creating view pg_rules."
echo "CREATE VIEW pg_rules AS \
SELECT \
C.relname AS tablename, \
R.rulename AS rulename, \
pg_get_ruledef(R.rulename) AS definition \
FROM pg_rewrite R, pg_class C \
WHERE R.rulename !~ '^_RET' \
AND C.oid = R.ev_class;" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo "Creating view pg_views."
echo "CREATE VIEW pg_views AS \
SELECT \
C.relname AS viewname, \
pg_get_userbyid(C.relowner) AS viewowner, \
pg_get_viewdef(C.relname) AS definition \
FROM pg_class C \
WHERE C.relhasrules \
AND EXISTS ( \
SELECT rulename FROM pg_rewrite R \
WHERE ev_class = C.oid AND ev_type = '1' \
)" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo "Creating view pg_tables."
echo "CREATE VIEW pg_tables AS \
SELECT \
C.relname AS tablename, \
pg_get_userbyid(C.relowner) AS tableowner, \
C.relhasindex AS hasindexes, \
C.relhasrules AS hasrules, \
(C.reltriggers > 0) AS hastriggers \
FROM pg_class C \
WHERE C.relkind IN ('r', 's') \
AND NOT EXISTS ( \
SELECT rulename FROM pg_rewrite \
WHERE ev_class = C.oid AND ev_type = '1' \
)" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo "Creating view pg_indexes."
echo "CREATE VIEW pg_indexes AS \
SELECT \
C.relname AS tablename, \
I.relname AS indexname, \
pg_get_indexdef(X.indexrelid) AS indexdef \
FROM pg_index X, pg_class C, pg_class I \
WHERE C.oid = X.indrelid \
AND I.oid = X.indexrelid" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo "Loading pg_description."
echo "COPY pg_description FROM STDIN" > $TEMPFILE
cat "$TEMPLATE_DESCR" >> $TEMPFILE
cat "$GLOBAL_DESCR" >> $TEMPFILE
cat $TEMPFILE \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
if [ "$noclean" -eq 0 ]
then
rm -f "$TEMPFILE" || exit_nicely
fi
echo "Vacuuming database."
echo "VACUUM ANALYZE" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo
echo "$CMDNAME completed successfully. You can now start the database server."
echo " $PGPATH/postmaster -D $PGDATA"
echo "or"
echo " $PGPATH/pg_ctl -D $PGDATA start"
echo
exit 0