ACC SHELL

Path : /proc/self/root/sbin/
File Upload :
Current File : //proc/self/root/sbin/netconfig

#!/bin/bash
#
# Copyright (c) 2008 SUSE LINUX Products GmbH, Nuernberg, Germany.
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place, Suite 330, Boston, MA 02111-1307 USA
#
# Author: Michael Calmer <mc@suse.de>
#         Marius Tomaschewski <mt@suse.de>
#

#
# Exit codes
#
# 0  success
# 1  error
# 20 a module was not able to change the configuration
#    because it was changed since the last run
#

unset POSIXLY_CORRECT ; set +o posix # we're using non-posix bash features

# The environment variable ROOT indicates the root of the system to be
# managed by SuSEconfig when that root is not '/'
r=$ROOT

. $r/etc/sysconfig/network/scripts/functions.netconfig

PROGNAME=${0##*/}
STATEDIR=$r/var/run/netconfig/

MODULEDIR=$r/etc/netconfig.d/

. $r/etc/sysconfig/network/config

INPUTFORMAT=dhcpcd

function modify() {
    if [ "x$SERVICE" = "x" ]; then
        warn "No service informations available"
        unLock "$PROGNAME"
        exit 1
    fi

    if test "x${LEASEFILE}" != x -a ! -r "${LEASEFILE}" ; then
        echo "Unable to read specified input file '${LEASEFILE}'" >&2
        exit 1
    fi

    local a b
    IFS=. read a b < /proc/uptime
    local CREATETIME=$a
    local _INTERFACE='' _SERVICE=''
    local -a KEYS VALS

    if [ "$INPUTFORMAT" == "dhcpcd" ]; then
        local key val err=0
        # add CREATETIME at index 0 !!
        KEYS=('CREATETIME'  'SERVICE')
        VALS=("$CREATETIME" "$SERVICE")
        while IFS== read -sr key val ; do
            test -n "$key" || {
                test -n "$val" || continue
                err=$val ; break
            }
            case $key in
                (CREATETIME) continue ;;
                (SERVICE|INTERFACE)
                    eval "_$key='$val'"
                    if test "x${!key}" != x -a "x${!key}" != "x$val" ; then
                        echo "Input value $key conflicts with command line argument" >&1
                        exit 1
                    fi
                ;;
            esac
            for k in ${KEYS[@]} ; do
                test "x$k" = "x$key" && continue 2
            done
            KEYS[${#KEYS[@]}]=$key
            VALS[${#VALS[@]}]=$val
        done < <(netconfig_kv_filter ${LEASEFILE:+"$LEASEFILE"})
        if test $err -ne 0 ; then
            echo "Invalid syntax in ${LEASEFILE:+${LEASEFILE}, }line $err" >&2
            exit 1
        fi
    else
	echo "Unsupported lease file / input format '$INPUTFORMAT'" >&2
	exit 1
    fi

    # NetworkManager policy merged settings
    if [ "x$SERVICE"        = "xNetworkManager" -a \
         "x$INTERFACE"      = "x" ] ;
    then
        # NetworkManager policy merged config
        CFGFILE="$STATEDIR/NetworkManager.netconfig"

        # first get the createtime. we want to keep it.
	get_variable CREATETIME "$CFGFILE"
	KEYS[0]='CREATETIME'
	VALS[0]="$CREATETIME"

        # remove it also in modify.
        # We want to create it with the same name again.
	rm -f "$CFGFILE"
    else
	# use interface name from config if provided
	if [ "x$INTERFACE" = "x" -a "x$_INTERFACE" != "x" ]; then
	     INTERFACE="$_INTERFACE"
        fi

	if [ "x$INTERFACE" = "x" ]; then
            warn "No interface informations available"
            unLock "$PROGNAME"
            exit 1
	fi

        if [ ! -d "$STATEDIR/$INTERFACE" ]; then
		mkdir -p "$STATEDIR/$INTERFACE" || {
			warn "Can not create interface state dir"
			unLock "$PROGNAME"
			exit 1
		}
	fi

        local CFGFILE=`find_cfgfile "$INTERFACE" "$SERVICE"`
        if [ "x$CFGFILE" != "x" ]; then
            # first get the createtime. we want to keep it.
            get_variable CREATETIME "$CFGFILE"
            KEYS[0]='CREATETIME'
            VALS[0]="$CREATETIME"

            # remove it also in modify. 
            # We want to create it with the same name again.
            rm -f "$CFGFILE"
        fi
    
        if [ "x$CFGFILE" = "x" ]; then
            local CFGNAME=`get_new_cfgname`
            CFGFILE="$STATEDIR/$INTERFACE/$CFGNAME"
        fi
   fi

   debug "write new STATE file $CFGFILE"
   for((i=0; i<${#KEYS[@]} && i<${#VALS[@]}; i++)) ; do
       printf "%s='%s'\n" "${KEYS[$i]}" "${VALS[$i]}"
   done > "$CFGFILE"

   return 0
}

function remove() {
    if [ "x$SERVICE" = "x" ]; then
        warn "No service informations available"
        unLock "$PROGNAME"
        exit 1
    fi

    # NetworkManager policy merged settings
    if [ "x$SERVICE"        = "xNetworkManager" -a \
         "x$INTERFACE"      = "x" ] ;
    then
        # NetworkManager policy merged config
        CFGFILE="$STATEDIR/NetworkManager.netconfig"

    else
	if [ "x$INTERFACE" = "x" ]; then
            warn "No interface informations available"
            unLock "$PROGNAME"
            exit 1
        fi

        CFGFILE=`find_cfgfile "$INTERFACE" "$SERVICE"`
    fi

    if [ "x$CFGFILE" != "x" ]; then
        debug "remove STATE file $CFGFILE"
        rm -f "$CFGFILE"
    fi

    return 0
}

#
# find_cfgfile <interface> <service>
#
function find_cfgfile() {

    test -z "$1" && return 1
    test -z "$2" && return 1

    local INTERFACE=$1
    local CUR_SERVICE=$2

    for CFG in `ls -X $STATEDIR/$INTERFACE/`; do
        get_variable "SERVICE" $STATEDIR/$INTERFACE/$CFG
            
        if [ "$CUR_SERVICE" = "$SERVICE" ]; then
                CFGNAME=$CFG
                echo "$STATEDIR/$INTERFACE/$CFG"
                return;
        fi
    done
    return 0;
}

function get_new_cfgname() {
    local CFGNAME=""

    for CFG in `ls -X -r $STATEDIR/$INTERFACE/`; do
        CNT=`echo "$CFG" | sed 's/netconfig//'`
        ((CNT++))
        CFGNAME="netconfig$CNT"
        break
    done
    
    if [ "x$CFGNAME" = "x" ]; then
        CFGNAME="netconfig0"
    fi
    echo $CFGNAME;
}

function run_modules() {
    local mfilter="$1"
    local errors=()
    local msg=""
    local ret=0 err=0

    if [ -n "$FORCE_REPLACE" ]; then
        export FORCE_REPLACE=$FORCE_REPLACE
    fi
    if [ -n "$r" ]; then
        export ROOT=$r
    fi

    debug "Module order: $NETCONFIG_MODULES_ORDER"
    for plg in $NETCONFIG_MODULES_ORDER; do
        case $plg in
            -*)
                debug "${plg:1} module is disabled" ;
                continue
            ;;
        esac
        if [ ! -x "$MODULEDIR/$plg" ]; then
            debug "$plg module is not executable"
            continue
        fi
        case "x$mfilter" in
            "x"|"x${plg}"|"x${plg%%-*}")   ;;
            *) debug "$plg module skipped" ;
               continue                    ;;
        esac

        msg=`"$MODULEDIR/$plg" 2>&1` ; ret=$?
        if [ "$ret" != "0" -a "$err" = "0" ]; then
            err=$ret
        fi
        if [ "x$msg" != x ]; then
            errors[${#errors[@]}]="$msg"
        fi
    done

    if [ ${#errors[@]} -gt 0 ]; then
        for msg in "${errors[@]}" ; do
            echo "$msg"
        done
    fi
    return $err
}


function usage () 
{
    typeset -a MODULES
    typeset -a MGROUPS
    local grp g plg

    for plg in $NETCONFIG_MODULES_ORDER; do
        case $plg in
          -*) continue ;;
        esac
        if [ ! -x "$MODULEDIR/$plg" ]; then
            continue
        fi
        MODULES=(${MODULES[@]} $plg)
        grp=${plg%%-*}
        for g in ${MGROUPS[@]} ; do
            test "x$grp" = "x$g" && continue 2
        done
        MGROUPS=(${MGROUPS[@]} $grp)
    done
    cat << EOT >&2
Usage:
 $PROGNAME <global options>
 $PROGNAME <action> <action options>

 actions:
  modify    Requires an interface and service specific settings via STDIN
            or as file using the --input-file or --lease-file option.
            Already existing settings for this interface and service will
            be replaced with the new one, otherwise netconfig creates a
            new state file. Finaly, netconfig updates the managed files.
  remove    Removes the interface and service specific settings and
            updates the managed files.
  update    Updates the managed files with the current set of settings.

 modify options:
  < -s|--service <service name> >       service providing settings
  [ -i|--interface <interface name> ]   interface providing settings
  [ -F|--input-format <input format> ]  currently 'dhcpcd' supported only
  [ -I|--input-file <file name> ]       file name to read, stdin by default
  [ -l|--lease-file <file name> ]       alias for --input-file
  [ -m|--module-only <name | prefix> ]  module or module group updates only
  [ -f|--force-replace ]                generate files, even user modified
  [ -v|--verbose ]                      enable debug and be verbose

 remove options:
  < -s|--service <service name> >       service providing settings
  [ -i|--interface <interface name> ]   interface providing settings
  [ -m|--module-only <name | prefix> ]  module or module group updates only
  [ -f|--force-replace ]                generate files, even user modified
  [ -v|--verbose ]                      enable debug and be verbose

 update options:
  [ -m|--module-only <name | prefix> ]  module or module group updates only
  [ -f|--force-replace ]                generate files, even user modified
  [ -v|--verbose ]                      enable debug and be verbose

 global options:
  <-h|--help>                           show this help text

Active modules: ${MODULES[@]}
Module groups : ${MGROUPS[@]}

EOT
  if [ -n "$1" ] ; then
     ERROR="  ERROR:   "
     echo -e "$*\n" | while read line; do
       echo "${ERROR}${line}" >&2
       ERROR="           "
     done
  fi
  exit 1
}

COMMANDLINE="$@"
ACTION=""
SERVICE=""
INTERFACE=""
VARIABLE=""
MODFILTER=""
while true ; do
    # Interface is checked against sysfs before the data is used;
    # reject just the most the ugliest characters...
    REGEX=''
    VARIABLE=''
    case "$1" in
        -s|--service)       VARIABLE=SERVICE ;
                            REGEX='^[[:alnum:]_-]+$' ;;
        -i|--interface)     VARIABLE=INTERFACE ;
                            REGEX='^[^'"'"'`"\\/[:space:][:cntrl:]]+$' ;;
        -l|--lease-file)    VARIABLE=LEASEFILE;;
        -I|--input-file)    VARIABLE=LEASEFILE;;
        -F|--input-format)  VARIABLE=INPUTFORMAT;;
        -f|--force-replace) FORCE_REPLACE="true";;
        -v|--verbose)       VERBOSE="yes";;
        -m|--module-only)   VARIABLE=MODFILTER;;
        -h|--help)          usage;;
        "") break ;;
        --)
            shift
            test -n "$ACTION" -o $# -gt 1 \
            && usage "Exactly one action may be given.\n"\
                "Currently given actions: $ACTION $*"
            ACTION="$1"
            shift
            break
            ;;
        *)
            test -n "$ACTION" && usage "Exactly one action may be given.\n"\
                                       "Currently given actions: $ACTION $1"
            ACTION="$1"
        ;;
        -*) usage Unknown option $1;;
    esac
    if [ -n "$VARIABLE" ] ; then
        case $2 in
        (""|-*) usage "Option $1 needs an argument" ;;
        esac
        if [ -n "$REGEX" ] ; then
            if ! [[ ${1} =~ ${REGEX} ]] ; then
                usage "Invalid character in value for option $VARIABLE"
            fi
        fi
        eval $VARIABLE=\$2
        shift
    fi
    shift
