#!/bin/sh

po_domain="alterator-hotstandby"
alterator_api_version=1

. alterator-sh-functions
. shell-config
. alterator-net-functions
. /etc/alterator/hotstandby/ahs.cfg

INITTAB=/etc/inittab
HOSTS_FILE=/etc/hosts
CSYNC2_CFGDIR=/etc/csync2
CSYNC2_CFG="$CSYNC2_CFGDIR/csync2.cfg"
CSYNC2_KEY="$CSYNC2_CFGDIR/csync2.key_alterator-hotstandby"
CSYNC2=/usr/sbin/csync2
CS2_SED_ADDR_REGEXP='/^[[:blank:]]*group alterator-hotstandby/,/^[[:blank:]]?}/'
HADIR=/etc/ha.d
HA_CF="$HADIR/ha.cf"
HA_AUTHKEYS="$HADIR/authkeys"
HARESOURCES="$HADIR/haresources"
SERVICE=/sbin/service
AHS_CONFIGDIR=/etc/alterator/hotstandby
CONFIG_LIST="$AHS_CONFIGDIR/config.list"
SERVICES_LIST="$AHS_CONFIGDIR/services.list"
AHS_CONFIG=/usr/lib/alterator-hotstandby/ahs_config
AHS_IFUPDOWN_EXTERNALS="$HADIR/resource.d/ahs_ifupdown_externals"
AHS_MENU="$HADIR/resource.d/ahs_menu"
AHS_RCDDIR=/var/lib/alterator-hotstandby/rc.d
AHS_BACKUPDIR=/var/lib/alterator-hotstandby/backup
AHS_EI_ORIGIN_BACKUPDIR="$AHS_BACKUPDIR/ext_ifaces_origin"
AHS_EI_RESERVE_BACKUPDIR="$AHS_BACKUPDIR/ext_ifaces_reserve"
AHS_CSYNC2_PERIODIC=/usr/lib/alterator-hotstandby/ahs_csync2_periodic
CHKCONFIG=/sbin/chkconfig
IPTABLES_HELPER=/usr/bin/iptables_helper
INCRONTAB_FILE=/var/spool/incron/root

CONFBUNDLE_CONF_START="ALTERATOR-HOTSTANDBY-BUNDLE-CONFIG-START:"
CONFBUNDLE_CONF_END="ALTERATOR-HOTSTANDBY-BUNDLE-CONFIG-END:"

###
list_mask()
{
    for i in `seq 32 -1 0`; do
        local mask="$(ipv4addr_prefix_to_mask "$i")"
        write_enum_item "$i" "/$i ($mask)"
    done
}

list_internal_ifaces()
{
    "$IPTABLES_HELPER" show -i 2>/dev/null
}

list_external_ifaces()
{
    "$IPTABLES_HELPER" show -e 2>/dev/null
}

list_ext_ifaces_config()
{
    local list=
    for i in $(list_external_ifaces); do
        local path="/etc/net/ifaces/$i"
        for file in "$path"/*; do
            list="$list${list:+ }$file"
        done
    done

    echo "$list"
}

read_ip()
{
    [ -n "$1" ] && netdev_read_ip "$1" | sed 1q | cut -f1 -d'/'
}

find_com_iface()
{
    local ip="$1"; shift
    local iface_addr=

    for i in $(list_iface); do
        iface_addr="$(netdev_read_ip "$i")"
        if [ -n "$iface_addr" ] && ipv4addr_is_in_subnet "$ip" "$iface_addr"; then
            echo "$i"
            return
        fi
    done
}

list_configs()
{
    cut -f1 -d'|' "$CONFIG_LIST"
}

list_backup_configs()
{
    list_configs | \
    grep -sv "^$HADIR" | \
    grep -sv "^$CSYNC2_CFGDIR" | \
    grep -sv "^$AHS_CONFIGDIR"
}

remove_configs()
{
    list_backup_configs | while read i; do
        if [ "${i##*/}" = '*' ]; then
            local path="${i%/*}"
            find "$path"/* -type f -exec rm {} \;
        else
            rm -f "$i"
        fi
    done
}

backup_configs()
{
    [ -n "$AHS_BACKUPDIR" ] || return 0
    rm -rf "$AHS_BACKUPDIR/$1"
    mkdir "$AHS_BACKUPDIR/$1"
    list_backup_configs | while read i; do
        if [ "${i##*/}" = '*' ]; then
            local path="${i%/*}"
            [ ! -d "$path" ] && continue
            mkdir -p "$AHS_BACKUPDIR/$1/${path%/*}" &&
            cp -a "$path" "$AHS_BACKUPDIR/$1/$path"
        elif [ -f "$i" ]; then
            mkdir -p "$AHS_BACKUPDIR/$1/${i%/*}" &&
            cp -a "$i" "$AHS_BACKUPDIR/$1/$i"
        fi
    done
}

