* Aaron Poffenberger <[email protected]> [2017-09-26 21:53:24 -0500]:
> I should add, I thought about adding commands like rcctl's > `get|getdef|set` commands to do full interface configuration (`set > nwid wapname` or `set bssid <value>`) but wanted to get feedback on > the current approach before going to far down the rabbit hole. > > --Aaron > > * Aaron Poffenberger <[email protected]> [2017-09-26 20:39:29 -0500]: > > > Attached is a cli utility to manage network locations. It's modeled > > after rcctl(8). > > > > It doesn't attempt to replace netstart(8) or ifconfig(8). It works > > with them by storing location information in a directory and > > symlinking the hostname.if files to the hostname.if for the selected > > location. > > > > At the moment if doesn't handle auto discovery of WAPs, but I have > > code I wrote earlier I'm rewriting and integrating. > > > > netctl is written in pure shell so in theory it could be called at > > boot time. To do that, I'd probably split netctl into two pieces > > similar to the way rcctl(8) and rc.subr(8) work. One file for > > inclusion in /etc and the main ctl for /usr. > > > > The code could be integrated into netstart at some later date. > > > > In addition to the netctl utility I've included a man page. > > > > Comments or feedback would be appreciated. > > > > --Aaron Below is a new unified diff. I added auto-detection and joining of wireless networks. I haven't done the work to allow boot-time auto-detect and joining of wireless networks, yet. It's on my todo list. I added a simple example script to the man page showing how to use it with apmd(8) for resuming. I also included the Makefile and README which were not in the original posting. --Aaron --- /dev/null Wed Sep 27 22:09:14 2017 +++ Makefile Wed Sep 27 21:40:26 2017 @@ -0,0 +1,11 @@ +# $OpenBSD$ + +MAN= netctl.8 + +SCRIPT= netctl.sh + +realinstall: + ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/${SCRIPT} ${DESTDIR}${BINDIR}/netctl + +.include <bsd.prog.mk> --- /dev/null Wed Sep 27 22:09:14 2017 +++ README.md Wed Sep 27 20:43:01 2017 @@ -0,0 +1,159 @@ +About netctl +============ + +`netctl` is a utility to manage network locations, interface +configuration files, and to start, stop, or restart interfaces on +OpenBSD. + +`netctl` is not a replacement for `ifconfig(8)` or `netstart(8)`. It's +utility to make managing locations easier. `netstart` and `ifconfig` +still do the work. `netctl` makes the user's life, especially portable +users, easier. + + +Features +-------- ++ Create, delete and switch between **locations** (including restarting + **interfaces**) ++ Enable and disable **configurations**. ++ Start, stop and restart **interfaces**. ++ Detect and join known wireless networks (**waps**). ++ Scan for wireless access points. ++ List **locations**, **configurations**, **interfaces**, and **waps**. + +See the man page for further details. + + +Install +------- + +There's no installer for `netctl` at the moment. `doas make install` +will install to **/usr/local** unless you override the PREFIX +variable. + +`make install` will also create **/etc/hostname.d/** and +**/etc/hostname.d/nwids/** + + +Locations +--------- + +`netctl` works by symlinking **hostname.if** files in location +directories to **/etc/hostname.if** so that the normal `netstart(8)` +code can do what it already does well. + +`netctl` will create **location** directories for you by calling `doas +netctl create location_name`. `netctl` will **not** at this time +create the **hostname.if** files. They have to be created the same +ways as documented in `hostname.if(5)`. See the `man` page for more +details. + + +Auto Detecting and Joining Networks +----------------------------------- + +Auto detecting and joining requires some setup. `netctl` will not +connect to wireless access points that are not known. To create a +*known* wap, a standard wireless **hostname.if** files should be +created in **/etc/hostname.d/nwids**. *E.g.,* + +``` + $ cat /etc/hostname.d/nwids/Silly\ Wap.nwid + nwid "Silly Wap" + wpakey '$w@pau7h99' + dhcp +``` + +The filename **must** be the same as the **nwid** in the file which +**must** match the **ESSID** of the wireless access point. Any valid +configuration directive `ifconfig(8)` will accept may be placed in the +file. + +Executing `doas netctl -a start iwm0` will cause `netctl` to scan the +local network (with `ifconfig iwm0 scan`) and attempt to match the +results with the names of the **nwids** found by `ls`-ing +**/etc/hostname.d/nwids**. + +**N.B.** `ifconfig scan` is called dwith *each* wlan device unless one +is specified after the **start** parameter. + + +Auto Detecting and Joining Networks When Resuming +------------------------------------------------- + +`netctl` is not a daemon so it doesn't know when a computer has +resumed from sleep. `apmd(8)` does know and will call a script called +**resume** if it exists in **/etc/apm** and is executable. + +A simple script like the following will work where the script is +called **suspend** and the other scripts are symlinked to it (see the +**man** page for `apmd(8)`): + +``` +#!/bin/sh + +cmd="${0##*([[:blank:]])/etc/apm/}" +case "${cmd}" in + powerup|resume) + /usr/local/bin/netctl -a restart + ;; + *) + ;; +esac +``` + + +TODO +---- + ++ Add boot time detecting and joining wireless networks ++ Create hostname.if files in locations + + +Maybe TODO +---------- ++ Set and get values in hostname.if files. *E.g.,* +``` + $ doas netctl get home nwid + "Silly Wap" + + $ doas netctl set home nwid "My WAP Name" + + $ doas netctl set home dhcp on +``` + + +Comments on Boot Time Configuration +-------- + +`netctl` is written in pure shell (using no commands outside of shell, +**/bin** and **/sbin**), so that it can run at boot time when **/usr** +may not be mounted yet. + +I think I can get automated location switching working at boot time. I +already have code from an earlier project that will match wap scans to +the correct configuration. I'm rewriting it in pure shell and +integrating it for use during boot. + + +Copyright and License +--------------------- + +Copyright (c) 2017 Aaron Poffenberger <[email protected]> + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +Updates and Suggestions +----------------------- + +Let me know by `Issue` or email if you find bugs or have suggestions. --- /dev/null Wed Sep 27 22:09:14 2017 +++ netctl.8 Wed Sep 27 20:59:39 2017 @@ -0,0 +1,326 @@ +.\" $OpenBSD$ +.\" +.\" Copyright (c) 2017 Aaron Poffenberger <[email protected]> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: Sep 23 2017 $ +.Dt NETCTL 8 +.Os +.Sh NAME +.Nm netctl +.Nd configure and control hostname.if definitions +.Sh SYNOPSIS +.Nm netctl +.Op Fl h +.Nm netctl +.Cm ls +.Op Ar lsarg ... +.Nm netctl +.Cm create|delete +.Ar location ... +.Nm netctl +.Op Fl dr +.Cm switch +.Ar location +.Op Ar interface ... +.Nm netctl +.Cm enable|disable +.Op Ar configuration ... +.Nm netctl +.Op Fl a +.Cm start|restart +.Op Ar interface ... +.Nm netctl +.Cm stop +.Op Ar interface ... +.Nm netctl +.Op Fl v +.Cm scan +.Op Ar interface ... +.Sh DESCRIPTION +The +.Nm +utility is used to manage network locations, interface configuration +files, and to start, stop, or restart interfaces. +.Pp +.Nm +works with +.Xr ifconfig 8 +and +.Xr netstart 8 . +It does not replace them. +.Pp +The following options are available: +.Bl -tag -width Ds +.It Fl h +Help message. +.It Cm ls Op Ar lsarg ... +Display a list of locations, configurations, interfaces and known wireless access points matching +.Ar lsarg , +which can be one of: +.Bl -tag -width "interfaces" -offset indent -compact +.It Cm all +all locations, configurations and interfaces +.It Cm configurations Op Ar location ... +all configurations for the current +.Ar location +or locations +.It Cm interfaces +all interfaces (exluding pseudo-devices) +.It Cm locations +all locations +.It Cm waps +all known (configured) wireless access points +.El +.It Ar location +The +.Ar location +parameter is the name of a collection of related +.Ar interface +configuration files. +.Pp +.Nm +locations are stored as directories in +.Pa /etc/hostname.d . +See +.Sx FILES . +.Pp +.Sy N.B . +May not include network pseudo-devices. +.It Ar configuration +The +.Ar configuration +parameter is a +.Xr hostname.if 5 +file in a +.Ar location +directory. +See +.Sx FILES . +.It Ar interface +The +.Ar interface +parameter is an interface +.Dq name unit +as defined in +.Xr ifconfig 8 +which includes groups. +.El +.Sh LOCATION +The following commands are available for working with network locations: +.Bl -tag -width Ds +.It Cm create Ar location ... +Create one or more locations. +.It Cm delete Ar location ... +Delete one or more locations. +.Pp +.Sy N.B . +Deletes all +.Ar interface +.Ar configuration +files in +.Ar location . +.It Oo Fl dr Oc Cm switch Ar location Oo Ar interface ... Oc +Switch to +.Ar location . +.It Fl d +Delete +.Pa /etc/hostname.if +not found in +.Ar location . +.Pp +.Sy N.B . +Does not affect actual interface. +Removes symlink from previous location. +Otherwise the symlink to the previous location configuration is left in place. +.Pp +.Sy Default : +leave in place. +.It Fl r +Restart the interface(s) after switching. +.El +.Sh CONFIGURATION +The following commands are available for working with interface configurations: +.Bl -tag -width Ds +.It Cm enable Ar configuration ... +Enable an interface +.Ar configuration . +.It Cm disable Ar configuration ... +Disable an interface +.Ar configuration . +.El +.Sh INTERFACE +The following commands are available for working with interfaces: +.Bl -tag -width Ds +.It Oo Fl a Oc Cm start Op Ar interface ... +Start one or more interfaces. +.It Fl a +If the interface is in the wlan group, try to connect to a known wireless access point. +.It Cm stop Op Ar interface ... +Stop one or more interfaces. +.It Oo Fl a Oc Cm restart Op Ar interface ... +Restart one or more interfaces. +.It Fl a +If the interface is in the wlan group, try to connect to a known wireless access point. +.It Oo Fl v Oc Cm scan Op Ar interface ... +Scan for wireless access point with one or more interfaces. +.It Fl v +Verbose scan. +.It Fl vv +Detailed scan (Same as +.Cm ifconfig Ar if Ar scan Ns +). +.El +.Sh ENVIRONMENT +.Bl -tag -width MANPATHX +.It Ev HN_DIR +Directory to find +.Ar location +directories and interface configuration files. +.El +.Sh FILES +.Bl -tag -width "/etc/hostname.d/nwids/NAME.nwid" -compact +.It Pa /etc/hostname.d +default +.Ar location +directory. +.Pp +.It Pa /etc/hostname.d/*/hostname.XXX +interface-specific +.Ar configuration +files by location. +.Pp +.It Pa /etc/hostname.d/nwids +default location for known wireless access point +.Ar configuration +files. +.Pp +.It Pa /etc/hostname.d/nwids/NAME.nwid +.Ar configuration +files for known wireless access points named for the access point (including spaces). +.El +.Sh EXAMPLES +Create new location: +.Bd -literal -offset indent +$ doas netctl create home +.Ed +.Pp +Start +.Ar em0 : +.Bd -literal -offset indent +$ doas netctl start em0 +.Ed +.Pp +Start +.Ar iwm +and connect to known wireless access point: +.Bd -literal -offset indent +$ doas netctl -a start iwm0 +Found "Silly Wap" +Switch iwm0 +iwm0: no link ..... got link +iwm0: DHCPREQUEST to 255.255.255.255 +iwm0: DHCPREQUEST to 255.255.255.255 +iwm0: DHCPACK from 192.168.1.1 (00:00:00:00:00:00) +iwm0: bound to 192.168.1.41 -- renewal in 3600 seconds +.Ed +.Pp +Switch location and restart all interfaces: +.Bd -literal -offset indent +netctl -r switch home +.Ed +.Pp +Switch location and restart +.Ar iwm0 : +.Bd -literal -offset indent +$ doas netctl -r switch home iwm0 +.Ed +.Pp +Switch location and remove unconfigured interfaces: +.Bd -literal -offset indent +$ ls /etc/hostname.{em,iwm}0 +/etc/hostname.em0@ /etc/hostname.iwm0@ + +$ ls /etc/hostname.d/work +/etc/hostname.d/work/hostname.iwm0 + +$ doas netctl -d switch work + +$ ls /etc/hostname.{em,iwm}0 +/etc/hostname.iwm0@ +.Ed +.Pp +Scan for wireless access points with +.Ar iwm0 : +.Bd -literal -offset indent +$ doas netctl -v scan iwm0 +iwm0: + supersecurewap + notsosecurewap + "Silly Wap" +.Ed +.Pp +Simple integration with +.Xr apmd 8 +might look like: +.Bd -literal -offset indent +$ ls -l +lrwxr-xr-x 1 root wheel 7 Sep 20 16:23 powerup@ -> suspend +lrwxr-xr-x 1 root wheel 7 Sep 20 16:23 resume@ -> suspend +-rwxr--r-- 1 root wheel 225 Sep 27 20:41 suspend* + +$ cat /etc/apm/suspend +#!/bin/sh + +cmd="${0##*([[:blank:]])/etc/apm/}" +case "${cmd}" in + powerup|resume) + /usr/local/bin/netctl -a restart + ;; + *) + ;; +esac +.Ed +.Sh DIAGNOSTICS +.Nm +utility always exits 0. +.Sh SEE ALSO +.Xr hostname.if 5 , +.Xr apmd 8 , +.Xr ifconfig 8 , +.Xr netstart 8 +.Sh HISTORY +.Nm +is a new utility but it draws inspiration and style from +.Xr rcctl 8 +and +.Xr netstart 8 . +.Pp +A great deal of credit is due to Antoine Jacoutot, Ingo Schwarze, and +Robert Nagy for their work on +.Xr rcctl 8 +and +.Xr netstart 8 . +.Sh AUTHORS +.An -nosplit +The +.Nm +utility was written by +.An Aaron Poffenberger Aq Mt [email protected] . +.Sh BUGS +.Nm +should prevent users from running commands that require superuser. +.Nm +should al work with some network pseudo-devices like +.Xr trunk 4 . --- /dev/null Wed Sep 27 22:09:14 2017 +++ netctl.sh Wed Sep 27 20:34:36 2017 @@ -0,0 +1,543 @@ +#!/bin/sh +# +# $OpenBSD$ +# +# Copyright (c) 2017 Aaron Poffenberger <[email protected]> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# cmd OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS cmd, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +# Turn off Strict Bourne shell mode. +set +o sh + +readonly __progname="netctl" +readonly TRUE=0 +readonly FALSE=1 +readonly HN_DIR=${HN_DIR:-/etc/hostname.d} + +# Log an error +# Usage: log_err msg [exit code] +# Cheerfully copied from rc.subr(8) +# Copyright (c) 2010, 2011, 2014-2017 Antoine Jacoutot <[email protected]> +# Copyright (c) 2010, 2011 Ingo Schwarze <[email protected]> +# Copyright (c) 2010, 2011, 2014 Robert Nagy <[email protected]> +log_err() { + [ -n "${1}" ] && echo "${1}" 1>&2 + [ -n "${2}" ] && exit "${2}" || exit 1 +} + +# Log a warning +# Usage: log_err msg [exit code] +log_warning() { + log_msg "${1}" 1>&2 +} + +# Log a message +# Usage: log_msg msg [right justify length] +log_msg() { + local -R${2:-0} _msg="${1}" + + [ -n "${_msg}" ] && echo "${_msg}" +} + +# Log a message to stdout or stderr +# Usage: usage [2] +usage() { + echo \ + "usage: netctl [-h] + netctl ls [lsarg ...] + netctl create|delete location ... + netctl [-dr] switch location [interface ...] + netctl enable|disable [configuration ...] + netctl [-a] start|restart [interface ...] + netctl stop [interface ...] + netctl [-v] scan [interface ...]" 1>&${1:-1} +} + +# Get interface configuration +# Expects variables to be typeset/local from calling fn +# Usage: get_if_conf if1 +get_if_conf() { + # use co-process to preserve values set in while loop + ifconfig $1 |& + while IFS=' ' read -r -p _l; do + _key=${_l%%*([[:blank:]])*(:) *} + _val=${_l##*([[:blank:]])*${_key}*(:)*([[:blank:]])} + + [[ ${_key} == 'groups' ]] && _groups=${_val} + [[ ${_key} == 'media' ]] && _media=${_val} + [[ ${_key} == 'status' ]] && _status=${_val} + [[ ${_key} == 'ieee80211' ]] && _ieee80211=${_val} + [[ ${_key} == 'inet' ]] && _inet=${_val} + [[ ${_key} == 'inet6' ]] && _inet6=${_val} + done +} + +# Get interfaces +# Expects variable _ifs to be typeset/local from calling fn +# Usage: get_ifs if1 +get_ifs() { + local _if _excl_keys + # exclude network pseudo-devices + set -A _pseudo_devices $(ifconfig -C) + + # use co-process to preserve values set in while loop + ifconfig $1 |& + while IFS=' ' read -r -p _l; do + [[ "${_l}" == *flags* ]] || continue + + _if=${_l%%*([[:blank:]])*():*} + + [ -z "${_if}" ] && continue + + #_if=${_l%%*([[:blank:]])*():*} + + # exclude if-type (san _if num) in pseudo-devices + [[ " ${_pseudo_devices[*]}0 " == *" ${_if%%*([[:digit:]])} "* ]] && + continue + + _ifs[${#_ifs[*]}]="${_if}" + done + + [ -n "${_ifs}" ] || return 1 +} + +get_locations() { + local _l + + ls -p "${HN_DIR}" |& + # use co-process to preserve values set in while loop + while IFS=' ' read -r -p _l ; do + # skip known nwids, not a location + [[ "${_l}" == *nwids* ]] && continue + # skip files + [[ "${_l}" == *([[:blank:]])*/ ]] || continue + _locations[${#_locations[*]}]="${_l%%/}" + done +} + +get_configurations() { + local _l _location + + _location="$1" + + ls -p "${HN_DIR}/${_location}" |& + # use co-process to preserve values set in while loop + while IFS=' ' read -r -p _l ; do + # skip directories + [[ "${_l}" == *([[:blank:]])*[!/] ]] || continue + + _configurations[${#_configurations[*]}]="${_l}" + done +} + +# Restart interface +# Usage: if_restart if1 +if_restart() { + if_stop $1 && if_start $1 +} + +# Start interface +# Usage: if_start if1 +if_start() { + local _if + + _if=$1 + [ ${dryrun} -eq 1 ] && + log_msg /bin/sh /etc/netstart -p ${_if} || + /bin/sh /etc/netstart ${_if} +} + +# Stop interface +# Usage: if_stop if1 +if_stop() { + local _options _groups _media _status _ieee80211 _inet _inet6 \ + _key _wlan_keys _inet_keys _mode_keys _if + + set -A _wlan_keys -- nwid chan mode nwkey powersave wpakey wpa + + _if=$1 + get_if_conf ${_if} + + # remove mode if the interface is wireless + [ -n "${_ieee80211}" ] && _options="${_options} -mode" + + for _key in ${_wlan_keys[*]} ; do + [[ "${_ieee80211}" == *"${_key}"* ]] && + _options="${_options} -${_key}" + done + + [ -n "${_inet}" ] && _options="${_options} -inet" + [ -n "${_inet6}" ] && _options="${_options} -inet6" + + [ ${dryrun} -eq 1 ] && + log_msg ifconfig ${_if} ${_options} down || + ifconfig ${_if} ${_options} down +} + +# Create link from configuration to /etc/hostname.if +# Usage: link_configuration if from to +link_configuration() { + local _if _from _to + + _if=$1 + _from="${2}" + _to="${3}" + + [ ! -f "${_to}" ] && + [ -f "/etc/hostname.${_if}.disabled" ] && + _to="/etc/hostname.${_if}.disabled" + + [ ! -f "${_from}" ] && + [ ${delete} -eq 1 ] && + rm -f "${_to}" && + return + + [ -f "${_from}" ] && + ln -fs "${_from}" "${_to}" && + log_msg "Switch ${_if}" || + log_warning "No configuration for ${_if}" + + [ -f "${_to}" ] && + [ ${restart} -eq 1 ] && + if_restart ${_if} +} + +ls_locations() { + local _l _locations + set -A _locations + + get_locations + + log_msg "Locations:" + for _l in "${_locations[@]}" ; do + log_msg "\t${_l}" + done +} + +ls_configurations(){ + local _c _configurations _l _locations + set -A _locations + set -A _configurations + + [[ -n "$@" ]] && set -A _locations "$@" || + get_locations + + log_msg "Configurations:" + for _l in "${_locations[@]}" ; do + get_configurations "${_l}" + + log_msg "\t${_l}:" + for _c in "${_configurations[@]}" ; do + log_msg "\t\t${_c}" + done + + set -A _configurations + done +} + +ls_interfaces(){ + local _if _ifs + set -A _ifs + + get_ifs + + log_msg "Interfaces:" + for _if in "${_ifs[@]}" ; do + log_msg "\t${_if}" + done +} + +ls_waps() { + local _nwid _path _paths + set -A _paths -- ${HN_DIR}/nwids/*.nwid + log_msg "Wireless access points (known waps):" + for _path in "${_paths[@]}" ; do + _nwid=${_path##*([[:blank:]])${HN_DIR}/nwids/} + _nwid=${_nwid%%.nwid} + log_msg "\t${_nwid}" + done +} + +# Get interface details +# Expects variable _nwids to be typeset/local from calling fn +# Usage: scan if1 +scan() { + local _nwid _i _iselem _if _verbose + + _if=$1 + _verbose=$2 + # use co-process to preserve values set in while loop + ifconfig ${_if} scan |& + while IFS=' ' read -r -p _l ; do + [[ "${_l}" == *([[:blank::]])nwid* ]] || continue + + [[ "${_verbose:-0}" -eq 1 ]] && + _nwids[${#_nwids[*]}]="${_l%%*([[:blank:]])*()% *}%" && + continue + + [[ "${_verbose:-0}" -eq 2 ]] && + _nwids[${#_nwids[*]}]="${_l}" && + continue + + _nwid=${_l%%*([[:blank:]])*()chan *} + _nwid=${_nwid##*nwid *()} + + [[ ${_nwid} == '""' ]] && continue + + + _iselem=0 && _i=0 + while ((_i < ${#_nwids[*]})) ; do + [[ "${_nwids[_i]}" == "${_nwid}" ]] && + _iselem=1 && break + ((_i++)) + done + [ ${_iselem} -eq 0 ] && _nwids[${#_nwids[*]}]="${_nwid}" + done + + [ -n "${_nwids}" ] || return 1 +} + +# Match scanned access points with first known wap +# Usage: wap_match if1 +wap_match() { + local _if _nwids _nwid _path _paths _wap _waps + set -A _paths -- ${HN_DIR}/nwids/*.nwid + + _if=$1 + + [ -z "${_paths}" ] && + log_warning "No known waps found." && + return 1 + + for _path in "${_paths[@]}" ; do + _wap=${_path##*([[:blank:]])${HN_DIR}/nwids/} + _wap=${_wap%%.nwid} + _waps[${#_waps[*]}]="${_wap}" + done + + scan ${_if} + for _nwid in "${_nwids[@]}" ; do + _nwid=${_nwid##\"} + _nwid=${_nwid%%\"} + [[ " ${_waps[*]} " == *" ${_nwid} "* ]] && + log_msg "Found '${_nwid}'" && + _match="${HN_DIR}/nwids/${_nwid}.nwid" && + return + done +} + +typeset -i autowap=0 delete=0 dryrun=0 restart=0 verbose=0 +while getopts :adhnqrv opt ; do + case ${opt} in + a) + autowap=1;; + d) + delete=1;; + h) + usage + exit + ;; + n) + dryrun=1;; + q) + quiet=1;; + r) + restart=1;; + v) + ((verbose++)) + cmd="scan";; + :) + log_msg ${__progname}: option requires an argument \ + -- ${OPTARG} + usage 2 + exit + ;; + \?) + log_msg ${__progname}: invalid option -- ${OPTARG} + usage 2 + exit + ;; + esac +done +shift $(( OPTIND - 1 )) +cmd=$1 + +case ${cmd} in + ls) + shift 1 + lsarg="$1" + [[ -z "$@" ]] && usage 2 && exit + shift 1 + lsparms="$@" + [[ ${lsarg} == @(all|locations|configurations|interfaces|waps) ]] || + usage 2 + ;; + create) + shift 1 + locations="$@" + ;; + delete) + shift 1 + locations="$@" + ;; + switch) + shift 1 + location="$1" + [ -d "${HN_DIR}/${location}" ] || usage 2 + [[ -z "$@" ]] && usage 2 && exit + shift 1 + ifs="$@" + get_ifs ${ifs} # throws its own errors + ifs="${_ifs[@]}" + ;; + enable|disable|stop) + shift 1 + ifs="$@" + get_ifs ${ifs} # throws its own errors + ifs="${_ifs[@]}" + ;; + start|restart) + shift 1 + ifs="$@" + if [ ${autowap} -eq 1 ] && [ -z "${ifs}" ] ; then + get_ifs wlan # throws its own errors + ifs="${_ifs[@]}" + elif [ ${autowap} -eq 1 ] && [ -n "${ifs}" ] ; then + # Check whether $ifs are in wlan group + get_ifs wlan # throws its own errors + for _if in ${ifs} ; do + [[ " ${_ifs} " == *" ${_if} "* ]] && + continue || + log_err "${_if} not in wlan group" 3 + done + else + get_ifs ${ifs} # throws its own errors + ifs="${_ifs[@]}" + fi + ;; + scan) + shift 1 + ifs="$@" + get_ifs "${ifs:-wlan}" # throws its own errors + ifs="${_ifs[@]}" + ;; + *) + usage 2 + exit + ;; +esac + +case ${cmd} in + ls) + case ${lsarg} in + all) + ls_locations + ls_configurations + ls_interfaces + ls_waps + ;; + locations) + ls_locations + ;; + configurations) + ls_configurations ${lsparms};; + interfaces) + ls_interfaces;; + waps) + ls_waps;; + *) + usage 2 + ;; + esac + ;; + create) + for _loc in ${locations} ; do + mkdir -p "${HN_DIR}/${_loc}" || + log_warning "Unable to create location ${_loc}" + done + ;; + delete) + for _loc in ${locations} ; do + rm -rf "${HN_DIR}/${_loc}" || + log_warning "Unable to delete location ${_loc}" + done + ;; + switch) + for _if in ${ifs} ; do + _from="${HN_DIR}/${location}/hostname.${_if}" + _to="/etc/hostname.${_if}" + link_configuration ${_if} "${_from}" "${_to}" + done + ;; + enable) + for _if in ${ifs} ; do + _from="/etc/hostname.${_if}.disabled" + _to="/etc/hostname.${_if}" + [ -f "${_from}" ] || continue + + [ -f "${_from}" ] && ! [ -f "${_to}" ] && + mv "${_from}" "${_to}" || + log_warning "Unable to enable ${_if}" + done + ;; + disable) + for _if in ${ifs} ; do + _from="/etc/hostname.${_if}" + _to="/etc/hostname.${_if}.disabled" + [ -f "${_from}" ] || continue + + [ -f "${_from}" ] && + mv "${_from}" "${_to}" || + log_warning "Unable to disable ${_if}" + done + ;; + start|restart) + local _match _groups _media _status _ieee80211 _inet _inet6 + set -A _match + + for _if in ${ifs} ; do + get_if_conf ${_if} + # if _if status == "no network" scanning fails + # stop the interface and reset + [[ "${_status}" == 'no network' ]] && + log_warning "Stopping ${_if} ..." && + if_stop ${_if} + wap_match ${_if} + [ -n "${_match}" ] || return + _to="/etc/hostname.${_if}" + link_configuration ${_if} "${_match}" "${_to}" + if_restart ${_if} + ifconfig ${_if} + done + ;; + stop) + for _if in ${ifs} ; do + if_stop ${_if} + done + ;; + scan) + local _nwids + set -A _nwids + for _if in ${ifs} ; do + log_msg "${_if}:" + scan ${_if} ${verbose} + for _nwid in "${_nwids[@]}" ; do + log_msg "\t${_nwid}" + done + done + ;; + *) + usage 2 + ;; +esac
