#!/bin/sh
# Copyright (c) Parallels
# All rights reserved

# first argument - return value, other - message
die()
{
	local retval=${1:-1}
	shift
	echo "Error: $@"
	echo $retval
	exit $retval
}

show_help()
{
	cat <<EOF
Usage:
    pg_manage --start
        Start PostgreSQL server.
    pg_manage --stop
        Stop PostgreSQL server
    pg_manage --restart
        Restart PostgreSQL server.
    pg_manage --status
        Check PostgreSQL server status.
    pg_manage --check-installed
        Exit 0 if PostgreSQL is installed, 1 otherwise
    pg_manage --create-admin-login LOGIN
        Create user LOGIN with administrative privileges.
        The password must be stored in PSA_PASSWORD environment variable.
    pg_manage --drop-admin-login LOGIN
        Drop administrative user LOGIN.
    pg_manage --set-admin-password LOGIN
        Change password for administrative user LOGIN.
        The password must be stored in PSA_PASSWORD environment variable.
    pg_manage --help
        Show this message.
EOF
}

postmaster_params()
{
    if [ -f "$rc_dir/postgresql-${pg_real_ver}" ]; then
	PGSQL_SCRIPT="$rc_dir/postgresql-${pg_real_ver}"
    elif [ -f $rc_dir/postgresql.sh ]; then
	PGSQL_SCRIPT="$rc_dir/postgresql.sh"
    else
	PGSQL_SCRIPT="$rc_dir/postgresql"
    fi
}

postmaster_run()
{
	if [ "" = "yes" ]; then
		PID=`ps axww | awk '$5 ~ "postmaster$|postgres$" {print $1}'`
		[ -n "$PID" ] && return 0 || return 1
	fi
	$PGSQL_SCRIPT status >/dev/null 2>&1
	return $?
}

postmaster_reload()
{
	$PGSQL_SCRIPT reload >/dev/null 2>&1
}

postmaster_start()
{
    if ! postmaster_run; then
	if [ "" = "yes" ]; then
		# Stupid systemd doesn't understand what process already dead.
		# So we flush "active" status before the real start
		$PGSQL_SCRIPT stop  >/dev/null 2>&1
	fi
	$PGSQL_SCRIPT start >/dev/null 2>&1

	[ -z "$1" ] || return
	count=5
	while ! $postmaster_run; do
	    sleep 1
	    count=$(($count-1))	
	    if [ 0$count -eq 0 ]; then
			die 1 "Unable to start PostgreSQL."
	    fi
	done
    fi
}

postmaster_stop()
{
    if postmaster_run; then
	$PGSQL_SCRIPT stop >/dev/null 2>&1

       if postmaster_run; then
           die 1 "Unable to stop PostgreSQL."
       fi
    fi
}

postmaster_check_installed()
{
	exec test -x $PGSQL_SCRIPT
}

psql_query()
{
	if ! $pg_bin_dir/psql -U postgres -d template1 -qtc "$@"; then
		echo "Error on query to PostgreSQL"
		echo 1
		setup_pg_hba_conf
		exit 1
	fi
}

setup_pg_hba_conf()
{
	local extra_rule

	# We add things at start, not at end, so that our rules have top priority
	echo >$pg_hba.tmp
	for extra_rule; do
		echo "$extra_rule #Added by Plesk" >>$pg_hba.tmp
	done
	echo "local samegroup all password #Added by Plesk" >>$pg_hba.tmp
	echo >>$pg_hba.tmp

	# Filter out anything added by Plesk earlier, as well as blank lines
	sed -e '/#Added by Plesk/d' -e '/^$/d' $pg_hba >>$pg_hba.tmp &&
	cat $pg_hba.tmp >$pg_hba &&
	chmod 644 $pg_hba &&
	rm -f $pg_hba.tmp

	if [ $? -gt 0 ]; then
		echo "Unable to rewrite $pg_hba"
		echo 1
		return 1
	fi

	if postmaster_run; then
		postmaster_reload
		sleep 1
	fi

	return 0
}