restore_configs()
{
    list_backup_configs | while read i; do
        if [ "${i##*/}" = '*' ]; then
            local path="${i%/*}"
            [ ! -d "$AHS_BACKUPDIR/$1/$path" ] && continue
            cp -a "$AHS_BACKUPDIR/$1/$path"/* "$path"
        elif [ -f "$AHS_BACKUPDIR/$1/$i" ]; then
            cp -a "$AHS_BACKUPDIR/$1/$i" "$i"
        fi
    done
    [ -n "$AHS_BACKUPDIR" ] && rm -rf "$AHS_BACKUPDIR/$1"
}

backup_ext_ifaces()
{
    local list="$1"; shift
    local backupdir="$1/etc/net/ifaces"

    [ -n "$1" -a -n "$list" ] || return 1
    [ -d "$backupdir" ] || mkdir -p "$backupdir"
    for i in $list; do
        rm -rf "$backupdir/$i"
        [ -d "/etc/net/ifaces/$i" ] && mv "/etc/net/ifaces/$i" "$backupdir"
    done
}

restore_ext_ifaces()
{
    local backupdir="$1/etc/net/ifaces"

    [ -n "$1" ] || return 1
    for i in "$backupdir"/*; do
        local iface="${i##*/}"
        rm -rf "/etc/net/ifaces/$iface"
        mv "$backupdir/$iface" /etc/net/ifaces
    done
    rm -rf "$1"
}

read_ha_nodes()
{
    sed -n 's;^[[:blank:]]*node[[:blank:]]\+\([^#]\+\).*$;\1;p' "$HA_CF" 2>/dev/null
}

main_node()
{
    read_ha_nodes | sed -n 1p
}

reserve_node()
{
    read_ha_nodes | sed -n 2p
}

read_res_iface()
{
    local main_node="$1"

    [ -n "$main_node" ] || return
    sed -rn "s;^[[:blank:]]*$main_node[[:blank:]]+IPaddr2::[[:digit:].]+/[[:digit:]]{1,2}/([^[:blank:]]+).*$;\1;p" \
                "$HARESOURCES" 2>/dev/null
}

read_res_ip()
{
    local main_node="$1"
    [ -n "$main_node" ] || return
    sed -n "s;^[[:blank:]]*$main_node[[:blank:]]\+IPaddr2::\([[:digit:].]\+\).*$;\1;p" "$HARESOURCES" 2>/dev/null
}

read_node_role()
{
    local csync_node="$(sed -rn "$CS2_SED_ADDR_REGEXP s;^[[:blank:]]*host[[:blank:]]+([^[:blank:]]+).*$;\1;p" "$CSYNC2_CFG" 2>/dev/null)"
    local hb_node="$(main_node)"
    if [ -n "$csync_node" -a -n "$hb_node" -a "$csync_node" = "$hb_node" ]; then
        if [ "$hb_node" = "$(uname -n)" ]; then
            echo 'main'
        else
            echo 'reserve'
        fi
    else
        echo 'disabled'
    fi
}

read_node_status()
{
    local main="$(main_node)"
    local iface="$(read_res_iface "$main")"
    local ip="$(read_res_ip "$main")"

    if is_enabled && [ -n "$iface" -a -n "$ip" ]; then
        if netdev_read_ip "$iface" | cut -f1 -d'/' | grep -qs "$ip"; then
            echo 'main'
        else
            echo 'reserve'
        fi
    else
        echo 'disabled'
    fi
}

is_enabled()
{
    [ "$(runlevel | cut -f2 -d' ')" = "$rl_hotstandby" ]
}

resolve_host()
{
    [ -n "$1" ] && /usr/bin/resolve -s "$1"
}

get_other_node()
{
    local hname="$(uname -n)"

    [ -n "$hname" ] && read_ha_nodes | grep -vs "$hname"
}

