#!/bin/bash
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
#

#
# Plesk script
#



#default values

product_default_conf()
{

PRODUCT_ROOT_D=/opt/psa
PRODUCT_RC_D=/etc/init.d
PRODUCT_ETC_D=/opt/psa/etc
PLESK_LIBEXEC_DIR=/usr/lib/plesk-9.0
HTTPD_VHOSTS_D=/var/www/vhosts
HTTPD_CONF_D=/etc/apache2
HTTPD_INCLUDE_D=/etc/apache2/conf-enabled
HTTPD_BIN=/usr/sbin/apache2
HTTPD_LOG_D=/var/log/apache2
HTTPD_SERVICE=apache2
QMAIL_ROOT_D=/var/qmail
PLESK_MAILNAMES_D=/var/qmail/mailnames
RBLSMTPD=/usr/sbin/rblsmtpd
NAMED_RUN_ROOT_D=/var/named/run-root
WEB_STAT=/usr/bin/webalizer
MYSQL_VAR_D=/var/lib/mysql
MYSQL_BIN_D=/usr/bin
MYSQL_SOCKET=/var/run/mysqld/mysqld.sock
PGSQL_DATA_D=/var/lib/postgresql/14/main
PGSQL_CONF_D=/etc/postgresql/14/main
PGSQL_BIN_D=/usr/lib/postgresql/14/bin
DUMP_D=/var/lib/psa/dumps
DUMP_TMP_D=/tmp
MAILMAN_ROOT_D=/usr/lib/mailman
MAILMAN_VAR_D=/var/lib/mailman
PYTHON_BIN=/usr/bin/python2
GPG_BIN=/usr/bin/gpg
TAR_BIN=/usr/lib/plesk-9.0/sw-tar
AWSTATS_ETC_D=/etc/awstats
AWSTATS_BIN_D=/usr/lib/cgi-bin
AWSTATS_TOOLS_D=/usr/share/awstats/tools
AWSTATS_DOC_D=/usr/share/awstats
OPENSSL_BIN=/usr/bin/openssl
LIB_SSL_PATH=/lib/libssl.so
LIB_CRYPTO_PATH=/lib/libcrypto.so
CLIENT_PHP_BIN=/opt/psa/bin/php-cli
SNI_SUPPORT=true
APS_DB_DRIVER_LIBRARY=/usr/lib/x86_64-linux-gnu/sw/libmysqlserver.so.2.0
SA_MAX_MAIL_SIZE=256000

}

### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
set_apache_params()
{
	apache_user="www-data"
	apache_UID=80
	apache_group="www-data"
	apache_GID=80

	apache_pid_file="$APACHE_ROOT/logs/httpd.pid"
	apache_lock_file="$APACHE_ROOT/logs/httpd.lock"
	product_lock_file="$HTTPD_CONF_D/cnf.lock"
	apache_service_name="apache2"

	apache_modules_d="/usr/lib/apache2/modules"

	apache_service="$apache_service_name"

	apache_httpd_conf="$HTTPD_CONF_D/apache2.conf"

	apache_httpd_include="$HTTPD_INCLUDE_D/zz010_psa_httpd.conf"

	APACHE_ROOT="/usr"

	min_suexec_UID=10000
	max_suexec_UID=16000
	min_suexec_GID=$min_suexec_UID
	max_suexec_GID=$max_suexec_UID

	suexec_storage=/usr/lib/plesk-9.0/suexec
	suexec=/usr/lib/apache2/suexec
	suexec_dir="`dirname "$suexec"`"
	suexec_file="`basename "$suexec"`"

	rpm_httpd_bin=/usr/sbin/httpd
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
# vim:ft=sh:

#courier-imap

set_courier_imap_params()
{
	COURIERIMAP_CONFDIR="/etc/courier-imap"
	COURIERIMAP_PIDPATH="/run"
	IMAPD_CERT="/usr/share/imapd.pem"
	POP3D_CERT="/usr/share/pop3d.pem"
	COURIER_DHPARAMS="/usr/share/dhparams.pem"

	# Certificate paths for Courier-IMAP <= 3.0.8
	OLD_IMAPD_CERT="/usr/share/courier-imap/imapd.pem"
	OLD_POP3D_CERT="/usr/share/courier-imap/pop3d.pem"

	COURIER_DELIVER_QUOTA="/usr/bin/deliverquota"

	courier_imapd_service="courier-imapd"
	courier_imaps_service="courier-imaps"
	courier_pop3d_service="courier-pop3d"
	courier_pop3s_service="courier-pop3s"
	courier_authdaemon_service="courier-authdaemon"

	# Service name for Courier-IMAP <= 3.0.8
	old_courier_service="courier-imap"
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
# vim:ft=sh:

set_dovecot_params()
{
	DOVECOT_CONFDIR="/etc/dovecot"
	DOVECOT_INCLUDE_DIR="/etc/dovecot/conf.d"
	DOVECOT_DIST_CONFDIR="/usr/share/doc/plesk-dovecot/dist-config"
	DOVECOT_CERT_DIR="/etc/dovecot/private"
	DOVECOT_CERT="$DOVECOT_CERT_DIR/ssl-cert-and-key.pem"

	DOVECOT_INTERNAL_USERGROUP="dovecot"
	DOVECOT_LOGIN_USERGROUP="dovenull"

	DOVECOT_LDA="/usr/lib/dovecot/dovecot-lda"

	dovecot_service="dovecot"
}

### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
set_drweb_params()
{
	drweb_service="drwebd"
	true drweb_status
}

drweb_status()
{
	local pidfile="/var/drweb/run/drwebd.pid"
	if [ ! -r "$pidfile" ]; then
		p_echo "drweb is stopped (no pidfile found)"
		return 1
	fi

	local pid=$(head -1 "$pidfile" 2>/dev/null)
	if  [ -z "$pid" ]; then
		p_echo "drweb is stopped (wrong pidfile)"
		return 1
	fi

	if kill -0 "$pid" 2>/dev/null || ps -p "$pid" >/dev/null 2>&1 ; then
		p_echo "drwebd (pid $pid) is running..."
		return 0
	fi
	p_echo "drwebd is stopped"
	return 1
}

is_remote_db_feature_enabled()
{
	[ -s "/etc/psa/private/dsn.ini" ]
}

get_dsn()
{
	local section="$1"
	local param="$2"
	! is_remote_db_feature_enabled || get_ini_conf_var "/etc/psa/private/dsn.ini" "$section" "$param"
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
# vim:ft=sh
# Usage:  pleskrc <service> <action>
pleskrc()
{
	[ 2 -le $# ] || die "Not enough arguments"

	local service_name=${1//[-.@]/_}
	local action=$2
	local ret=0
	local inten
	shift
	shift

	# Now check redefined functions
	if test "$machine" = "linux" && is_function "${service_name}_${action}_${machine}_${linux_distr}"; then
		"${service_name}_${action}_${machine}_${linux_distr}" "$@"
		return $?
	elif is_function "${service_name}_${action}_${machine}"; then
		"${service_name}_${action}_${machine}" "$@"
		return $?
	elif is_function "${service_name}_${action}"; then
		"${service_name}_${action}" "$@"
		return $?
	fi

	# Not redefined - call default action
	eval "service=\$${service_name}_service"
	[ -n "$service" ] || die "$action $service_name service (Empty service name for '$service_name')"

	if [ "$action" = "name" ]; then
		echo "${service}.service"
		return 0
	fi

	inten="$action service $service"
	pleskrc_is_failure_for_action_ok "$action" || echo_try "$inten"

	if [ -x "/bin/systemctl" -a "$do_upgrade" = "1" -a ! -f "/var/lock/parallels-panel-bootstrapper-running.lock" -a -z "$SYSTEMD_DAEMON_RELOADED" ]; then
		# reload systemd units if requested from an upgrade package script - in case a unit was changed
		/bin/systemctl daemon-reload
		SYSTEMD_DAEMON_RELOADED="yes"
	fi

	service_ctl "$action" "$service" "$service_name"
	ret="$?"

	pleskrc_is_failure_for_action_ok "$action" || {
		if [ "$ret" -eq 0 ]; then
			suc
		else
			if [ -x "/bin/systemctl" ]; then
				p_echo "`/bin/systemctl -l status \"${service}.service\" | awk 'BEGIN {s=0} s==1 {s=2} /^$/ {s=1} s==2 {print}'`"
			fi
			warn "$inten failed"
		fi
	}

	return $ret
}

pleskrc_is_failure_for_action_ok()
{
	local action="$1"
	case "$action" in
		status|exists|is-active|is-enabled|is-failed) return 0 ;;
	esac
	return 1
}

pleskrc_actions_usage()
{
cat << EOT
Actions:
  start                Start (activate) service
  stop                 Stop (deactivate) service
  restart              Start or restart service
  try-restart          Restart service if active, do nothing otherwise
  reload-or-restart    Reload service if active, otherwise start or restart
  reload               Reload or restart service if active, do nothing otherwise
  try-reload           Reload or restart service if active, do nothing otherwise
  status               Check if service is active
  exists               Check if service exists
  name                 Print service name

Other actions may be available, but may be removed in future.
EOT
}

# NOTE:
#	Function service_ctl is just helper for pleskrc().
#	Do not call it directly, use pleskrc()!!!
service_ctl()
{
	local action=$1
	local service=$2
	local service_name=$3

	if [ "$action" != "exists" ]; then
		_service_exec $service exists
		if [ "$?" != "0" ]; then
			p_echo "attempt to ${inten} - service doesn't exist (missing unit file or not executable control script)"
			return 1
		fi
	fi

	case "$action" in
		start)
			pleskrc "$service_name" status || _service_exec "$service" "$action"
			;;
		stop)
			! pleskrc "$service_name" status || _service_exec "$service" "$action"
			;;
		restart)
			if pleskrc "$service_name" status; then
				_service_exec "$service" "$action"
			else
				_service_exec "$service" start
			fi
			;;
		reload)
			! pleskrc "$service_name" status || _service_exec "$service" "$action"
			;;
		status)
			_service_exec "$service" status
			;;
		try-restart)
			if [ -x "/bin/systemctl" ]; then
				_service_exec "$service" "$action"
			else
				! pleskrc "$service_name" status || _service_exec "$service" "restart"
			fi
			;;
		try-reload)
			! pleskrc "$service_name" status || _service_exec "$service" "reload"
			;;
		reload-or-restart)
			if [ -x "/bin/systemctl" ]; then
				_service_exec "$service" "$action"
			elif pleskrc "$service_name" status; then
				_service_exec "$service" "reload"
			else
				_service_exec "$service" "start"
			fi
			;;
		*)
			_service_exec "$service" "$action"
			;;
	esac >> "$product_log"
}

