1322 lines
36 KiB
Bash
Executable File
1322 lines
36 KiB
Bash
Executable File
#!/bin/bash
|
|
### Copyright 1999-2025. 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/16/main
|
|
PGSQL_CONF_D=/etc/postgresql/16/main
|
|
PGSQL_BIN_D=/usr/lib/postgresql/16/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
|
|
|
|
}
|
|
|
|
# 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
|
|
}
|
|
|
|
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"
|
|
}
|
|
|
|
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"
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
log_is_in_dev()
|
|
{
|
|
test "${1:0:5}" = "/dev/"
|
|
}
|
|
### Copyright 1999-2025. 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'
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
|
|
|
|
err()
|
|
{
|
|
echo "$*" >&2
|
|
}
|
|
|
|
php_module_extract_name()
|
|
{
|
|
local config="$1"
|
|
local state="${2:-}" # "", enabled, disabled
|
|
local short="$3"
|
|
|
|
local prefix=""
|
|
[ ! "$state" = "enabled" ] || prefix='^\s*'
|
|
[ ! "$state" = "disabled" ] || prefix='^\s*;\s*'
|
|
|
|
local module=$(perl -nle 'print $2 if /'"${prefix}"'(?:zend_|)extension\s*=\s*([\"'"\'"']?)(.*)\.so\1/' "$config")
|
|
|
|
if [ -z "$module" -a -n "$short" ]; then
|
|
perl -nle 'print $2 if /'"${prefix}"'(?:zend_|)extension\s*=\s*([\"'"\'"']?)(.*)\1/' "$config"
|
|
else
|
|
echo "$module"
|
|
fi
|
|
}
|
|
|
|
php_module_is_enabled()
|
|
{
|
|
local config="$1"
|
|
local ext_s="$2"
|
|
local short="$3"
|
|
php_module_extract_name "$config" 'enabled' "${short}" | grep -q --ignore-case "^$ext_s\$"
|
|
}
|
|
|
|
php_module_is_disabled()
|
|
{
|
|
local config="$1"
|
|
local ext_s="$2"
|
|
local short="$3"
|
|
php_module_extract_name "$config" 'disabled' "${short}" | grep -q --ignore-case "^$ext_s\$"
|
|
}
|
|
|
|
php_module_enable()
|
|
{
|
|
local config="$1"
|
|
local ext_s="$2"
|
|
local short="$3"
|
|
|
|
local suffix=
|
|
[ -n "$short" ] || suffix='\.so'
|
|
|
|
perl -pi -e 's#^\s*;\s*((?:zend_|)extension\s*=\s*([\"'"\'"']?)'"${ext_s}"''"${suffix}"'\b\2)#\1#gi' "$config"
|
|
}
|
|
|
|
php_module_disable()
|
|
{
|
|
local config="$1"
|
|
local ext_s="$2"
|
|
local short="$3"
|
|
|
|
local suffix=
|
|
[ -n "$short" ] || suffix='\.so'
|
|
|
|
perl -pi -e 's#^\s*((?:zend_|)extension\s*=\s*([\"'"\'"']?)'"${ext_s}"''"${suffix}"'\b\2)#; \1#gi' "$config"
|
|
}
|
|
|
|
pecl_package_to_ext_name()
|
|
{
|
|
# PECL package syntax: [channel/]name[-version|stability][.tar|tgz|xml]
|
|
local package="$1"
|
|
local file_name="${package##*/}"
|
|
local name_version="${file_name%.gz}"
|
|
name_version="${name_version%.[ttxz][agmi][rzlp]}"
|
|
local ext_name="${name_version%%[-]*}"
|
|
echo "$ext_name"
|
|
}
|
|
|
|
pecl_package_to_version_or_stability()
|
|
{
|
|
local package="$1"
|
|
local file_name="${package##*/}"
|
|
local version_and_extension="${file_name#*-}"
|
|
if [ "$version_and_extension" = "$file_name" ]; then
|
|
version_and_extension=
|
|
else
|
|
version_and_extension="${version_and_extension%.gz}"
|
|
fi
|
|
local version="${version_and_extension%.[ttxz][agmi][rzlp]}"
|
|
echo "$version"
|
|
}
|
|
|
|
is_ioncube_loader_package_name()
|
|
{
|
|
[[ "$1" =~ ^ioncube_loader(_lin_[0-9]+\.[0-9]+)?(-[0-9.]+)?$ ]]
|
|
}
|
|
|
|
have()
|
|
{
|
|
local needle="$1"
|
|
[ -n "$needle" ] || {
|
|
err "Error: not enough arguments for the 'have' function"
|
|
return 1
|
|
}
|
|
|
|
shift
|
|
[[ " $* " =~ " $needle " ]]
|
|
}
|
|
|
|
prioritize_configs_by_name()
|
|
{
|
|
local extension_name="`basename "$1" .so`"
|
|
extension_name="${extension_name,,}"
|
|
[ -n "$extension_name" ] || {
|
|
cat -
|
|
return 0
|
|
}
|
|
|
|
local exact_matches=()
|
|
local partial_matches=()
|
|
local non_matches=()
|
|
|
|
local path=
|
|
while IFS= read -r path; do
|
|
[ -n "$path" ] || continue
|
|
local ext="`basename "$path" .ini`"
|
|
case "${ext,,}" in
|
|
"$extension_name") exact_matches+=("$path") ;;
|
|
*"$extension_name"*) partial_matches+=("$path") ;;
|
|
*) non_matches+=("$path") ;;
|
|
esac
|
|
done
|
|
|
|
[ -z "${exact_matches[*]}" ] || printf '%s\n' "${exact_matches[@]}"
|
|
[ -z "${partial_matches[*]}" ] || printf '%s\n' "${partial_matches[@]}"
|
|
[ -z "${non_matches[*]}" ] || printf '%s\n' "${non_matches[@]}"
|
|
}
|
|
|
|
# vim:ft=sh:
|
|
#!/bin/bash
|
|
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
|
|
# vim:ft=sh:
|
|
|
|
option_error()
|
|
{
|
|
err "$*"
|
|
err ""
|
|
usage
|
|
}
|
|
|
|
debug()
|
|
{
|
|
if [ $_V -ge 1 ]; then
|
|
echo "debug: $*" >&2
|
|
fi
|
|
}
|
|
|
|
usage()
|
|
{
|
|
cat << EOT >&2
|
|
Usage: $prog [OPTIONS]
|
|
-p,--php-cli Appropriate PHP cli for operations. Mandatory.
|
|
-c,--php-ini php.ini config for operations. Mandatory.
|
|
-l,--list Display extensions availiable for load
|
|
-s,--list-all Display all extensions (loadable and static)
|
|
-a,--list-installable Display installable extensions as JSON
|
|
-e,--enable=ext Enable specified extension. Can be specified several times.
|
|
-d,--disable=ext Disable specified extension. Can be specified several times.
|
|
-i,--install=ext Install extension. Can be specified several times.
|
|
-u,--uninstall=ext Uninstall extension. Can be specified several times.
|
|
-v,--verbose Be more verbose.
|
|
-h,--help Display this message.
|
|
|
|
Notes on --install and --uninstall commands:
|
|
* no checks whether the corresponding extensions are already installed and provided
|
|
by system package manager are performed (i.e. running these commands for packaged
|
|
extensions is destructive);
|
|
* these commands accept PECL packages as arguments - this means you may specify
|
|
versions, e.g. '--install redis-5.3.5', or states, e.g. '--install redis-beta',
|
|
using '--install redis' also works and will use the latest stable version;
|
|
* these commands mostly use PECL, except when operating on 'ioncube_loader' or
|
|
'ioncube_loader_lin_<php_major>.<php_minor>' (preferable name), in which case
|
|
the extension is downloaded directly from the vendor site;
|
|
* '--install' expects that required system dependencies are already installed,
|
|
this includes PHP development files, compiler, make, libraries' development files;
|
|
* no version compatibility checks are performed except those that PECL does;
|
|
* neither of the commands restarts or reloads any PHP-FPM or web server services.
|
|
|
|
Notes on --enable and --disable commands:
|
|
* these commands accept extension names as arguments, but PECL packages are also
|
|
accepted for uniformity with '--install' and '--uninstall' options (note that
|
|
in general PECL package name may not match corresponding extension name).
|
|
EOT
|
|
exit 1
|
|
}
|
|
|
|
get_extension_type()
|
|
{
|
|
# Check got from ext/standard/dl.c. But may be we should attempt to load via dl or -d
|
|
# However, dl can be disabled, and failure of load in -d doesn't cause php to return 1
|
|
|
|
local ext_file="$extension_dir/$1.so"
|
|
if [ ! -e "$ext_file" ] ; then
|
|
ext_file="$extension_dir/$(echo "$1" | tr '[:upper:]' '[:lower:]').so"
|
|
fi
|
|
|
|
|
|
if readelf -s --wide "$ext_file" | awk '{print $8}' 2>/dev/null | grep -q -E '^(_|)zend_extension_entry$'; then
|
|
debug "$ext_file: zend_extension detected"
|
|
echo "zend_extension"
|
|
return
|
|
elif readelf -s --wide "$ext_file" | awk '{print $8}' 2>/dev/null | grep -q -E '^(_|)get_module$'; then
|
|
debug "$ext_file: common_extension detected"
|
|
echo "extension"
|
|
return
|
|
else
|
|
debug "$ext_file: not a php extension"
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
find_config()
|
|
{
|
|
local ext="$1"
|
|
local status="$2"
|
|
for config_path in `get_configs | prioritize_configs_by_name "$ext"`; do
|
|
php_module_extract_name "$config_path" "$status" "$shortname_allowed" |
|
|
xargs -r -n1 basename |
|
|
grep --ignore-case "^$ext\$" >/dev/null ||
|
|
continue
|
|
echo "$config_path"
|
|
return
|
|
done
|
|
}
|
|
|
|
enmod()
|
|
{
|
|
local ext="$1"
|
|
if [ -z "$ext" ]; then
|
|
err "empty extension specified"
|
|
return 1
|
|
fi
|
|
|
|
local config=$(find_config "$ext")
|
|
local ext_s="$ext"
|
|
local ext_type=$(get_extension_type "$ext")
|
|
|
|
if [ -z "$config" ]; then
|
|
err "cannot find config for extension '$ext'"
|
|
return 1
|
|
fi
|
|
|
|
if [ "$ext_type" != "extension" -a "$ext_type" != "zend_extension" ]; then
|
|
err "$ext: invalid extension format - not a PHP library"
|
|
return 1
|
|
fi
|
|
|
|
if [ "$ext_type" = "zend_extension" ]; then
|
|
ext_s="$extension_dir/${ext}"
|
|
fi
|
|
|
|
if php_module_is_enabled "$config" "$ext" "$shortname_allowed"; then
|
|
debug "$ext (${ext}.so) already enabled in $config, do nothing"
|
|
return 0
|
|
fi
|
|
|
|
if [ "$ext_type" = "zend_extension" ] && php_module_is_enabled "$config" "$ext_s" "$shortname_allowed"; then
|
|
debug "$ext (${ext_s}.so) already enabled in $config, do nothing"
|
|
return 0
|
|
fi
|
|
|
|
if php_module_is_disabled "$config" "$ext" "$shortname_allowed"; then
|
|
debug "$ext (${ext}.so) disabled in $config, switch it on"
|
|
php_module_enable "$config" "$ext" "$shortname_allowed"
|
|
return 0
|
|
fi
|
|
|
|
if [ "$ext_type" = "zend_extension" ] && php_module_is_disabled "$config" "$ext_s" "$shortname_allowed"; then
|
|
debug "$ext (${ext_s}.so) disabled in $config, switch it on"
|
|
php_module_enable "$config" "$ext_s" "$shortname_allowed"
|
|
return 0
|
|
fi
|
|
|
|
debug "$ext is not found in $config, add new line"
|
|
echo "${ext_type}=${ext_s}.so" >> "$config"
|
|
return 0
|
|
}
|
|
|
|
dismod()
|
|
{
|
|
local ext="$1"
|
|
if [ -z "$ext" ]; then
|
|
err "empty extension specified"
|
|
return 1
|
|
fi
|
|
|
|
if [ -z "`find_config "$ext"`" ]; then
|
|
err "cannot find config for extension '$ext'"
|
|
return 1
|
|
fi
|
|
|
|
# Disable the extension in all configuration files
|
|
local config=
|
|
while config="`find_config "$ext" "enabled"`" && [ -n "$config" ]; do
|
|
local ext_s="$ext"
|
|
local ext_type=$(get_extension_type "$ext")
|
|
|
|
if [ "$ext_type" != "extension" -a "$ext_type" != "zend_extension" ]; then
|
|
err "$ext: invalid extension format - not a PHP library"
|
|
return 1
|
|
fi
|
|
|
|
if [ "$ext_type" = "zend_extension" ]; then
|
|
ext_s="$extension_dir/${ext}"
|
|
fi
|
|
|
|
if php_module_is_disabled "$config" "$ext" "$shortname_allowed"; then
|
|
debug "$ext ($ext) already disabled in $config, do nothing"
|
|
continue
|
|
fi
|
|
|
|
if [ "$ext_type" = "zend_extension" ] && php_module_is_disabled "$config" "$ext_s" "$shortname_allowed"; then
|
|
debug "$ext (${ext_s}.so) already disabled in $config, do nothing"
|
|
continue
|
|
fi
|
|
|
|
if php_module_is_enabled "$config" "$ext" "$shortname_allowed"; then
|
|
debug "$ext (${ext}.so) enabled in $config, switch it off"
|
|
php_module_disable "$config" "$ext" "$shortname_allowed"
|
|
fi
|
|
|
|
if [ "$ext_type" = "zend_extension" ] && php_module_is_enabled "$config" "$ext_s" "$shortname_allowed"; then
|
|
debug "$ext (${ext_s}.so) enabled in $config, switch it off"
|
|
php_module_disable "$config" "$ext_s" "$shortname_allowed"
|
|
fi
|
|
done
|
|
|
|
return 0
|
|
}
|
|
|
|
get_native_php_version()
|
|
{
|
|
local php_bin="`readlink -e "$php_cli"`"
|
|
if [[ "$php_bin" =~ ^/usr/bin/php.*$ ]] ; then
|
|
echo "${php_bin:12}"
|
|
fi
|
|
}
|
|
|
|
native_debian_php_extensions_op()
|
|
{
|
|
local enmod_or_dismod_bin="$1"
|
|
shift
|
|
|
|
local extensions=("$@")
|
|
for i in "${!extensions[@]}"; do
|
|
# make sure ionCube Loader has the same name as the config under mods-availiable/
|
|
! is_ioncube_loader_package_name "${extensions[$i]}" || extensions[$i]="ioncube-loader"
|
|
done
|
|
|
|
local php_version=`get_native_php_version`
|
|
if [ -z "$php_version" ] ; then
|
|
if [ -L "$php_cli" ] ; then
|
|
err "Debian native PHP binary has unexpected link: '`readlink -e "$php_cli"`'. The endpoint should be at /usr/bin and named phpX.Y"
|
|
else
|
|
err "Unexpected path for debian native PHP binary: '$php_cli'. The binary should be at /usr/bin and named phpX.Y"
|
|
fi
|
|
return 1
|
|
fi
|
|
|
|
"$enmod_or_dismod_bin" "-v" "$php_version" "${extensions[@]}"
|
|
}
|
|
|
|
enable_extensions()
|
|
{
|
|
|
|
[ -n "$1" ] || return 0
|
|
|
|
if check_native_debian_php; then
|
|
native_debian_php_extensions_op "$debian_mods_enmod_bin" "$@"
|
|
return $?
|
|
fi
|
|
|
|
for i in "$@"; do
|
|
if ! enmod $i; then
|
|
err "Cannot enable extension '$i'"
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
disable_extensions()
|
|
{
|
|
[ -n "$1" ] || return 0
|
|
|
|
if check_native_debian_php; then
|
|
native_debian_php_extensions_op "$debian_mods_dismod_bin" "$@"
|
|
return $?
|
|
fi
|
|
|
|
for i in "$@"; do
|
|
if ! dismod $i; then
|
|
err "Cannot disable extension '$i'"
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
check_native_debian_php()
|
|
{
|
|
|
|
if [ -n "${debian}" ]; then
|
|
return $debian
|
|
fi
|
|
|
|
debian=1
|
|
|
|
if [ ! -x "/usr/sbin/phpenmod" ]; then
|
|
return "$debian"
|
|
fi
|
|
|
|
local php_version=`get_native_php_version`
|
|
[ -n "$php_version" ] || return "$debian"
|
|
|
|
debian=0
|
|
debian_mods_availiable_dir="/etc/php/$php_version/mods-available"
|
|
debian_mods_enmod_bin="/usr/sbin/phpenmod"
|
|
debian_mods_dismod_bin="/usr/sbin/phpdismod"
|
|
return "$debian"
|
|
}
|
|
|
|
get_configs()
|
|
{
|
|
if ! check_native_debian_php; then
|
|
_get_configs
|
|
return
|
|
fi
|
|
|
|
# On debian, we have separate configs for enabled and disabled extensions.
|
|
if [ "$1" = "enabled" ]; then
|
|
_get_configs
|
|
return
|
|
fi
|
|
|
|
{
|
|
_get_configs
|
|
ls $debian_mods_availiable_dir/*.ini
|
|
} | xargs -n1 readlink -f | sort -u
|
|
}
|
|
|
|
_get_configs()
|
|
{
|
|
$php_cli -c $php_ini -r 'print(php_ini_scanned_files());' | tr ',' '\n' | sort -u | grep -v '^$'
|
|
if [ -f "$php_ini" ] ; then
|
|
echo "$php_ini"
|
|
fi
|
|
}
|
|
|
|
get_all_extensions()
|
|
{
|
|
"$php_cli" -c "$php_ini" -m |
|
|
sed -ne '/^\[PHP Modules\]$/,/^\[/ p' |
|
|
sed -e '/^\[/ d' -e '/^\s*$/ d' |
|
|
tr '[A-Z]' '[a-z]' |
|
|
sort -u |
|
|
while read -r ext; do
|
|
case "$ext" in
|
|
"ioncube loader") ext="ioncube_loader" ;;
|
|
"zend opcache") ext="opcache" ;;
|
|
esac
|
|
echo "$ext"
|
|
done
|
|
}
|
|
|
|
list_extensions()
|
|
{
|
|
local list_all="$1"
|
|
declare -a got_extensions=()
|
|
|
|
_list_extensions_by_status()
|
|
{
|
|
local status="$1"
|
|
local mark="$2"
|
|
for config_path in `get_configs "$status"`; do
|
|
for line in `php_module_extract_name "$config_path" "$status" "$shortname_allowed"`; do
|
|
[ -n "$line" ] || continue
|
|
[ -f "$extension_dir/${line}.so" -o -f "${line}.so" ] || continue
|
|
local ext="`basename "$line"`"
|
|
! have "$ext" "${got_extensions[@]}" || continue
|
|
got_extensions+=("$ext")
|
|
if is_ioncube_loader_package_name "$ext" && [ "$ext" != "ioncube_loader" ]; then
|
|
# ensure ioncube_loader is not listed as "static" even if its name differs
|
|
got_extensions+=("ioncube_loader")
|
|
fi
|
|
echo "$ext $mark"
|
|
done
|
|
done
|
|
}
|
|
|
|
_list_extensions_static()
|
|
{
|
|
local mark="$1"
|
|
for ext in `get_all_extensions`; do
|
|
! have "$ext" "${got_extensions[@]}" || continue
|
|
got_extensions+=("$ext")
|
|
echo "$ext $mark"
|
|
done
|
|
}
|
|
|
|
_list_extensions_by_status "enabled" "on"
|
|
_list_extensions_by_status "" "off"
|
|
[ -z "$list_all" ] ||
|
|
_list_extensions_static "static"
|
|
}
|
|
|
|
list_installable_extensions()
|
|
{
|
|
product_default_conf
|
|
|
|
local ioncube_loader="`list_installable_ioncube_loader_as_python_dict`"
|
|
local python_bin="$PRODUCT_ROOT_D/bin/py3-python"
|
|
"$pecl_bin" list-all |
|
|
"$python_bin" -c '
|
|
import sys, operator, json
|
|
|
|
lines = [""]
|
|
for line in sys.stdin:
|
|
# Process line continuations for description
|
|
if line[:1].isspace():
|
|
lines[-1] += line.lstrip()
|
|
else:
|
|
lines.append(line)
|
|
|
|
fields = ["package", "latest", "local", "description"]
|
|
packages = ['"$ioncube_loader"']
|
|
slice_start = {}
|
|
slice_end = {}
|
|
cookie_cutter = {}
|
|
|
|
for line in lines:
|
|
# Header includes only 3 first columns
|
|
if not slice_start and line.split() == [field.upper() for field in fields[:3]]:
|
|
starts = {item.lower(): line.index(item) for item in line.split()}
|
|
slice_start = {sf: starts.get(sf) for sf in fields}
|
|
slice_end = {sf: starts.get(ef) for sf, ef in zip(fields, fields[1:])}
|
|
continue
|
|
# Then determine the 4th column parameters based on the first row
|
|
if not cookie_cutter and slice_start.get("local") and not slice_end.get("local"):
|
|
last_columns = line[slice_start["local"]:]
|
|
if last_columns[:1].isspace():
|
|
desc_start = slice_start["local"] + (len(last_columns) - len(last_columns.lstrip()))
|
|
else:
|
|
desc_start = slice_start["local"] + (len(last_columns) - len(last_columns.split(maxsplit=1)[1]))
|
|
slice_start["description"] = slice_end["local"] = desc_start
|
|
slice_end["description"] = None
|
|
cookie_cutter = {field: operator.itemgetter(slice(slice_start[field], slice_end[field])) for field in fields}
|
|
# Parse each table row
|
|
if cookie_cutter:
|
|
pkg = {field: cutter(line).strip() for field, cutter in cookie_cutter.items()}
|
|
pkg["package"] = pkg["package"].rsplit("/", maxsplit=1)[-1]
|
|
pkg["latest"] = pkg["latest"] or pkg["local"]
|
|
packages.append(pkg)
|
|
|
|
json.dump(packages, sys.stdout, indent=2)
|
|
'
|
|
}
|
|
|
|
check_runtime_for_pecl()
|
|
{
|
|
[ -z "${CHECK_RUNTIME_FOR_PECL_DONE:-}" ] || return 0
|
|
|
|
debug "Check 'temp_dir' configured in $pecl_bin"
|
|
|
|
local pecl_temp_dir="`"$pecl_bin" config-get temp_dir`"
|
|
if [ -d "$pecl_temp_dir" ]; then
|
|
# PECL will create directory if needed.
|
|
# 'pecl config-set' doesn't work, but 'pear config-set' does.
|
|
! findmnt -o OPTIONS -nkT "$pecl_temp_dir" | grep -qwF noexec ||
|
|
echo "WARNING: PECL temp_dir '$pecl_temp_dir' is mounted with 'noexec'." \
|
|
"Extension installation will most likely fail." \
|
|
"Remount the FS with 'exec' option or configure a new directory" \
|
|
"using '${pecl_bin/pecl/pear} config-set temp_dir ... system'."
|
|
fi
|
|
|
|
CHECK_RUNTIME_FOR_PECL_DONE="yes"
|
|
}
|
|
|
|
install_extension_pecl()
|
|
{
|
|
local package="$1"
|
|
local ext="`pecl_package_to_ext_name "$package"`"
|
|
local libname="$ext.so"
|
|
|
|
check_runtime_for_pecl
|
|
|
|
debug "Execute: $pecl_bin install $package"
|
|
"$pecl_bin" install "$package" </dev/null || return $?
|
|
|
|
if [ ! -e "$extension_dir/$libname" ] ; then
|
|
libname="$(echo "$libname" | tr '[:upper:]' '[:lower:]')"
|
|
fi
|
|
|
|
debug "Set up correct permissions on $extension_dir/$libname"
|
|
[ ! -x "/usr/sbin/restorecon" ] || /usr/sbin/restorecon "$extension_dir/$libname"
|
|
|
|
local extension_type="extension"
|
|
case $("$pecl_bin" info "$package" | grep "Release Type") in
|
|
*"Zend extension"*)
|
|
extension_type="zend_extension"
|
|
;;
|
|
esac
|
|
|
|
debug "Create: $config_dir/$ext.ini (in disabled state)"
|
|
if check_native_debian_php; then
|
|
cat > "$config_dir/$ext.ini" <<-EOT
|
|
; Installed by Plesk via 'pecl'
|
|
; priority=20
|
|
$extension_type=$libname
|
|
EOT
|
|
else
|
|
cat > "$config_dir/$ext.ini" <<-EOT
|
|
; Installed by Plesk via 'pecl'
|
|
; $extension_type=$libname
|
|
EOT
|
|
fi
|
|
}
|
|
|
|
uninstall_extension_pecl()
|
|
{
|
|
local package="$1"
|
|
local ext="`pecl_package_to_ext_name "$package"`"
|
|
|
|
disable_extensions "$ext"
|
|
|
|
debug "Execute: $pecl_bin uninstall $package"
|
|
"$pecl_bin" uninstall "$package" </dev/null || return $?
|
|
|
|
debug "Remove: $config_dir/$ext.ini (should already be disabled)"
|
|
rm -f "$config_dir/$ext.ini"
|
|
}
|
|
|
|
list_installable_ioncube_loader_as_python_dict()
|
|
{
|
|
local arch="`uname -m`"
|
|
arch="${arch//_/-}"
|
|
local php_major_minor="${phpversion%.*}"
|
|
local ext_name="ioncube_loader_lin_${php_major_minor}"
|
|
local ext_file="$extension_dir/$ext_name.so"
|
|
local installed_version="`! test -f "$ext_file" ||
|
|
strings "$ext_file" | grep '^version:' | cut -d' ' -f2`"
|
|
|
|
echo "{
|
|
'package': '$ext_name',
|
|
'latest': 'latest',
|
|
'local': '$installed_version',
|
|
'description': 'ionCube PHP Loader',
|
|
}"
|
|
}
|
|
|
|
install_extension_ioncube_loader()
|
|
{
|
|
local package="$1"
|
|
local ext="`pecl_package_to_ext_name "$package"`"
|
|
local version="`pecl_package_to_version_or_stability "$package"`"
|
|
local arch="`uname -m`"
|
|
arch="${arch//_/-}"
|
|
local url="https://downloads.ioncube.com/loader_downloads/ioncube_loaders_lin_${arch}${version:+_$version}.tar.gz"
|
|
local php_major_minor="${phpversion%.*}"
|
|
local ext_name="ioncube_loader_lin_${php_major_minor}"
|
|
|
|
is_ioncube_loader_package_name "$ext" || return 1
|
|
|
|
debug "Download ionCube Loaders archive from $url"
|
|
local archive=
|
|
archive="`mktemp -t ioncube_loaders_${arch}${version:+_$version}.XXXXXXXX.tar.gz`" || {
|
|
err "Failed to create local file to download ionCube Loaders to"
|
|
return 1
|
|
}
|
|
curl -m 300 --retry 3 -fsSL "$url" -o "$archive" &&
|
|
[[ "`file -b --mime-type "$archive"`" =~ ^application/(gzip|x-gzip)$ ]] ||
|
|
{
|
|
err "Failed to download ionCube Loaders archive (is the version correct?) from: $url"
|
|
rm -f "$archive"
|
|
return 1
|
|
}
|
|
|
|
debug "Extract ionCube Loader extension from the archive to $extension_dir/$ext_name.so"
|
|
tar -tzf "$archive" --strip-components 1 -C "$extension_dir" "ioncube/$ext_name.so" >/dev/null || {
|
|
err "Downloaded ionCube Loaders archive doesn't contain expected $ext_name.so file"
|
|
rm -f "$archive"
|
|
return 1
|
|
}
|
|
tar -xzf "$archive" --strip-components 1 -C "$extension_dir" "ioncube/$ext_name.so" &&
|
|
[ -f "$extension_dir/$ext_name.so" ] ||
|
|
{
|
|
err "Failed to unpack ionCube loader file $ext_name.so"
|
|
rm -f "$archive"
|
|
return 1
|
|
}
|
|
|
|
# Clean up
|
|
rm -f "$archive"
|
|
|
|
debug "Set up correct permissions on $extension_dir/$ext_name.so"
|
|
# We'll consider 'execstack -c "$extension_dir/$ext_name.so"' excessive nowadays
|
|
chown root:root "$extension_dir/$ext_name.so"
|
|
chmod 0644 "$extension_dir/$ext_name.so"
|
|
[ ! -x "/usr/sbin/restorecon" ] || /usr/sbin/restorecon "$extension_dir/$ext_name.so"
|
|
|
|
# The loader should be declared first in PHP configuration, hence the config name or priority
|
|
if check_native_debian_php; then
|
|
local config="$config_dir/ioncube-loader.ini"
|
|
debug "Create: $config (uncommented, but not enabled)"
|
|
cat > "$config" <<-EOT
|
|
; Installed by Plesk (non-packaged file)
|
|
; priority=00
|
|
zend_extension=$ext_name.so
|
|
EOT
|
|
else
|
|
local config="$config_dir/00-ioncube-loader.ini"
|
|
debug "Create: $config (in disabled state)"
|
|
cat > "$config" <<-EOT
|
|
; Installed by Plesk (non-packaged file)
|
|
; zend_extension=$ext_name.so
|
|
EOT
|
|
fi
|
|
}
|
|
|
|
uninstall_extension_ioncube_loader()
|
|
{
|
|
local package="$1"
|
|
local ext="`pecl_package_to_ext_name "$package"`"
|
|
local php_major_minor="${phpversion%.*}"
|
|
local ext_name="ioncube_loader_lin_${php_major_minor}"
|
|
|
|
is_ioncube_loader_package_name "$ext" || return 1
|
|
|
|
disable_extensions "$ext"
|
|
|
|
debug "Remove: $extension_dir/$ext_name.so and $config_dir/*ioncube-loader.ini (should already be disabled)"
|
|
if check_native_debian_php; then
|
|
rm -f "$config_dir/ioncube-loader.ini"
|
|
else
|
|
rm -f "$config_dir/00-ioncube-loader.ini"
|
|
fi
|
|
rm -f "$extension_dir/$ext_name.so"
|
|
}
|
|
|
|
install_extensions()
|
|
{
|
|
for ext in "$@"; do
|
|
debug "Installing '$ext'"
|
|
if is_ioncube_loader_package_name "$ext"; then
|
|
install_extension_ioncube_loader "$ext" || return $?
|
|
else
|
|
install_extension_pecl "$ext" || return $?
|
|
fi
|
|
done
|
|
}
|
|
|
|
uninstall_extensions()
|
|
{
|
|
for ext in "$@"; do
|
|
debug "Uninstalling '$ext'"
|
|
if is_ioncube_loader_package_name "$ext"; then
|
|
uninstall_extension_ioncube_loader "$ext" || return $?
|
|
else
|
|
uninstall_extension_pecl "$ext" || return $?
|
|
fi
|
|
done
|
|
}
|
|
|
|
prog="`basename $0`"
|
|
|
|
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
|
umask 022
|
|
|
|
TEMP=`getopt -o vhlsap:c:e:d:i:u: \
|
|
--long help,verbose,php-cli:,php-ini:,list,list-all,list-installable,enable:,disable:,install:,uninstall: \
|
|
-n "$prog" -- "$@"`
|
|
|
|
if [ $? != 0 ]; then
|
|
echo "Internal Error: getopt cannot parse this command line: $@" >&2
|
|
exit 1
|
|
fi
|
|
|
|
php_cli=
|
|
php_ini=
|
|
declare -a ext_enable=()
|
|
declare -a ext_disable=()
|
|
declare -a ext_install=()
|
|
declare -a ext_uninstall=()
|
|
list_cmd=
|
|
list_all_cmd=
|
|
list_installable_cmd=
|
|
|
|
_V=0
|
|
eval set -- "$TEMP"
|
|
while true ; do
|
|
case "$1" in
|
|
-p|--php-cli) php_cli="$2"; shift 2;;
|
|
-c|--php-ini) php_ini="$2"; shift 2;;
|
|
-e|--enable) ext_enable+=("`pecl_package_to_ext_name "$2"`"); shift 2;;
|
|
-d|--disable) ext_disable+=("`pecl_package_to_ext_name "$2"`"); shift 2;;
|
|
-i|--install) ext_install+=("$2"); shift 2;;
|
|
-u|--uninstall) ext_uninstall+=("$2"); shift 2;;
|
|
-l|--list) list_cmd="1"; shift;;
|
|
-s|--list-all) list_all_cmd="1"; shift;;
|
|
-a|--list-installable) list_installable_cmd="1"; shift;;
|
|
-v|--verbose) let _V++; shift;;
|
|
-h|--help) usage ;;
|
|
--) shift ; break ;;
|
|
*) echo "Unknown option '$1'" ; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "$php_cli" ]; then
|
|
option_error "No php cli (--php-cli) specified"
|
|
fi
|
|
|
|
if [ ! -x "$php_cli" ]; then
|
|
option_error "PHP cli ($php_cli) should be executable"
|
|
fi
|
|
|
|
pecl_bin="`dirname "$php_cli"`/pecl"
|
|
if [ ! -x "$pecl_bin" -a \( -n "${ext_install[*]}" -o -n "${ext_uninstall[*]}" \) ]; then
|
|
option_error "PECL binary ($pecl_bin) should be executable"
|
|
fi
|
|
|
|
if [ -z "$php_ini" ]; then
|
|
option_error "No php ini (--php-ini) specified"
|
|
fi
|
|
|
|
if [ ! -f "$php_ini" ]; then
|
|
warn "PHP ini ($php_ini) doesn't exist, or not a file"
|
|
fi
|
|
|
|
extension_dir=$("$php_cli" -c "$php_ini" -r 'print(ini_get("extension_dir"));')
|
|
if [ -z "$extension_dir" -o ! -d "$extension_dir" ]; then
|
|
option_error "Extension dir \"$extension_dir\" is empty or not a directory"
|
|
fi
|
|
|
|
config_dir="`"$php_cli" --ini -c "$php_ini" |
|
|
sed -ne 's|^Scan for additional \.ini files in:\s*\(.*\)$|\1| p' | xargs`"
|
|
! check_native_debian_php || config_dir="$debian_mods_availiable_dir"
|
|
if [ -z "$config_dir" -o ! -d "$config_dir" ]; then
|
|
option_error "PHP ini configuration directory \"$config_dir\" is empty or not a directory"
|
|
fi
|
|
|
|
if [ -z "$list_cmd" -a -z "$list_all_cmd" -a -z "$list_installable_cmd" -a \
|
|
-z "${ext_enable[*]}" -a -z "${ext_disable[*]}" -a \
|
|
-z "${ext_install[*]}" -a -z "${ext_uninstall[*]}" ]; then
|
|
option_error "No action specified"
|
|
fi
|
|
|
|
if [ "`echo $list_cmd $list_all_cmd $list_installable_cmd | wc -w`" -gt 1 ]; then
|
|
option_error "Cannot use multiple listing options (--list, --list-all, --list-installable) simultaneously"
|
|
fi
|
|
|
|
if [ -n "${ext_enable[*]}" -o -n "${ext_disable[*]}" -o \
|
|
-n "${ext_install[*]}" -o -n "${ext_uninstall[*]}" ]; then
|
|
[ -z "$list_cmd" ] ||
|
|
option_error "Cannot use --list and --enable/--disable/--install/--uninstall simultaneously"
|
|
[ -z "$list_all_cmd" ] ||
|
|
option_error "Cannot use --list-all and --enable/--disable/--install/--uninstall simultaneously"
|
|
[ -z "$list_installable_cmd" ] ||
|
|
option_error "Cannot use --list-installable and --enable/--disable/--install/--uninstall simultaneously"
|
|
fi
|
|
|
|
phpversion=$("$php_cli" -r '
|
|
if (defined("PHP_MAJOR_VERSION"))
|
|
echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . "." . PHP_RELEASE_VERSION;
|
|
else
|
|
echo phpversion();
|
|
')
|
|
shortname_allowed=""
|
|
case $phpversion in
|
|
[45]*) shortname_allowed="" ;;
|
|
7.0.*) shortname_allowed="" ;;
|
|
7.1.*) shortname_allowed="" ;;
|
|
*) shortname_allowed="1" ;;
|
|
esac
|
|
|
|
if [ -n "$list_cmd" ]; then
|
|
list_extensions
|
|
exit $?
|
|
elif [ -n "$list_all_cmd" ]; then
|
|
list_extensions --all
|
|
exit $?
|
|
elif [ -n "$list_installable_cmd" ]; then
|
|
list_installable_extensions
|
|
exit $?
|
|
fi
|
|
|
|
true &&
|
|
install_extensions "${ext_install[@]}" &&
|
|
uninstall_extensions "${ext_uninstall[@]}" &&
|
|
enable_extensions "${ext_enable[@]}" &&
|
|
disable_extensions "${ext_disable[@]}"
|