read_config()
{
    local failback= res_iface= res_ip= res_netmsk= com_iface= other_node_hostname= other_node_ip=
    local keepalive= initdead= deadtime=
    local role= main_node=

    if is_enabled; then
        write_string_param state_enabled '#t'
    else
        write_string_param state_enabled '#f'
    fi
    main_node="$(main_node)"
    if is_enabled; then
        role="$(read_node_role)"
    else
        role='disabled'
    fi
    write_string_param node_role "$role"
    other_node_hostname="$(get_other_node)"
    [ -n "$other_node_hostname" ] && other_node_ip="$(resolve_host "$other_node_hostname")"
    write_string_param other_node_hostname "$other_node_hostname"
    write_string_param other_node_ip "$other_node_ip"

    failback="$(shell_config_get "$HA_CF" auto_failback ' ')"
    write_bool_param failback "${failback:-on}"
    keepalive="$(shell_config_get "$HA_CF" keepalive ' ')"
    write_string_param keepalive "${keepalive:-2}"
    initdead="$(shell_config_get "$HA_CF" initdead ' ')"
    write_string_param initdead "${initdead:-120}"
    deadtime="$(shell_config_get "$HA_CF" deadtime ' ')"
    write_string_param deadtime "${deadtime:-30}"
    res_iface="$(sed -rn "s;^[[:blank:]]*$main_node[[:blank:]]+IPaddr2::[[:digit:].]+/[[:digit:]]{1,2}/([^[:blank:]]+).*$;\1;p" "$HARESOURCES" 2>/dev/null)"
    [ -n "$res_iface" ] && write_string_param res_iface "$res_iface"
    res_ip="$(sed -n "s;^[[:blank:]]*$main_node[[:blank:]]\+IPaddr2::\([[:digit:].]\+\).*$;\1;p" "$HARESOURCES" 2>/dev/null)"
    [ -n "$res_ip" ] && write_string_param res_ip "$res_ip"
    res_netmask="$(sed -rn "s;^[[:blank:]]*$main_node[[:blank:]]+IPaddr2::[[:digit:].]+/([[:digit:]]{1,2}).*$;\1;p" "$HARESOURCES" 2>/dev/null)"
    write_string_param res_netmask "${res_netmask:-24}"
    com_iface="$(sed -n 's;^[[:blank:]]*ucast[[:blank:]]\+\([^[:blank:]]\+\).*$;\1;p' "$HA_CF" 2>/dev/null)"
    [ -n "$com_iface" ] && write_string_param com_iface "$com_iface"
}

read_config_bundle()
{
    local bundle="$(mktemp -t alterator-hotstandby.confbundleXXXXXXXX)"
    for f in $*; do
        if [ -f "$f" ]; then
            echo "${CONFBUNDLE_CONF_START}$f" >>"$bundle"
            case "$f" in
                "$HOSTS_FILE")             
                for node in $(read_ha_nodes); do
                    for ip in $(grep -sv '^127' "$HOSTS_FILE" | grep -s "$node" | cut -f1); do
                        printf "$ip\t$node\n" >>"$bundle"
                    done
                done
                ;;
                /etc/net/ifaces/*/options)
                if grep -qs '^ONBOOT' "$f"; then
                    sed "s/ONBOOT=y.*/ONBOOT=no/" "$f" >>"$bundle"
                else
                    cat "$f" >>"$bundle"
                    echo 'ONBOOT=no' >>"$bundle"
                fi
                ;;
                *)
                cat "$f" >>"$bundle"
                ;;
            esac
            echo "${CONFBUNDLE_CONF_END}$f" >>"$bundle"
        fi
    done
    echo "$bundle"
}

config_bundle_part()
{
    local bundle="$1"; shift
    local dest="$1"; shift

    sed -n "\|^${CONFBUNDLE_CONF_START}$dest|,\|^${CONFBUNDLE_CONF_END}$dest| { /^$CONFBUNDLE_CONF_START/b; /^$CONFBUNDLE_CONF_END/b; p }" "$bundle"
}

