#!/bin/ksh

#========================================
# chnetconf - change network configuration
#             with dirs under netconfs
#
# Yoshihiro Kawamata, kaw@on.rim.or.jp
# $Id: chnetconf,v 1.20 2025/01/01 00:58:54 kaw Exp $
#========================================

# Copyright (c) 2021--2025
# Yoshihiro Kawamata
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#   * Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#
#   * Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in
#     the documentation and/or other materials provided with the
#     distribution.
#
#   * Neither the name of Yoshihiro Kawamata nor the names of its
#     contributors may be used to endorse or promote products derived
#     from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# print usage
#
usage () {
    cat <<EOT

$PROGNAME: change network configuration
Usage: $PROGNAME [options] [config_name]
Syntax:
  [config_name]     : symlink myname and copy other files
                      from /etc/netconf/config_name to /etc
                      then perform "sh /etc/netstart"
                      reconfig current setting unless config_name specified
  -d [config_name]  : don't perform /etc/netstart, symlink and copy only
  -f [config_name]  : force reconfig for config_name
                      even if current config files don't exist in /etc
  -r                : reset or destroy all network interfaces
  -p                : print current config_name
  -l                : print list of configs
  -h                : print this help
EOT
}

# reset all network interfaces
#
resetif () {
    for if in `ifconfig -a | egrep '^[a-z]' | cut -d: -f1`; do
        case "$if" in
            lo[0-9]*|enc[0-9]*|pflog[0-9]*)
                # make this if untouched
                ;;
            *)
                ifconfig $if down
                ifconfig $if -inet -inet6
                if ! ifconfig $if destroy 2>/dev/null; then
                    # physical device ... can't destroy
                    ifconfig $if | grep -q '^	groups: wlan' && ifconfig $if -nwid -nwkey -wpakey
                fi
                ;;
        esac
    done >/dev/null 2>&1
}

printconfig() {
    local file=$(stat -f %Y /etc/myname)
    file=${file#"${confdir}/"}
    file=${file%/myname}
    [[ -n "$file" ]] && echo $file
}

listconfig() {
    local path
    local defconf=${confdir}/$(printconfig)
    local defmark

    for path in $(ls -1d ${confdir}/*); do
        defmark=' '
        [[ "$path" = "$defconf" ]] && defmark='*'
        if [[ -e "$path/myname" ]]; then
            printf "%1s%-10s " "$defmark" ${path#"${confdir}/"}
            [[ -r "$path/description" ]] && echo -n $(<$path/description)
            echo
        fi
    done
}


#=====================
# main runs from here
#=====================

PROGNAME="${0##*/}"

# for fail-safe
#
cd /etc || exit

# system-wide constants
#
confdir=/etc/fuguita/netconfs

# parsing command line options
#
cmd=normal
cmds=0
force_config=no
maxargs=1
while getopts dfrplh OPT; do
    case "$OPT" in
        d) cmd=dont_netstart; cmds=$((cmds+1)) ;;
        f) force_config=yes ;;
        r) cmd=reset_allnic;  cmds=$((cmds+1)) ;;
        p) cmd=print_config;  cmds=$((cmds+1)) ;;
        l) cmd=list_config;   cmds=$((cmds+1)) ;;
        h) usage; exit;;
        *) usage; exit 1;;
    esac
    case "$OPT" in
        d|f)   maxargs=1;;
        r|p|l) maxargs=0;;
    esac
done
shift $((OPTIND-1))

# check options/arguments
#
if [[ 1 < $cmds ]]; then
    echo "$PROGNAME: -d, -r, -p, or -l is mutually exclusive"
    usage
    exit 1
elif [[ $force_config = yes && 1 < $# ]]; then
    echo "$PROGNAME: requires one argument"
    usage
    exit 1
elif [[ $maxargs < $# ]]; then
    echo "$PROGNAME: too much arguments - $*"
    usage
    exit 1
fi

# perform -r, -p or -l
#
case "$cmd" in
    'reset_allinc') resetif; exit;;
    'print_config') printconfig; exit;;
    'list_config')  listconfig; exit;;
esac

# this is "config_name"
#
if [[ -z "$1" ]]; then
    newconf=$(printconfig)
else
    newconf="$1"
fi

# extra argument exists
#
if [[ "$newconf" = 'templ.head' || "$newconf" = 'templ.tail' ]]; then
    echo "$PROGNAME: You cannot change to '$newconf'"
    exit
elif [ ! -f "${confdir}/${newconf}/myname" ]; then
    echo "$PROGNAME: no such conf - $newconf"
    exit
fi

# start of reconfiguration

# remove current files in /etc
#
if [[ -L /etc/myname ]]; then
    curconf=$(stat -f %Y /etc/myname)
    curconf=${curconf%/*}
    if [[ -n "$curconf" ]] && cd "$curconf"; then
        for f in *; do
            rm -f "/etc/$f"
        done
    elif [[ ! $cmd = 'force_config' ]]; then
        exit 1
    fi
fi

# check sprious hostname.if files
#
set -- /etc/hostname.*
if [[ -e "$1" ]]; then
    echo "$PROGNAME: warning: extra hostname.if(s) found: $*"
    echo "Remove them manually if not needed."
fi


# collect file names to put into /etc
#
putfiles=$(ls -1d $confdir/{templ.{head,tail},$newconf}/* 2>/dev/null | sed -e 's/.*\///' | sort | uniq)

# link myname and copy other files to /etc
#
cd $confdir/$newconf || exit 1
for f in $putfiles; do
    case "$f" in
        'description')
            :  # do nothing
            ;;
        'myname')
            ln -sf $confdir/$newconf/myname /etc/myname
            ;;
        *)
            [[ -e "$f" ]] && cp -p "$f" /etc  # create a file with the same attribute
            : > "/etc/$f"                     # and make it empty

            # write the setting value with
            # concatenating head/tail template (if any)
            cat "${confdir}/templ.head/$f" \
                "$f" \
                "${confdir}/templ.tail/$f" >> "/etc/$f" 2>/dev/null
            ;;
    esac
done

# perform -d option
#
if [[ $cmd = 'dont_netstart' ]]; then
    exit
fi

# starting network by new configuration
#
resetif
hostname $(</etc/myname)
sh /etc/netstart