create_admin_login()
{
	# Note: "grep -q ." checks for non-empty lines in output
	local login password login_esc
	login=`echo "$1" | sed -e "s/'/''/g"`
	password=`echo "$2" | sed -e "s/'/''/g"`
	login_esc=`echo "$1" | sed -e 's/\(["\\]\)/\\\1/g'`
	if ! psql_query "select * from pg_group where groname='template1'" | grep -q .; then
		psql_query "create group template1"
	fi
	if psql_query "select * from pg_user where usename='$login'" | grep -q .; then
		psql_query "alter user \"$login_esc\" password '$password' createdb createuser"
	else
		psql_query "create user \"$login_esc\" password '$password' createdb createuser"
	fi
	psql_query "alter group template1 add user \"$login_esc\""
}

drop_admin_login()
{
	# Note: "grep -q ." checks for non-empty lines in output
	local login login_esc
	login=`echo "$1" | sed -e "s/'/''/g"`
	login_esc=`echo "$1" | sed -e 's/\(["\\]\)/\\\1/g'`
	if ! psql_query "select * from pg_group where groname='template1'" | grep -q .; then
		psql_query "create group template1"
	fi
	if [ "X$login" != "Xpostgres" ]; then
		if psql_query "select * from pg_user where usename='$login'" | grep -q .; then
			psql_query "update pg_database set datdba=(select usesysid from pg_shadow where usename='postgres') where datdba=(select usesysid from pg_shadow where usename='$login')"
			psql_query "drop user \"$login_esc\""
		fi
	else
		psql_query "alter group template1 drop user \"$login_esc\""
	fi
}

set_admin_password()
{
	# Note: "grep -q ." checks for non-empty lines in output
	local login password login_esc
	login=`echo "$1" | sed -e "s/'/''/g"`
	password=`echo "$2" | sed -e "s/'/''/g"`
	login_esc=`echo "$1" | sed -e 's/\(["\\]\)/\\\1/g'`
	if ! psql_query "select * from pg_group where groname='template1'" | grep -q .; then
		psql_query "create group template1"
	fi
	if ! psql_query "select * from pg_user where usename='$login'" | grep -q .; then
		psql_query "create user \"$login_esc\" password '$password' createdb createuser"
	else
		psql_query "alter user \"$login_esc\" password '$password'"
	fi
	psql_query "alter group template1 add user \"$login_esc\""
}

pg_init_db()
{
	[ ! -e "$pg_data_dir/PG_VERSION" ] || return 0
	LC_MESSAGES=C $PGSQL_SCRIPT 2>&1 | grep -q "initdb" && \
		$PGSQL_SCRIPT initdb
}

conf_setval()
{
    cat $1 | awk -v varname="$2" -v varvalue="$3" \
'BEGIN { f = 0 }
{ if ($1 == varname) { f = 1; print varname "\t" varvalue } else { print $0 } }
END { if (f == 0) { print "\n" varname "\t" varvalue } }' \
        > $1.new

    if [ -s "$1.new" ]; then
      if cmp -s $1.new $1; then
        rm -f $1.new
        return 1
      else
        rm -f $1.old
        ln $1  $1.old
        mv -f $1.new $1
        rm -f $1.old
        chmod 644 "$1"
        return 0
      fi
    fi
    return 2
}

if [ "$PLESK_INSTALLER_DEBUG" = yes ]; then
	set -x
fi

export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin

if [ "0`id -u`" -ne 0 ]; then
	die 1 "This script must be run as root"
fi

config="/etc/psa/psa.conf"

if [ ! -f $config ]; then
	die 3 "Unable to open $config file."
fi

config_text=`sed -e '/^#/d' -e '/^$/d' $config | awk '{print $1"="$2}'`
eval $config_text