write_config_bundle()
{
    local bundle="$1"; shift
    local main_node_hostname= main_node_ip= com_iface=

    [ -f "$bundle" ] || return

    [ -d "$AHS_EI_RESERVE_BACKUPDIR" ] && rm -rf "$AHS_EI_RESERVE_BACKUPDIR"
    for i in $(sed -n "s;^$CONFBUNDLE_CONF_START\(.\+\)\$;\1;p" "$bundle"); do
        case "$i" in
            "$HOSTS_FILE")
            (IFS=$'\n'
            for h in $(config_bundle_part "$bundle" "$i"); do
                write_hosts_file "$(echo "$h" | cut -f1)" "$(echo "$h" | cut -f2)"
            done)
            ;;
            /etc/net/ifaces/*)
            local end="${i#/etc/net/ifaces/}"
            local iface="${end%/*}"
            mkdir -p "$AHS_EI_RESERVE_BACKUPDIR/etc/net/ifaces/$iface"
            config_bundle_part "$bundle" "$i" >"$AHS_EI_RESERVE_BACKUPDIR/etc/net/ifaces/$end"
            ;;
            *)
            config_bundle_part "$bundle" "$i" >"$i"
            ;;
        esac
    done

    [ -f "$HA_AUTHKEYS" ] && chmod 0600 "$HA_AUTHKEYS"
    [ -f "$CSYNC2_KEY" ] && chmod 0600 "$CSYNC2_KEY"

    main_node_hostname="$(main_node)"
    main_node_ip="$(resolve_host "$main_node_hostname")"
    com_iface="$(find_com_iface "$main_node_ip")"
    shell_config_set "$HA_CF" ucast "$com_iface $main_node_ip" ' ' ' '
}

check_csync2_cfg()
{
    if [ -f "$CSYNC2_CFG" ] && grep -qs '^[[:blank:]]*group alterator-hotstandby' "$CSYNC2_CFG"; then
        return 0
    else
        write_error "`_ "Suitable csync2.cfg not found!"`"
        return 1
    fi
}

read_csync2_configs_list()
{
    list_configs | while read i; do
        echo "     include $i;"
    done
}

read_csync2_actions_list()
{
    local list="$(grep -s '|' "$CONFIG_LIST")"

    [ -z "$list" ] && return

    local IFS=$'\n'
    for a in $list; do
        cat <<CSYNC2_ACTION_TEMPLATE

     action
     {
         pattern ${a%%|*};
         exec "${a##*|}";
     }
CSYNC2_ACTION_TEMPLATE
    done
}

reset_csync2_cfg()
{
    if check_csync2_cfg; then
        local tmp="$(mktemp -t csync2.cfgXXXXXXXX)"
        [ -n "$tmp" ] || return
        /bin/cp -f "$CSYNC2_CFG" "$tmp"
        sed -ir "$CS2_SED_ADDR_REGEXP { /^[[:blank:]]*include/d }" "$CSYNC2_CFG"
        "$CSYNC2" -R
        /bin/mv -f "$tmp" "$CSYNC2_CFG"
    fi
}

make_csync2_cfg()
{
    local main="$1"; shift
    local reserve="$1"; shift

    [ -n "$main" -a -n "$reserve" ] || return
    if [ -f "$CSYNC2_CFG" ] && grep -qs '^[[:blank:]]*group alterator-hotstandby' "$CSYNC2_CFG"; then
        sed -ir "$CS2_SED_ADDR_REGEXP d" "$CSYNC2_CFG"
    fi

    cat >>"$CSYNC2_CFG" <<CSYNC2_CFG_TEMPLATE
 group alterator-hotstandby
 {
     host $main ($reserve);
     key $CSYNC2_KEY;

CSYNC2_CFG_TEMPLATE

    read_csync2_configs_list >>"$CSYNC2_CFG"
    read_csync2_actions_list >>"$CSYNC2_CFG"
    echo ' }' >>"$CSYNC2_CFG"
}

check_csync2_key()
{
    if [ -f "$CSYNC2_KEY" ]; then
        return 0
    else
        write_error "`_ "csync2 key not found!"`"
        return 1
    fi
}

make_csync2_key()
{
    [ -f "$CSYNC2_KEY" ] || "$CSYNC2" --urandom -k "$CSYNC2_KEY"
}

check_ha_cf()
{
    if [ -f "$HA_CF" ]; then
        return 0
    else
        write_error "`_ "Suitable heartbeat config not found!"`"
        return 1
    fi
}

make_ha_cf()
{
    local main="$1"; shift
    local reserve="$1"; shift
    local reserve_ip="$1"; shift
    local com_iface="$1"; shift
    local failback="$1"; shift
    local keepalive="$1"; shift
    local initdead="$1"; shift
    local deadtime="$1"; shift

    if [ "$failback" = '#t' ]; then
        failback=on
    else
        failback=off
    fi
    printf "node $main\nnode $reserve\n" >"$HA_CF"
    shell_config_set "$HA_CF" udpport 694 ' ' ' '
    shell_config_set "$HA_CF" autojoin none ' ' ' '
    shell_config_set "$HA_CF" keepalive "$keepalive" ' ' ' '
    shell_config_set "$HA_CF" deadtime "$deadtime" ' ' ' '
    shell_config_set "$HA_CF" initdead "$initdead" ' ' ' '
    shell_config_set "$HA_CF" auto_failback "$failback" ' ' ' '
    shell_config_set "$HA_CF" ucast "$com_iface $reserve_ip" ' ' ' '
}

check_ha_authkeys()
{
    if [ -f "$HA_AUTHKEYS" ]; then
        return 0
    else
        write_error "`_ "Suitable heartbeat key not found!"`"
        return 1
    fi
}

make_ha_authkeys()
{
    local key=
    
    if [ ! -f "$HA_AUTHKEYS" ]; then
        key="$(dd if=/dev/urandom bs=512 count=1 status=noxfer 2>/dev/null | openssl md5)"
        cat >"$HA_AUTHKEYS" <<HA_AUTHKEYS_TEMPLATE
auth 1
1 sha1 $key
HA_AUTHKEYS_TEMPLATE
        /bin/chmod 0600 "$HA_AUTHKEYS"
    fi
}

check_haresource()
{
    if [ -f "$HARESOURCES" ]; then
        return 0
    else
        write_error "`_ "Suitable heartbeat resources not found!"`"
        return 1
    fi
}

make_haresource()
{
    local node="$1"; shift
    local ip="$1"; shift
    local prefix="$1"; shift
    local iface="$1"; shift

    echo "$node IPaddr2::$ip/$prefix/$iface ahs_menu ahs_ifupdown_externals ahs_csync2 ahs_services" >"$HARESOURCES"
}

write_hosts_file()
{
    local ip="$1"; shift
    local name="$1"; shift

    [ -n "$ip" -a -n "$name" ] || return
    if grep -qs "^$ip" "$HOSTS_FILE"; then
        if grep -s "^$ip" "$HOSTS_FILE" | grep -qsv "$name"; then
            sed -i "s/^$ip.*/& $name/" "$HOSTS_FILE"
        fi
    else
        printf "$ip\t$name\n" >>"$HOSTS_FILE"
    fi
}

