usage_postgresql()
{
	echo >&2 "	[-X]"
	echo >&2 "	[-E]"
	return 0 # backend-specific option(s) exist(s)
}

sanity_postgresql()
{
	rv=0
#	case $SCHEMA_VERSION in
#	1|2)	:;;
#	*)	echo "ERROR: schema version $SCHEMA_VERSION is not supported" >&2
#		rv=1;;
#	esac
	case $BACKEND_VERSION in
	[1-6].*|7.[0-3]|unknown)	# 7.3 or before
		echo "WARNING: PostgreSQL version 7.4 or later required: $BACKEND_VERSION" >&2
		rv=1
		;;
	8.*|9.[0-1])
		if [ $BACKEND_DATA_CHECKSUMS = yes ]; then
			echo "WARNING: PostgreSQL $BACKEND_VERSION doesn't support data checksums" >&2
			rv=1
		fi
		;;
	esac
	if [ ! -x "$BACKEND_PREFIX/bin/pg_config" ]; then
		echo "WARNING: command not found: pg_config" >&2
		rv=1
	fi
	if [ ! -x "$PGSQL_BINDIR/pg_ctl" ]; then
		echo "WARNING: command not found: pg_ctl" >&2
		rv=1
	fi
	if [ ! -x "$PGSQL_BINDIR/psql" ]; then
		echo "WARNING: command not found: psql" >&2
		rv=1
	fi
	return $rv
}

display_plain_params_backend_postgresql()
{
	display_plain_param_backend_data_dir
	display_plain_param_backend_log_dir

#	echo "postgresql schema version    [-S]: $SCHEMA_VERSION"
	echo "postgresql admin user        [-U]: $BACKEND_ADMIN_USER"
	echo "postgresql admin password    [-W]: `if [ -r $admin_password ]; then cat $admin_password; else echo '(auto generated)'; fi`"
	echo "postgresql user              [-u]: $BACKEND_USER"
	echo "postgresql password          [-w]: `if [ -r $password ]; then cat $password; else echo '(auto generated)'; fi`"
	echo "postgresql prefix            [-P]: $BACKEND_PREFIX"
	echo "postgresql version           [-V]: $BACKEND_VERSION"
	echo "postgresql XML supported     [-X]: $SUPPORT_XML_TYPE"
	echo "postgresql data checksum support"
	echo "                             [-E]: $BACKEND_DATA_CHECKSUMS"
}

display_script_params_backend_postgresql()
{
	display_script_param_backend_data_dir
	display_script_param_backend_log_dir

#	echo "SCHEMA_VERSION=$SCHEMA_VERSION"
	echo "BACKEND_ADMIN_USER=$BACKEND_ADMIN_USER"
	echo "BACKEND_ADMIN_PASSWORD='`if [ -r $admin_password ]; then cat $admin_password; else echo \*; fi`'"
	echo "BACKEND_USER=$BACKEND_USER"
	echo "BACKEND_PASSWORD='`if [ -r $password ]; then cat $password; else echo \*; fi`'"
	echo "BACKEND_PREFIX=$BACKEND_PREFIX"
	echo "BACKEND_VERSION=$BACKEND_VERSION"
	echo "BACKEND_SUPPORT_XML_TYPE=$SUPPORT_XML_TYPE"
	echo "BACKEND_DATA_CHECKSUMS=$BACKEND_DATA_CHECKSUMS"
}

display_plain_params_backend_port_postgresql()
{
	echo "portmaster port              [-p]: $BACKEND_PORT"
}

display_script_params_backend_port_postgresql()
{
	
	echo "BACKEND_PORT=$BACKEND_PORT"
}

display_plain_params_backend_optional_postgresql()
{
	:
}

display_script_params_backend_optional_postgresql()
{
	:
}

# $argshift is an output parameter, if this function returns success.
parse_argument_postgresql()
{
	case "$1" in
#	  -S) [ $# -ge 2 ] || usage
#		SCHEMA_VERSION=$2
#		argshift=1
#		true;;
	  -X)
		SUPPORT_XML_TYPE=yes
		argshift=0
		true;;
	  -E)
		BACKEND_DATA_CHECKSUMS=yes
		argshift=0
		true;;
	  *)	false;;
	esac
}

#
# search default $BACKEND_PREFIX
#

set_default_backend_prefix_postgresql()
{
	if [ -z "${BACKEND_PREFIX-}" ]; then
		OIFS=$IFS
		IFS=":"
		set $search_path
		IFS=$OIFS
		for d
		do
			if [ -x "$d/pg_config" ]; then
				BACKEND_PREFIX=`dirname "$d"`
				: ${PGSQL_BINDIR:=`$d/pg_config --bindir`}
				break
			fi
		done
	fi
}