_service_exec()
{
	# Keep in sync with pylibplesk/plesk_service.py
	local service=$1
	local action=$2

	local action_cmd
	local sysvinit_service="/etc/init.d/$service"

	if [ -x "/bin/systemctl" ]; then
		case "${action}" in
			exists)
				if /bin/systemctl cat "$service.service" >/dev/null 2>&1; then
					return 0 # systemd unit
				elif [ -f "/lib/systemd/system/$service.service" ]; then
					/bin/systemctl daemon-reload
					return 0 # systemd unit which exists but was changed and has not been reloaded before
				elif [ -x "$sysvinit_service" ]; then
					return 0 # sysvinit compat
				fi
				return 1 # not found
				;;
			status)
				action="is-active"
				;;
			reload|graceful)
				action='reload-or-try-restart'
				;;
		esac
		/bin/systemctl "$action" "${service}.service"
	else
		warn "Cannot $action $service on this system: no executable /bin/systemctl"
		return 1
	fi
}

is_function()
{
	local type_output=$(type -t "$1")
	test "X${type_output}" = "Xfunction"
}

# echo message to product log, also to console in debug mode
p_echo()
{
    if [ -n "$product_log" ] ; then
        echo "$@" >> "$product_log" 2>&1
    fi
    if [ -n "$PLESK_INSTALLER_DEBUG" -o -n "$PLESK_INSTALLER_VERBOSE" -o -z "$product_log" ] ; then
        echo "$@" >&2
    fi
}

# same as p_echo, but without new line
pnnl_echo()
{
	p_echo -n "$@"
}

int_err()
{
	report_problem "internal" "Internal error: $@"
	exit 1
}

p_see_product_log()
{
	log_is_in_dev "${product_log}" || printf " (see log file: ${product_log})" >&2
}

die()
{
	report_problem "fatal" "ERROR while trying to $@"
	printf "Check the error reason" >&2
	p_see_product_log
	echo ", fix and try again" >&2

	selinux_close

	exit 1
}

warn()
{
	local inten="$1"

	if [ -n "$PLESK_INSTALLER_DEBUG" -o -n "$PLESK_INSTALLER_VERBOSE" ]; then
		p_echo
		p_echo "WARNING!"
		pnnl_echo "Some problems are found during $inten"
		p_see_product_log
		p_echo
		p_echo "Continue..."
		p_echo
	fi

	report_problem "warning" "Warning: $inten"
}

echo_try()
{
	msg="$*"
	pnnl_echo " Trying to $msg... "
}

suc()
{
	p_echo "done"
}