make_incrontab()
{
    local cmd="$AHS_CSYNC2_PERIODIC start $csync2_period"

    list_configs | while read i; do
        if [ "${i##*/}" = '*' ]; then
            for d in $(find "${i%/*}" -type d); do
                printf "$d IN_MODIFY,IN_CREATE,IN_DELETE $cmd\n"
            done
        else
            printf "$i IN_MODIFY $cmd\n${i%/*} IN_CREATE,IN_DELETE $cmd\n"
        fi
    done | sort -u >"$INCRONTAB_FILE"
}

set_rl()
{
    local rl="$1"; shift

    [ -n "$rl" ] || return

    telinit "$rl"
    sed -i "s/id:[[:digit:]]:initdefault:/id:$rl:initdefault:/" "$INITTAB"
}

check_input()
{
    if [ -z "$in_res_iface" ]; then
        write_error "`_ "Service interface is not specified"`"
        return 1
    elif [ -z "$in_res_ip" ]; then
        write_error "`_ "Service IP address is not specified"`"
        return 1
    elif [ -z "$in_res_netmask" ]; then
        write_error "`_ "Service netmask is not specified"`"
        return 1
    elif [ -z "$in_com_iface" ]; then
        write_error "`_ "Administrative interface is not specified"`"
        return 1
    elif [ -z "$in_other_node_hostname" ]; then
        write_error "`_ "Hostname of another node is not specified"`"
        return 1
    elif [ -z "$in_other_node_ip" ]; then
        write_error "`_ "IP address of another node is not specified"`"
        return 1
    else
        return 0
    fi
}

# dhcpd config hook
dhcpd_set_dns()
{
    local dhcp_reset=/usr/bin/alterator-dhcp-reset
    local dhcp_generalconf_file=/etc/alterator/dhcp/general

    [ -n "$1" ] || return 1
    [ -x "$dhcp_reset" -a -s "$dhcp_generalconf_file" ] || return 0

    shell_config_set "$dhcp_generalconf_file" client_dns "$1"
    $dhcp_reset && $SERVICE dhcpd condreload
}
#