#
# default values
#

# NOTE: This needs to set $RC_BACKEND_BASENAME, at least.
set_first_defaults_postgresql()
{
	: ${RC_BACKEND_BASENAME=gfarm-pgsql}
	: ${PGSQL_BINDIR:="$BACKEND_PREFIX/bin"}
	: ${SUPPORT_XML_TYPE:="no"}
	: ${BACKEND_DATA_CHECKSUMS:="no"}
}

set_last_defaults_postgresql()
{
#	: ${SCHEMA_VERSION:=2}
	: ${DB_NAME:="gfarm"}

	if [ -w / ]; then # is root?
		case `uname` in
		*BSD|DragonFly)
			: ${BACKEND_ADMIN_USER:="pgsql"};;
		Darwin)	: ${BACKEND_ADMIN_USER:="_postgres"};;
		*)	: ${BACKEND_ADMIN_USER:="postgres"};;
		esac
		: ${BACKEND_PRIVILEGE:="$BACKEND_ADMIN_USER"}
	else
		: ${BACKEND_ADMIN_USER:="`whoami`"}
		: ${BACKEND_PRIVILEGE:=""}
	fi
	: ${PGSQL_GROUP:="`id -gn $BACKEND_ADMIN_USER`"}
	if [ -f /usr/bin/getent ]; then
		if getent passwd "$BACKEND_ADMIN_USER" >/dev/null; then
			:
		else
			ABORT "postgresql admin user '$BACKEND_ADMIN_USER' doesn't exist"
		fi
	fi

	: ${BACKEND_USER:="gfarm"}
	# default PostgreSQL port number is 5432
	: ${BACKEND_PORT:="10602"}

	: ${BACKEND_DATA_DIR:="$CONFIG_PREFIX/var/gfarm-pgsql"}
	BACKEND_LOG_DIR_DEFAULT="$BACKEND_DATA_DIR/pg_xlog"
	: ${BACKEND_LOG_DIR:="$BACKEND_LOG_DIR_DEFAULT"}
	: ${BACKEND_PID_FILE:="$RUN_DIR/postmaster.pid"}

	if [ -z "${BACKEND_VERSION-}" ]; then
		if [ -x "$BACKEND_PREFIX/bin/pg_config" ]; then
			BACKEND_VERSION=`$BACKEND_PREFIX/bin/pg_config --version 2>&1 |
			  sed -n 's/.*PostgreSQL.* \([0-9][0-9]*\.[0-9][0-9]*\).*/\1/p'`
			if [ -z "$BACKEND_VERSION" ]
			then
				BACKEND_VERSION="unknown"
			elif expr "$BACKEND_VERSION" : '[0-9][0-9]*\.[0-9][0-9]*' \
					>/dev/null; then
				:
			else
				BACKEND_VERSION="unknown"
			fi
		else
			BACKEND_VERSION="unknown"
		fi
	fi
	WAIT_F='-w '
	case $BACKEND_VERSION in
	7.*) # -w option makes "pg_ctl start" ask password on PostgreSQL-7.4
		WAIT_F='' ;;
	esac
	# For 'systemd', variable names are surrounded by ${...}.
	: ${PGSQL_OPTIONS:=$WAIT_F'-s -m fast -D ${PGDATA} -l ${PGDATA}/logfile'}
	# In private mode, we change the directory of the unix-domain socket
	# for PostgreSQL since some Linux distributions set the default
	# directory to somewhere other than /tmp, which is restricted to be
	# written by owner of the directory.
	if $PRIVATE_MODE; then
		PGSQL_OPTIONS="$PGSQL_OPTIONS -o '-k /tmp'"
	fi
}

#
# do configuration
#

init_replace_postgresql()
{
	init_replace_common

	cat <<_EOF_
s|@config_gfarm_database_name@|$DB_NAME|g
s|@config_gfarm_pgsql_bindir@|$PGSQL_BINDIR|g
s|@config_gfarm_pgsql_options@|$PGSQL_OPTIONS|g
s|@config_gfarm_pgsql_group@|$PGSQL_GROUP|g
_EOF_
}

make_configuration_directory_postgresql()
{
	:
}