if [ -x "/usr/bin/pg_lsclusters" ]; then
	# Debian/ubuntu cluster mode support
	pg_real_ver=`/usr/bin/pg_lsclusters  -h | awk '{if ( $3 == 5432)  print $1}'`
	pg_cluster_name=`/usr/bin/pg_lsclusters  -h | awk '{if ( $3 == 5432)  print $2}'`
	if [ -z "$pg_real_ver" -o -z "$pg_cluster_name" ]; then
		die 3 "Unable to detect posgres version ($pg_real_ver) or cluster name ($pg_cluster_name)"
	fi
	PGSQL_DATA_D="/var/lib/postgresql/$pg_real_ver/$pg_cluster_name"
	PGSQL_CONF_D="/etc/postgresql/$pg_real_ver/$pg_cluster_name"
	PGSQL_BIN_D="/usr/lib/postgresql/$pg_real_ver/bin"

	conf_setval "$config" PGSQL_DATA_D "$PGSQL_DATA_D"
	conf_setval "$config" PGSQL_BIN_D "$PGSQL_BIN_D"
	
else
	if [ ! -x "$PGSQL_BIN_D/psql" ]; then
		die 3 "PostgreSQL is not installed."
	fi

	pg_real_ver="`$PGSQL_BIN_D/psql --version | head -1 | awk '{print $3}' - | awk -F'.' '{print $1"."$2}' -`"
fi

pg_bin_dir=$PGSQL_BIN_D
pg_data_dir=$PGSQL_DATA_D
pg_conf_dir=$PGSQL_CONF_D

rc_dir=$PRODUCT_RC_D
if [ -z "$rc_dir" ]; then
	rc_dir=$PRODUCT_ROOT_D/rc.d
fi

pg_hba="$pg_conf_dir/pg_hba.conf"

postmaster_params

case "$1" in
	--status)
		if postmaster_run; then
			echo "is running"
		else
			echo "is stopped"
		fi
		;;

	--start)
		postmaster_start
		;;

	--stop)
		postmaster_stop
		;;

	--restart)
		postmaster_stop
		postmaster_start
		;;

	--check-installed)
		postmaster_check_installed
		;;

	--create-admin-login)
		if [ -z "$2" ]; then
			show_help
			exit 1
		fi

		login=$2
		password=$PSA_PASSWORD

		if [ -z "$password" ]; then
			die 1 "Variable PSA_PASSWORD is undefined"
		fi

		postmaster_start 1 || \
			pg_init_db && postmaster_start
		setup_pg_hba_conf "local template1 postgres trust"
		create_admin_login "$login" "$password"
		setup_pg_hba_conf

		;;

	--drop-admin-login)
		if [ -z "$2" ]; then
			show_help
			exit 1
		fi

		login=$2

		postmaster_start
		setup_pg_hba_conf "local template1 postgres trust"
		drop_admin_login "$login"
		setup_pg_hba_conf

		;;

	--set-admin-password)
		if [ -z "$2" ]; then
			show_help
			exit 1
		fi

		login=$2
		password=$PSA_PASSWORD

		if [ -z "$password" ]; then
			die 1 "Variable PSA_PASSWORD is undefined"
		fi

		postmaster_start
		setup_pg_hba_conf "local template1 postgres trust"
		set_admin_password "$login" "$password"
		setup_pg_hba_conf

		;;

	--repair-db-groups)
		postmaster_start
		setup_pg_hba_conf "local template1 postgres trust"
		while read database; do
			group=`echo "$database" | sed -e "s/'/''/g"`
			group_esc=`echo "$database" | sed -e 's/\(["\\]\)/\\\1/g'`
			if ! psql_query "select * from pg_group where groname='$group'" | grep -q .; then
				psql_query "create group \"$group_esc\""
			fi
			rm -f "$pg_data_dir/usrs_$database"
		done
		setup_pg_hba_conf

		;;

	--repair-db-users)
		postmaster_start
		setup_pg_hba_conf "local template1 postgres trust"
		while read user database; do
			user_esc=`echo "$user" | sed -e 's/\(["\\]\)/\\\1/g'`
			group_esc=`echo "$database" | sed -e 's/\(["\\]\)/\\\1/g'`
			psql_query "alter group \"$group_esc\" add user \"$user_esc\""
		done
		setup_pg_hba_conf

		;;

	*)
		show_help
		exit 1
esac

echo 0
exit 0