#!/bin/sh -
#
-# $OpenBSD: netstart,v 1.176 2017/04/08 08:33:05 rpe Exp $
+# $OpenBSD: netstart,v 1.177 2017/04/24 20:31:48 rpe Exp $
# Turn off Strict Bourne shell mode.
set +o sh
done <$_file
}
+# Parse and "unpack" a hostname.if(5) line given as positional parameters.
+# Fill the _cmds array with the resulting interface configuration commands.
+parse_hn_line() {
+ local _af=0 _name=1 _mask=2 _bc=3 _prefix=2 _c _cmd _prev _daddr
+ set -A _c -- "$@"
+ set -o noglob
+
+ case ${_c[_af]} in
+ ''|*([[:blank:]])'#'*)
+ return
+ ;;
+ inet) ((${#_c[*]} > 1)) || return
+ [[ ${_c[_name]} == alias ]] && _mask=3 _bc=4
+ [[ -n ${_c[_mask]} ]] && _c[_mask]="netmask ${_c[_mask]}"
+ if [[ -n ${_c[_bc]} ]]; then
+ _c[_bc]="broadcast ${_c[_bc]}"
+ [[ ${_c[_bc]} == *NONE ]] && _c[_bc]=
+ fi
+ _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
+ ;;
+ inet6) ((${#_c[*]} > 1)) || return
+ if [[ ${_c[_name]} == autoconf ]]; then
+ _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
+ rtsolif="$rtsolif $_if"
+ return
+ fi
+ [[ ${_c[_name]} == alias ]] && _prefix=3
+ [[ -n ${_c[_prefix]} ]] && _c[_prefix]="prefixlen ${_c[_prefix]}"
+ _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
+ ;;
+ dest) ((${#_c[*]} == 2)) && _daddr=${_c[1]} || return
+ _prev=$((${#_cmds[*]} - 1))
+ ((_prev >= 0)) || return
+ set -A _c -- ${_cmds[_prev]}
+ _name=3
+ [[ ${_c[_name]} == alias ]] && _name=4
+ _c[_name]="${_c[_name]} $_daddr"
+ _cmds[$_prev]="${_c[@]}"
+ ;;
+ dhcp) _c[0]=
+ _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]} down;dhclient $_if"
+ dhcpif="$dhcpif $_if"
+ ;;
+ rtsol) # XXX Support the rtsol keyword for some time to enable a smooth
+ # XXX transition to autoconf.
+ _c[0]=
+ _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]} up"
+ _cmds[${#_cmds[*]}]="ifconfig $_if inet6 autoconf"
+ rtsolif="$rtsolif $_if"
+ ;;
+ '!'*) _cmd=$(print -- "${_c[@]}" | sed 's/\$if/'$_if'/g')
+ _cmds[${#_cmds[*]}]="${_cmd#!}"
+ ;;
+ *) _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
+ ;;
+ esac
+ unset _c
+}
+
# Start a single interface.
# Usage: ifstart if1
ifstart() {
- # Note: Do not rename the 'if' variable which is documented as being
- # usable in hostname.if(5) files.
- local if=$1 _file=/etc/hostname.$1 _stat
+ local _if=$1 _file=$HN_DIR/hostname.$1 _cmds _i=0 _line _stat
+ set -A _cmds
# Interface names must be alphanumeric only. We check to avoid
# configuring backup or temp files, and to catch the "*" case.
- [[ $if != +([[:alpha:]])+([[:digit:]]) ]] && return
+ [[ $_if != +([[:alpha:]])+([[:digit:]]) ]] && return
if [[ ! -f $_file ]]; then
echo "netstart: $_file: No such file or directory"
return
fi
+
# Not using stat(1), we can't rely on having /usr yet.
set -A _stat -- $(ls -nL $_file)
if [ "${_stat[0]#???????} ${_stat[2]} ${_stat[3]}" != "--- 0 0" ]; then
chmod -LR o-rwx $_file
chown -LR root.wheel $_file
fi
- # Check for ifconfig'able interface.
- (ifconfig $if || ifconfig $if create) >/dev/null 2>&1 || return
-
- # Now parse the hostname.* file.
- while :; do
- if [ "$cmd2" ]; then
- # We are carrying over from the 'read dt dtaddr'
- # last time.
- set -- $cmd2
- af=$1 name=$2 mask=$3 bcaddr=$4 ext1=$5 cmd2=
- # Make sure and get any remaining args in ext2,
- # like the read below.
- i=1
- while [ $i -lt 6 -a -n "$1" ]; do shift; let i=i+1; done
- ext2="$@"
+
+ # Check for ifconfig'able interface, except if -n option is specified.
+ if ! $PRINT_ONLY; then
+ (ifconfig $_if || ifconfig $_if create) >/dev/null 2>&1 ||
+ return
+ fi
+
+ # Parse the hostname.if(5) file and fill _cmds array with interface
+ # configuration commands.
+ set -o noglob
+ while IFS= read -- _line; do
+ parse_hn_line $_line
+ done <$_file
+
+ # Apply the interface configuration commands stored in _cmds array.
+ while ((_i < ${#_cmds[*]})); do
+ if $PRINT_ONLY; then
+ print -r -- "${_cmds[_i]}"
else
- # Read the next line or exit the while loop.
- read af name mask bcaddr ext1 ext2 || break
+ eval "${_cmds[_i]}"
fi
- # $af can be "dhcp", "up", "rtsol", an address family, commands,
- # or a comment.
- case "$af" in
- "#"*|"")
- # Skip comments and empty lines.
- continue
- ;;
- "!"*) # Parse commands.
- cmd="${af#*!} ${name} ${mask} ${bcaddr} ${ext1} ${ext2}"
- ;;
- "dhcp")
- [ "$name" = "NONE" ] && name=
- [ "$mask" = "NONE" ] && mask=
- [ "$bcaddr" = "NONE" ] && bcaddr=
- cmd="ifconfig $if $name $mask $bcaddr $ext1 $ext2 down"
- cmd="$cmd;dhclient $if"
- dhcpif="$dhcpif $if"
- ;;
- "rtsol")
- rtsolif="$rtsolif $if"
- cmd="ifconfig $if $name $mask $bcaddr $ext1 $ext2 up"
- ;;
- *)
- read dt dtaddr
- if [ "$name" = "alias" ]; then
- # Perform a 'shift' of sorts.
- alias=$name
- name=$mask
- mask=$bcaddr
- bcaddr=$ext1
- ext1=$ext2
- ext2=
- else
- alias=
- fi
- cmd="ifconfig $if $af $alias $name"
- case "$dt" in
- dest)
- cmd="$cmd $dtaddr"
- ;;
- *)
- cmd2="$dt $dtaddr"
- ;;
- esac
- case $af in
- inet)
- if [ ! -n "$name" ]; then
- echo "/etc/hostname.$if: inet alone is invalid"
- return
- fi
- [ "$mask" ] && cmd="$cmd netmask $mask"
- if [ "$bcaddr" -a "X$bcaddr" != "XNONE" ]; then
- cmd="$cmd broadcast $bcaddr"
- fi
- ;;
- inet6)
- if [ ! -n "$name" ]; then
- echo "/etc/hostname.$if: inet6 alone is invalid"
- return
- fi
- [ "$mask" ] && cmd="$cmd prefixlen $mask"
- cmd="$cmd $bcaddr"
- ;;
- *)
- cmd="$cmd $mask $bcaddr"
- ;;
- esac
- cmd="$cmd $ext1 $ext2"
- ;;
- esac
- eval "$cmd"
- done <$_file
+ ((_i++))
+ done
+ unset _cmds
}
# Start multiple interfaces by driver name.
FUNCS_ONLY=1 . /etc/rc.d/rc.subr
_rc_parse_conf
+HN_DIR=${HN_DIR:-/etc}
+PRINT_ONLY=false
+USAGE="USAGE: ${0##*/} [-n] [interface ...]"
+while getopts ":n" opt; do
+ case $opt in
+ n) PRINT_ONLY=true;;
+ *) print -u2 "$USAGE"; exit 1;;
+ esac
+done
+shift $((OPTIND-1))
+
+# Option -n is only supported if interface names are specified as parameters.
+if $PRINT_ONLY && (($# == 0)); then
+ print -u2 "Missing parameters.\n$USAGE"
+ exit 1
+fi
+
# If we were invoked with a list of interface names, just reconfigure these
# interfaces (or bridges), add default routes and return.
if (($# > 0)); then