summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/php.eselect.in.in')
-rw-r--r--src/php.eselect.in.in603
1 files changed, 603 insertions, 0 deletions
diff --git a/src/php.eselect.in.in b/src/php.eselect.in.in
new file mode 100644
index 0000000..b2a0dd5
--- /dev/null
+++ b/src/php.eselect.in.in
@@ -0,0 +1,603 @@
+# Copyright 2010-2016 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+inherit config multilib
+
+DESCRIPTION="Manage php installations"
+MAINTAINER="php-bugs@gentoo.org"
+
+MODULES="cli apache2 fpm cgi phpdbg"
+
+#
+# Output a list of link names (not full paths) belonging to the given
+# SAPI. These need to be updated when the user changes his active
+# target.
+#
+# INPUT:
+#
+# The name of a SAPI.
+#
+# OUTPUT:
+#
+# A space-separated list of link names belonging to the given
+# SAPI. For example, the "cli" SAPI has three link names: "php phpize
+# php-config". The "cgi" sapi has only "php-cgi".
+#
+sapi_active_link_names() {
+ local sapi="${1}"
+
+ case "${sapi}" in
+ apache2) echo "mod_php.so" ;;
+ cli) echo "php phpize php-config" ;;
+ fpm) echo "php-fpm" ;;
+ cgi) echo "php-cgi" ;;
+ phpdbg) echo "phpdbg" ;;
+ *) die "invalid SAPI name: ${sapi}" ;;
+ esac
+}
+
+# The link names obtained from sapi_active_link_names() all need to
+# point somewhere. Usually the target is the same as the link name
+# itself, but not always. This function returns the link-target for a
+# given sapi, sapi-target, and link name.
+#
+# INPUT:
+#
+# The first parameter is a SAPI name. The second parameter is the
+# SAPI-target name (for example, "php7.0"). The third parameter is a
+# link name.
+#
+# OUTPUT:
+#
+# The name of the target (that is, file) for the given link name.
+#
+sapi_link_name_target() {
+ local sapi="${1}"
+ local target_name="${2}"
+ local link_name="${3}"
+
+ # For now, only apache2's mod_php.so gets special treatment.
+ if [[ "${sapi}" == "apache2" && "${link_name}" == "mod_php.so" ]] ; then
+ local major=$(parse_target_major_version "${target_name}")
+ echo "libphp${major}.so"
+ else
+ echo "${link_name}"
+ fi
+}
+
+# Each SAPI provides a few (one or more) "active" links in a
+# predictable location. The target directory (where they point) is
+# fixed for a given SAPI, and this function returns it.
+#
+# The name "target" is unfortunate, but that's the terminology that
+# "ln" uses. The link_name is the name of the link on the filesystem,
+# and target is where it points.
+#
+# INPUT:
+#
+# The first parameter is the name of a SAPI. The second parameter is
+# the name of a target.
+#
+# OUTPUT:
+#
+# The directory to which the given SAPI's symlinks point. For example,
+# the "cli" sapi has three executable symlinks and all of them point
+# to executables in /usr/lib/phpX.Y/bin.
+#
+sapi_active_link_target_dir() {
+ local sapi="${1}"
+ local target="${2}"
+
+ local link_target_dir="${EROOT}$(get_active_libdir)/${target}/bin"
+ if [[ "${sapi}" == "apache2" ]] ; then
+ link_target_dir+="/../apache2"
+ fi
+
+ echo "${link_target_dir}"
+}
+
+
+# Each SAPI provides a few (one or more) "active" links in a
+# predictable location. And fortunately that location is fixed for a
+# given SAPI. For example, the "cgi" SAPI has its sole active symlink,
+# /usr/bin/php-cgi, in /usr/bin. Given a SAPI name, we return the
+# directory where that SAPI's links are located.
+#
+# INPUT:
+#
+# The name of a SAPI.
+#
+# OUTPUT:
+#
+# The directory in which the given SAPI's symlinks are located. For
+# example, the "cli" sapi has its three executable links in "/usr/bin".
+#
+sapi_active_link_dir() {
+ local sapi="${1}"
+ local bin_dir="${EROOT}/usr/bin"
+
+ case "${sapi}" in
+ apache2) echo "${EROOT}$(get_active_libdir)/apache2/modules" ;;
+ cli) echo "${bin_dir}" ;;
+ fpm) echo "${bin_dir}" ;;
+ cgi) echo "${bin_dir}" ;;
+ phpdbg) echo "${bin_dir}" ;;
+ *) die "invalid SAPI name: ${sapi}" ;;
+ esac
+}
+
+
+# Each SAPI provides at least one "active" link in a predictable
+# location. For example, the "cgi" SAPI has its active symlink at
+# /usr/bin/php-cgi. Given a SAPI name we return the path to that link.
+#
+# Note that SAPIs may provide more than one active link -- we return
+# the path for only the first.
+#
+# INPUT:
+#
+# The name of a SAPI.
+#
+# OUTPUT:
+#
+# The path of the main symlink provided by the active version of the
+# given SAPI. An error is raised if the given SAPI is not valid.
+#
+sapi_active_link_path() {
+ local sapi="${1}"
+ local dir=$(sapi_active_link_dir "${sapi}")
+ local link_names=( $(sapi_active_link_names "${sapi}") )
+
+ # Use the first link name only.
+ echo "${dir}/${link_names[0]}"
+}
+
+
+# Parse and return the major version from a target name. For example,
+# the "php5.6" target has a major version of "5".
+#
+# INPUT:
+#
+# The name of a valid PHP target, like php5.6 or php7.0.
+#
+# OUTPUT:
+#
+# A major version number. An error is raised if the given target is
+# not valid.
+#
+parse_target_major_version() {
+ local target="${1}"
+ local major="${target:3:1}"
+ case "${major}" in
+ 5|7) echo "${major}" ;;
+ *) die "invalid PHP target name: ${target}" ;;
+ esac
+}
+
+cleanup_sapis() {
+ local m
+ local link
+ for m in $MODULES ; do
+ cleanup_sapi $m
+ done
+}
+
+cleanup_sapi() {
+ local sapi="${1}"
+ local l="${sapi}_link"
+ local link=${!l}
+ if [[ -L $link && ! -e $link ]] ; then
+ echo -n "Broken link for ${sapi}"
+ if update_sapi $1 ; then
+ echo ", updated version to $(get_sapi_active_target "${sapi}")"
+ return
+ else
+ rm $link || die "failed to remove ${link}"
+
+ return
+ fi
+ fi
+
+ if [[ "${sapi}" == "apache2" ]] ; then
+ rm -f "${EROOT}$(get_active_libdir)"/apache2/modules/libphp[57].so \
+ || die "failed to remove old libphp.so symlink"
+ fi
+
+ return 1
+}
+
+update_sapi() {
+ local sapi="${1}"
+ local target=$(find_sapi_targets "${sapi}" | tail -n 1)
+ local current=$(get_sapi_active_target "${sapi}")
+ [[ -z $target ]] && return 1
+ [[ $current = $target ]] && return 1
+ set_$sapi $target
+}
+
+get_libdirs() {
+ local dir libdirs
+ for dir in $(list_libdirs); do
+ [[ -L ${EROOT}/usr/${dir} ]] && continue
+ ls "${EROOT}"/usr/${dir}/php*.* > /dev/null 2>&1 || continue
+
+ libdirs+=' '/usr/${dir}
+ done
+ echo ${libdirs:-/usr/lib}
+}
+
+get_active_libdir() {
+ local dir
+ for dir in $(get_libdirs); do
+ echo ${dir}
+ return
+ done
+ echo /usr/lib
+}
+
+find_targets() {
+ local dir dirs libdir
+ for libdir in $(get_libdirs); do
+ for dir in "${EROOT}"${libdir}/php*.*; do
+ t=$(basename $dir)
+ has $t $dirs || dirs="${dirs} $t"
+ done
+ done
+ echo $dirs
+}
+
+# List all valid targets for the given SAPI. The list is obtained by
+# searching the filesystem for a particular (SAPI-specific) file in
+# locations determined by find_targets(). This list should therefore
+# be a subset of find_targets().
+#
+# INPUT:
+#
+# The name of a SAPI.
+#
+# OUTPUT:
+#
+# The "display name" of every available target for this SAPI, one per
+# line. For example,
+#
+# php5.6
+# php7.0
+#
+find_sapi_targets() {
+ local sapi="${1}"
+
+ local pattern_suffix
+ case "${sapi}" in
+ apache2) pattern_suffix="apache2/libphp[57].so" ;;
+ cli) pattern_suffix="bin/php" ;;
+ fpm) pattern_suffix="bin/php-fpm" ;;
+ cgi) pattern_suffix="bin/php-cgi" ;;
+ phpdbg) pattern_suffix="bin/phpdbg" ;;
+ *) die "invalid SAPI name: ${sapi}" ;;
+ esac
+
+ for target in $(find_targets); do
+ for libdir in $(get_libdirs); do
+ local pattern="${EROOT}${libdir}/${target}/${pattern_suffix}"
+ for file in $pattern; do
+ [[ -f "${file}" ]] && echo "${target}"
+ done
+ done
+ done | @SORT@ | @UNIQ@
+}
+
+
+# Find the active (selected) target for the given SAPI. This is used
+# to decorate the output of the `eselect php list <sapi>` command.
+#
+# INPUT:
+#
+# The name of a SAPI.
+#
+# OUTPUT:
+#
+# The "display name" of the active target for the given SAPI. For
+# example, "php5.6" or "php7.0".
+#
+get_sapi_active_target() {
+ local sapi="${1}"
+ local active_symlink=$(sapi_active_link_path "${sapi}")
+
+ if [[ -L "${active_symlink}" ]] ; then
+ local active_file=$(canonicalise "${active_symlink}")
+ if [[ -a "${active_file}" ]] ; then
+ # This sed command (regular expression) finds a target name
+ # contained in a filesystem path. For example, it parses
+ # "php5.6" from "/usr/lib64/php5.6/apache2/libphp5.so".
+ # The curly braces are an attempt to avoid '+' which is
+ # a GNU extension.
+ local sed_cmd='s:.*/\(php[0-9]\.[0-9]\{1,\}\)/.*:\1:p'
+ echo "${active_file}" | @SED@ -ne "${sed_cmd}"
+ fi
+ fi
+}
+
+# Write an apache configuration file to load the active version of
+# mod_php. The 5.x and 7.x series (at least...) have different module
+# names, and so require a different apache configuration when
+# switching between the two.
+#
+# INPUT:
+#
+# The name of the target (php5.6, php7.0) for which to write the
+# configuration file.
+#
+# OUTPUT:
+#
+# None.
+#
+write_mod_php_conf() {
+ local target="${1}"
+ local conf_dir="${EROOT}"/var/lib/eselect-php
+ local conf_path="${conf_dir}/mod_php.conf"
+
+ @MKDIR_P@ "${conf_dir}" || die "failed to create ${conf_dir}"
+
+ local major=$(parse_target_major_version "${target}")
+ cat <<-EOF > "${conf_path}" || die "failed to write mod_php.conf"
+ <IfModule !php${major}_module>
+ LoadModule php${major}_module modules/mod_php.so
+ </IfModule>
+ EOF
+}
+
+
+# Resolve an index or target name for a given SAPI into the "display
+# name" of that target.
+#
+# INPUT:
+#
+# The first parameter is the name of a SAPI. The second parameter is
+# either a number (the index of a target), or a target name.
+#
+# OUTPUT:
+#
+# The "display name" of the given target for the given SAPI. For
+# example, if the first parameter is "cli" and the second parameter is
+# "1", then the output will be the display name of the first target
+# for the cli SAPI (e.g. "php5.6").
+#
+# If the index or target name is invalid (that is, does not correspond
+# to one of the valid targets for the given SAPI), then nothing is
+# output.
+#
+resolv_target() {
+ local sapi="${1}"
+ local target="${2}"
+
+ # $targets is an array of things like "php5.6" and "php7.0"
+ local targets=( $(find_sapi_targets "${sapi}") )
+
+ if is_number "${target}" ; then
+ if [[ $target -le ${#targets[@]} && $target -gt 0 ]] ; then
+ # $target looks like an index into the $targets array.
+ echo "${targets[ $(( $target - 1 )) ]}"
+ fi
+ elif has "${target}" ${targets[@]} ; then
+ # $target is the *name* of a valid target for this SAPI.
+ echo "${target}"
+ fi
+}
+
+
+# Die if the given module name is not valid.
+#
+# INPUT:
+#
+# A module name.
+#
+# OUTPUT:
+#
+# None; the function will die() if the given module name is invalid
+# (that is, not one of our declared $MODULES), and do nothing
+# otherwise.
+#
+check_module() {
+ local module="${1}"
+ has "${module}" $MODULES || \
+ die -q "Please choose one of the following modules: ${MODULES}"
+}
+
+## Actual actions
+
+# Perform the "list" action for the given SAPI.
+#
+# INPUT:
+#
+# The SAPI name.
+#
+# OUTPUT:
+#
+# A numbered and decorated list of targets for the given SAPI.
+#
+list_sapi() {
+ local sapi="${1}"
+ local targets=( $(find_sapi_targets "${sapi}") )
+ local active=$(get_sapi_active_target "${sapi}")
+
+ for (( i = 0; i < ${#targets[@]}; i++ )) ; do
+ if [[ $active == ${targets[i]} ]] ; then
+ targets[i]=$(highlight_marker "${targets[i]}")
+ fi
+ done
+ write_numbered_list -m "(none found)" "${targets[@]}"
+}
+
+
+# Perform the "set" action for the given SAPI.
+#
+# INPUT:
+#
+# The first parameter is the SAPI name, and the second parameter is
+# the desired target.
+#
+# OUTPUT:
+#
+# None.
+#
+set_sapi() {
+ local sapi="${1}"
+ local target="${2}"
+ local target_name=$(resolv_target "${sapi}" "${target}")
+ [[ -z $target_name ]] && die -q "invalid target ${target} for SAPI ${sapi}"
+
+ local link_tgt_dir=$(sapi_active_link_target_dir "${sapi}" "${target_name}")
+ local link_dir=$(sapi_active_link_dir "${sapi}")
+
+ for link_name in $(sapi_active_link_names "${sapi}"); do
+ local link_target=$(sapi_link_name_target "${sapi}" "${target_name}" "${link_name}")
+
+ @LN_S@ --force "${link_tgt_dir}/${link_target}" \
+ "${link_dir}/${link_name}" || \
+ die -q "failed to create active ${link_name} symlink"
+ done
+}
+
+
+# Check to see if the user is still using the old-style apache
+# configuration with -DPHP5 and 70_mod_php5.conf. If he is, warn him
+# that it is outdated, and that his eselect choices will not have any
+# effect until the configuration is updated.
+#
+# This can be removed after around a year.
+#
+apache2_php5_config_check() {
+ if [ -f "${EROOT}/etc/apache2/modules.d/70_mod_php5.conf" ] ; then
+ local msg
+ write_warning_msg "The apache2 configuration has changed in this"
+ write_warning_msg "version of eselect-php. You should define \"-D PHP\""
+ write_warning_msg "and not \"-D PHP5\" for apache. The module is now"
+ write_warning_msg "loaded by 70_mod_php.conf (was 70_mod_php5.conf)."
+ write_warning_msg "After you have changed \"-D PHP5\" to \"-D PHP\", "
+ write_warning_msg "you should remove 70_mod_php5.conf to eliminate"
+ write_warning_msg "this warning. Until you have done so, your eselect"
+ write_warning_msg "choices for apache2 will have no effect."
+ echo
+ fi
+}
+
+## set action
+
+describe_set() {
+ echo "Sets the current configuration for a module"
+}
+
+describe_set_parameters() {
+ echo "<module> <target>"
+}
+
+describe_set_options() {
+ echo "module: one of ${MODULES}"
+ echo "target: Target name or number (from the 'list' action)"
+}
+
+
+do_set() {
+ local sapi="${1}"
+ local target="${2}"
+ check_module "${sapi}"
+
+ set_sapi "${sapi}" "${target}"
+
+ if [[ "${sapi}" == "apache2" ]]; then
+ apache2_php5_config_check
+ write_mod_php_conf "$(resolv_target apache2 "${target}")"
+ echo "Please restart apache for the changes to take effect."
+ elif [[ "${sapi}" == "fpm" ]]; then
+ echo "Please restart php-fpm for the changes to take effect."
+ fi
+}
+
+
+
+## List action
+
+describe_list() {
+ echo "Lists available php installs for a module"
+}
+
+describe_list_parameters() {
+ echo "<module>"
+}
+
+describe_list_options() {
+ echo "module: one of ${MODULES}"
+}
+
+do_list() {
+ local sapi="${1}"
+ check_module "${sapi}"
+ list_sapi "${sapi}"
+}
+
+## Show action
+
+describe_show() {
+ echo "Lists available php installs for a module"
+}
+
+describe_show_parameters() {
+ echo "<module>"
+}
+
+describe_show_options() {
+ echo "module: one of ${MODULES}"
+}
+
+do_show() {
+ local sapi="${1}"
+ check_module "${sapi}"
+ get_sapi_active_target "${sapi}"
+}
+
+## update action
+
+describe_update() {
+ echo "Automatically update the php versions"
+}
+
+describe_update_parameters() {
+ echo "<module> [ifunset]"
+}
+
+describe_update_options() {
+ echo "module: one of ${MODULES}"
+ echo "ifunset : Do not override existing implementation"
+}
+
+do_update() {
+ local sapi="${1}"
+ check_module "${sapi}"
+ [[ -z ${2} || ( -z ${3} && ( ${2} == ifunset || ${2} == '--if-unset' ) ) ]] || \
+ die -q "Usage error"
+
+ if [[ (${2} == ifunset || ${2} == '--if-unset') && -n $(get_sapi_active_target "${sapi}") ]];
+ then
+ return
+ fi
+
+ update_sapi "${sapi}" || echo "Nothing to update"
+}
+
+## cleanup action
+
+describe_cleanup() {
+ echo "Automatically clean up stale links"
+}
+
+describe_cleanup_parameters() {
+ echo
+}
+
+describe_cleanup_options() {
+ echo
+}
+
+do_cleanup() {
+ cleanup_sapis
+}