make_configuration_file_postgresql()
{
	INITDB_OPTIONS='--no-locale -E SQL_ASCII'
	if [ $BACKEND_DATA_CHECKSUMS = yes ]; then
		INITDB_OPTIONS="$INITDB_OPTIONS --data-checksums"
	fi	

	cat << _EOF_ | $run_with_backend_privilege || ABORT "initdb failed"
	$PGSQL_BINDIR/initdb -D "$BACKEND_DATA_DIR" $INITDB_OPTIONS
_EOF_

	# record the password
	cp -p $admin_password $BACKEND_DATA_DIR/admin_password

	cp -p "$BACKEND_DATA_DIR"/postgresql.conf \
	      "$BACKEND_DATA_DIR"/postgresql.conf.org

	$awk '
	/^[ 	]*#*[ 	]*listen_addresses[ 	]*=/ {
		if (/^[ 	]*listen_addresses/) {
			print "#" $0
		} else {
			print $0
		}
		if (!tcpip_socket_done && !listen_addresses_done) {
			print "listen_addresses = '"'*'"'"
			listen_addresses_done = 1
		}
		next
	}
	/^[ 	]*#*[ 	]*tcpip_socket[ 	]*=/ {
		if (/^[ 	]*tcpip_socket/) {
			print "#" $0
		} else {
			print $0
		}
		if (!tcpip_socket_done && !listen_addresses_done) {
			print "tcpip_socket = true"
			tcpip_socket_done = 1
		}
		next
	}
	/^[ 	]*#*[ 	]*port[ 	]*=/ {
		if (/^[ 	]*port/) {
			print "#" $0
		} else {
			print $0
		}
		if (!port_done) {
			print "port = '$BACKEND_PORT'"
			port_done = 1
		}
		next
	}
	/^[ 	]*#*[ 	]*password_encryption[ 	]*=/ {
		if (/^[ 	]*password_encryption/) {
			print "#" $0
		} else {
			print $0
		}
		if (!password_encryption_done) {
			print "password_encryption = true"
			password_encryption_done = 1
		}
		next
	}
	/^[ 	]*#*[ 	]*autovacuum[ 	]*=/ {
		if (/^[ 	]*autovacuum/) {
			print "#" $0
		} else {
			print $0
		}
		if (!autovacuum_done) {
			print "autovacuum = true"
			autovacuum_done = 1
		}
		next
	}
	/^[ 	]*#*[ 	]*stats_row_level[ 	]*=/ {
		if (/^[ 	]*stats_row_level/) {
			print "#" $0
		} else {
			print $0
		}
		if (!stats_row_level_done) {
			print "stats_row_level = on"
			stats_row_level_done = 1
		}
		next
	}
	{print}
	END {
		if (!listen_addresses_done && !tcpip_socket_done)
			print "listen_addresses = '"'*'"'"
		if (!port_done)
			print "port = '$BACKEND_PORT'"
		if (!password_encryption_done)
			print "password_encryption = true"
		# ignore autovacuum_done and stats_row_level_done for now.
		# PostgreSQL should be earlier than 8.0.X
	}'	 "$BACKEND_DATA_DIR"/postgresql.conf.org \
		>"$BACKEND_DATA_DIR"/postgresql.conf

	cp -p "$BACKEND_DATA_DIR"/pg_hba.conf \
	      "$BACKEND_DATA_DIR"/pg_hba.conf.org

	(
	# all comment out
	sed 's/^[0-9A-Za-z]/#&/' "$BACKEND_DATA_DIR"/pg_hba.conf.org

	echo ""
	echo ""
	echo "# TYPE	DATABASE	USER	CIDR-ADDRESS	METHOD"
	echo ""
	echo '# "local" is for Unix domain socket connections only'
	echo 'local	all		all			md5'
	echo '# IPv4 local connections:'
	echo 'host	all		all	127.0.0.1/32	md5'
	echo '# IPv6 local connections:'
	echo 'host	all		all	::1/128		md5'

	echo ""
	echo "## The following should work, but actually doesn't with PostgreSQL-7.4"
	echo "#host	$DB_NAME		$BACKEND_USER	0.0.0.0/0	md5"
	echo "# TYPE	DATABASE	USER	IP-ADDRESS IP-MASK	METHOD"
	echo "host	$DB_NAME		$BACKEND_USER	0.0.0.0	0.0.0.0	md5"
	echo "host	$DB_NAME		$BACKEND_USER	::/0	md5"
	) > "$BACKEND_DATA_DIR"/pg_hba.conf
}

