commit:     4fd0650ed9ef4cec5477038fcfb2e59db2cf2b93
Author:     Patrick McLean <patrick.mclean <AT> sony <DOT> com>
AuthorDate: Sat May  9 02:21:40 2020 +0000
Commit:     Patrick McLean <chutzpah <AT> gentoo <DOT> org>
CommitDate: Sat May  9 02:22:21 2020 +0000
URL:        https://gitweb.gentoo.org/proj/eselect.git/commit/?id=4fd0650e

modules/iptables.eselect: Complete rewrite, solve issues in bug #721578

Signed-off-by: Patrick McLean <patrick.mclean <AT> sony.com>

 modules/iptables.eselect | 320 +++++++++++++++++++++++++++++++----------------
 1 file changed, 214 insertions(+), 106 deletions(-)

diff --git a/modules/iptables.eselect b/modules/iptables.eselect
index f94b25c..e3e5906 100644
--- a/modules/iptables.eselect
+++ b/modules/iptables.eselect
@@ -2,43 +2,128 @@
 # Copyright 2005-2020 Gentoo Authors
 # Distributed under the terms of the GNU GPL version 2 or later
 
-DESCRIPTION="Manage the iptables and ip6tables symlink"
-AUTHOR="ch...@christopherpritchard.co.uk"
+inherit package-manager
+
+DESCRIPTION="Manage the iptables/arptables/ebtables symlinks"
 MAINTAINER="base-sys...@gentoo.org"
-VERSION="20200319"
+VERSION="20200508"
+
+# a simple list of symlinks does for iptables
+IPTABLES_SYMLINKS=(
+       "iptables-xml"
+       "iptables" "iptables-restore" "iptables-save"
+)
+IP6TABLES_SYMLINKS=(
+       "ip6tables" "ip6tables-restore" "ip6tables-save"
+)
+
+# for arptables and ebtables we map names to legacy targets
+ARPTABLES_TARGETS=(
+       "arptables-legacy"
+       "xtables-nft-multi"
+)
+declare -A ARPTABLES_SYMLINKS=(
+       [arptables]="arptables-legacy"
+       [arptables-restore]="arptables-legacy-restore"
+       [arptables-save]="arptables-legacy-save"
+)
+
+EBTABLES_TARGETS=(
+       "ebtables-legacy"
+       "xtables-nft-multi"
+)
+declare -A EBTABLES_SYMLINKS=(
+       [ebtables]="ebtables-legacy"
+       [ebtables-restore]="ebtables-legacy-restore"
+       [ebtables-save]="ebtables-legacy-save"
+)
 
-IPTABLES_TARGETS=("iptables" "iptables-restore" "iptables-save")
-IP6TABLES_TARGETS=("ip6tables" "ip6tables-restore" "ip6tables-save")
+# get which module is running
+get_module() {
+       local module
+       module="${BASH_SOURCE[0]##*/}"
 
-# find a list of xtables symlink targets
+       printf -- '%s\n' "${module%.eselect}"
+}
+
+# find a list of symlink targets for the current module
 find_targets() {
-       local f
-       for f in "${EROOT}"/sbin/xtables-*-multi; do
-               [[ -f ${f} ]] && basename "${f}"
-       done
+       local module target
+
+       module="$(get_module)"
+       case "${module}" in
+               iptables)
+                       for target in "${EROOT}"/sbin/xtables-*-multi; do
+                               [[ -x ${target} ]] && printf -- '%s\n' 
"${target##*/}"
+                       done
+               ;;
+               arptables)
+                       for target in "${ARPTABLES_TARGETS[@]}"; do
+                               [[ -x ${EROOT}/sbin/${target} ]] && printf -- 
'%s\n' "${target}"
+                       done
+               ;;
+               ebtables)
+                       for target in "${EBTABLES_TARGETS[@]}"; do
+                               [[ -x ${EROOT}/sbin/${target} ]] && printf -- 
'%s\n' "${target}"
+                       done
+               ;;
+               *) die "Invalid module name ${module}"
+       esac
 }
 
-# remove the iptables symlink
-remove_symlinks() {
-       local ipt
-       for ipt in "${IPTABLES_TARGETS[@]}"; do
-               rm -f "${EROOT}/sbin/${ipt}" &>/dev/null
-       done
-       if [[ -n ${ipv6} && -n ${ipv6_remove} ]]; then
-               local ip6t
-               for ip6t in "${IP6TABLES_TARGETS[@]}"; do
-                       rm -f "${EROOT}/sbin/${ip6t}" &>/dev/null
-               done
-       fi
+# get the list of symlinks for the current module
+get_symlinks_list() {
+       local module
+       module="$(get_module)"
+
+       case "${module}" in
+               iptables)
+                       printf -- '%s\n' "${IPTABLES_SYMLINKS[@]}"
+
+                       if [[ ${1} == -a ]] || has_version 
'net-firewall/iptables[ipv6]'
+                       then
+                               printf -- '%s\n' "${IP6TABLES_SYMLINKS[@]}"
+                       fi
+               ;;
+               arptables) printf -- '%s\n' "${!ARPTABLES_SYMLINKS[@]}";;
+               ebtables) printf -- '%s\n' "${!EBTABLES_SYMLINKS[@]}";;
+               *) die "Invalid module name ${module}"
+       esac
+}
+
+# get the symlink target given a symlink name and the target implementation
+get_symlink_target() { 
+       local link="${1}" target="${2}" module
+       module="$(get_module)"
+
+       case "${module}" in
+               iptables) printf -- '%s\n' "${target}";;
+               arptables)
+                       if [[ ${target} == *-legacy ]]; then
+                               printf -- '%s\n' 
"${ARPTABLES_SYMLINKS[${link}]}"
+                       else
+                               printf -- '%s\n' "${target}"
+                       fi
+               ;;
+               ebtables)
+                       if [[ ${target} == *-legacy ]]; then
+                               printf -- '%s\n' "${EBTABLES_SYMLINKS[${link}]}"
+                       else
+                               printf -- '%s\n' "${target}"
+                       fi
+               ;;
+               *) die "Invalid module name ${module}"
+       esac
 }
 