start_ahs()
{
    check_csync2_key || return
    check_csync2_cfg || return
    check_ha_cf || return
    check_ha_authkeys || return
    check_haresource || return

    if is_enabled; then
        "$SERVICE" heartbeat reload >/dev/null 2>&1
    else
        reset_csync2_cfg
        set_rl "$rl_hotstandby"
    fi
}

stop_ahs()
{
    if is_enabled; then
        "$SERVICE" heartbeat stop >/dev/null 2>&1
        "$AHS_IFUPDOWN_EXTERNALS" start
        "$AHS_MENU" start
        set_rl "$rl_normal"
    fi
}

on_message()
{
    local iface_ip=
    case "$in_action" in
        type)
        write_type_item keepalive ahs-digit
        write_type_item deadtime ahs-digit
        write_type_item initdead ahs-digit
        write_type_item res_ip ipv4-address
        write_type_item other_node_hostname hostname
        write_type_item other_node_ip ipv4-address
        ;;
        read)
        case "$in__objects" in
            /)
            read_config
            ;;
            confbundle)
            make_csync2_key || return
            check_csync2_cfg || return
            check_ha_cf || return
            check_ha_authkeys || return
            check_haresource || return
            local bundle="$(read_config_bundle /etc/hosts "$CSYNC2_KEY" "$CSYNC2_CFG" \
                                               "$HA_CF" "$HA_AUTHKEYS" "$HARESOURCES" \
                                               $(list_ext_ifaces_config))"
            write_blob_param confbundle "$bundle"
            /bin/rm -f "$bundle"
            ;;
        esac
        ;;
        write)
        case "$in__objects" in
            /)
            case "$in_node_role" in
                main)
                check_input || return
                iface_ip="$(read_ip "$in_com_iface")"
                local host_name="$(uname -n)"
                if [ -z "$iface_ip" ]; then
                    write_error "`_ "Administrative interface has no IP address"`"
                    return
                elif [ -z "$host_name" ]; then
                    write_error "`_ "Unable to determine hostname"`"
                    return
                else
                    write_hosts_file "$iface_ip" "$host_name"
                fi
                write_hosts_file "$in_other_node_ip" "$in_other_node_hostname"
                make_csync2_cfg "$host_name" "$in_other_node_hostname"
                make_csync2_key
                if [ "$in_deadtime" -gt "$in_initdead" ]; then
                    write_error "`_ "Death detection time greater then initial deadtime"`"
                    return
                fi
                make_ha_cf "$host_name" "$in_other_node_hostname" "$in_other_node_ip" "$in_com_iface" "$in_failback" \
                           "$in_keepalive" "$in_initdead" "$in_deadtime"
                make_ha_authkeys
                make_haresource "$host_name" "$in_res_ip" "$in_res_netmask" "$in_res_iface"
                make_incrontab
                "$AHS_MENU" start
                dhcpd_set_dns "$in_res_ip"
                start_ahs
                ;;
                reserve)
                if ! is_enabled; then
                    "$AHS_IFUPDOWN_EXTERNALS" stop
                    "$AHS_MENU" stop
                    backup_configs origin &&
                    remove_configs
                    restore_configs reserve
                    backup_ext_ifaces "$(ls "$AHS_EI_RESERVE_BACKUPDIR"/etc/net/ifaces)" "$AHS_EI_ORIGIN_BACKUPDIR"
                    restore_ext_ifaces "$AHS_EI_RESERVE_BACKUPDIR"
                fi
                start_ahs
                ;;
                disabled)
                if is_enabled && [ "$(read_node_role)" = 'reserve' ]; then
                    backup_configs reserve
                    remove_configs
                    restore_configs origin
                    backup_ext_ifaces "$(list_external_ifaces)" "$AHS_EI_RESERVE_BACKUPDIR"
                    restore_ext_ifaces "$AHS_EI_ORIGIN_BACKUPDIR"
                fi
                dhcpd_set_dns '*'
                stop_ahs
                ;;
            esac
            ;;
            confbundle)
            write_config_bundle "$in_confbundle"
            ;;
        esac
        ;;
        list)
        case "${in__objects##*/}" in
            avail_ifaces)
            for iface in $(list_internal_ifaces); do
                iface_ip="$(read_ip "$iface")"
                write_enum_item "$iface" "$iface${iface_ip:+ - }$iface_ip"
            done
            ;;
            avail_netmasks) list_mask
            ;;
        esac
        ;;
    esac
}

message_loop