write_structured_report()
{
	# Write json error report into file $PLESK_INSTALLER_ERROR_REPORT if specified.
	# @params are tags in format "key=value"
	# Report body (human readable information) is read from stdin.
	local report_file="$PLESK_INSTALLER_ERROR_REPORT"

	[ -n "$report_file" ] || return 0

	local python_bin=
	for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/usr/libexec/platform-python" "/usr/bin/python3"; do
		if [ -x "$bin" ]; then
			python_bin="$bin"
			break
		fi
	done

	if [ ! -x "$python_bin" ]; then
		p_echo "Cannot write structured error report: python interpreter not found."
		return 1
	fi

	"$python_bin" -c 'import sys, json
report_file = sys.argv[1]
error = sys.stdin.read()

data = {
    "error": error,
}

for tag in sys.argv[2:]:
    k, v = tag.split("=", 1)
    data[k] = v

with open(report_file, "a") as f:
    json.dump(data, f)
    f.write("\n")
' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@"
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
reexec_with_clean_env()
{
	# Usage: call this function as 'reexec_with_clean_env "$@"' at the start of a script.
	#        Don't use with scripts that require sensitive environment variables.
	#        Don't put the call under any input/output redirection.
	# Purpose: make sure the script is executed with a sane environment.

	local lc="`get_default_locale`"
	export LANG="$lc" LC_MESSAGES="$lc" LC_ALL="$lc"
	export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
	umask 022

	PLESK_SCRIPT_COMMAND_LINE="$0 $*"
	[ -z "$PLESK_INSTALLER_ENV_CLEANED" ] || { unset PLESK_INSTALLER_ENV_CLEANED; return 0; }
	[ -n "$BASH" ] || exec /bin/bash "$0" "$@"

	# N.B.: the following code requires Bash. On Dash it would cause syntax error upon parse w/o eval.
	eval '
	local extra_vars=()                     # list of variables to preserve
	for var in "${!PLESK_@}"; do            # enumerate all PLESK_* variables
		extra_vars+=("$var=${!var}")
	done
	extra_vars+=("PLESK_INSTALLER_ENV_CLEANED=1")

	# Exec self with clean env except for extra_vars, shell opts, and arguments.
	exec /usr/bin/env -i "${extra_vars[@]}" /bin/bash ${-:+-$-} "$0" "$@" || {
		echo "Failed to reexec self ($0) with clean environment" >&2
		exit 91		# Just some relatively unique error code
	}
	'
}

get_default_locale()
{
	# Note that CentOS 7 typically doesn't have C.UTF-8
	for lc in "C.UTF-8" "en_US.UTF-8" "C"; do
		if [ -z "`LC_ALL=$lc locale 2>&1 >/dev/null`" ]; then
			echo "$lc"
			return 0
		fi
	done
	echo "C"
}

# accumulates chown and chmod
set_ac()
{
	local u_owner g_owner perms node
	u_owner="$1"
	g_owner="$2"
	perms="$3"
	node="$4"

	# A very small optimization - replacing of two execs by one,
	#    it works only if the following conditions are observed:
	#       - u_owner is username (not UID);
	#       - g_owner is group (not GID);
	#       - perms is in octal mode.
	# If some conditions aren't observed,
	#    optimization doesn't work,
	#    but it doesn't break function
	[ "$(stat -c '%U:%G 0%a' $node)" != "$u_owner:$g_owner $perms" ] || return 0
	chown $u_owner:$g_owner $node || die "chown $u_owner:$g_owner $node"
	chmod $perms $node || die "chmod $perms $node"
}

detect_vz()
{
	[ -z "$PLESK_VZ_RESULT" ] || return $PLESK_VZ_RESULT

	PLESK_VZ_RESULT=1
	PLESK_VZ=0
	PLESK_VE_HW_NODE=0
	PLESK_VZ_TYPE=

	local issue_file="/etc/issue"
	local vzcheck_file="/proc/self/status"
	[ -f "$vzcheck_file" ] || return 1

	local env_id=`sed -ne 's|^envID\:[[:space:]]*\([[:digit:]]\+\)$|\1|p' "$vzcheck_file"`
	[ -n "$env_id" ] || return 1
	if [ "$env_id" = "0" ]; then
		# Either VZ/OpenVZ HW node or unjailed CloudLinux
		PLESK_VE_HW_NODE=1
		return 1
	fi

	if grep -q "CloudLinux" "$issue_file" >/dev/null 2>&1 ; then
		return 1
	fi

	if [ -f "/proc/vz/veredir" ]; then
		PLESK_VZ_TYPE="vz"
	elif [ -d "/proc/vz" ]; then
		PLESK_VZ_TYPE="openvz"
	fi

	PLESK_VZ=1
	PLESK_VZ_RESULT=0
	return 0
}

# detects lxc and docker containers
detect_lxc()
{
	[ -z "$PLESK_LXC_RESULT" ] || return $PLESK_LXC_RESULT
	PLESK_LXC_RESULT=1
	PLESK_LXC=0
	if  { [ -f /proc/1/cgroup ] && grep -q 'docker\|lxc' /proc/1/cgroup; } || \
		{ [ -f /proc/1/environ ] && cat /proc/1/environ | tr \\0 \\n | grep -q "container=lxc"; };
	then
		PLESK_LXC_RESULT=0
		PLESK_LXC=1
	fi
	return "$PLESK_LXC_RESULT"
}

call_optional_function()
{
	local type_output="`LC_ALL=C type \"$1\" 2>/dev/null | head -n 1`"
	case "$type_output" in
		*function)
			"$@"
			;;
		*)
			return 0
			;;
	esac
}

get_ini_conf_var()
{
	local conf="$1"
	local section="$2"
	local param="$3"

	[ -n "$conf" -a -n "$param" ] || die "get_ini_conf_var(): required parameters missing"

	local section_empty=0
	[ -n "$section" ] || section_empty=1

	perl -n -e 'BEGIN { $insect='$section_empty' }
				next if (/^\s*;/);
				$insect=0 if (/^\s*\[.*\]/);
				$insect=1 if (/^\s*\['$section'\]/);
				$val = $2, $val =~ s/\s+$//, print $val . "\n" 
					if ($insect && /^\s*('$param')\s*=\s*([^;\n]*)(;.*)?$/);' $conf | head -n 1
}

### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
set_xinetd_params()
{
    xinetd_conf="/etc/xinetd.conf"
    xinetd_service="xinetd"
    xinetd_dir="/etc/xinetd.d"
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
#-*- vim:syntax=sh

product_log_name_ex()
{
	local aux_descr="$1"
	local action="${CUSTOM_LOG_ACTION_NAME-installation}"

	if [ -n "$aux_descr" ]; then
		aux_descr="_${aux_descr}"
	fi

	if [ -n "$CUSTOM_LOG_NAME" ]; then
		echo "${CUSTOM_LOG_NAME}${action:+_$action}${aux_descr}.log"
	else
		get_product_versions
		echo "plesk_${product_this_version}${action:+_$action}${aux_descr}.log"
	fi
}

product_log_name()
{
	product_log_name_ex
}

product_problems_log_name()
{
	product_log_name_ex "problems"
}

problems_log_tail()
{
	[ -f "$product_problems_log" ] || return 0
	{
		tac "$product_problems_log" | awk '/^START/ { exit } { print }' | tac
	} 2>/dev/null
}

product_log_tail()
{
	[ -f "$product_log" ] || return 0
	{
		tac "$product_log" | awk '/^START/ { exit } { print }' | tac
	} 2>/dev/null
}

product_and_problems_log_tail()
{
	product_log_tail
	[ "$product_log" = "$product_problems_log" ] || problems_log_tail
}

cleanup_problems_log()
{
	[ -f "$product_problems_log" ] || return 0
	touch "$product_problems_log.tmp"
	chmod 0600 "$product_problems_log.tmp"
	awk 'BEGIN 							{ st = "" }
		/^START/ && (st ~ /^START/) 	{ print st; }
		/^START/ 						{ st=$0; next }
		/^STOP/ && (st ~ /^START/) 		{ st=""; next }
		(st != "") 						{ print st; st="" }
										{ print }
		' "$product_problems_log" > "$product_problems_log.tmp" && \
	mv -f "$product_problems_log.tmp" "$product_problems_log" || \
	rm -f "$product_problems_log.tmp"

	if [ ! -s "$product_problems_log" ]; then
		rm -f "$product_problems_log"
	fi
}

mktemp_log()
{
	local logname="$1"
	local dir="$2"

	if [ "${logname:0:1}" != "/" ]; then
		logname="$dir/$logname"
	fi
	dir="`dirname $logname`"
	if [ ! -d "$dir" ]; then
		mkdir -p "$dir" || { echo "Unable to create log directory : $dir"; exit 1; }
		if [ "$EUID" -eq "0" ]; then
			set_ac root root 0700 "$dir"
		fi
	fi

	if [ "${logname%XXX}" != "$logname" ]; then
		mktemp "$logname"
	else
		echo "$logname"
	fi
}

log_is_in_dev()
{
	test "${1:0:5}" = "/dev/"
}

start_writing_logfile()
{
	local logfile="$1"
	local title="$2"
	! log_is_in_dev "$logfile" || return 0
	echo "START $title" >> "$logfile" || { echo "Cannot write installation log $logfile" >&2; exit 1; }
	[ "$EUID" -ne "0" ] || set_ac root root 0600 "$logfile"
}

log_start()
{
	true product_log_name product_problems_log_name mktemp_log

	local title="$1"
	local custom_log="$2"
	local custom_problems_log="$3"

	local product_log_dir="/var/log/plesk/install"

	product_log="$product_log_dir/`product_log_name`"
	product_problems_log="$product_log_dir/`product_problems_log_name`"
	problems_occured=0

	# init product log
	[ ! -n "$custom_log" ] || product_log="$custom_log"
	product_log=`mktemp_log "$product_log" "$product_log_dir"`

	# init problems log
	if [ -n "$custom_problems_log" ]; then
		product_problems_log=`mktemp_log "$custom_problems_log" "$product_log_dir"`
	elif [ -n "$custom_log" ]; then
		product_problems_log="$product_log"
	else
		product_problems_log=`mktemp_log "$product_problems_log" "$product_log_dir"`
	fi

	# write starting message into logs
	start_writing_logfile "$product_log" "$title"
	if [ "$product_log" != "$product_problems_log" ]; then
		start_writing_logfile "$product_problems_log" "$title"
	fi

	is_function profiler_setup && profiler_setup "$title" || :
}

log_transaction_start()
{
	LOG_TRANSACTION_TITLE="$1"
	LOG_TRANSACTION_SUBJECT="$2"
	local log_transaction_custom_logfile="$3"
	local log_transaction_custom_problems_logfile="$4"

	transaction_begin autocommit
	log_start "$LOG_TRANSACTION_TITLE" "$log_transaction_custom_logfile" "$log_transaction_custom_problems_logfile"
	transaction_add_commit_action "log_transaction_stop"
	transaction_add_rollback_action "log_transaction_stop"
}

log_transaction_stop()
{
	log_stop "$LOG_TRANSACTION_TITLE" "$LOG_TRANSACTION_SUBJECT"
}

log_stop()
{
	local title="$1"
	local subject="$2"

	if [ "$product_log" = "$product_problems_log" ] || \
			log_is_in_dev "$product_problems_log"; then
		[ -e "$product_log" ] && echo "STOP $title" >>"$product_log"
		is_function profiler_stop && profiler_stop || :
		return
	fi

	if [ -z "$subject" ]; then
		subject="[${title}]"
	fi

	# check if problems are non-empty, check for problems_occured
	local status
	local problem_lines="`problems_log_tail | wc -l`"
	if [ "$problem_lines" -eq 0 ]; then
		status="completed successfully"
	else
		if [ $problems_occured -ne 0 ]; then
			status="failed"
		else
			status="completed with warnings"
		fi
	fi

	if [ -e "$product_log" ]; then
		p_echo
		p_echo "**** $subject $status."
		p_echo
	fi

	if [ "$problem_lines" -ne 0 ]; then
		[ ! -e "$product_log" ] || problems_log_tail >>"$product_log" 2>&1
		problems_log_tail
	fi

	[ ! -e "$product_log" ] || echo "STOP $title" >>"$product_log"
	if [ $problems_occured -ne 0 ]; then
		echo "STOP $title: PROBLEMS FOUND" >>"$product_problems_log"
	else
		[ ! -s "$product_problems_log" ] || echo "STOP $title: OK" >>"$product_problems_log"
	fi

	if [ "X${PLESK_INSTALLER_KEEP_PROBLEMS_LOG}" = "X" ]; then
		cleanup_problems_log
	fi

	is_function profiler_stop && profiler_stop || :
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.

get_pid()
{
	local i

	local ex_f="$1"
	local opt="$2"
	local owner="$3"

	local min_num="1"
	local ps_long="ps axuw"

	# Use pidof by default, bug 121868, except for FreeBSD - 140182
	if type pidof >/dev/null 2>&1 && [ "$os" != "BSD" ]; then
		for pid in `pidof -o $$ -o $PPID -o %PPID -x $ex_f`; do
			# Check for owner
			[ "$opt" = "true" -a "$owner" != "`ps -p $pid -o ruser=`" ] && continue
			min_num=$pid
			break
		done
		common_var=$min_num
		return $min_num
	fi

	case "$opt" in
		false)
			for i in `$ps_long | grep $ex_f | grep -v grep | grep -v httpsdctl | grep -v apachectl | awk '{print $2}' -`; do
				min_num=$i
				break
			done
			;;
		true)
			for i in `$ps_long | grep $ex_f | grep -v grep | grep -v httpsdctl | grep -v apachectl | grep "$owner" | awk '{print $2}' -`; do
				min_num=$i
				break
			done
			;;
		*)
			p_echo "get_pid: wrong parameter"
			die "get_pid $ex_f $opt $owner"
			;;
	esac

	common_var=$min_num
	return $min_num
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.