apply_configuration_postgresql()
{
	# backup configuration during temporary change
	cp -p "$BACKEND_DATA_DIR"/postgresql.conf \
	      "$BACKEND_DATA_DIR"/postgresql.conf.bak
	cp -p "$BACKEND_DATA_DIR"/pg_hba.conf \
	      "$BACKEND_DATA_DIR"/pg_hba.conf.bak

	#
	# Beginning with PostgreSQL 9.3, 'unix_socket_directory' is renamed
	# to 'unix_socket_directories'.  However, Red Hat Enterprise Linux
	# applies the patch named 'postgresql-multi-sockets.patch' to
	# PostgreSQL 9.2.x.  It makes PostgreSQL 9.2 recognize
	# 'unix_socket_directories'.
	#
	# To get an appropriate parameter name for PostgreSQL installed on
	# the system, we test which parameter name is appeared in the
	# 'postgresql.conf' file.
	#
	grep unix_socket_directories $BACKEND_DATA_DIR/postgresql.conf \
	     >/dev/null 2>&1
	if [ $? -eq 0 ]; then
		UNIX_SOCKET_DIR_PARAM=unix_socket_directories
	else
		UNIX_SOCKET_DIR_PARAM=unix_socket_directory
	fi

	# create temporary configuration files 
	$awk '
	BEGIN {
		unix_socket_dir_param = "'$UNIX_SOCKET_DIR_PARAM'"
	}
	/^[ 	]*#*[ 	]*listen_addresses[ 	]*=/ {
		if (/^[ 	]*listen_addresses/) {
			print "#" $0
		} else {
			print $0
		}
		if (!tcpip_socket_done && !listen_addresses_done) {
			# disable TCP access to be sure
			print "listen_addresses = '"''"'"
			listen_addresses_done = 1
		}
		next
	}
	/^[ 	]*#*[ 	]*tcpip_socket[ 	]*=/ {
		if (/^[ 	]*tcpip_socket/) {
			print "#" $0
		} else {
			print $0
		}
		if (!tcpip_socket_done && !listen_addresses_done) {
			# disable TCP access to be sure
			print "tcpip_socket = false"
			tcpip_socket_done = 1
		}
		next
	}
	/^[ 	]*#*[ 	]*unix_socket_director(y|ies)[ 	]*=/ {
		if (/^[ 	]*unix_socket_director(y|ies)/) {
			print "#" $0
		} else {
			print $0
		}
		if (!unix_socket_directory_done) {
			# prevent access except $BACKEND_ADMIN_USER
			print unix_socket_dir_param " = '"'$BACKEND_DATA_DIR'"'"
			unix_socket_directory_done = 1
		}
		next
	}
	/^[ 	]*#*[ 	]*client_min_messages[ 	]*=/ {
		if (/^[ 	]*client_min_messages/) {
			print "#" $0
		} else {
			print $0
		}
		if (!client_min_messages_done) {
			# make "psql -f gfarm.sql" slient
			print "client_min_messages = '"'WARNING'"'"
			client_min_messages_done = 1
		}
		next
	}
	{print}
	END {
		if (!tcpip_socket_done && !listen_addresses_done)
			print "listen_addresses = '"''"'"
		if (!unix_socket_directory_done)
			print unix_socket_dir_param " = '"'$BACKEND_DATA_DIR'"'"
		# ignore client_min_messages for now.
		# PostgreSQL should be earlier than 7.4
	}'	 "$BACKEND_DATA_DIR"/postgresql.conf.bak \
		>"$BACKEND_DATA_DIR"/postgresql.conf
	echo 'local all	all trust' > "$BACKEND_DATA_DIR"/pg_hba.conf

	# We can't use rc.d script here, because "-w" option of pg_ctl doesn't
	# work, if unix_socket_directory is changed from default, at least on
	# PostgreSQL-8.0.3.
	# Also, we cannot use "restart" here, because it doesn't work either
	# at first invocation.
	cat << _EOF_ | $run_with_backend_privilege || ABORT "pg_ctl start failed"
	$PGSQL_BINDIR/pg_ctl -s -m fast \
		-D $BACKEND_DATA_DIR -l $BACKEND_DATA_DIR/logfile start