-# set the iptables symlink
+# set the symlinks for the current target
 set_symlinks() {
        local target="${1}"
+       local retval=0
 
        if is_number "${target}" && [[ ${target} -ge 1 ]]; then
                local -a targets
-               readarray -t targets <<< "$(find_targets)"
+               readarray -t targets < <(find_targets)
                target=${targets[$((target-1))]}
        fi
 
@@ -46,130 +131,153 @@ set_symlinks() {
                die -q "Target \"${target}\" doesn't appear to be valid!"
        fi
 
-       local ipt
-       for ipt in "${IPTABLES_TARGETS[@]}"; do
-         ln -s "${target}" "${EROOT}/sbin/${ipt}"
-       done
+       # create an array of symlinks to be created, then create them
+       # in a separate pass, it's done this way in an attempt to be atomic
+       # either all symlinks get updated, or none
+       local -a symlinks_list
+       readarray -t symlinks_list < <(get_symlinks_list)
+
+       local symlink
+       local -A do_symlinks
+       for symlink in "${symlinks_list[@]}"; do
+               local symlink_path="${EROOT}/sbin/${symlink}"
+
+               if [[ -L ${symlink_path} || ! -e ${symlink_path} ]]; then
+                       do_symlinks["${symlink_path}"]="$(get_symlink_target 
"${symlink}" "${target}")"
        
-       if [[ -n ${ipv6} ]]; then
-               local ip6t
-               for ip6t in "${IP6TABLES_TARGETS[@]}"; do
-                       ln -s "${target}" "${EROOT}/sbin/${ip6t}"
-               done
-       fi
+               else
+                       die -q "Could not create symlink at ${symlink_path}:" \
+                               "path exits and is not a symlink"
+               fi
+       done
+
+       for symlink in "${!do_symlinks[@]}"; do
+               if ! ln -sfn "${do_symlinks["${symlink}"]}" "${symlink}"; then
+                       write_error_message "Failed to create symlink at 
${symlink}"
+                       retval=1
+               fi
+       done
+
+       return "${retval}"
 }
 
 ### show action ###
 
 describe_show() {
-       echo "Show the current iptables symlink"
+       printf -- 'Show the current %s symlink\n' "$(get_module)"
 }
 
 do_show() {
-       local ipv6
-       if [[ -d ${EROOT}/var/lib/ip6tables ]]; then
-               ipv6=1
-       fi
-       write_list_start "Current iptables symlinks:"
-       local ipt all_unset=1
-       for ipt in "${IPTABLES_TARGETS[@]}"; do
-               if [[ -L ${EROOT}/sbin/${ipt} ]]; then
-                       local ipta
-                       ipta=$(canonicalise "${EROOT}/sbin/${ipt}")
-                       write_kv_list_entry "${ipt}" "${ipta%/}"
+       local -a symlinks_list
+       readarray -t symlinks_list < <(get_symlinks_list)
+
+       local all_unset=1 symlink
+       write_list_start "Current $(get_module) symlinks:"
+       for symlink in "${symlinks_list[@]}"; do
+               symlink_path="${EROOT}/sbin/${symlink}"
+
+               if [[ -L ${symlink_path} ]]; then
+                       local symlink_target
+                       symlink_target=$(canonicalise "${symlink_path}")
+                       write_kv_list_entry "${symlink}" "${symlink_target%/}"
                        all_unset=0
-               else
-                       write_kv_list_entry "${ipt}" "(unset)"
+               elif [[ ! -f ${symlink_path} ]]; then
+                       write_kv_list_entry "${symlink}" "(unset)"
          fi
        done
-       if [[ ${ipv6} -eq 1 ]]; then
-               write_list_start "Current ip6tables symlinks:"
-               local ip6t
-               for ip6t in "${IP6TABLES_TARGETS[@]}"; do
-                       if [[ -L ${EROOT}/sbin/${ip6t} ]]; then
-                               local ipta
-                               ipta=$(canonicalise "${EROOT}/sbin/${ip6t}")
-                               write_kv_list_entry "${ip6t}" "${ipta%/}"
-                               all_unset=0
-                       else
-                               write_kv_list_entry "${ip6t}" "(unset)"
-                       fi
-               done
-       fi
+
        return "${all_unset}"
 }
 ### list action ###
 
 describe_list() {
-       echo "List available iptables symlink targets"
+       printf -- 'List available %s symlink targets\n' "$(get_module)"
 }
 
 do_list() {
-       local ipv6
-       local -a targets
-       readarray -t targets <<< "$(find_targets)"
-       if [[ -L ${EROOT}/var/lib/ip6tables ]]; then
-               ipv6=1
-       fi
-       write_list_start "Available iptables symlink targets:"
-       local i
-       for (( i = 0; i < ${#targets[@]}; i++ )); do
-               # highlight the target where the symlink is pointing to
-               [[ ${targets[i]} = \
-                       $(basename "$(canonicalise "${EROOT}/sbin/iptables")") 
]] \
-                       && targets[i]=$(highlight_marker "${targets[i]}")
+       local module
+       module="$(get_module)"
+
+       local -a targets_list symlinks_list
+       readarray -t targets_list < <(find_targets)
+       readarray -t symlinks_list < <(get_symlinks_list)
+
+       local -a targets_output
+
+       write_list_start "Available ${module} symlink targets:"
+       local symlink current_target
+       for symlink in "${symlinks_list[@]}"; do
+               local symlink_path="${EROOT}/sbin/${symlink}"
+               local target
+               for target in "${targets_list[@]}"; do
+                       local symlink_target resolved_target
+                       symlink_target="$(get_symlink_target "${symlink}" 
"${target}")"
+                       resolved_target="$(basename "$(canonicalise 
"${symlink_path}")")"
+
+                       if [[ ${resolved_target} == "${symlink_target}" ]]; then
+                               if [[ -z ${current_target} ]]; then
+                                       current_target="${target}"
+                                       break
+                               elif [[ ${current_target} != "${target}" ]]; 
then
+                                       write_warning_msg "Target mismatch"
+                                       unset current_target
+                                       break 2
+                               fi
+                       fi
+               done
+       done
+       for target in "${targets_list[@]}"; do
+               if [[ ${target} == "${current_target}" ]]; then
+                       targets_output+=("$(highlight_marker "${target}")")
+               else
+                       targets_output+=("${target}")
+               fi
        done
-       write_numbered_list -m "(none found)" "${targets[@]}"
+
+       write_numbered_list -m "(none found)" "${targets_output[@]}"
 }
 
 ### set action ###
 
 describe_set() {
-       echo "Set a new iptables symlink target"
-}
-
-describe_set_parameters() {
-       echo "[--ipv6] <target>"
+       printf "Set a new $(get_module) symlink target\\n"
 }
 
 describe_set_options() {
-       echo "--ipv6: Forces creation of ip6tables symlinks"
-       echo "target : Target name or number (from 'list' action)"
+       printf -- "target : Target name or number (from 'list' action)\\n"
 }
 
 do_set() {
-       local ipv6 ipv6_remove
-       if [[ ${1} == "--ipv6" ]]; then
-               ipv6=1
-               shift
-       fi
        local target="${1}"
 
        [[ -z ${target} ]] && die -q "You didn't tell me what to set the 
symlink to"
-       [[ ${#} -gt 2 ]] && die -q "Too many parameters"
+       [[ ${#} -gt 1 ]] && die -q "Too many parameters"
 
-       if [[ -d ${EROOT}/var/lib/ip6tables ]]; then
-               ipv6=1
-               [[ -L ${EROOT}/sbin/ip6tables ]] && ipv6_remove=1
-       fi
-       if [[ -L ${EROOT}/sbin/iptables ]]; then
-               # existing symlink
-               remove_symlinks || die -q "Couldn't remove existing symlink"
-               set_symlinks "${target}" || die -q "Couldn't set a new symlink"
-       elif [[ -e ${EROOT}/sbin/iptables ]]; then
-               # we have something strange
-               die -q "${EROOT}/sbin/iptables exists but is not a symlink"
-       else
-               set_symlinks "${target}" || die -q "Couldn't set a new symlink"
-       fi
+       set_symlinks "${target}" || die -q "Couldn't set symlinks"
 }
 
 ### unset action ###
 
 describe_unset() {
-       echo "Unset iptables symlink targets"
+       printf -- 'Unset %s symlink targets\n' "$(get_module)"
 }
 
 do_unset() {
-       remove_symlinks
+       local retval=0
+
+       local -a symlinks_list
+       readarray -t symlinks_list < <(get_symlinks_list -a)
+
+       local symlink
+       for symlink in "${symlinks_list[@]}"; do
+               local symlink_path="${EROOT}/sbin/${symlink}"
+               if [[ -L ${symlink_path} ]]; then
+                       unlink "${symlink_path}" || retval=${?}
+               elif [[ -e ${symlink_path} ]]; then
+                       write_error_msg "Not removing non-symlink 
\"${symlink_path}\""
+                       retval=1
+               fi
+       done
+
+       return ${retval}
 }

Reply via email to