construct_report_template()
{
	local severity="${1:-error}"
	local summary="$2"

	local update_ticket="`get_update_ticket`"

	set_error_report_source
	set_error_report_component
	set_error_report_params
	set_error_report_environment

	true construct_report_code construct_report_debug construct_report_message

cat <<-EOL
<?xml version="1.0" encoding="UTF-8" ?>
<error>
  <source>$report_source</source>
  <severity>$severity</severity>
  <datetime>`date --iso-8601=seconds`</datetime>

  <component>$report_component</component>
  <summary><![CDATA[`echo "$summary" | sed -e 's/\]\]>/] ]>/g'`]]></summary>
  <message encoding="base64">`construct_report_message | base64`</message>

  <additional_info>
    <component_params encoding="base64">$report_params</component_params>
    <code encoding="base64">`construct_report_code | base64`</code>
    <debug encoding="base64">`construct_report_debug | base64`</debug>
    <environment encoding="base64">$report_environment</environment>
    <update_ticket>$update_ticket</update_ticket>
  </additional_info>
</error>
EOL
}

construct_report_code()
{
	local call_level=${1:-5}
	local func_level=$[call_level - 1]
	local lineno_func=${BASH_LINENO[ $func_level ]}
	local script_name=${BASH_SOURCE[ $[func_level + 1] ]}

	echo "# Call of ${FUNCNAME[$func_level]}() from ${FUNCNAME[$[func_level + 1]]}() at `readlink -m $script_name`:${BASH_LINENO[$func_level]}"
	head -n $[lineno_func + 4] "$script_name" 2>/dev/null | tail -n 8
}

construct_report_debug()
{
	local call_level=${1:-5}
	call_level=$[call_level-1]

	# Generate calls stack trace.
	for i in `seq $call_level ${#FUNCNAME[@]}`; do
		[ "${FUNCNAME[$i]}" != "main" ] || break

		local func_call="`sed -n -e "${BASH_LINENO[$i]}p" "${BASH_SOURCE[$[i+1]]}" 2>/dev/null |
			sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'`"
		[ -n "$func_call" -a -z "${func_call##*${FUNCNAME[$i]}*}" ] || func_call="${FUNCNAME[$i]}"
		echo "#$[i - $call_level] `readlink -m ${BASH_SOURCE[$[i+1]]}`(${BASH_LINENO[$i]}): $func_call"
	done
}

construct_report_message()
{
	product_and_problems_log_tail

	echo ""
	if [ -n "$report_context" ]; then
		echo "Context: $report_context"
		echo ""
	fi
	if [ -n "$RP_LOADED_PATCHES" ]; then
		echo "Loaded runtime patches: $RP_LOADED_PATCHES"
		echo ""
	fi
}

# Construct report to send it to our errors tracker
construct_report()
{
	local severity="${1:-error}"
	local summary="$2"

	[ -n "$summary" ] || int_err "Unable to send error report. Some parameters are not defined."

	set_error_report_source
	get_product_versions

	construct_report_template "$severity" "$summary" \
		| $PRODUCT_ROOT_D/admin/bin/send-error-report --version "$product_this_version" $report_source >/dev/null 2>&1
}

# Use this function to report failed actions.
# Typical report should contain
# - reason or problem description (example: file copying failed)
# - how to resolve or investigate problem (example: check file permissions, free disk space)
# - how to re-run action (example: perform specific command, restart bootstrapper script, run installation again)
report_problem()
{
	local severity="${1:-error}"

	# Get first string of error as a summary of report
	shift

	local summary="$1"

	[ -n "$product_problems_log" ] || product_problems_log="/dev/stderr"

	p_echo
	if [ "0$problems_occured" -eq 0 ]; then
		echo "***** $process problem report *****" >> "$product_problems_log" 2>&1
	fi
	for problem_message in "$@"; do
		p_echo "$problem_message"
		if [ "$product_log" != "$product_problems_log" ]; then
			echo "$problem_message" >> "$product_problems_log" 2>&1
		fi
	done
	p_echo

	construct_report "$severity" "$summary"

	[ -n "$PLESK_INSTALLER_DEBUG" -o -n "$PLESK_INSTALLER_VERBOSE" ] || \
		product_log_tail

	problems_occured=1
}

set_error_report_source()
{
	[ -z "$1" ] || report_source="$1"
	[ -n "$report_source" ] || {
		if [ -n "$PACKAGE_ID" -o -n "$PACKAGE_ACTION" -o -n "$PACKAGE_NAME" -o -n "$PACKAGE_VERSION" ]; then
			report_source="install"
		else
			report_source="backend"
		fi
	}
}

set_error_report_component()
{
	local component="$1"

	if [ "$report_source" = "install" ]; then
		[ -n "$report_component" ] || report_component="$PACKAGE_ID"
		return 0
	fi

	[ -z "$component" ] || report_component="$1"
	[ -n "$report_component" ] || report_component="`basename $0`"
}

set_error_report_params()
{
	if [ "$report_source" = "install" ]; then
		[ -n "$report_params" ] || report_params="`echo "$PACKAGE_ACTION of $PACKAGE_NAME $PACKAGE_VERSION" | base64`"
		return 0
	fi

	[ -z "$*" ] || report_params="`echo "$*" | base64`"
	[ -n "$report_params" ] || report_params="`echo "$PLESK_SCRIPT_COMMAND_LINE" | base64`"
}

detect_virtualization()
{
	detect_vz
	detect_lxc
	local is_docker="`[ -f "/.dockerenv" ] && echo yes || :`"
	local systemd_detect_virt_ct="`/usr/bin/systemd-detect-virt -c 2>/dev/null | grep -v '^none$' || :`"
	local systemd_detect_virt_vm="`/usr/bin/systemd-detect-virt -v 2>/dev/null | grep -v '^none$' || :`"
	local virt_what="`/usr/sbin/virt-what 2>/dev/null | xargs || :`"

	if [ -n "$is_docker" ]; then
		echo "docker $virt_what"
	elif [ "$PLESK_VZ" = "1" ]; then
		echo "${PLESK_VZ_TYPE:-virtuozzo}"
	elif [ "$PLESK_LXC" = "1" ]; then
		echo "lxc $virt_what"
	elif [ -n "$systemd_detect_virt_ct" ]; then
		echo "$systemd_detect_virt_ct $systemd_detect_virt_vm"
	elif [ -n "$virt_what" ]; then
		echo "$virt_what"
	elif [ -n "$systemd_detect_virt_vm" ]; then
		echo "$systemd_detect_virt_vm"
	fi
}

default_error_report_environment()
{
	local virtualization="`detect_virtualization`"

	if [ -n "$virtualization" ]; then
		echo "virtualization: $virtualization"
	fi
}

set_error_report_environment()
{
	[ -z "$*" ] || report_environment="`echo "$*" | base64`"
	[ -n "$report_environment" ] || report_environment="`default_error_report_environment | base64`"
}