done

test -z "$ACTION" && usage No action was given

if [ "$VERBOSE" = "yes" ]; then
    export VERBOSE=$VERBOSE
fi

#
# before we start, check for root
#
if test "$UID" != "0" -a "$USER" != root -a -z "$ROOT" ; then
    echo "You must be root to start $0." >&2
    exit 1
fi

# Check if we can write in /tmp
if ! touch $r/tmp &>/dev/null; then
    echo "Filesystem read only: Cannot modify anything" >&2
    exit 1
fi

# Set usefull default umask
umask 0022

# Create state directory
if ! mkdir -p "$STATEDIR" ; then
    echo "Unable to create netconfig state directory '$STATEDIR'" >&2
    exit 1
fi

#
# try to get the lock
#
openLockWait "$PROGNAME" 5
if [ "$?" != 0 ]; then
    log "open lock for $PROGNAME failed. Abort."
    exit 1;
fi

RET=0
ERR=0

case "$ACTION" in
    modify)
           modify                   ; RET=$?
           if [ "$RET" != "0" -a "$ERR" = "0" ]; then ERR=$RET; fi
           run_modules "$MODFILTER" ; RET=$?
           if [ "$RET" != "0" -a "$ERR" = "0" ]; then ERR=$RET; fi
           ;;
    update)
           run_modules "$MODFILTER" ; RET=$?
           if [ "$RET" != "0" -a "$ERR" = "0" ]; then ERR=$RET; fi
           ;;
    remove)
           remove                   ; RET=$?
           if [ "$RET" != "0" -a "$ERR" = "0" ]; then ERR=$RET; fi
           run_modules "$MODFILTER" ; RET=$?
           if [ "$RET" != "0" -a "$ERR" = "0" ]; then ERR=$RET; fi
           ;;
    *)
    usage "Invalid action given.\n"
    ;;
esac

unLock "$PROGNAME"

exit $ERR

# vim: set ts=8 sts=4 sw=4 ai et:

ACC SHELL 2018