_EOF_

	case "$BACKEND_VERSION" in
	[1-7].*|8.0)
		createuser_option=;;
	*)  # Don't ask the following question on PostgreSQL 8.1 or later:
	    #    Shall the new role be allowed to create more new roles? (y/n) 
		createuser_option=--no-createrole;;
	esac

	if [ X"$SUPPORT_XML_TYPE" = X"yes" ]; then
		XMLATTR_TABLENAME=", XmlAttr "
	else
		XMLATTR_TABLENAME=""
	fi

	cat << _EOF_ | $run_with_backend_privilege || ABORT "createdb failed"
	PGHOST="$BACKEND_DATA_DIR"; export PGHOST
	PGPORT="$BACKEND_PORT"; export PGPORT
	unset PGDATABASE PGUSER PGPASSWORD PGSERVICE
	unset PGREALM PGOPTIONS PGSSLMODE PGREQUIRESSL PGCONNECT_TIMEOUT
	unset LANG

	# wait for postmaster to start up
	iter=0
	while if $PGSQL_BINDIR/psql -l; then false; else true; fi >/dev/null 2>&1
	do
		iter=\`expr \$iter + 1\`
		if [ \$iter -gt 6 ]; then
			echo give up
			exit 1
		fi
		echo wait 5 seconds for postmaster to start up
		sleep 5
	done
	# -q option for createuser and createdb is obsolete in 8.4
	$PGSQL_BINDIR/createuser $createuser_option -A -D $BACKEND_USER
	$PGSQL_BINDIR/createdb $DB_NAME
#	$PGSQL_BINDIR/psql -q \
#		-f "$config_dir/gfarm.schema-$SCHEMA_VERSION.sql" $DB_NAME
	$PGSQL_BINDIR/psql -q \
		-f "$config_dir/gfarm.sql" $DB_NAME
	if [ X"$SUPPORT_XML_TYPE" = X"yes" ]; then
		$PGSQL_BINDIR/psql -q \
			-f "$config_dir/gfarm-xmlattr.sql" $DB_NAME
	fi
	$awk 'BEGIN {
		print "GRANT SELECT, INSERT, UPDATE, DELETE"
		print "	ON Host, HostAliases, "
		print "    GfarmUser, GfarmGroup, GfarmGroupAssignment, "
		print "    INode, FileInfo, FileCopy, DeadFileCopy, DirEntry, "
		print "    Symlink, QuotaUser, QuotaGroup, "
		print "    QuotaDirSet, QuotaDirectory, SeqNum, MdHost, "
		print "    XAttr $XMLATTR_TABLENAME"
		print "	TO $BACKEND_USER;"
#		if ($SCHEMA_VERSION > 1) {
#			print "GRANT SELECT, UPDATE"
#			print "	ON Host_hostid_seq, Path_pathid_seq"
#			print "	TO $BACKEND_USER;"
#		}
	}
	FILENAME == "$admin_password" {
		print "ALTER USER \"$BACKEND_ADMIN_USER\""
		printf "  WITH ENCRYPTED PASSWORD '"'%s'"';\n", \$0
	}
	FILENAME == "$password" {
		print "ALTER USER \"$BACKEND_USER\""
		printf "  WITH ENCRYPTED PASSWORD '"'%s'"';\n", \$0
	}' $admin_password $password | $PGSQL_BINDIR/psql -q $DB_NAME
	echo "INSERT INTO SeqNum (name, value) VALUES ('', '1')" \
		| $PGSQL_BINDIR/psql -q $DB_NAME
_EOF_

	#
	# Since we start PostgreSQL with pg_ctl, we use pg_ctl again.
	#
	cat << _EOF_ | $run_with_backend_privilege || ABORT "pg_ctl stop failed"
	$PGSQL_BINDIR/pg_ctl -s -m fast \
		-D $BACKEND_DATA_DIR -l $BACKEND_DATA_DIR/logfile stop
_EOF_

	# save configuration for administration
	mv "$BACKEND_DATA_DIR"/postgresql.conf \
	   "$BACKEND_DATA_DIR"/postgresql.conf.adm
	mv "$BACKEND_DATA_DIR"/pg_hba.conf \
	   "$BACKEND_DATA_DIR"/pg_hba.conf.adm
	# restore configuration
	mv "$BACKEND_DATA_DIR"/postgresql.conf.bak \
	   "$BACKEND_DATA_DIR"/postgresql.conf
	mv "$BACKEND_DATA_DIR"/pg_hba.conf.bak \
	   "$BACKEND_DATA_DIR"/pg_hba.conf

	if [ X"$BACKEND_LOG_DIR" != X"$BACKEND_LOG_DIR_DEFAULT" ]; then
		# if [ -n "$BACKEND_PRIVILEGE" ], `whoami` should be root, and
		# the following should preserve the owner of the directory.
		# otherwise $BACKEND_ADMIN_USER must be `whoami`.
		mv "$BACKEND_LOG_DIR_DEFAULT" "$BACKEND_LOG_DIR"
		ln -s "$BACKEND_LOG_DIR" "$BACKEND_LOG_DIR_DEFAULT"
	fi
}

service_start_postgresql()
{
	service_start_common ${1+"$@"}
}

service_stop_postgresql()
{
	opt=
	if [ X"$1" = X-n ]; then
		opt="-n"
		shift
	fi

	service=$1
	shift

	service_ctl $opt $service stop ${1+"$@"}
}

service_remove_postgresql()
{
	service_remove ${1+"$@"}
}