get_update_ticket()
{
	[ -r $PRODUCT_ROOT_D/var/update_ticket ] && cat $PRODUCT_ROOT_D/var/update_ticket | awk '{$1=$1};1'
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.

#
# Support for runtime patching of shell scripts (including utilities and package scripts).
#

# --- Service functions ---

# Load and apply a patch in a relatively safe way
rp_safe_load_patch()
{
	local patch_file="$1"
	echo_try "load shell patch '$patch_file'"
	/bin/sh -n "$RP_BASEDIR/$patch_file" && 
	{
		. "$RP_BASEDIR/$patch_file"
		RP_LOADED_PATCHES="$RP_LOADED_PATCHES $patch_file"
	} &&
	suc
}

# Apply patches specific to the current context (e.g., depending on utility basename or package name)
# This is currently not implemented. This may be overriden by "spark".
rp_patch_runtime_context_specific()
{
	:
}

# --- Main entry points ---

rp_patch_runtime()
{
	# List of loaded patch files
	RP_LOADED_PATCHES=

	local RP_BASEDIR="$PRODUCT_BOOTSTRAPPER_DIR/rp"
	[ -d "$RP_BASEDIR" ] || return 0

	if [ -r "$RP_BASEDIR/spark" ]; then
		rp_safe_load_patch "spark"
	fi

	call_optional_function rp_patch_runtime_context_specific "$@"
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
transaction_begin()
{
	[ -n "$TRANSACTION_STARTED" ] && die "Another transaction in progress!"
	TRANSACTION_STARTED="true"
	TRANSACTION_ROLLBACK_FUNCS=
	TRANSACTION_COMMIT_FUNCS=
	local transaction_autocommit="$1"
	if [ -n "$transaction_autocommit" ]; then
		trap "transaction_commit_auto" EXIT
		trap "transaction_rollback" HUP PIPE INT QUIT TERM
	else
		trap "transaction_rollback" HUP PIPE INT QUIT TERM EXIT
	fi
}

transaction_rollback()
{
	TRANSACTION_RETURN_CODE="${TRANSACTION_RETURN_CODE:-$?}"
	[ -z "$TRANSACTION_STARTED" ] && die "Transaction is not started!"
	# perform rollback actions
	local f
	for f in ${TRANSACTION_ROLLBACK_FUNCS}; do
		"$f"
	done
	TRANSACTION_STARTED=
	TRANSACTION_ROLLBACK_FUNCS=
	TRANSACTION_COMMIT_FUNCS=
	trap - HUP PIPE INT QUIT TERM EXIT
	exit 1
}

transaction_commit()
{
	TRANSACTION_RETURN_CODE="${TRANSACTION_RETURN_CODE:-$?}"
	[ -z "$TRANSACTION_STARTED" ] && die "Transaction is not started!"
	# perform commit actions
	local f
	for f in ${TRANSACTION_COMMIT_FUNCS}; do
		"$f"
	done
	TRANSACTION_STARTED=
	TRANSACTION_ROLLBACK_FUNCS=
	TRANSACTION_COMMIT_FUNCS=
	trap - HUP PIPE INT QUIT TERM EXIT
}

transaction_commit_auto()
{
	TRANSACTION_RETURN_CODE="$?"
	if [ "$TRANSACTION_RETURN_CODE" -eq 0 ]; then
		transaction_commit "$@"
	else
		transaction_rollback "$@"
	fi
}

transaction_add_rollback_action()
{
	[ -z "$TRANSACTION_STARTED" ] && die "Transaction is not started!"
	# LIFO rollback order
	[ -z "$TRANSACTION_ROLLBACK_FUNCS" ] \
		&& TRANSACTION_ROLLBACK_FUNCS="$1" \
		|| TRANSACTION_ROLLBACK_FUNCS="$1 $TRANSACTION_ROLLBACK_FUNCS"
}

transaction_add_commit_action()
{
	[ -z "$TRANSACTION_STARTED" ] && die "Transaction is not started!"
	# FIFO commit order
	[ -z "$TRANSACTION_COMMIT_FUNCS" ] \
		&& TRANSACTION_COMMIT_FUNCS="$1" \
		|| TRANSACTION_COMMIT_FUNCS="$TRANSACTION_COMMIT_FUNCS $1"
}

### Copyright 1999-2026. WebPros International GmbH. All rights reserved.

get_user_id()
{
	local name="$1"

	[ -n "$name" ] || int_err "Wrong value of argument 'name': $name"

	getent passwd "$name" 2>/dev/null | awk -F':' '{print $3}'
}

get_group_id()
{
	local name="$1"

	[ -n "$name" ] || int_err "Wrong value of argument 'name': $name"

	getent group "$name" 2>/dev/null | awk -F':' '{print $3}'
}

read_conf()
{
	[ -n "$prod_conf_t" ] || prod_conf_t=/etc/psa/psa.conf

	if [ -s $prod_conf_t ]; then
		tmp_var=`perl -e 'undef $/; $_=<>; s/#.*$//gm;
		         s/^\s*(\S+)\s*/$1=/mg;
		         print' $prod_conf_t`
		eval $tmp_var
	else
		if ! is_product_installation; then
			p_echo "Unable to find product configuration file: $prod_conf_t. Default values will be used."
			return 1
		fi
	fi
	return 0
}

get_my_cnf_param()
{
	local r=

	local my_cnf
	find_my_cnf "non-fatal" && \
		r=`perl -e '$p="'"$1"'";
		undef $/; $_=<>; s/#.*$//gm;
		/\[mysqld\](.*?)\[/sg;
		$_=substr($1, rindex $1,"$p") and
		/$p\s*=(.*)/m and print $1
		' ${my_cnf}`
	echo $r
}

get_mysql_socket()
{
	# Marked as local as it's not used anywhere else now.
	local mysql_socket="/var/run/mysqld/mysqld.sock"

	local mysqlsock=`get_my_cnf_param  socket`
	local MYSQL_SOCKETS="/var/lib/mysql/mysql.sock /tmp/mysql.sock /var/run/mysqld/mysqld.sock"

	for i in $mysql_socket $mysqlsock $MYSQL_SOCKETS; do
		if [ -S "$i" ]; then
			# This is used internally by mysqld_safe. Maybe this whole function isn't required nowadays.
			# See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-mysql-sock.html
			MYSQL_UNIX_PORT=$i
			export MYSQL_UNIX_PORT
			mysql_socket="$i"
			break
		fi
	done
}

selinux_close()
{
	if [ -z "$SELINUX_ENFORCE" -o "$SELINUX_ENFORCE" = "Disabled" ]; then
		return
	fi

	setenforce "$SELINUX_ENFORCE"
}

### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
# vim:ft=sh:

#set_params

set_common_params()
{
	common_var=0

	PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
	LANG="`get_default_locale`"
	export PATH LANG
	unset GREP_OPTIONS
	umask 022
	ulimit -n 65535 2>/dev/null

	get_product_versions

	certificate_file="$PRODUCT_ETC_D/httpsd.pem"
	services="/etc/services"

	crontab="/usr/bin/crontab"

	SYSTEM_RC_D="/etc/init.d"
	PLESK_LIBEXEC_DIR="/usr/lib/plesk-9.0"
	PLESK_DB_DIR="/var/lib/plesk"
	PRODUCT_BOOTSTRAPPER_DIR="`printf "/opt/psa/bootstrapper/pp%s-bootstrapper" "$product_this_version"`"
	AUTOGENERATED_CONFIGS="#ATTENTION!\n#\n#DO NOT MODIFY THIS FILE BECAUSE IT WAS GENERATED AUTOMATICALLY,\n#SO ALL YOUR CHANGES WILL BE LOST THE NEXT TIME THE FILE IS GENERATED.\n"
	AUTOGENERATED_CONFIGS_UPGRADE="#ATTENTION!\n#\n#DO NOT MODIFY THIS FILE BECAUSE IT WAS GENERATED AUTOMATICALLY,\n#SO ALL YOUR CHANGES WILL BE LOST AFTER YOU UPGRADE PLESK.\n"
	PRODUCT_LOGS_D="/var/log/plesk"

	sendmail="/usr/sbin/sendmail"
	ps="ps axw"
	ifconfig="/sbin/ifconfig -a"

	machine="linux"
	if [ -f /etc/debian_version ]; then
		linux_distr="debian"
	else
		linux_distr="redhat"
	fi

	dummy_home="/"
	if [ -x /usr/sbin/nologin ]; then
		dummy_shell="/usr/sbin/nologin"
	else
		dummy_shell="/bin/false"
	fi

	rp_patch_runtime
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
# -*- vim:syntax=sh

set_syslog_params()
{
	syslog_conf_ng="/etc/syslog-ng/syslog-ng.conf"

	syslog_conf=""
	for config in rsyslog.conf rsyslog.d/50-default.conf rsyslog.early.conf syslog.conf; do
		[ -f "/etc/$config" ] && syslog_conf="$syslog_conf /etc/$config"
	done

	syslog_service=""
	syslog_binary=""

	# Make sure the sequence of services is correlate with binaries
	local syslog_services="syslog sysklogd rsyslog syslog-ng"
	local syslog_binaries="syslogd syslogd rsyslogd syslog-ng"

	for service in $syslog_services; do
		[ -f "/lib/systemd/system/${service}.service" ] && \
			syslog_service="$service" && break
	done

	for binary in $syslog_binaries; do
		for bin_path in /sbin /usr/sbin; do
			[ -x "$bin_path/${binary}" ] && \
				syslog_binary="$bin_path/${binary}" && break
		done
		[ -n "$syslog_binary" ] && break
	done

	[ -n "$syslog_conf" ] || p_echo "\$syslog_conf: not found"
	[ -n "$syslog_service" ] || p_echo "\$syslog_service: not found"
	[ -n "$syslog_binary" ] || p_echo "\$syslog_binary: not found"

	[ -n "$syslog_conf" -a -n "$syslog_service" -a -n "$syslog_binary" ]
}

get_product_versions()
{
	# Don't use global variables set elsewhere in this code. Use substitutions if needed.
	local prod_root_d="/opt/psa"

	product_name="psa"

	if [ -z "$product_this_version" ]; then
		# 1. Try to fetch version from file created by bootstrapper (should be 3-component).
		product_this_version="`cat "/var/lock/plesk-target-version" 2>/dev/null`"
		# 2. Fallback to $PRODUCT_ROOT_D/version (should be 3-component).
		if [ -z "$product_this_version" -a -r "$prod_root_d/version" ]; then
			product_this_version="`awk '{ print $1 }' "$prod_root_d/version"`"
		fi
		# 3. Fallback to hardcoded version (2-component). This may cause some other code to fail.
		if [ -z "$product_this_version" ]; then
			product_this_version="18.0"
			echo "Unable to determine \$product_this_version, will use less precise value '$product_this_version'" >&2
		fi
	fi

	product_version="$product_this_version"

	if [ -z "$product_prev_version" ]; then
		if [ -r "$prod_root_d/version.upg" ]; then
			product_prev_version=`awk '{ print $1 }' "$prod_root_d/version.upg"`
		elif [ -r "$prod_root_d/version" ]; then
			product_prev_version=`awk '{ print $1 }' "$prod_root_d/version"`
		else
			product_prev_version="$product_this_version"
		fi
	fi
}

# Clean installation of the product is being performed
is_product_installation()
{
	[ "X$do_upgrade" != "X1" -a ! -s "/opt/psa/version.upg" ]
}

true exim_status_linux_debian
exim_status_linux_debian()
{
	get_pid /usr/lib/exim/exim3 false
	local pid=$common_var

	if test "$pid" -ne 1; then
		#running
		return 0;
	fi
	return 1
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.

#all functions in this file are valid for Standard builds only
set_mailman_params()
{
	mailman_user="list"
	mailman_group="list"
	MAILMAN_ROOT_D="/usr/lib/mailman"
	MAILMAN_VHOST_D="${HTTPD_VHOSTS_D}"/mailman

	mailman_service="mailman"
	mailman_log="/dev/null"
}

find_my_cnf()
{
	local non_fatal="$1"
	local cnf_files="/etc/my.cnf /etc/mysql/my.cnf /var/db/mysql/my.cnf"

	for my_cnf in $cnf_files; do
		if [ -f ${my_cnf} ]; then
			break
		fi
	done

	[ -f "$my_cnf" -o -n "$non_fatal" ] || {
		local msg="find the MySQL server configuration file. \
If you use a third-party MySQL server build, make sure you do not use implicit default configuration \
and you have the MySQL configuration file in one of the following locations: $cnf_files"
		echo "Failed to $msg" | write_structured_report 'stage=mysqlsetup' 'level=fatal' 'errtype=mysqlnomycnf' "mycnffiles=$cnf_files" || :
		die "$msg"
	}

	[ -f "$my_cnf" ] || return 1

	my_cnf_d=`awk '/^\s*!includedir\>/ {print $2}' "$my_cnf" | head -1`

	return 0
}

### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
# -*- vim:ft=sh

# mysql

set_mysqld_params()
{
	mysqld_user="mysql"
	mysqld_UID=3306
	mysqld_group="mysql"
	mysqld_GID=3306

	product_db_sql="$PRODUCT_BOOTSTRAPPER_DIR/db/${PRODNAME}_db.sql"
	admin_password_needs_encryption_flag="$PLESK_DB_DIR/.encrypt_admin_password.flag"

	set_mysql_server_params
	set_mysql_client_params
}

set_mysql_server_params()
{
	get_mysql_socket

	if [ -n "/lib/systemd/system" -a -f "/lib/systemd/system/mariadb.service" ]; then
	    mysql_service="mariadb"
	elif [ -n "/lib/systemd/system" -a -f "/lib/systemd/system/mysqld.service" ]; then
	    # Percona server
	    mysql_service="mysqld"
	elif [ -n "/lib/systemd/system" -a -f "/lib/systemd/system/mysql.service" ]; then
	    # MySQL 8 installations on debian / ubuntu
	    mysql_service="mysql"
	elif [ -x "${PRODUCT_RC_D}/mysql" ]; then
	    mysql_service="mysql"
	elif [ -x "${PRODUCT_RC_D}/mysql.sh" ]; then
	    mysql_service="mysql.sh"
	elif [ -x "${PRODUCT_RC_D}/mysqld" ]; then
	    mysql_service="mysqld"
	elif [ -x "${PRODUCT_RC_D}/mysql" ]; then
	    mysql_service="mysql"
	else
	    die "detect MySQL service name"
	fi
}

set_mysql_client_params()
{
	mysql_client="$MYSQL_BIN_D/mysql"
	[ -f "$MYSQL_BIN_D/mariadb" ] && mysql_client="$MYSQL_BIN_D/mariadb"

	# Override this variable as needed
	mysql_db_name="$PRODNAME"
	mysql_passwd_file="$product_etc/.${PRODNAME}.shadow"

	mysql_args="-N"
	mysql_args_raw="-Br"

	local dsn_plesk_dbname="`get_dsn plesk dbname`"
	[ -z "$dsn_plesk_dbname" ] || mysql_db_name="$dsn_plesk_dbname"
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
# -*- vim:ft=sh

# MySQL service action handlers

###	FIXME: probably need var service_restart warn
true mysql_stop
mysql_stop()
{
	local op_result i

	inten="stop MySQL server"
	echo_try $inten

	service_ctl stop $mysql_service mysql
	op_result=$?

	if [ "X$linux_distr" = "Xdebian" ]; then
		# Debian has well designed mysql stopping code
		[ "$op_result" -eq 0 ] || die $inten
		suc
		return 0
	fi

	for i in 2 4 6 8 16; do
		if ! mysql_status ; then
			suc
			return 0
		fi

		# I just want to be sure that mysql really stopped
		killall -TERM mysqld mysql safe_mysqld mysqld_safe >> $product_log 2>&1

		sleep $i
	done

	die "$inten"
}

true mysql_status
mysql_status()
{
	# Previously this handler also checked for mysqld pid on Debian systems. Should not be needed nowadays.
	service_ctl status $mysql_service mysql
}

### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
# vim:ft=sh:

set_named_params()
{
	# set up default values
	bind_UID=53
	bind_GID=53
	bind_user="bind";
	bind_group="bind";

	# get UID of named user, if exists
	bind_UID="`get_user_id $bind_user`"

	# get GID of named group, if exists
	bind_GID="`get_group_id $bind_group`"

	# path to directory of internal named
	NAMED_ROOT_D="${PRODUCT_ROOT_D:?'PRODUCT_ROOT_D is undefined'}/named"

	# path to directory of named pid file
	bind_run="${NAMED_RUN_ROOT_D:?'NAMED_RUN_ROOT_D is undefined'}/var/run/named"

	named_bin="/usr/sbin/named"
	named_service="named"
	named_log="/dev/null"

	named_sysconf_file="/etc/default/$named_service"

	# path to named config file
	named_conf="/etc/named.conf"
	named_run_root_template="/opt/psa/var/run-root.tar"
	rndc_conf="/etc/rndc.conf"
	rndc_namedb_conf="/etc/namedb/rndc.conf"
	rndc_bind_conf="/etc/bind/rndc.conf"
	named_user_options_conf="/etc/named-user-options.conf"

	#140025. Restrict CPU cores for Bind
	bind_number_of_workers=2
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
# vim:syntax=sh

set_nginx_params()
{
	nginx_service=nginx
	nginx_rc_config="/etc/default/nginx"
	nginx_user="nginx"
	nginx_bin="/usr/sbin/nginx"
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
# vim:syntax=sh
# mode: shell-script

set_fpm_params()
{
	fpm_service=php8.1-fpm
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.

set_postfix_params()
{
	postfix_service="postfix"
	pc_remote_service="pc-remote"
}

true postfix_status
postfix_status()
{
	# here be dragons.
	# the practical experience shows that simple checking of status of
	# Postfix "master" process is not enough. So we read Postfix master
	# process pid file if any, then try to look for a process with
	# name ``qmgr'' and parent pid being equal to
	# the pid read from the pidfile. If pgrep finds such a process
	# it returns 0, if not its exit status is non-zero.
	# pgrep is portable enough to prefer it to "hand-made" alternatives
	# such as famous ``ps | grep $name | grep -v grep...'' pipes
	# bug 147822. do not interrupt installation for FreeBSD

	[ -f "/var/spool/postfix/pid/master.pid" ] || return 1

	local ppid

	read ppid </var/spool/postfix/pid/master.pid 2>/dev/null
	if [ $? -ne 0 -o -z "$ppid" ]; then
		# not found or other error
		return 1;
	fi
	pgrep -P $ppid qmgr >/dev/null 2>/dev/null
}
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
#qmail

set_qmail_params()
{
    QMAIL_DIR="/var/qmail"
    QMAIL_USERS="alias:2021:nofiles:false:alias qmaild:2020:nofiles:false: qmaill:2022:nofiles:false: qmailp:2023:nofiles:false: qmailq:2520:qmail: qmailr:2521:qmail: qmails:2522:qmail:"
    QMAIL_GROUPS="qmail:2520 nofiles:2020"

    #variable from psa.conf but used in mail-qc-driver
    #so we need define this before install psa base package
    if [ -z "$QMAIL_ROOT_D" ]; then 
	    QMAIL_ROOT_D="/var/qmail"
    fi

    qmail_service="qmail"
    qmail_extra_cmd=""
}

### Copyright 1999-2026. WebPros International GmbH. All rights reserved.

set_sshd_params()
{
	sshd_service="ssh"
}

#!/bin/bash
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.

option_error()
{
	echo $@ >&2
	echo >&2
	usage
	exit 1
}

usage()
{
cat << EOT >&2
Usage: $prog service action

Perform specified action on specified service

EOT
	pleskrc_actions_usage >&2
}

set_mysql_params()
{
	set_mysqld_params
}

reexec_with_clean_env "$@"

prog="`basename $0`"

action=$2
service=${1}
service_name=${1//[-.@]/_}

product_default_conf
set_common_params
read_conf

log_transaction_start "$prog${*:+ $*}" "" "/var/log/plesk/rc_actions.log"

: set_apache_params set_courier_imap_params set_dovecot_params set_drweb_params set_fpm_params set_mailman_params set_named_params set_nginx_params set_postfix_params set_qmail_params set_xinetd_params set_mysql_params set_syslog_params set_sshd_params

[ -n "$service" ] || option_error "Service not specified"
[ -n "$action" ] || option_error "Action not specified"

echo "INFO: [`date`]: Service: $service, Action: $action" >> $product_log
# FIXME: check known services
param_function="set_${service_name}_params"
if is_function "$param_function"; then
	eval "$param_function"
else
	eval "${service_name}_service=${service}"
fi

pleskrc "$service_name" "$action"
