summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouke Witteveen <j.witteveen@gmail.com>2012-12-28 02:43:13 +0100
committerJouke Witteveen <j.witteveen@gmail.com>2012-12-28 02:57:35 +0100
commit27c11787d7c58b02f12d7afd476ea66abfeecaaf (patch)
treee203812a9e6d2a901568ca36de3b1fc7380a369b
parent4e457e0efd0e5fd5df24c7e9ed63b02d0196ea8d (diff)
downloadnetctl-27c11787d7c58b02f12d7afd476ea66abfeecaaf.tar.gz
netctl-27c11787d7c58b02f12d7afd476ea66abfeecaaf.tar.xz
Forking netcfg to netctl (2/2)
This commit contains the refactoring and rewriting of code.
-rw-r--r--contrib/bash-completion63
-rw-r--r--docs/examples/bonding15
-rw-r--r--docs/examples/bridge14
-rw-r--r--docs/examples/ethernet-dhcp12
-rw-r--r--docs/examples/ethernet-iproute10
-rw-r--r--docs/examples/ethernet-static22
-rw-r--r--docs/examples/pppoe34
-rw-r--r--docs/examples/tunnel-he-ipv619
-rw-r--r--docs/examples/tuntap15
-rw-r--r--docs/examples/vlan-dhcp11
-rw-r--r--docs/examples/vlan-static22
-rw-r--r--docs/examples/wireless-open10
-rw-r--r--docs/examples/wireless-wep17
-rw-r--r--docs/examples/wireless-wep-string-key12
-rw-r--r--docs/examples/wireless-wpa16
-rw-r--r--docs/examples/wireless-wpa-config12
-rw-r--r--docs/examples/wireless-wpa-configsection31
-rw-r--r--docs/examples/wireless-wpa-static18
-rw-r--r--docs/netctl.1.txt141
-rw-r--r--docs/netctl.profile.5.txt599
-rw-r--r--docs/netctl.special.7.txt55
-rw-r--r--services/netctl-auto@.service8
-rw-r--r--services/netctl-ifplugd@.service7
-rw-r--r--services/netctl.service7
-rw-r--r--services/netctl@.service9
-rwxr-xr-xsrc/ifplugd.action29
-rw-r--r--src/lib/8021x341
-rwxr-xr-xsrc/lib/auto.action85
-rw-r--r--src/lib/connections/bond41
-rw-r--r--src/lib/connections/bridge53
-rw-r--r--src/lib/connections/ethernet276
-rw-r--r--src/lib/connections/pppoe55
-rw-r--r--src/lib/connections/tunnel34
-rw-r--r--src/lib/connections/tuntap32
-rw-r--r--src/lib/connections/vlan34
-rw-r--r--src/lib/connections/wireless137
-rw-r--r--src/lib/globals159
-rw-r--r--src/lib/ip215
-rwxr-xr-x[-rw-r--r--]src/lib/network419
-rw-r--r--src/lib/rfkill85
-rwxr-xr-xsrc/netctl232
-rwxr-xr-xsrc/netctl-auto137
-rwxr-xr-xsrc/wifi-menu76
43 files changed, 1674 insertions, 1945 deletions
diff --git a/contrib/bash-completion b/contrib/bash-completion
index dab52ea..b47d92b 100644
--- a/contrib/bash-completion
+++ b/contrib/bash-completion
@@ -1,49 +1,30 @@
-# netcfg completion
+# netctl completion
-_netcfg ()
+_netctl()
{
- local cur prev opts lopts cmds prfls
+ local cur prev prof
- COMPREPLY=()
- cur="${COMP_WORDS[COMP_CWORD]}"
- prev="${COMP_WORDS[COMP_CWORD-1]}"
+ cur=${COMP_WORDS[COMP_CWORD]}
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ prof=$(find -L /etc/network.d -maxdepth 1 -type f -not -name '.*' -not -name '*~' -not -name '*.conf' -not -name '*.service' -printf "%f\n")
- opts="-l -c -u -r -R -d -D -a -v -h"
- lopts="--help --version"
- cmds="list current check-iface up reconnect iface-recon down iface-down all-down all-suspend"
- prfls="$(find -L /etc/network.d/ -maxdepth 1 -type f -not -name '*~' -not -name '*.conf' -not -name '.*' -printf '%f\n')"
-
- case "${prev}" in
- -R|iface-recon|-D|iface-down)
- COMPREPLY=( $( compgen -W "$(ls /run/network/interfaces/)" -- $cur ) )
- return 0
- ;;
- -r|reconnect|-d|down)
- COMPREPLY=( $( compgen -W "$(ls /run/network/profiles/)" -- $cur ) )
- return 0
- ;;
- -c|check-iface|-u|up)
- COMPREPLY=( $( compgen -W "${prfls}" -- $cur ) )
- return 0
- ;;
- esac
-
- case "${cur}" in
- --*)
- COMPREPLY=( $( compgen -W "${lopts}" -- $cur ) )
- return 0
- ;;
- -*)
- COMPREPLY=( $( compgen -W "${opts} ${lopts}" -- $cur ) )
- return 0
- ;;
- *)
- ((COMP_CWORD == 1)) && \
- COMPREPLY=( $( compgen -W "${opts} ${lopts} ${cmds} ${prfls}" -- $cur ) )
+ case $COMP_CWORD in
+ 1)
+ COMPREPLY=( $(compgen -W "--help --version list store restore stop-all start stop restart switch-to status enable disable reenable" -- $cur) )
+ ;;
+ 2)
+ case $prev in
+ start|stop|restart|switch-to|status|enable|disable|reenable)
+ mapfile -t COMPREPLY < <(IFS=$'\n'; compgen -W "$prof" -- $cur)
;;
+ esac
+ ;;
+ *)
+ COMPREPLY=()
+ ;;
esac
+} &&
+complete -F _netctl netctl
- return 0
-}
-complete -F _netcfg netcfg
+# ex: ts=4 sw=4 et filetype=sh
diff --git a/docs/examples/bonding b/docs/examples/bonding
index e8d4a7f..090892d 100644
--- a/docs/examples/bonding
+++ b/docs/examples/bonding
@@ -1,9 +1,6 @@
-CONNECTION="bond"
-DESCRIPTION='Bond Interface'
-INTERFACE='bond0'
-IP='static'
-ADDR="10.0.0.1"
-NETMASK="255.0.0.0"
-SLAVE_INTERFACES=("eth0" "eth2")
-SKIPNOCARRIER="yes"
-
+Description='Bond Interface'
+Interface='bond0'
+Connection=bond
+BindsToInterfaces=(eth0 eth2)
+IP=static
+Address="10.0.0.1/8"
diff --git a/docs/examples/bridge b/docs/examples/bridge
index bd422fa..f8d2915 100644
--- a/docs/examples/bridge
+++ b/docs/examples/bridge
@@ -1,9 +1,9 @@
-INTERFACE="br0"
-CONNECTION="bridge"
-DESCRIPTION="Example Bridge connection"
-BRIDGE_INTERFACES="eth0 eth1 tap0"
-IP="dhcp"
+Description="Example Bridge connection"
+Interface=br0
+Connection=bridge
+BindsToInterfaces=(eth0 eth1 tap0)
+IP=dhcp
## sets forward delay time
-#FWD_DELAY=0
+#FWDDelay=0
## sets max age of hello message
-#MAX_AGE=10
+#MaxAge=10
diff --git a/docs/examples/ethernet-dhcp b/docs/examples/ethernet-dhcp
index 0719632..5866238 100644
--- a/docs/examples/ethernet-dhcp
+++ b/docs/examples/ethernet-dhcp
@@ -1,9 +1,9 @@
-CONNECTION='ethernet'
-DESCRIPTION='A basic dhcp ethernet connection using iproute'
-INTERFACE='eth0'
-IP='dhcp'
+Description='A basic dhcp ethernet connection using iproute'
+Interface=eth0
+Connection=ethernet
+IP=dhcp
## for DHCPv6
-#IP6='dhcp'
+#IP6=dhcp
## for IPv6 autoconfiguration
-#IP6='stateless'
+#IP6=stateless
diff --git a/docs/examples/ethernet-iproute b/docs/examples/ethernet-iproute
index d22dd17..972f5bb 100644
--- a/docs/examples/ethernet-iproute
+++ b/docs/examples/ethernet-iproute
@@ -1,7 +1,7 @@
-CONNECTION='ethernet'
-DESCRIPTION='A more versatile static ethernet connection using iproute'
-INTERFACE='eth0'
-IP='static'
+Description='A more versatile static ethernet connection using iproute'
+Interface=eth0
+Connection=ethernet
+IP=static
# Any valid iproute command can be placed in this array
-IPCFG=('addr add dev eth0 192.168.1.23/24 brd +' 'route add default via 192.168.1.1')
+IPCustom=('addr add dev eth0 192.168.1.23/24 brd +' 'route add default via 192.168.1.1')
DNS=('192.168.1.1')
diff --git a/docs/examples/ethernet-static b/docs/examples/ethernet-static
index ea88bde..0d6b5a2 100644
--- a/docs/examples/ethernet-static
+++ b/docs/examples/ethernet-static
@@ -1,17 +1,17 @@
-CONNECTION='ethernet'
-DESCRIPTION='A basic static ethernet connection using iproute'
-INTERFACE='eth0'
-IP='static'
-ADDR='192.168.1.23'
-#ROUTES=('192.168.0.0/24 via 192.168.1.2')
-GATEWAY='192.168.1.1'
+Description='A basic static ethernet connection using iproute'
+Interface=eth0
+Connection=ethernet
+IP=static
+Address='192.168.1.23'
+#Routes=('192.168.0.0/24 via 192.168.1.2')
+Gateway='192.168.1.1'
DNS=('192.168.1.1')
## For IPv6 autoconfiguration
#IP6=stateless
## For IPv6 static address configuration
-#IP6='static'
-#ADDR6=('1234:5678:9abc:def::1/64' '1234:3456::123/96')
-#ROUTES6=('abcd::1234')
-#GATEWAY6='1234:0:123::abcd'
+#IP6=static
+#Address6=('1234:5678:9abc:def::1/64' '1234:3456::123/96')
+#Routes6=('abcd::1234')
+#Gateway6='1234:0:123::abcd'
diff --git a/docs/examples/pppoe b/docs/examples/pppoe
index c11d125..74cc9ff 100644
--- a/docs/examples/pppoe
+++ b/docs/examples/pppoe
@@ -1,33 +1,33 @@
-CONNECTION='pppoe'
-DESCRIPTION='Example PPPoE connection'
-INTERFACE='eth0'
-USER='example@yourprovider.com'
-PASSWORD='very secret'
+Description='Example PPPoE connection'
+Interface=eth0
+Connection=pppoe
+User='example@yourprovider.com'
+Password='very secret'
# Always keep a connection established
-CONNECTION_MODE='persist'
+ConnectionMode='persist'
# Establish connection on demand
-#CONNECTION_MODE='demand'
-#IDLE_TIMEOUT=300
+#ConnectionMode='demand'
+#IdleTimeout=300
# Use default route provided by the peer (default: true)
-#DEFAULTROUTE=1
+#DefaultRoute=true
# Use DNS provided by the peer (default: true)
-#USEPEERDNS=1
+#UsePeerDNS=true
# Override default LCP parameters from /etc/ppp/options
-#LCP_ECHO_INTERVAL=15
-#LCP_ECHO_FAILURE=10
+#LCPEchoInterval=15
+#LCPEchoFailure=10
# PPPoE options - experts only
#
# PPPoE service name
-#PPPOE_SERVICE=''
+#PPPoEService=''
# PPPoE access concentrator name
-#PPPOE_AC=''
+#PPPoEAC=''
# Attach to existing session (sessid:macaddr)
-#PPPOE_SESSION=''
+#PPPoESession=''
# Only connect to specified MAC address
-#PPPOE_MAC=''
+#PPPoEMAC=''
# Enable IPv6 support
-#PPPOE_IP6='yes'
+#PPPoEIP6=yes
diff --git a/docs/examples/tunnel-he-ipv6 b/docs/examples/tunnel-he-ipv6
index 81b18ad..2a19406 100644
--- a/docs/examples/tunnel-he-ipv6
+++ b/docs/examples/tunnel-he-ipv6
@@ -1,11 +1,10 @@
-CONNECTION='tunnel'
-DESCRIPTION='An example ipv6 tunnel with Hurricane Electric'
+Description='An example ipv6 tunnel with Hurricane Electric'
+Interface=he-ipv6
+Connection=tunnel
+Mode='sit'
+Remote='216.66.80.26'
+#Local='172.16.0.1'
-INTERFACE='he-ipv6'
-MODE='sit'
-REMOTE='216.66.80.26'
-#LOCAL='172.16.0.1'
-
-IP6='static'
-ADDR6='2001:470:1f08:d87::2/64'
-ROUTES6=('::/0')
+IP6=static
+Address6='2001:470:1f08:d87::2/64'
+Routes6=('::/0')
diff --git a/docs/examples/tuntap b/docs/examples/tuntap
index 1563520..8ce78ac 100644
--- a/docs/examples/tuntap
+++ b/docs/examples/tuntap
@@ -1,11 +1,10 @@
-INTERFACE='tun0'
-CONNECTION='tuntap'
-MODE='tun'
-USER='nobody'
-GROUP='nobody'
+Interface=tun0
+Connection=tuntap
+Mode='tun'
+User='nobody'
+Group='nobody'
## Example IP configuration
-#IP='static'
-#SKIPNOCARRIER='yes'
-#ADDR='10.10.1.2'
+#IP=static
+#Address='10.10.1.2'
diff --git a/docs/examples/vlan-dhcp b/docs/examples/vlan-dhcp
index 8c6ad23..c412618 100644
--- a/docs/examples/vlan-dhcp
+++ b/docs/examples/vlan-dhcp
@@ -1,5 +1,6 @@
-INTERFACE="eth0.55"
-VLAN_PHYS_DEV="eth0"
-VLAN_ID="55"
-CONNECTION="vlan"
-IP="dhcp"
+Interface=eth0.55
+Connection=vlan
+# The variable name is plural, but needs precisely one interface
+BindsToInterfaces=eth0
+VLANID=55
+IP=dhcp
diff --git a/docs/examples/vlan-static b/docs/examples/vlan-static
index b7b9753..f9e1ae5 100644
--- a/docs/examples/vlan-static
+++ b/docs/examples/vlan-static
@@ -1,12 +1,12 @@
-INTERFACE="eth0.11"
-VLAN_PHYS_DEV="eth0"
-VLAN_ID="11"
-CONNECTION="vlan"
-IP="static"
-ADDR="192.168.0.100"
-NETMASK="255.255.255.0"
-GATEWAY="192.168.0.1"
+Interface=eth0.11
+Connection=vlan
+# The variable name is plural, but needs precisely one interface
+BindsToInterfaces=eth0
+VLANID=11
+IP=static
+Address="192.168.0.100/24"
+Gateway="192.168.0.1"
DNS=("192.168.0.2")
-HOSTNAME="myhost"
-DOMAIN="mydomain.com"
-SEARCH="mydomain.com"
+Hostname="myhost"
+DNSDomain="mydomain.com"
+DNSSearch="mydomain.com"
diff --git a/docs/examples/wireless-open b/docs/examples/wireless-open
index db8d6ef..f4bf9bb 100644
--- a/docs/examples/wireless-open
+++ b/docs/examples/wireless-open
@@ -1,8 +1,8 @@
-CONNECTION='wireless'
-DESCRIPTION='A simple opened wireless connection'
-INTERFACE='wlan0'
-SECURITY='none'
+Description='A simple opened wireless connection'
+Interface=wlan0
+Connection=wireless
+Security=none
ESSID='MyNetwork'
IP='dhcp'
# Uncomment this if your ssid is hidden
-#HIDDEN=yes
+#Hidden=yes
diff --git a/docs/examples/wireless-wep b/docs/examples/wireless-wep
index b16f65e..479b8a3 100644
--- a/docs/examples/wireless-wep
+++ b/docs/examples/wireless-wep
@@ -1,11 +1,12 @@
-CONNECTION='wireless'
-DESCRIPTION='A simple WEP encrypted wireless connection'
-INTERFACE='wlan0'
-SECURITY='wep'
+Description='A simple WEP encrypted wireless connection'
+Interface=wlan0
+Connection=wireless
+Security=wep
ESSID='MyNetwork'
-KEY='1234567890'
+# Prepend hexadecimal keys with \"
+Key=\"1234567890abcdef
IP='dhcp'
# Uncomment this if your ssid is hidden
-#HIDDEN=yes
-## Uncomment if you are using an ad-hoc connection
-#ADHOC=1
+#Hidden=yes
+# Uncomment if you are using an ad-hoc connection
+#AdHoc=yes
diff --git a/docs/examples/wireless-wep-string-key b/docs/examples/wireless-wep-string-key
index ebc4b0a..12483c0 100644
--- a/docs/examples/wireless-wep-string-key
+++ b/docs/examples/wireless-wep-string-key
@@ -1,9 +1,9 @@
-CONNECTION='wireless'
-DESCRIPTION='A simple WEP encrypted wireless connection'
-INTERFACE='wlan0'
-SECURITY='wep'
+Description='A simple WEP encrypted wireless connection'
+Interface=wlan0
+Connection=wireless
+Security=wep
ESSID='MyNetwork'
-KEY='s:Wireless Key'
+Key='Wireless Key'
IP='dhcp'
# Uncomment this if your ssid is hidden
-#HIDDEN=yes
+#Hidden=yes
diff --git a/docs/examples/wireless-wpa b/docs/examples/wireless-wpa
index e2511f3..16d17e9 100644
--- a/docs/examples/wireless-wpa
+++ b/docs/examples/wireless-wpa
@@ -1,14 +1,14 @@
-CONNECTION='wireless'
-DESCRIPTION='A simple WPA encrypted wireless connection'
-INTERFACE='wlan0'
-SECURITY='wpa'
+Description='A simple WPA encrypted wireless connection'
+Interface=wlan0
+Connection=wireless
+Security=wpa
ESSID='MyNetwork'
-## Uncomment if the supplied ESSID is hexadecimal
-#ESSID_TYPE='hex'
-KEY='WirelessKey'
+# Prepend hexadecimal keys with \"
+# If your key starts with ", write it as '"""<key>"'
+Key='WirelessKey'
IP='dhcp'
# Uncomment this if your ssid is hidden
-#HIDDEN=yes
+#Hidden=yes
diff --git a/docs/examples/wireless-wpa-config b/docs/examples/wireless-wpa-config
index 955d845..e598dce 100644
--- a/docs/examples/wireless-wpa-config
+++ b/docs/examples/wireless-wpa-config
@@ -1,8 +1,8 @@
-CONNECTION='wireless'
-DESCRIPTION='A wpa_supplicant configuration based wireless connection'
-INTERFACE='wlan0'
-SECURITY='wpa-config'
-WPA_CONF='/etc/wpa_supplicant.conf'
+Description='A wpa_supplicant configuration based wireless connection'
+Interface=wlan0
+Connection=wireless
+Security=wpa-config
+WPAConfigFile='/etc/wpa_supplicant.conf'
IP='dhcp'
# Uncomment this if your ssid is hidden
-#HIDDEN=yes
+#Hidden=yes
diff --git a/docs/examples/wireless-wpa-configsection b/docs/examples/wireless-wpa-configsection
index d6cc8ad..dde9ccd 100644
--- a/docs/examples/wireless-wpa-configsection
+++ b/docs/examples/wireless-wpa-configsection
@@ -1,17 +1,18 @@
-CONNECTION='wireless'
-INTERFACE=wlan0
-SECURITY='wpa-configsection'
+Interface=wlan0
+Connection=wireless
+Security=wpa-configsection
# Uncomment this if your ssid is hidden
-#HIDDEN=yes
+#Hidden=yes
IP='dhcp'
-CONFIGSECTION='
- ssid="University"
- key_mgmt=WPA-EAP
- eap=TTLS
- group=TKIP
- pairwise=TKIP CCMP
- anonymous_identity="anonymous"
- identity="myusername"
- password="mypassword"
- priority=1
- phase2="auth=PAP"'
+WPAConfigSection=(
+ 'ssid="University"'
+ 'key_mgmt=WPA-EAP'
+ 'eap=TTLS'
+ 'group=TKIP'
+ 'pairwise=TKIP CCMP'
+ 'anonymous_identity="anonymous"'
+ 'identity="myusername"'
+ 'password="mypassword"'
+ 'priority=1'
+ 'phase2="auth=PAP"'
+)
diff --git a/docs/examples/wireless-wpa-static b/docs/examples/wireless-wpa-static
index 25da514..66b6970 100644
--- a/docs/examples/wireless-wpa-static
+++ b/docs/examples/wireless-wpa-static
@@ -1,12 +1,12 @@
-CONNECTION='wireless'
-DESCRIPTION='A simple WPA encrypted wireless connection using a static IP'
-INTERFACE='wlan0'
-SECURITY='wpa'
+Description='A simple WPA encrypted wireless connection using a static IP'
+Interface=wlan0
+Connection=wireless
+Security=wpa
ESSID='MyNetwork'
-KEY='WirelessKey'
-IP='static' # Any other CONNECTION='ethernet' options may be used.
-ADDR='192.168.1.23'
-GATEWAY='192.168.1.1'
+Key='WirelessKey'
+IP=static
+Address='192.168.1.23'
+Gateway='192.168.1.1'
DNS=('192.168.1.1')
# Uncomment this if your ssid is hidden
-#HIDDEN=yes
+#Hidden=yes
diff --git a/docs/netctl.1.txt b/docs/netctl.1.txt
index 54fbd78..06638a2 100644
--- a/docs/netctl.1.txt
+++ b/docs/netctl.1.txt
@@ -1,91 +1,92 @@
-NETCFG(8)
+NETCTL(1)
=========
NAME
----
-netcfg - start/stop/control network profiles
+netctl - Control the netctl network profile manager
SYNOPSIS
--------
-netcfg [_options_]
+*netctl* {*COMMAND*} [+PROFILE+]
-netcfg *profile*
+*netctl* [--help | --version]
DESCRIPTION
-----------
-*netcfg* is used to configure and manage network connections via
-profiles. It has pluggable support for a range of connection types, such
-as wireless, ethernet, ppp. It is also capable of starting/stopping many
-to one connections, that is, multiple connections within the same
-profile, optionally with bonding.
-
-It may be run at boot, by enabling the 'netcfg' systemd service, or, on
-legacy systems, by adding 'net-profiles' to +DAEMONS+ in '/etc/rc.conf'.
-After boot time, it may be used to start profiles, simply by passing only
-the profile name.
-
-When run without options, `netcfg profile` is equivalent to `netcfg -u
-profile`.
+*netctl* may be used to introspect and control the state of the systemd
+services for the network profile manager.
OPTIONS
-------
-*-l, list*::
- List all available profiles
-*current*::
- Report currently running profiles
-*-c, check-iface* _profile_::
- Start the specified profile, only if it's interface is not currently up.
-*-u, up* _profile_::
- Start the specified profile
-*-r, reconnect* _profile_::
- Disconnect and reconnect the specified profile
-*-R, iface-recon* _interface_::
- Reconnect profile active on specified interface
-*-d, down* _profile_::
- Stop the specified profile
-*-D, iface-down* _interface_::
- Stop the profile up on the specified interface.
-*-a, all-down*::
- Stop all connected profiles
-*all-suspend*::
- Suspend and store the name of all active profiles.
-*all-resume*::
- Reconnect any profiles that have been suspended.
-*-v, --version*::
- Display version information and exit
-*-h, --help*::
- Display help message and exit
-
-
-CONFIGURATION FILES
--------------------
-'/etc/conf.d/netcfg'::
- Parameters for startup.
-'/etc/network.d/'::
- User-defined profiles.
-
-
-FILES
------
-'/usr/lib/network/connections/'::
- Currently installed network profile types.
-'/etc/network.d/examples/'::
- Example profiles.
-'/usr/share/doc/netcfg/contrib/'::
- Inspirational scripts.
-
-
-ENVIRONMENT VARIABLES
----------------------
-+NETCFG_DEBUG+::
- Set to 1 to activate debug output.
+The following commands are understood:
+
+*list*::
+ List all available profiles. Active profiles will be marked with a
+ `*'.
+
+*store*::
+ Saves which profiles are currently active.
+
+*restore*::
+ Loads the profiles that were active during the last invocation of
+ `*store*'.
+
+*stop-all*::
+ Stops all active network profiles.
+
+*start [+PROFILE+]*::
+ Start the network profile specified on the command line.
+
+*stop [+PROFILE+]*::
+ Stop the network profile specified on the command line.
+
+*restart [+PROFILE+]*::
+ Restart the network profile specified on the command line. If it is
+ not started yet, it will be started.
+
+*switch-to [+PROFILE+]*::
+ Starts the network profile specified on the command line after
+ stopping all profiles that refer to the same interface.
+
+*status [+PROFILE+]*::
+ Show terse runtime status information about a profile, followed by
+ its most recent log data from the journal.
+
+*enable [+PROFILE+]*::
+ Enable the systemd unit for the profile specified. This will create
+ a unit configuration file. If the file already exists, the command
+ fails. No other profiles than the one specified will be enabled.
+ Changes to the general options in a profile specification will not
+ propagate to the unit configuration file automatically. After such
+ changes, it is necessary to `*reenable*' the profile.
+
+*disable [+PROFILE+]*::
+ Disable the systemd unit for the profile specified. This will remove
+ the file created by `*enable*' even if it was customized, so be
+ carefull.
+
+*reenable [+PROFILE+]*::
+ Reenable the systemd unit for the profile specified. This is
+ effectively a combination of `*disable*' and `*enable*'.
+
+
+EXIT STATUS
+-----------
+On success 0 is returned, a non-zero failure code otherwise.
+
+
+ENVIRONMENT
+-----------
+'$NETCTL_DEBUG'::
+ If set to `"yes"`, debugging output is generated.
+'$NETCTL_STATE_FILE'::
+ The location of the state file. Defaults to
+ '/var/lib/netctl/netctl.state'.
SEE ALSO
--------
-*netcfg-profiles*(5) on how to configure netcfg.
-
-include::footer.txt[]
+*netctl.profile*(5) *netctl.special*(7) *systemctl*(1)
diff --git a/docs/netctl.profile.5.txt b/docs/netctl.profile.5.txt
index f929e47..21ea52c 100644
--- a/docs/netctl.profile.5.txt
+++ b/docs/netctl.profile.5.txt
@@ -1,321 +1,362 @@
-NETCFG-PROFILES(5)
-==================
+NETCTL.PROFILE(5)
+=================
NAME
----
-netcfg-profiles - netcfg profiles documentation and syntax
+netctl.profile - Profile options
+
+
+SYNOPSIS
+--------
+netctl.profile
DESCRIPTION
-----------
-The *netcfg*(8) profiles are plain text files that defines variables for
-netcfg behavior. They must be compliant with *bash*(1) shell syntax and
-usually do not execute any code.
+Profiles for netctl live under '/etc/network.d/' and are plain text
+files. The files consist of variable definitions following the bash
+shell syntax and are not expected to execute any code. It is good to
+omit as much quoting as possible. For a few WPA-related variables,
+special quoting rules (see below) apply.
-They are named '/etc/network.d/$\{profile_name}', where
-+$\{profile_name\}+ must not contain a newline character and should not
-start with the `@'-sign.
+The name of the profile is the name of the file. Profile names must not
+contain newlines and should not end in '.service' or '.conf'. Whenever a
+profile is read, all executable scripts in '/etc/network.d/hooks/' and
+any executable script in '/etc/network.d/interfaces/' with the name of
+the interface for the profile are sourced. For each connection type,
+there are example profile files in '/etc/network.d/examples/'.
-OVERVIEW
---------
-Profiles must define mandatory variables:
+AVAILABLE CONNECTION TYPES
+--------------------------
++ethernet+::
+ For wired connections.
++wireless+::
+ For wireless connections. This connection type requires
+ *wpa_supplicant* to be available.
++bond+::
+ Network bonding. This connection type requires *ifenslave* to be
+ available.
++bridge+::
+ Network bridging. This connection type requires *brctl* to be
+ available.
++pppoe+::
+ For PPPoE connections.
++tunnel+::
+ For tunnel interfaces.
++tuntap+::
+ For TUN/TAP interfaces.
++vlan+::
+ For VLANs on ethernet-like connections.
+
+
+GENERAL OPTIONS
+---------------
+'Description='::
+ A description of the profile.
+
+'Connection=' [mandatory for all profiles]::
+ The connection type used by the profile.
+
+'Interface=' [mandatory for all profiles]::
+ The name of the associated network interface. The interface name
+ should not be quoted.
+
+'BindsToInterfaces=()'::
+ An array of physical network interfaces that this profile needs
+ before it can be started. For `enabled' profiles, *systemd* will
+ wait for the presence of the specified interfaces before starting a
+ profile. If this variable is not specified, it defaults to the value
+ of 'Interface'.
+
+'After=()'::
+ An array of profile names that should be started before this profile
+ is started. This is only an ordering dependency and is not intended
+ to be a list of profiles that this profile requires. The meaning is
+ the same as 'After' in *systemd.unit*(5).
+
+'ExecUpPost='::
+ A command that is executed after a connection is established. If the
+ specified command returns anything other than 0 (success), *netctl*
+ will abort and stop the profile. If the command should be allowed to
+ fail, add ``|| true`' to the end of it.
+
+'ExecDownPre='::
+ A command that is executed after a connection is brought down.
+ Similar precautions should be taken as with 'ExecUpPost'.
+
+
+IP OPTIONS
+----------
+These options apply to all connections that set up an IP-enabled
+network. In particular, these connection types are +ethernet+,
++wireless+, +bond+, +bridge+, +tunnel+, +tuntap+, and +vlan+.
+
+'IP=' [mandatory for IPv4]::
+ One of `static', `dhcp', or `no', depending on the desired way of
+ obtaining an address.
+
+'IP6=' [mandatory for IPv6]::
+ One of `static', `stateless', `dhcp-noaddr', `dhcp', `no' or left
+ out (empty) altogether. The difference between not specifying and
+ setting to `no' is in the handling of __router advertisement__
+ packages, which is blocked by `no'.
+
+'Address=()' [requires 'IP=static']::
+ An array of IP addresses, optionally suffixed with ``/<netmask>`',
+ where netmask is an integer between 0 and 255. The default netmask
+ is 24. Leaving out brackets for arrays consisting of a single
+ element is accepted in the Bash syntax.
+
+'Gateway=' [requires 'IP=static']::
+ An IP routing gateway address.
+
+'Routes='::
+ An array of custom routes of the form +
+ `**<address range>** via **<gateway>**'.
+
+'Address6=()' [requires 'IP6=static']::
+ An array of IPv6 addresses. Prefix length may be specified via
+ `1234:bcd::11/64' syntax.
+
+'Gateway6=' [requires 'IP6=static']::
+ An IPv6 routing gateway address.
+
+'Routes6='::
+ An array of custom routes of the form +
+ `**<address range>** via **<gateway>**'.
+
+'DHCPClient=' [requires a DHCP setting]::
+ The name of the preferred DHCP client. Supported options are
+ `dhcpcd' and `dhclient'. Defaults to `dhcpcd'.
+
+'IPCustom=()'::
+ An array of argument lines to pass to `ip`. This can be used to
+ achieve complicated configurations within the framework of *netctl*.
+
+'Hostname='::
+ A system hostname.
+
+'DNS=()'::
+ An array of DNS nameservers. Simply specify the IP addresses of each
+ of the DNS nameservers.
-+INTERFACE+::
- The name of the associated network interface.
-+DESCRIPTION+::
- A description of the profile.
-+CONNECTION+::
- The connection type used by the profile.
+'DNSDomain='::
+ A ``domain`' line for '/etc/resolv.conf'.
-Connections define how the network is set up for the profile and also
-determine additional configuration variable that control their
-behavior. The available connection types are determined by files in
-'/usr/lib/network/connections/'.
+'DNSSearch='::
+ A ``search`' line for '/etc/resolv.conf'.
+'DNSOptions=()'::
+ An array of ``options`' lines for '/etc/resolv.conf'.
-Available connections
----------------------
-ethernet::
- Standard network configuration, suitable for wired connections.
-wireless::
- Wireless connection, with *wpa_supplicant*(1) as configuration
- back-end.
-bond::
- Bonded network interfaces using *ifenslave*.
-bridge::
- Network bridge setup using *brctl*(8).
-tuntap::
- TUN/TAP interfaces.
-tunnel::
- Tunnel interfaces.
-vlan::
- VLAN setup.
-openvpn::
- OpenVPN setup.
-ppp::
- PPP connections setup.
-pppoe::
- PPPoE connections setup.
-
-The configuration variable for these connection types is described in
-the following sections.
-
-
-Ethernet options reference
---------------------------
+'TimeoutDHCP='::
+ Maximum time, in seconds, to wait for DHCP to be successful.
+ Defaults to ``10`'.
-Description
-~~~~~~~~~~~
-This connection method uses the iproute suite of tools and dhcpcd to
-gain an IP address.
-
-+IP+ (required for IPv4)::
- Either `static' or `dhcp'. Set to `no' to have netcfg bring the interface
- up but assign no addresses. Static requires at least one of +ADDR+ or
- +IPCFG+.
-
-IPv4 options
-~~~~~~~~~~~~
-+ADDR+ (requires +IP+ of `static')::
- A single IP address to configure a static IP.
-+GATEWAY+ (requires +IP+ of `static')::
- Set specified gateway
-+NETMASK+ (requires +IP+ of `static')::
- Set specified netmask. Defaults to 24.
-+ROUTES+::
- An array of custom routes (of the form _address range_ via _gateway_)
-
-IPv6 options
-~~~~~~~~~~~~
-+IP6+ (required for IPv6)::
- Either `dhcp', `dhcp-noaddr', `stateless', `static'. Set to `no' to
- disable IPv6.
-+ADDR6+ (required when +IP6+ is `static')::
- An array of IPv6 addresses: prefix length may be specified via
- `1234:bcd::11/64' syntax.
-+GATEWAY6+ (requires +IP6+ of `static')::
- The gateway address for IPv6 routing.
-+ROUTES6+::
- An array of custom routes (of the form _address range_ via _gateway_)
-+DAD_TIMEOUT+::
- Time to wait for Duplicate Address Detection to succeed. Defaults to
- 3 seconds.
-
-DNS configuration
-^^^^^^^^^^^^^^^^^
-+DNS+::
- Array of DNS nameservers. Simply specify the IP's of each of the DNS
- nameservers.
-+DNS_OPTIONS+::
- Array of ``option'' lines for '/etc/resolv.conf'
-+SEARCH+::
- ``search'' line for '/etc/resolv.conf'
-+DOMAIN+::
- ``domain'' line for '/etc/resolv.conf'
-+HOSTNAME+::
- Set the system hostname. Ensure any hostname is correctly referenced
- in '/etc/hosts'
-
-DHCP configuration
-^^^^^^^^^^^^^^^^^^
-+DHCP_OPTIONS+ (ipv4)::
- String. Any extra arguments to pass to the dhcp client, presently
- dhcpcd.
-+DHCP_TIMEOUT+::
- Integer. Maximum time to try for a DHCP IP. Default is 10 seconds.
-+DHCLIENT+::
- yes/no. Use dhclient instead of dhcpcd. Defaults to no
-+DHCLIENT_OPTIONS+ (ipv4)::
- String. Extra options to pass to dhclient for IPv4.
-+DHCLIENT6_OPTIONS+ (ipv6)::
- String. Extra options to pass to dhclient for IPv6.
-
-802.11x Authentication
-^^^^^^^^^^^^^^^^^^^^^^
-+AUTH8021X+::
- Use 802.11x authentication. Enable with `yes'.
-+WPA_CONF+ (required for an +AUTH8021X+ of `yes' only)::
- Path to wpa_supplicant configuration. Defaults to
- '/etc/wpa_supplicant.conf'
-+WPA_OPTS+ (optional for an +AUTH8021X+ of `yes')::
- Extra arguments for wpa_supplicant not specified otherwise. Any option
- here must specify wpa_supplicant driver. Defaults to _-Dwired_.
-
-Miscellaneous options
-^^^^^^^^^^^^^^^^^^^^^
-+IPCFG+::
- Array of arguments to pass to `ip`. The power of this options is that
- it allows both simple and complicated routing configurations, within
- the framework of netcfg.
-+SKIPNOCARRIER+::
- `yes'/`no'. Don't abort interface setup if no carrier is found.
-
-
-Examples
-~~~~~~~~
-
-Using ADDR and GATEWAY to set static IP and gateway
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
----------------------
-IP="static"
-ADDR="192.168.1.23"
-GATEWAY="192.168.1.1"
----------------------
+'TimeoutDAD='::
+ Maximum time, in seconds, to wait for IPv6's Duplicate Address
+ Detection to succeed. Defaults to ``3`'.
-Using IPCFG to set a static IP and gateway with custom DNS
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
--------------------------------------------------------------------------------------
-IP="static"
-IPCFG=("addr add dev eth0 192.168.1.23/24 brd +" "route add default via 192.168.1.1")
-DNS=("208.67.222.222" "208.67.220.220")
--------------------------------------------------------------------------------------
+OPTIONS FOR `ethernet' CONNECTIONS
+----------------------------------
+Next to the *ip options*, the following are understood for connections
+of the `ethernet' type:
-Wireless options reference
---------------------------
+'SkipNoCarrier='::
+ Whether or not the absence of a carrier (plugged-in cable) is
+ acceptable. Defaults to ``no`'.
-Description
-~~~~~~~~~~~
-This connection method uses wpa_supplicant to configure a wireless
-network connection. This connection uses the 'ethernet' connection after
-successful association and thus supports all of its options.
-
-Options
-~~~~~~~
-+SECURITY+ (required for security of `wep', `wpa', `wpa-configsection' or `wpa-config')::
- One of `wpa', `wep', `none', `wpa-configsection' or `wpa-config'.
- Defaults to `none'.
-+KEY+ (required for +SECURITY+ of `wpa' or `wep' only)::
- Wireless encryption key.
-+ESSID+ (this or +AP+ is required)::
- Name of network to connect to, or hexadecimal digits (see
- `ESSID_TYPE')
-+ESSID_TYPE+ (optional, defaults to `ascii')::
- Set to `ascii' or `hex', if set to `hex', +ESSID+ will be interpreted as
- an hexadecimal +SSID+ and written unquoted to the wpa_supplicant
- configuration file.
-+AP+ (this or +ESSID+ is required)::
- AP (BSSID) of the network to connect to.
-+HIDDEN+ (optional)::
- Define this to connect to hidden ESSIDs.
-+ADHOC+ (optional)::
- Define this to use ad-hoc mode for wireless.
-+TIMEOUT+ (optional)::
- Time to wait for association. Defaults to 15 seconds.
-+SCAN+ (optional)::
- `yes'/`no'. Scan for a wireless network rather than blindly attempting to
- connect. Hidden SSID networks do not appear in a scan.
-+PRIORITY+ (optional)::
- Priority group for the network. The matched network with the highest
- priority will be selected. Defaults to 0.
-
-WPA options
-^^^^^^^^^^^
-+WPA_CONF+ (for +SECURITY+ of `wpa-config' only)::
- Path to wpa_supplicant configuration. Defaults to
- '/etc/wpa_supplicant.conf'
-+WPA_OPTS+::
- Extra arguments for wpa_supplicant not specified otherwise.
-+WPA_GROUP+::
- Group that has authority to configure wpa_supplicant via it's control
- interface. Used in any configuration that is generated by netcfg.
-+WPA_COUNTRY+ (optional, nl80211 based drivers)::
- The country where the device will be used. This allows wpa_supplicant
- to enforce any local regulatory limitations and will allow all
- appropriate channels/frequencies for your device.
-+WPA_DRIVER+ (optional)::
- A comma-separated list of wpa_supplicant driver interfaces to try.
- Defaults to `nl80211,wext'.
-
-rfkill (Radio Kill Switch) options
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-+RFKILL+::
- hard/soft A switch with physical on/off state that cannot be
- controlled via software is considered a *hard* switch. Any switch that
- can be controlled via software is considered *soft*.
-+RFKILL_NAME+::
- Some switches sysfs entries are not linked with the interface. To
- match them up, configure the name from '/sys/class/rfkill/rfkillX/name'
- here so that netcfg can identify which to control.
-
-
-Options for `bridge' connections
---------------------------------
-The options of `ethernet' connections apply to set up standard IP
-connectivity.
+'Auth8021X='::
+ Set to ``yes`' to use 802.11x authentication.
-+BRIDGE_INTERFACES+::
- List of network interfaces taking part in the bridge.
-+FWD_DELAY+::
- Forward delay of the bridge, see *brctl*(8)
-+MAX_AGE+::
- maxage parameter, see *brctl*(8)
+'WPAConfigFile='::
+ Path to a *wpa_supplicant* configuration file. Defaults to
+ '/etc/wpa_supplicant.conf'.
+'WPADriver='::
+ The *wpa_supplicant* driver to use for 802.11x authentication.
+ Defaults to ``wired`'.
-Options for `tuntap' connections
---------------------------------
-The options of `ethernet' connections apply to set up standard IP
-connectivity.
+'TimeoutCarrier='::
+ Maximum time, in seconds, to wait for a carrier. Defaults to ``5`'.
+
+'TimeoutWPA='::
+ Maximum time, in seconds, to wait for 802.11x authentication to
+ succeed. Defaults to ``15`'.
+
+
+OPTIONS FOR `wireless' CONNECTIONS
+----------------------------------
+Next to the *ip options*, the following are understood for connections
+of the `wireless' type:
+
+'Security='::
+ One of `none', `wep', `wpa', `wpa-configsection', or `wpa-config'.
+ Defaults to ``none`'.
+
+'ESSID=' [mandatory]::
+ The name of the network to connect to.
+ Special quoting rules (see below) apply.
+
+'AP='::
+ The BSSID (MAC address) of the access point to connect to.
+
+'Key='::
+ The secret key to a WEP, or WPA encrypted network.
+ Special quoting rules (see below) apply.
-+MODE+::
- Set to `tun' or `tap'.
-+USER+::
- The owning user of the tun/tap interface.
-+GROUP+::
- The owning group of the tun/tap interface.
+'Hidden='::
+ Whether or not the specified network is a hidden network. Defaults
+ to ``no`'.
+'Scan='::
+ Whether or not to scan for the presence of a network before
+ attempting to connect. Hidden networks do not appear in a scan.
+ Defaults to ``no`'.
-Options for `ppp' connections
------------------------------
-+PEER+::
- The *pppd*(8) peer to use.
-+PPP_TIMEOUT+::
- *pppd*(8) timeout.
+'AdHoc='::
+ Whether or not to use ad-hoc mode. Defaults to ``no`'.
+'Country='::
+ The country for which frequency regulations will be enforced.
-Options for `vlan' connections
+'Priority='::
+ Priority group for the network. In case of automatic profile
+ selection, the matched network with the highest priority will be
+ selected. Defaults to ``0`'.
+
+'WPAGroup='::
+ Group that has the authority to configure *wpa_supplicant* via its
+ control interface. Defaults to ``wheel`'.
+
+'WPAConfigSection=()' [mandatory for 'Security=wpa-configsection']::
+ Array of lines that form a network block for *wpa_supplicant*.
+
+'WPAConfigFile='::
+ Path to a *wpa_supplicant* configuration file. Defaults to
+ '/etc/wpa_supplicant.conf'. Used for 'Security=wpa-config'.
+
+'WPADriver='::
+ The *wpa_supplicant* driver to use. Defaults to ``nl80211,wext`'.
+
+'TimeoutWPA='::
+ Maximum time, in seconds, to wait for steps in the association and
+ authentication to succeed. Defaults to ``15`'.
+
+'RFKill='::
+ The name of an *rfkill* device. When specified, the device is used
+ to block/unblock the interface when appropriate. Names can be found
+ in '/sys/class/rfkill/rfkillX/name'. It is also possible to set this
+ variable to ``auto`'. In that case an *rfkill* device that is
+ associated with the network interface is used.
+
+
+OPTIONS FOR `bond' CONNECTIONS
------------------------------
-+INTERFACE+::
- The name of the virtual interface.
-+VLAN_PHYS_DEV+::
- The name of the associated physical interface.
-+VLAN_ID+::
- See *ip*(8).
+The interfaces of 'BindsToInterfaces' are bound together in the
+interface named by 'Interface'. All *ip options* are understood for
+connections of the `bond' type.
-Options for `tunnel' connections
+OPTIONS FOR `bridge' CONNECTIONS
--------------------------------
-Standard `ethernet' options apply for IP configuration.
+The interfaces of 'BindsToInterfaces' take part in the bridge named by
+'Interface'. Next to the *ip options*, the following are understood for
+connections of the `bridge' type:
+
+'FwdDelay='::
+ Forward delay of the bridge. See *brctl*(8) for details.
+
+'MaxAge='::
+ Maximum age parameter. See *brctl*(8) for details.
-+INTERFACE+::
- The name of the tunnel interface.
-+MODE+::
- The tunnel type (e.g. `sit'). See *ip*(8) for available modes.
-+LOCAL+::
- The address of the local end of the tunnel.
-+REMOTE+::
- The address of the remote end of the tunnel.
+OPTIONS FOR `tunnel' CONNECTIONS
+----------------------------------
+The name of the tunnel interface is specified in 'Interface'. Next to
+the *ip options*, the following are understood for connections of the
+`tunnel' type:
-Options for `bond' connections
+'Mode='::
+ The tunnel type (e.g. `sit'). See *ip*(8) for available modes.
+
+'Local='::
+ The address of the local end of the tunnel.
+'Remote='::
+ The address of the remote end of the tunnel.
+
+
+OPTIONS FOR `tuntap' CONNECTIONS
+----------------------------------
+The name of the tuntap interface is specified in 'Interface'. Next to
+the *ip options*, the following are understood for connections of the
+`tuntap' type:
+
+'Mode='::
+ Either ``tun`', or ``tap`'.
+
+'User='::
+ The owning user of the tun/tap interface.
+
+'Group='::
+ The owning group of the tun/tap interface.
+
+
+OPTIONS FOR `vlan' CONNECTIONS
------------------------------
-Standard `ethernet' options apply for IP configuration.
+The name of the vlan interface is specified in 'Interface'. The
+underlying physical interface is specified in 'BindsToInterfaces'.
+Hence, for vlan profiles, 'BindsToInterfaces' contains the name of a
+single network interface.
-+SLAVE_INTERFACES+ (Bash array)::
- An array of names of interfaces to be bound together.
+All options for connections of the `ethernet' type are understood for
+connections of the `vlan' type. Additionally, connections of the `vlan'
+type can set a vlan identifier using 'VLANID='. See *ip*(8) for details.
-Options for `openvpn' connections
----------------------------------
-+OVPN_CONFIG+::
- Path to the *openvpn*(8) config file.
-+OVPN_PID_FILE+::
- Path to the *openvpn*(8) PID file.
-+OVPN_FLAGS+::
- Options to pass to *openvpn*(8) invocation.
+SPECIAL QUOTING RULES
+---------------------
+Configuration files for *wpa_supplicant* use non-standard quoting.
+Therefore, non-standard quoting rules exist for some variables for
+connections of the `wireless' type. In particular, these variables are
+'ESSID', and 'Key'.
+
+A variable is considered *quoted* by *wpa_supplicant* if it is enclosed
+in double quotes ("). A variable is considered *non-quoted* by
+*wpa_supplicant* if it does not start with a double quote. Hexadecimal
+values are specified *non-quoted* in configuration files of
+*wpa_supplicant*. In *netctl*, variables are written to *wpa_supplicant*
+configuration files *quoted* by default. When special quoting rules
+apply, it is possible to specify an unquoted (hexadecimal) value using a
+special syntax.
+
+The special quoting rules of *netctl* are as follows. A string that
+starts with a literal double quote is considered *non-quoted*. Any other
+string is considered *quoted*. It is possible to specify quoted strings
+that start with a double quote by quoting manually. An extreme example
+is the specification of a *quoted* double quote: '`X='""""'`'. On the
+other end of the spectrum there is the *non-quoted* backslash:
+'`X=\"\\`'.
+
+Further examples of *quoted* strings (all equivalent):
+-------------
+X=string
+X="string"
+X='""string"'
+-------------
+
+Further examples of *non-quoted* strings (all equivalent):
+------------
+X=\"string
+X="\"string"
+X='"string'
+------------
+
+A mnemonic is to think of the prefix ``\"`' as saying `non'-`quote'.
SEE ALSO
--------
-include::footer.txt[]
+*netctl*(1)
diff --git a/docs/netctl.special.7.txt b/docs/netctl.special.7.txt
new file mode 100644
index 0000000..eabb4d3
--- /dev/null
+++ b/docs/netctl.special.7.txt
@@ -0,0 +1,55 @@
+NETCTL.SPECIAL(7)
+=================
+
+NAME
+----
+netctl.special - Special netctl systemd units
+
+
+SYNOPSIS
+--------
+netctl.service, netctl-auto.service, netctl-ifplugd.service
+
+
+DESCRIPTION
+-----------
+Bundled with netctl come a few systemd units that are not controlled
+through the netctl command. They can be used through the systemctl
+utility of systemd.
+
+
+SPECIAL UNITS
+-------------
+netctl.service::
+ When started, this unit tries to start the profiles that were
+ running when the unit was last stopped. In some cases, the interface
+ a profile binds to might not be available yet, when netctl.service
+ tries to bring a profile up. A simple, hackish, solution is to do:
+--------------------------------------------------------------------
+echo "[[ -t 0 ]] || sleep 3" > /etc/network.d/interfaces/<interface>
+chmod 755 /etc/network.d/interfaces/<interface>
+--------------------------------------------------------------------
+ A more concise solution is to first enable a profile through netctl
+ and then disable it again through systemctl:
+--------------------------------------------------------------------
+netctl enable <profile>
+systemctl disable netctl@<profile>
+--------------------------------------------------------------------
+ This way the unit configuration file for the profile remains in
+ existence, while the profile is not enabled.
+
+netctl-auto@<interface>.service::
+ This unit issues a scan on the interface it is used for and tries to
+ start a profile for a network it finds. It is targeted to wireless
+ interfaces.
+
+netctl-ifplugd@<interface>.service::
+ This unit starts ifplugd on the interface it is used for. It will
+ try to start a netctl profile whenever a cable is plugged into the
+ interface and stop the profile when the cable is unplugged. Note
+ that this unit does not provide network.target.
+
+
+SEE ALSO
+--------
+*netctl*(1), *netctl.profile*(5)
diff --git a/services/netctl-auto@.service b/services/netctl-auto@.service
index 81f2369..9a035da 100644
--- a/services/netctl-auto@.service
+++ b/services/netctl-auto@.service
@@ -1,12 +1,12 @@
[Unit]
-Description=Automatic wireless network connection via netcfg
+Description=Automatic wireless network connection using netctl profiles
+Documentation=man:netctl.special(7)
Before=network.target
Wants=network.target
[Service]
-EnvironmentFile=/etc/conf.d/netcfg
-ExecStart=/usr/bin/netcfg-wpa_actiond $WIRELESS_INTERFACE
-ExecStop=/usr/bin/netcfg-wpa_actiond stop $WIRELESS_INTERFACE
+ExecStart=/usr/bin/netctl-auto start %i
+ExecStop=/usr/bin/netctl-auto stop %i
RemainAfterExit=yes
Type=forking
diff --git a/services/netctl-ifplugd@.service b/services/netctl-ifplugd@.service
index 8948ac6..05cb1cf 100644
--- a/services/netctl-ifplugd@.service
+++ b/services/netctl-ifplugd@.service
@@ -1,10 +1,9 @@
[Unit]
-Description=Automatic wired network connection via netcfg
+Description=Automatic wired network connection using netctl profiles
+Documentation=man:netctl.special(7)
[Service]
-EnvironmentFile=/etc/conf.d/netcfg
-ExecStart=/usr/bin/ifplugd -i $WIRED_INTERFACE -r /etc/ifplugd/netcfg.action -fIns
-ExecStop=/usr/bin/netcfg iface-down $WIRED_INTERFACE
+ExecStart=/usr/bin/ifplugd -i %i -r /etc/ifplugd/netctl.action -fIns
[Install]
WantedBy=multi-user.target
diff --git a/services/netctl.service b/services/netctl.service
index f400be0..593d36f 100644
--- a/services/netctl.service
+++ b/services/netctl.service
@@ -1,13 +1,12 @@
[Unit]
-Description=Netcfg multi-profile daemon
+Description=(Re)store the netctl profile state
Before=network.target
-Wants=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
-ExecStart=/usr/bin/netcfg-daemon start
-ExecStop=/usr/bin/netcfg-daemon stop
+ExecStart=-/usr/bin/netctl restore
+ExecStop=/usr/bin/netctl store
KillMode=none
[Install]
diff --git a/services/netctl@.service b/services/netctl@.service
index 57229f8..9bd99b6 100644
--- a/services/netctl@.service
+++ b/services/netctl@.service
@@ -1,13 +1,14 @@
[Unit]
-Description=Netcfg networking service for profile %i
-Before=network.target
+Description=Networking for netctl profile %i
+Documentation=man:netctl.profile(5)
+Before=network.target netctl.service
Wants=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
-ExecStart=/usr/bin/netcfg check-iface %i
-ExecStop=-/usr/bin/netcfg down %i
+ExecStart=/usr/lib/network/network start %i
+ExecStop=/usr/lib/network/network stop %i
KillMode=none
[Install]
diff --git a/src/ifplugd.action b/src/ifplugd.action
index ea3a16c..3a28505 100755
--- a/src/ifplugd.action
+++ b/src/ifplugd.action
@@ -1,8 +1,10 @@
#!/bin/bash
#
-# ifplugd.action script for netcfg
+# ifplugd.action script for netctl
-. /usr/lib/network/network
+. /usr/lib/network/globals
+
+PROFILE_FILE="$STATE_DIR/ifplugd_$1.profile"
case "$2" in
up)
@@ -14,12 +16,12 @@ case "$2" in
declare -a preferred_profiles
declare -a dhcp_profiles
declare -a static_profiles
- for profile in $(list_profiles); do
+ while read -r profile; do
(
- echo "loading $profile"
- load_profile "$profile"
- [[ "$INTERFACE" == "$1" && "$CONNECTION" == "ethernet" ]] || continue
- checkyesno "${AUTO_WIRED:-no}" && exit 1 # user preferred AUTO profile
+ echo "Reading profile '$profile'"
+ source "$PROFILE_DIR/$profile"
+ [[ "$Interface" == "$1" && "$Connection" == "ethernet" ]] || continue
+ is_yes "${AutoWired:-no}" && exit 1 # user preferred AUTO profile
[[ "$IP" == "dhcp" ]] && exit 2 # dhcp profile
exit 3 # static profile
)
@@ -28,17 +30,20 @@ case "$2" in
2) dhcp_profiles+=("$profile");;
3) static_profiles+=("$profile");;
esac
- done
+ done < <(list_profiles)
if [[ ${#preferred_profiles[@]} > 1 ]]; then
- echo "AUTO_WIRED flag for $1 set in more than one profile (${preferred_profiles[*]})"
+ echo "AutoWired flag for '$1' set in more than one profile (${preferred_profiles[*]})"
fi
for profile in "${preferred_profiles[@]}" "${dhcp_profiles[@]}" "${static_profiles[@]}"; do
- profile_up "$profile" && exit 0
+ if "$SUBR_DIR/nework" start "$profile"; then
+ printf "%s" "$profile" > "$PROFILE_FILE"
+ exit 0
+ fi
done
;;
down)
- if check_iface "$1"; then
- interface_down "$1" && exit 0
+ if [[ -e "$PROFILE_FILE" ]]; then
+ "$SUBR_DIR/nework" stop "$(< "$PROFILE_FILE")" && rm -f "$PROFILE_FILE"
fi
;;
*)
diff --git a/src/lib/8021x b/src/lib/8021x
index d2ddfe4..60f3552 100644
--- a/src/lib/8021x
+++ b/src/lib/8021x
@@ -1,171 +1,129 @@
-# Usage: wpa_call $interface $call ...
-# Wrapper around wpa_cli to deal with supplicant configurations that set a
-# non-standard control path.
-wpa_call()
-{
- local args=("-i" "$1")
+## /usr/lib/network/globals needs to be sourced before this file
+
+
+## Wrapper around wpa_cli to deal with supplicant configurations that set a
+## non-standard control path.
+# $1: interface name
+# $2...: call to the supplicant
+wpa_call() {
+ local args=( "-i" "$1" )
shift
- if [[ -n "$WPA_CTRL_DIR" ]]; then
+ if [[ $WPA_CTRL_DIR ]]; then
args+=("-p" "$WPA_CTRL_DIR")
- elif [[ -n "$WPA_CONF" ]] && grep -q "^[[:space:]]*ctrl_interface=" "$WPA_CONF"; then
- WPA_CTRL_DIR=$(grep -m 1 "^[[:space:]]*ctrl_interface=" "$WPA_CONF")
+ elif [[ $WPAConfigFile ]] && grep -q "^[[:space:]]*ctrl_interface=" "$WPAConfigFile"; then
+ WPA_CTRL_DIR=$(grep -m1 "^[[:space:]]*ctrl_interface=" "$WPAConfigFile")
WPA_CTRL_DIR=${WPA_CTRL_DIR#*ctrl_interface=}
- if [[ "$WPA_CTRL_DIR" == DIR=* ]]; then
+ if [[ $WPA_CTRL_DIR == DIR=* ]]; then
WPA_CTRL_DIR=${WPA_CTRL_DIR:4}
WPA_CTRL_DIR=${WPA_CTRL_DIR%% GROUP=*}
fi
- args+=("-p" "$WPA_CTRL_DIR")
+ args+=( "-p" "$WPA_CTRL_DIR" )
fi
- report_debug wpa_cli "${args[@]}" "$@"
- wpa_cli "${args[@]}" "$@"
+ do_debug wpa_cli "${args[@]}" "$@"
}
-# Uses wpa_supplicant to check for association to a network
-# wpa_check interface [timeout]
-wpa_check()
-{
- local timeout=0 INTERFACE="$1" TIMEOUT="${2:-15}" CONDITION="${3:-COMPLETED}"
- # CONDITION is required as wired connections are ready at ASSOCIATED not COMPLETED FS#20150
-
- while (( timeout < TIMEOUT )); do
- ( # Sometimes wpa_supplicant isn't ready so silence errors for 2s only to avoid hiding real errors
- if (( timeout < 2 )); then
- eval $(wpa_call "$INTERFACE" status 2> /dev/null | grep -F "wpa_state=")
- else
- eval $(wpa_call "$INTERFACE" status | grep -F "wpa_state=")
- fi
- [[ "$wpa_state" = "$CONDITION" ]]
- ) && return 0
- sleep 1
- (( ++timeout ))
- done
- echo "$wpa_state"
- # wpa_cli -i "$INTERFACE" terminate >/dev/null 2>&1 # callers sometimes called stop_wpa, which does more but seems redundant
- # termination should either be handled properly here, or by callers
- stop_wpa "$INTERFACE"
- return 1
+## Retrieves the state of an instance of the wpa supplicant
+## Displays one of: DISCONNECTED, INTERFACE_DISABLED, INACTIVE, SCANNING,
+## AUTHENTICATING, ASSOCIATING, ASSOCIATED, 4WAY_HANDSHAKE,
+## GROUP_HANDSHAKE, COMPLETED
+# $1: interface name
+wpa_get_state() {
+ local state
+ state=$(wpa_call $1 status | grep -m1 "^wpa_state=") || return 1
+ echo ${state#wpa_state=}
}
-start_wpa()
-{
- local INTERFACE="$1" WPA_CONF="$2" WPA_DRIVER="$3"
- shift 3
- local WPA_OPTS="$@" PIDFILE="/run/wpa_supplicant_${INTERFACE}.pid"
-
- if [[ -n "$WPA_CONF" ]]; then
- WPA_CONF="-c$WPA_CONF"
- else
- WPA_CTRL_DIR="/run/wpa_supplicant"
- WPA_CONF="-C$WPA_CTRL_DIR"
- fi
-
- wpa_supplicant -B -P "$PIDFILE" -i "$INTERFACE" -D "$WPA_DRIVER" "$WPA_CONF" $WPA_OPTS
-
- # wait up to one second for the pid file to appear
- timeout_wait 1 '[[ -f "$PIDFILE" ]]';
- return $?
+## Waits until the wpa supplicant reaches a listed state
+# $1: timeout
+# $2: interface name
+# $3...: accepted states
+wpa_wait_until_state() {
+ local timeout=$1 interface=$2 states=( "${@:3}" )
+ timeout_wait "$timeout" \
+ 'in_array "$(wpa_get_state "$interface")" "${states[@]}"'
}
-stop_wpa()
-{
- local INTERFACE="$1"
- # we need this as long as wpa_cli has a different default than netcfg
- [[ -z "$WPA_CTRL_DIR" && -z "$WPA_CONF" ]] && WPA_CTRL_DIR="/run/wpa_supplicant"
-
- # done if wpa_supplicant is already terminated for this interface
- [[ -e "$WPA_CTRL_DIR/$INTERFACE" ]] || return
-
- wpa_call "$INTERFACE" terminate > /dev/null
-
- # wait up to one second for the pid file to be removed
- timeout_wait 1 '[[ ! -f "/run/wpa_supplicant_${INTERFACE}.pid" ]]' || \
- kill "$(< "/run/wpa_supplicant_${INTERFACE}.pid")" &> /dev/null &
+## Waits while the wpa supplicant is in a listed state
+# $1: timeout
+# $2: interface name
+# $3...: rejected states
+wpa_wait_while_state() {
+ local timeout=$1 interface=$2 states=( "${@:3}" )
+ timeout_wait "$timeout" \
+ '! in_array "$(wpa_get_state "$interface")" "${states[@]}"'
}
-wpa_reconfigure() {
- wpa_call "$1" reconfigure > /dev/null
- return $?
-}
+## Start an instance of the wpa supplicant
+# $1: interface name
+# $2: interface driver(s)
+# $3: configuration file
+wpa_start() {
+ local interface=$1 driver=$2 configuration=$3
+ local pidfile="/run/wpa_supplicant_$interface.pid"
-wpa_check_current_essid() {
- # usage: wpa_check_current_essid $interface $essid
- # check that wpa_supplicant is connected to the right essid
- local INTERFACE=$1 ESSID=$2 status
- status=$(wpa_call "$INTERFACE" status | grep "^ssid=")
- if (( $? == 0 )) && [[ "$status" == "ssid=$ESSID" ]]; then
- return 0
+ if [[ $configuration ]]; then
+ configuration="-c$configuration"
else
+ WPA_CTRL_DIR="/run/wpa_supplicant"
+ configuration="-C$WPA_CTRL_DIR"
+ fi
+
+ do_debug wpa_supplicant -B -P "$pidfile" -i "$interface" -D "$driver" \
+ "$configuration" $WPAOptions
+
+ # Wait up to one second for the pid file to appear
+ if ! timeout_wait 1 '[[ -f "$pidfile" ]]'; then
+ # Remove the configuration file if it was generated
+ configuration="$STATE_DIR/wpa_supplicant_$interface.conf"
+ [[ -f $configuration && -O $configuration ]] && rm -f "$configuration"
return 1
fi
}
-wpa_find_essid() {
- # usage: wpa_find_essid $INTERFACE $ESSID
- # look for existence of a given essid. Assumes wpa_supplicant is
- # running
- result=$(wpa_supplicant_scan_and_find "$1" 5 "$2")
- ret=$?
- echo $result
- report_debug wpa_find_essid "\"$result\""
- return $ret
-}
+## Stop an instance of the wpa supplicant
+# $1: interface name
+wpa_stop() {
+ local interface=$1 config_file="$STATE_DIR/wpa_supplicant_$1.conf"
+ # We need this as long as wpa_cli has a different default than netctl
+ if [[ -z $WPA_CTRL_DIR && -z $WPAConfigFile ]]; then
+ WPA_CTRL_DIR="/run/wpa_supplicant"
+ fi
-wpa_find_ap() {
- # usage: wpa_find_essid $INTERFACE $ESSID
- # look for existence of a given essid. Assumes wpa_supplicant is
- # running
- bssid=${2,,} # set to lowercase
- result=$(wpa_supplicant_scan_and_find "$1" 1 "$bssid")
- ret=$?
- echo $result
- report_debug wpa_find_ap "\"$result\""
- return $ret
-}
+ # Done if wpa_supplicant is already terminated for this interface
+ [[ -z $WPA_CTR_DIR || -e "$WPA_CTRL_DIR/$interface" ]] || return
-wpa_supplicant_scan_and_find() {
- #usage: wpa_supplicant_scan_and_find $INTERFACE $FIELD $ITEM
- # field = 1 for bssid, 5 for essid
- # item = string to lookup
- local INTERFACE="$1" FIELD="$2" ITEM="$3" RETRIES=5 scan_ok=0 try
- for ((try=0; try < $RETRIES; try++)); do
- local found
- wpa_call "$INTERFACE" scan > /dev/null
- sleep 2
- found=$(wpa_call "$INTERFACE" scan_results | tail -n+2 | cut -f "$FIELD" | grep -F -x -m 1 -- "$ITEM")
- (( $? == 0 )) && scan_ok=1
-
- # ITEM has been found, echo it
- if [[ -n "$found" ]]; then
- echo "$found"
- return 0
- fi
- done
- if (( $scan_ok != 1 )); then
- report_debug wpa_supplicant_scan_and_find "unable to retrieve scan results"
+ wpa_call "$interface" terminate > /dev/null
+ [[ -f $config_file && -O $config_file ]] && rm -f "$config_file"
+
+ # Wait up to one second for the pid file to be removed
+ if ! timeout_wait 1 '[[ ! -f "/run/wpa_supplicant_$interface.pid" ]]'; then
+ kill "$(< "/run/wpa_supplicant_$interface.pid")" &> /dev/null
fi
- return 1
}
+## Scan for networks within range
+# $1: interface name
+# $2: fields of the wpa_supplicant scan_results
wpa_supplicant_scan() {
- local INTERFACE="$1" fields="$2" spawned_wpa=0 essids
+ local interface=$1 fields=$2 spawned_wpa=0 essids
# temp file used, as keeping ESSID's with spaces in their name in arrays
# is hard, obscure and kinda nasty. This is simpler and clearer.
- [[ -z "$INTERFACE" ]] && return 1
+ [[ $interface ]] || return 1
essids=$(mktemp --tmpdir essid.XXXXXXXX)
- if [[ "$(wpa_call "$INTERFACE" ping 2> /dev/null)" != "PONG" ]]; then
- start_wpa "$INTERFACE" "" "${WPA_DRIVER:-nl80211,wext}" || return 1
+ if [[ "$(wpa_call "$interface" ping 2> /dev/null)" != "PONG" ]]; then
+ wpa_start "$interface" "${WPADriver:-nl80211,wext}" || return 1
spawned_wpa=1
fi
- wpa_call "$INTERFACE" scan > /dev/null
+ wpa_call "$interface" scan > /dev/null
# Wait at least 3 seconds for scan results
sleep 3
- # Sometimes, that is not enough (FS#29946)
- timeout_wait 7 '! wpa_call "$INTERFACE" status | grep -F -q "wpa_state=SCANNING"'
- wpa_call "$INTERFACE" scan_results |
+ # Sometimes, that is not enough
+ wpa_wait_while_state 7 "$interface" "SCANNING"
+ wpa_call "$interface" scan_results |
tail -n+2 |
sort -rn -k3 |
sort -u -k5 |
@@ -179,97 +137,100 @@ wpa_supplicant_scan() {
# Re-sort by strength as the removal disorders the list
# Cut to the AP/essid fields only
- (( $spawned_wpa == 1 )) && stop_wpa "$INTERFACE"
+ (( spawned_wpa == 1 )) && wpa_stop "$interface"
- # File of 0 length, ie. no ssid's.
+ # File of 0 length: no ssid's
if [[ ! -s "$essids" ]]; then
rm -f "$essids"
return 1
fi
echo "$essids"
- return 0
}
-# Requires already loaded profile
-make_wpa_config_file() {
- local WPA_CONFD="$STATE_DIR/wpa.$1"
-
- # make empty tmp dir with correct permissions, rename it
- check_make_state_dir
- mkdir -p /run/wpa_supplicant
- rm -rf "$WPA_CONFD"
- mv -f "$(mktemp -d --tmpdir=$STATE_DIR)" "$WPA_CONFD" || return 1
- echo "ctrl_interface=/run/wpa_supplicant" >> "$WPA_CONFD/wpa.conf"
- echo "ctrl_interface_group=${WPA_GROUP:-wheel}" >> "$WPA_CONFD/wpa.conf"
- [[ $WPA_COUNTRY ]] && echo "country=$WPA_COUNTRY" >> "$WPA_CONFD/wpa.conf"
- [[ -n "$ADHOC" ]] && echo "ap_scan=2" >> "$WPA_CONFD/wpa.conf"
- echo "$WPA_CONFD/wpa.conf"
+## Print a string within quotes, unless it starts with the "-modifier
+## Quoted: string "string" '""string"'
+## Non-quoted: \"string "\"string" '"string'
+# $1: string
+wpa_quote() {
+ local string=$1
+ if [[ $string == \"* ]]; then
+ printf '%s' "${string:1}"
+ else
+ printf '"%s"' "$string"
+ fi
}
-# Requires already loaded profile
-make_wpa_config() {
- case $SECURITY in
- none|wep|wpa)
- case "${ESSID_TYPE:-ascii}" in
- ascii)
- echo "ssid=\"$ESSID\""
- ;;
- hex)
- # Hex ESSID is written unquoted and in lowercase (FS#24333)
- echo "ssid=${ESSID,,}"
- ;;
- *)
- report_fail "ESSID_TYPE must be set to 'ascii' or 'hex'."
- return 1
- ;;
- esac
- if [[ -n "$AP" ]]; then
- echo "bssid=${AP,,}"
- fi
- [[ -n "$ADHOC" ]] && echo "mode=1"
+## Create a configuration file for wpa_supplicant without any network blocks
+# $1: interface name
+wpa_make_config_file() {
+ local config_file="$STATE_DIR/wpa_supplicant_$1.conf"
+
+ if [[ -e $config_file ]]; then
+ report_debug "The anticipated filename '$config_file' is not available"
+ return 1
+ fi
+ mkdir -p "$STATE_DIR" /run/wpa_supplicant
+ if ! : > "$config_file"; then
+ report_debug "Could not create the configuration file '$config_file'"
+ return 1
+ fi
+ chmod 600 "$config_file"
+
+ echo "ctrl_interface=/run/wpa_supplicant" >> "$config_file"
+ echo "ctrl_interface_group=${WPAGroup:-wheel}" >> "$config_file"
+ [[ $Country ]] && echo "country=$Country" >> "$config_file"
+ if is_yes "${AdHoc:-no}"; then
+ echo "ap_scan=2" >> "$config_file"
+ fi
+ echo "$config_file"
+}
+
+## Generate a network block for wpa_supplicant
+# $Security: type of wireless security
+wpa_make_config_block() {
+ case $Security in
+ none|wep|wpa)
+ echo "ssid=$(wpa_quote "$ESSID")"
+ [[ $AP ]] && echo "bssid=${AP,,}"
+ is_yes "${AdHoc:-no}" && echo "mode=1"
;;
- wpa-configsection)
- echo "$CONFIGSECTION"
+ wpa-configsection)
+ printf "%s\n" "${WPAConfigSection[@]}"
+ return
;;
- *)
+ *)
+ report_error "Unsupported security setting: '$Security'"
return 1
;;
esac
# Key management
- case $SECURITY in
- none)
+ case $Security in
+ none)
echo "key_mgmt=NONE"
;;
- wep)
+ wep)
echo "key_mgmt=NONE"
echo "wep_tx_keyidx=0"
- if [[ ${KEY:0:2} == "s:" ]]; then # TODO: does wpa_supplicant handle this as expected?
- echo "wep_key0=\"${KEY:2}\""
- else
- echo "wep_key0=$KEY"
- fi
+ echo "wep_key0=$(wpa_quote "$Key")"
;;
- wpa)
+ wpa)
echo "proto=RSN WPA"
- if [[ "${#KEY}" -eq 64 ]]; then
- echo "psk=$KEY"
+ if [[ "${#Key}" -eq 64 ]]; then
+ echo "psk=$Key"
else
- echo "psk=\"$KEY\""
+ echo "psk=$(wpa_quote "$Key")"
fi
;;
esac
# Hidden SSID
- if checkyesno ${HIDDEN:-no}; then
- echo "scan_ssid=1"
- fi
+ is_yes "${Hidden:-no}" && echo "scan_ssid=1"
# Priority group for the network
- if [[ -n "$PRIORITY" ]]; then
- echo "priority=$PRIORITY"
- fi
+ [[ $Priority ]] && echo "priority=$Priority"
}
-# vim: ft=sh ts=4 et sw=4 tw=0:
+
+# vim: ft=sh ts=4 et sw=4:
diff --git a/src/lib/auto.action b/src/lib/auto.action
index 1f29364..00a4d14 100755
--- a/src/lib/auto.action
+++ b/src/lib/auto.action
@@ -1,56 +1,57 @@
#! /bin/bash
+. /usr/lib/network/globals
+. "$SUBR_DIR/ip"
+
interface="$1"
ssid="$2"
profile="$3"
action="$4"
+PROFILE_FILE="$STATE_DIR/wpa_actiond_$interface.profile"
-. /usr/lib/network/network
+# Is it possible that we don't get a profile?!
[[ "$profile" ]] && load_profile "$profile"
+# TODO: copy some from 'network'
case $action in
- CONNECT)
- if [[ -z $profile ]]; then
- # Load interface specific config
- [[ -f "$IFACE_DIR/$interface" ]] && source "$IFACE_DIR/$interface"
- dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" -K $DHCP_OPTIONS "$interface"
- exit $?
- fi
- if ! DHCPCD_INTERNAL_OPTIONS="-K" $CONN_DIR/ethernet up "$profile"; then
- exit 1 # what to do if fail?
- fi
-
- set_profile up "$profile"
-
- if ! ( eval $POST_UP ); then # JP: sandbox the eval
- # failing POST_UP will take interface down
- "$CONN_DIR/$ethernet" down "$profile"
- exit 1
- fi
- ;;
- DISCONNECT)
- if [[ -z $profile ]]; then
- dhcpcd -k "$interface"
- exit $?
+ CONNECT)
+ if [[ -z $profile ]]; then
+ if [[ -x "$PROFILE_DIR/interfaces/$interface" ]]; then
+ source "$PROFILE_DIR/interfaces/$interface"
fi
- if ! ( eval $PRE_DOWN ); then # JP: sandbox the eval
- exit 1
- fi
- if ! "$CONN_DIR/ethernet" down "$profile"; then
- exit 1
- fi
- if ! ( eval $POST_DOWN ); then # JP: sandbox the eval
- exit 1
- fi
- set_profile down "$profile"
- ;;
- LOST|REESTABLISHED)
- # Not handled.
- exit 0
- ;;
- *)
- # ???
+ dhcpcd -qL -t "${TimeoutDHCP:-10}" $DHCPOptions -K "$interface"
+ exit $?
+ fi
+ DHCPOptions+=" -K"
+ ip_set || exit 1
+ printf "%s" "$profile" > "$PROFILE_FILE"
+ # JP: sandbox the eval
+ if ! ( eval $ExecUpPost ); then
+ # Failing ExecUpPost will take the connection down
+ netctl-auto stop "$interface"
exit 1
- ;;
+ fi
+ ;;
+ DISCONNECT)
+ if [[ -z $profile ]]; then
+ dhcpcd -k "$interface"
+ exit $?
+ fi
+ # JP: sandbox the eval
+ if ! ( eval $ExecDownPre ); then
+ exit 1
+ fi
+ ip_unset && rm -f "$PROFILE_FILE"
+ ;;
+ LOST|REESTABLISHED)
+ # Not handled.
+ exit 0
+ ;;
+ *)
+ # ???
+ exit 1
+ ;;
esac
+
+# vim: ft=sh ts=4 et sw=4:
diff --git a/src/lib/connections/bond b/src/lib/connections/bond
index bc5aa95..09e51c6 100644
--- a/src/lib/connections/bond
+++ b/src/lib/connections/bond
@@ -1,40 +1,35 @@
-#! /bin/bash
-. /usr/lib/network/network
+# Contributed by: Byron Williams <byron@112percent.com>
+
+. "$SUBR_DIR/ip"
+
IFENSLAVE="/sbin/ifenslave"
bond_up() {
- load_profile "$1"
-
- if [[ -e "/sys/class/net/$INTERFACE" ]]; then
- report_fail "Interface $INTERFACE already exists."
- exit 1
+ if is_interface "$Interface"; then
+ report_error "Interface '$Interface' already exists"
+ return 1
else
- ip link add dev $INTERFACE type bond
+ ip link add dev "$Interface" type bond
fi
- bring_interface up "$INTERFACE"
+ bring_interface_up "$Interface"
- for slave in "${SLAVE_INTERFACES[@]}"; do
- bring_interface up "$slave"
- $IFENSLAVE $INTERFACE $slave
+ for slave in "${BindsToInterfaces[@]}"; do
+ bring_interface_up "$slave"
+ $IFENSLAVE "$Interface" "$slave"
done
- "$CONN_DIR/ethernet" up "$1"
- return 0
+ ip_set
}
bond_down() {
- load_profile "$1"
-
- for slave in "${SLAVE_INTERFACES[@]}"; do
- $IFENSLAVE $INTERFACE -d $slave
+ for slave in "${BindsToInterfaces[@]}"; do
+ $IFENSLAVE "$Interface" -d "$slave"
done
- "$CONN_DIR/ethernet" down "$1"
- ip link delete "$INTERFACE"
- return 0
+ ip_unset
+ bring_interface_down "$Interface"
+ ip link delete "$Interface"
}
-bond_$1 "$2"
-exit $?
# vim: set ts=4 et sw=4:
diff --git a/src/lib/connections/bridge b/src/lib/connections/bridge
index 6b3ab67..929a76b 100644
--- a/src/lib/connections/bridge
+++ b/src/lib/connections/bridge
@@ -1,47 +1,42 @@
-#! /bin/bash
-. /usr/lib/network/network
+# Contributed by: Thomas Bächler <thomas@archlinux.org>
+
+. "$SUBR_DIR/ip"
+
BRCTL="/usr/sbin/brctl"
bridge_up() {
- local bridge_interface
- load_profile "$1"
-
- if [[ -e "/sys/class/net/$INTERFACE" ]]; then
- if [[ ! -d "/sys/class/net/$INTERFACE/brif" ]]; then
- report_fail "Interface $INTERFACE already exists and is not a bridge."
- exit 1
+ if is_interface "$Interface"; then
+ if [[ ! -d "/sys/class/net/$Interface/brif" ]]; then
+ report_error "Interface '$Interface' already exists and is not a bridge"
+ return 1
fi
else
- $BRCTL addbr "$INTERFACE"
+ $BRCTL addbr "$Interface"
fi
- for bridge_client in $BRIDGE_INTERFACES; do
- ip link set "$bridge_client" promisc on up
- ip addr flush dev "$bridge_client"
- $BRCTL addif "$INTERFACE" "$bridge_client"
+ for member in "${BindsToInterfaces[@]}"; do
+ ip link set "$member" promisc on up
+ ip addr flush dev "$member"
+ $BRCTL addif "$Interface" "$member"
done
# Set options
- [[ "$FWD_DELAY" ]] && $BRCTL setfd "$INTERFACE" "$FWD_DELAY"
- [[ "$MAX_AGE" ]] && $BRCTL setmaxage "$INTERFACE" "$MAX_AGE"
+ [[ "$FwdDelay" ]] && $BRCTL setfd "$Interface" "$FwdDelay"
+ [[ "$MaxAge" ]] && $BRCTL setmaxage "$Interface" "$MaxAge"
- "$CONN_DIR/ethernet" up "$1"
- return 0
+ bring_interface_up "$Interface"
+ ip_set
}
bridge_down() {
- local bridge_interface
- load_profile "$1"
-
- for bridge_client in $BRIDGE_INTERFACES; do
- ip link set "$bridge_client" promisc off down
- $BRCTL delif "$INTERFACE" "$bridge_client"
+ for member in "${BindsToInterfaces[@]}"; do
+ ip link set "$member" promisc off down
+ $BRCTL delif "$Interface" "$member"
done
- "$CONN_DIR/ethernet" down "$1"
- $BRCTL delbr "$INTERFACE"
- return 0
+ ip_unset
+ bring_interface_down "$Interface"
+ $BRCTL delbr "$Interface"
}
-bridge_$1 "$2"
-exit $?
+
# vim: set ts=4 et sw=4:
diff --git a/src/lib/connections/ethernet b/src/lib/connections/ethernet
index 487adf8..0fff668 100644
--- a/src/lib/connections/ethernet
+++ b/src/lib/connections/ethernet
@@ -1,279 +1,75 @@
-#! /bin/bash
-# Source file for the 'ethernet' connection
-# ethernet_up $profile
-# ethernet_down $profile
-# ethernet_status
+# Ethernet connection support for netctl
-. /usr/lib/network/network
+. "$SUBR_DIR/ip"
-report_iproute()
-{
- report_fail "$*"
- bring_interface down "$INTERFACE"
- exit 1
-}
ethernet_up() {
- load_profile "$1"
- SYSCTL_INTERFACE="${INTERFACE/.//}"
-
- if ! is_interface "$INTERFACE"; then
- report_iproute "Interface $INTERFACE does not exist"
+ if ! is_interface "$Interface"; then
+ report_error "Interface '$Interface' does not exist"
+ return 1
fi
# Disable IPv6 before bringing the interface up to prevent SLAAC
- if [[ "$IP6" == "no" ]]; then
- sysctl -q -w "net.ipv6.conf.$SYSCTL_INTERFACE.disable_ipv6=1"
+ if [[ $IP6 == "no" ]]; then
+ sysctl -q -w "net.ipv6.conf.${Interface/.//}.disable_ipv6=1"
fi
- report_debug ethernet_up bring_interface up "$INTERFACE"
- bring_interface up "$INTERFACE"
+ if ! bring_interface_up "$Interface"; then
+ report_error "Failed to bring interface '$Interface' up"
+ return 1
+ fi
- if ! checkyesno "${SKIPNOCARRIER:-no}"; then
+ if ! is_yes "${SkipNoCarrier:-no}"; then
# Some cards are plain slow to come up. Don't fail immediately.
- if ! timeout_wait "${CARRIER_TIMEOUT:-5}" '(( $(< "/sys/class/net/$INTERFACE/carrier") ))'; then
- report_iproute "No connection"
+ if ! timeout_wait "${TimeoutCarrier:-5}" '(( $(< "/sys/class/net/$Interface/carrier") ))'; then
+ report_error "No connection on interface '$Interface'"
+ bring_interface_down "$Interface"
+ return 1
fi
fi
- if checkyesno "${AUTH8021X:-no}"; then
+ if is_yes "${Auth8021X:-no}"; then
. "$SUBR_DIR/8021x"
- [[ -z "$WPA_CONF" ]] && WPA_CONF="/etc/wpa_supplicant.conf"
- [[ -z "$WPA_DRIVER" ]] && WPA_DRIVER="wired"
+ : ${WPAConfigFile:=/etc/wpa_supplicant.conf}
+ : ${WPADriver:=wired}
+ : ${TimeoutWPA:=15}
- report_debug ethernet_up start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_DRIVER" "$WPA_OPTS"
- if ! start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_DRIVER" "$WPA_OPTS"; then
- report_fail "wpa_supplicant did not start, possible configuration error"
+ if ! wpa_start "$Interface" "$WPADriver" "$WPAConfigFile"; then
+ report_error "The WPA supplicant did not start for interface '$Interface'"
+ bring_interface_down "$Interface"
return 1
fi
- if ! wpa_check "$INTERFACE" "$TIMEOUT" "ASSOCIATED"; then
- bring_interface down "$INTERFACE"
- report_fail "WPA Authentication/Association Failed"
+ if ! wpa_wait_until_state "$TimeoutWPA" "$Interface" "ASSOCIATED"; then
+ wpa_stop "$Interface"
+ bring_interface_down "$Interface"
+ report_error "WPA Authentication/Association Failed"
return 1
fi
fi
- if [[ -z "$IP" && -z "$IP6" ]]; then
- report_iproute "At least one of IP or IP6 should be specified"
+ if ! ip_set; then
+ stop_80211x
+ bring_interface_down "$Interface"
return 1
fi
-
- case "$IP" in
- dhcp)
- if checkyesno "${DHCLIENT:-no}"; then
- rm -r "/run/dhclient-${INTERFACE}.pid" >/dev/null 2>&1
- report_debug ethernet_up dhclient -q -e TIMEOUT="${DHCP_TIMEOUT:-10}" -pf "/run/dhclient-$INTERFACE.pid" "$INTERFACE"
- if ! dhclient -q -e TIMEOUT="${DHCP_TIMEOUT:-10}" -pf "/run/dhclient-${INTERFACE}.pid" ${DHCLIENT_OPTIONS} "$INTERFACE"; then
- report_fail "DHCP IP lease attempt failed."
- stop_80211x
- return 1
- fi
- else
- # Clear remaining pid files.
- rm -f "/run/dhcpcd-$INTERFACE".{pid,cache} >/dev/null 2>&1
- # If using own dns, tell dhcpcd to NOT replace resolv.conf
- [[ -n "$DNS" ]] && DHCP_OPTIONS="-C resolv.conf $DHCP_OPTIONS"
- # Start dhcpcd
- report_debug ethernet_up dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" $DHCPCD_INTERNAL_OPTIONS $DHCP_OPTIONS "$INTERFACE"
- dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" $DHCPCD_INTERNAL_OPTIONS $DHCP_OPTIONS "$INTERFACE" 2>&1 | report_debug "$(cat)"
- if [[ "$PIPESTATUS" -ne 0 ]]; then
- report_fail "DHCP IP lease attempt failed."
- stop_80211x
- return 1
- fi
- fi
- ;;
- static)
- if [[ -n "$ADDR" ]]; then
- [[ -z $NETMASK ]] && NETMASK=24
- report_debug ethernet_up ip addr add "$ADDR/$NETMASK" brd + dev "$INTERFACE"
- if ! ip addr add "$ADDR/$NETMASK" brd + dev "$INTERFACE"; then
- report_iproute "Could not configure interface"
- fi
- fi
- if [[ -n "$GATEWAY" ]]; then
- report_debug ethernet_up ip route add default via "$GATEWAY" dev "$INTERFACE"
- if ! ip route add default via "$GATEWAY" dev "$INTERFACE"; then
- report_iproute "Adding gateway $GATEWAY failed"
- fi
- fi
- ;;
- ""|no)
- ;;
- *)
- report_iproute "IP must be either 'dhcp', 'static' or 'no'"
- ;;
- esac
-
- if [[ -n "$IP" && -n "$ROUTES" ]]; then
- for route in "${ROUTES[@]}"; do
- report_debug ethernet_up ip route add $route dev "$INTERFACE"
- if ! ip route add $route dev "$INTERFACE"; then
- report_iproute "Adding route '$route' failed"
- fi
- done
- fi
-
- # Load ipv6 module if necessary (FS#25530)
- case "$IP6" in
- dhcp*|stateless|static)
- [[ -d "/proc/sys/net/ipv6" ]] || modprobe ipv6
- ;;
- no)
- [[ -d "/proc/sys/net/ipv6" ]] && sysctl -q -w "net.ipv6.conf.$SYSCTL_INTERFACE.accept_ra=0"
- ;;
- "") # undefined IP6 does not prevent RA's from being received -> nop
- ;;
- *)
- report_iproute "IP6 must be 'dhcp', 'dhcp-noaddr', 'stateless', 'static' or 'no'"
- ;;
- esac
-
- case "$IP6" in
- dhcp*)
- if ! type dhclient &>/dev/null; then
- report_fail "You need to install dhclient to use DHCPv6."
- stop_80211x
- return 1
- fi
- sysctl -q -w "net.ipv6.conf.$SYSCTL_INTERFACE.accept_ra=1"
- if [[ "$IP6" == "dhcp-noaddr" ]]; then
- DHCLIENT6_OPTIONS="-S ${DHCLIENT6_OPTIONS}"
- fi
- _DHCLIENT_PIDFILE="/run/dhclient6-${INTERFACE}.pid"
- rm -r ${_DHCLIENT_PIDFILE} &>/dev/null
- report_debug ethernet_up dhclient -6 -q -e TIMEOUT="${DHCP_TIMEOUT:-10}" -pf ${_DHCLIENT_PIDFILE} "$INTERFACE"
- if ! dhclient -6 -q -e TIMEOUT="${DHCP_TIMEOUT:-10}" -pf ${_DHCLIENT_PIDFILE} ${DHCLIENT6_OPTIONS} "$INTERFACE"; then
- report_fail "DHCPv6 IP lease attempt failed."
- stop_80211x
- return 1
- fi
- ;;
- stateless)
- sysctl -q -w "net.ipv6.conf.$SYSCTL_INTERFACE.accept_ra=1"
- ;;
- static)
- sysctl -q -w "net.ipv6.conf.$SYSCTL_INTERFACE.accept_ra=0"
- if [[ -n "$ADDR6" ]]; then
- for addr in "${ADDR6[@]}"; do
- report_debug ethernet_up ip -6 addr add $addr dev "$INTERFACE"
- if ! ip -6 addr add $addr dev "$INTERFACE"; then
- report_iproute "Could not add address '$addr' to interface"
- fi
- done
- fi
- ;;
- esac
-
- if [[ -n "$IP6" ]]; then
- # Wait for DAD to finish (FS#28887)
- report_debug ethernet_up ip -6 addr show dev "$INTERFACE" tentative
- if ! timeout_wait "${DAD_TIMEOUT:-3}" '[[ -z "$(ip -6 addr show dev "$INTERFACE" tentative)" ]]'; then
- report_iproute "Duplicate Address Detection is taking too long"
- fi
-
- # Add static IPv6 routes
- if [[ -n "$ROUTES6" ]]; then
- for route in "${ROUTES6[@]}"; do
- report_debug ethernet_up ip -6 route add $route dev "$INTERFACE"
- if ! ip -6 route add $route dev "$INTERFACE"; then
- report_iproute "Adding route '$route' failed"
- fi
- done
- fi
-
- # Set a custom gateway after waiting for DAD to finish
- if [[ "$IP6" == "static" && -n "$GATEWAY6" ]]; then
- report_debug ethernet_up ip -6 route replace default via "$GATEWAY6" dev "$INTERFACE"
- if ! ip -6 route replace default via "$GATEWAY6" dev "$INTERFACE"; then
- report_iproute "Adding gateway $GATEWAY6 failed"
- fi
- fi
- fi
-
- if [[ -n "$IPCFG" ]]; then
- for line in "${IPCFG[@]}"; do
- report_debug ethernet_up ip "$line"
- if ! ip $line; then
- report_iproute "Could not configure interface ($line)."
- fi
- done
- fi
-
- # Set hostname
- if [[ -n "$HOSTNAME" ]]; then
- report_debug ethernet_up hostname "$HOSTNAME"
- if ! echo "$HOSTNAME" >/proc/sys/kernel/hostname; then
- report_iproute "Cannot set hostname to $HOSTNAME"
- fi
- fi
-
- # Generate a new resolv.conf
- if [[ -n "$DNS" ]]; then
- : >/etc/resolv.conf
- [[ -n "$DOMAIN" ]] && echo "domain $DOMAIN" >>/etc/resolv.conf
- [[ -n "$SEARCH" ]] && echo "search $SEARCH" >>/etc/resolv.conf
- for dns in "${DNS[@]}"; do
- echo "nameserver $dns" >>/etc/resolv.conf
- done
- for dnsoption in "${DNS_OPTIONS[@]}"; do
- echo "options $dnsoption" >>/etc/resolv.conf
- done
- fi
-
- return 0
}
ethernet_down() {
- load_profile "$1"
-
- if [[ "$IP" == "dhcp" ]]; then
- if checkyesno "${DHCLIENT:-no}"; then
- if [[ -f "/run/dhclient-$INTERFACE.pid" ]]; then
- report_debug ethernet_down dhclient -q -x "$INTERFACE" -pf "/run/dhclient-$INTERFACE.pid"
- dhclient -q -x "$INTERFACE" -pf "/run/dhclient-$INTERFACE.pid" &>/dev/null
- #dhclient -q -r "$INTERFACE" &>/dev/null
- fi
- else
- if [[ -f "/run/dhcpcd-$INTERFACE.pid" ]]; then
- report_debug ethernet_down dhcpcd -qk "$INTERFACE"
- dhcpcd -qk "$INTERFACE" &>/dev/null
- fi
- fi
- fi
- if [[ "$IP6" == dhcp* ]]; then
- if [[ -f "/run/dhclient6-$INTERFACE.pid" ]]; then
- report_debug ethernet_down dhclient -6 -q -x "$INTERFACE" -pf "/run/dhclient6-$INTERFACE.pid"
- dhclient -6 -q -x "$INTERFACE" -pf "/run/dhclient6-$INTERFACE.pid" &>/dev/null
- report_debug ethernet_down /bin/kill $(< /run/dhclient6-$INTERFACE.pid)
- /bin/kill $(< /run/dhclient6-$INTERFACE.pid) &>/dev/null
- fi
- fi
-
+ ip_unset
stop_80211x
-
- if [[ "$CONNECTION" == "wireless" ]]; then
- report_debug ethernet_down bring_interface flush "$INTERFACE"
- bring_interface flush "$INTERFACE"
- else
- report_debug ethernet_down bring_interface down "$INTERFACE"
- bring_interface down "$INTERFACE"
- fi
- return 0
+ bring_interface_down "$Interface"
}
# Stop wpa_supplicant if neccessary
stop_80211x() {
- if checkyesno "${AUTH8021X:-no}"; then
+ if is_yes "${Auth8021X:-no}"; then
. "$SUBR_DIR/8021x"
- [[ -z "$WPA_CONF" ]] && WPA_CONF="/etc/wpa_supplicant.conf"
- report_debug ethernet_down stop_wpa "$INTERFACE"
- stop_wpa "$INTERFACE"
+ : ${WPAConfigFile:=/etc/wpa_supplicant.conf}
+ do_debug wpa_stop "$Interface"
fi
}
-ethernet_$1 "$2"
-exit $?
+
# vim: set ts=4 et sw=4:
diff --git a/src/lib/connections/pppoe b/src/lib/connections/pppoe
index 17fe42d..b24b503 100644
--- a/src/lib/connections/pppoe
+++ b/src/lib/connections/pppoe
@@ -1,5 +1,4 @@
-#! /bin/bash
-. /usr/lib/network/network
+# Contributed by: Thomas Bächler <thomas@archlinux.org>
_quotestring() {
echo "\"${1/\"/\\\"}\""
@@ -7,60 +6,58 @@ _quotestring() {
pppoe_up() {
local cfg
- load_profile "$1"
- mkdir -p "$STATE_DIR/pppoe.${INTERFACE}.$1/"
- chmod 700 "$STATE_DIR/pppoe.${INTERFACE}.$1/"
- cfg="$STATE_DIR/pppoe.${INTERFACE}.$1/options"
+ mkdir -p "$STATE_DIR/pppoe.${Interface}.$1/"
+ chmod 700 "$STATE_DIR/pppoe.${Interface}.${Profile}/"
+ cfg="$STATE_DIR/pppoe.${Interface}.${Profile}/options"
: > "${cfg}"
chmod 600 "${cfg}"
echo "plugin rp-pppoe.so" >> "${cfg}"
- echo "nic-${INTERFACE}" >> "${cfg}"
+ echo "nic-${Interface}" >> "${cfg}"
echo "noauth" >> "${cfg}"
- if checkyesno ${DEFAULTROUTE:-1}; then
+ if is_yes "${DefaultRoute:-yes}"; then
echo "defaultroute" >> "${cfg}"
else
echo "nodefaultroute" >> "${cfg}"
fi
- if checkyesno ${USEPEERDNS:-1}; then
+ if is_yes "${UsePeerDNS:-yes}"; then
echo "usepeerdns" >> "${cfg}"
fi
- echo "linkname $(_quotestring "$1")" >> "${cfg}"
+ echo "linkname $(_quotestring "${Profile}")" >> "${cfg}"
echo "maxfail 5" >> "${cfg}"
echo "updetach" >> "${cfg}"
- if [[ ${CONNECTION_MODE} == demand ]]; then
+ if [[ ${ConnectionMode} == demand ]]; then
echo "demand" >> "${cfg}"
- echo "idle ${IDLE_TIMEOUT}" >> "${cfg}"
+ echo "idle ${IdleTimeout}" >> "${cfg}"
else
echo "persist" >> "${cfg}"
fi
- echo "user $(_quotestring "${USER}")" >> "${cfg}"
- echo "password $(_quotestring "${PASSWORD}")" >> "${cfg}"
- [[ -n ${LCP_ECHO_INTERVAL} ]] && echo "lcp-echo-interval ${LCP_ECHO_INTERVAL}" >> "${cfg}"
- [[ -n ${LCP_ECHO_FAILURE} ]] && echo "lcp-echo-failure ${LCP_ECHO_FAILURE}" >> "${cfg}"
- [[ -n ${PPPOE_SERVICE} ]] && echo "rp_pppoe_service $(_quotestring "${PPPOE_SERVICE}")" >> "${cfg}"
- [[ -n ${PPPOE_AC} ]] && echo "rp_pppoe_ac $(_quotestring "${PPPOE_AC}")" >> "${cfg}"
- [[ -n ${PPPOE_SESSION} ]] && echo "rp_pppoe_sess $(_quotestring "${PPPOE_SESSION}")" >> "${cfg}"
- [[ -n ${PPPOE_MAC} ]] && echo "pppoe-mac $(_quotestring "${PPPOE_MAC}")" >> "${cfg}"
- [[ ${PPPOE_IP6} == yes ]] && echo "+ipv6" >> "${cfg}"
+ echo "user $(_quotestring "${User}")" >> "${cfg}"
+ echo "password $(_quotestring "${Password}")" >> "${cfg}"
+ [[ -n ${LCPEchoInterval} ]] && echo "lcp-echo-interval ${LCPEchoInterval}" >> "${cfg}"
+ [[ -n ${LCPEchoFailure} ]] && echo "lcp-echo-failure ${LCPEchoFailure}" >> "${cfg}"
+ [[ -n ${PPPoEService} ]] && echo "rp_pppoe_service $(_quotestring "${PPPoEService}")" >> "${cfg}"
+ [[ -n ${PPPoEAC} ]] && echo "rp_pppoe_ac $(_quotestring "${PPPoEAC}")" >> "${cfg}"
+ [[ -n ${PPPoESession} ]] && echo "rp_pppoe_sess $(_quotestring "${PPPoESession}")" >> "${cfg}"
+ [[ -n ${PPPoEMAC} ]] && echo "pppoe-mac $(_quotestring "${PPPoEMAC}")" >> "${cfg}"
+ [[ ${PPPoEIP6} == yes ]] && echo "+ipv6" >> "${cfg}"
- /sbin/ip link set dev "${INTERFACE}" up
+ /sbin/ip link set dev "${Interface}" up
/usr/sbin/pppd file "${cfg}"
if [[ $? -ne 0 ]]; then
rm "${cfg}"
- rmdir "$STATE_DIR/pppoe.${INTERFACE}.$1/"
- report_fail "Couldn't make pppd connection."
+ rmdir "$STATE_DIR/pppoe.${Interface}.${Profile}/"
+ report_error "Couldn't make pppd connection."
return 1
fi
}
pppoe_down() {
- load_profile "$1"
local cfg
- cfg="$STATE_DIR/pppoe.${INTERFACE}.$1/options"
- PIDFILE="/var/run/ppp-$1.pid"
+ cfg="$STATE_DIR/pppoe.${Interface}.${Profile}/options"
+ PIDFILE="/var/run/ppp-${Profile}.pid"
if [[ -e $PIDFILE ]]; then
read PID < "$PIDFILE"
@@ -68,10 +65,8 @@ pppoe_down() {
fi
rm "${cfg}"
- rmdir "$STATE_DIR/pppoe.${INTERFACE}.$1/"
+ rmdir "$STATE_DIR/pppoe.${Interface}.${Profile}/"
}
-pppoe_$1 "$2"
-exit $?
# vim: ft=sh ts=4 et sw=4:
diff --git a/src/lib/connections/tunnel b/src/lib/connections/tunnel
index 6cefc5c..f202371 100644
--- a/src/lib/connections/tunnel
+++ b/src/lib/connections/tunnel
@@ -1,34 +1,28 @@
-#! /bin/bash
-. /usr/lib/network/network
+# Contributed by: Kyle Fuller <inbox@kylefuller.co.uk>
-tunnel_up() {
- load_profile "$1"
+. "$SUBR_DIR/ip"
- if [[ -e "/sys/class/net/$INTERFACE" ]]; then
- report_fail "Interface $INTERFACE already exists."
- exit 1
+tunnel_up() {
+ if is_interface "$Interface"; then
+ report_error "Interface '$Interface' already exists"
+ return 1
else
- ip tunnel add "$INTERFACE" mode "$MODE" remote "$REMOTE"
+ ip tunnel add "$Interface" mode "$Mode" remote "$Remote"
fi
- if [[ -n "$LOCAL" ]]; then
- ip tunnel change "$INTERFACE" local "$LOCAL"
+ if [[ -n "$Local" ]]; then
+ ip tunnel change "$Interface" local "$Local"
fi
- "$CONN_DIR/ethernet" up "$1"
- return 0
+ bring_interface_up "$Interface"
+ ip_set
}
tunnel_down() {
- load_profile "$1"
-
- "$CONN_DIR/ethernet" down "$1"
- ip tunnel del "$INTERFACE"
-
- return 0
+ ip_unset
+ bring_interface_down "$Interface"
+ ip tunnel del "$Interface"
}
-tunnel_$1 "$2"
-exit $?
# vim: set ts=4 et sw=4:
diff --git a/src/lib/connections/tuntap b/src/lib/connections/tuntap
index 6985c8c..1ff5203 100644
--- a/src/lib/connections/tuntap
+++ b/src/lib/connections/tuntap
@@ -1,28 +1,24 @@
-#! /bin/bash
-. /usr/lib/network/network
+# Contributed by: Rémy Oudompheng <remy@archlinux.org>
-tuntap_up() {
- load_profile "$1"
+. "$SUBR_DIR/ip"
- if [[ -e /sys/class/net/$INTERFACE ]]; then
- report_fail "Interface $INTERFACE already exists."
- exit 1
+tuntap_up() {
+ if is_interface "$Interface"; then
+ report_error "Interface '$Interface' already exists"
+ return 1
else
- ip tuntap add dev "$INTERFACE" mode "$MODE" \
- user "$USER" group "$GROUP"
+ ip tuntap add dev "$Interface" mode "$Mode" \
+ user "$User" group "$Group"
fi
- IP=${IP-no} "$CONN_DIR/ethernet" up "$1"
- return 0
+ bring_interface_up "$Interface"
+ IP=${IP-no} ip_set
}
tuntap_down() {
- load_profile "$1"
-
- "$CONN_DIR/ethernet" down "$1"
- ip tuntap del dev "$INTERFACE" mode "$MODE"
- return 0
+ ip_unset
+ bring_interface_down "$Interface"
+ ip tuntap del dev "$Interface" mode "$Mode"
}
-tuntap_$1 "$2"
-exit $?
+
# vim: set ts=4 et sw=4 tw=0:
diff --git a/src/lib/connections/vlan b/src/lib/connections/vlan
index 75c7fa9..86d1a2d 100644
--- a/src/lib/connections/vlan
+++ b/src/lib/connections/vlan
@@ -1,28 +1,26 @@
-#! /bin/bash
-. /usr/lib/network/network
+# Contributed by: Thomas S Hatch <thatch45@gmail.com>
-vlan_up() {
- load_profile "$1"
+. "$CONN_DIR/ethernet"
- if [[ -e "/sys/class/net/$INTERFACE" ]]; then
- report_fail "Interface $INTERFACE already exists."
- exit 1
+vlan_up() {
+ if [[ ${#BindsToInterfaces} -ne 1 ]]; then
+ report_error "No unique physical device for VLAN interface '$Interface' specified"
+ return 1
+ fi
+ if is_interface "$Interface"; then
+ report_error "Interface '$Interface' already exists"
+ return 1
else
- bring_interface up "$VLAN_PHYS_DEV"
- ip link add link "$VLAN_PHYS_DEV" name "$INTERFACE" type vlan id "$VLAN_ID"
+ bring_interface_up "$BindsToInterfaces"
+ ip link add link "$BindsToInterfaces" name "$Interface" type vlan id "$VLANID"
fi
- "$CONN_DIR/ethernet" up "$1"
- return 0
+
+ ethernet_up
}
vlan_down() {
- load_profile "$1"
-
- "$CONN_DIR/ethernet" down "$1"
- ip link delete "$INTERFACE"
- return 0
+ ethernet_down
+ ip link delete "$Interface"
}
-vlan_$1 "$2"
-exit $?
# vim: set ts=4 et sw=4:
diff --git a/src/lib/connections/wireless b/src/lib/connections/wireless
index 135bec7..a3b324b 100644
--- a/src/lib/connections/wireless
+++ b/src/lib/connections/wireless
@@ -1,116 +1,89 @@
-#! /bin/bash
-. /usr/lib/network/network
+# Wireless connection support for netctl
+
. "$SUBR_DIR/8021x"
+. "$SUBR_DIR/ip"
. "$SUBR_DIR/rfkill"
-wireless_up() {
- PROFILE="$1"
- load_profile "$PROFILE"
- # Default settings
- SECURITY=${SECURITY:-none}
- WPA_DRIVER=${WPA_DRIVER:-nl80211,wext}
+wireless_up() {
+ local config_file
- enable_rf $INTERFACE $RFKILL $RFKILL_NAME || return 1
+ if ! is_interface "$Interface"; then
+ report_error "Interface '$Interface' does not exist"
+ return 1
+ fi
- # Check if interface exists
- is_interface "$INTERFACE" || { report_fail "interface $INTERFACE does not exist"; return 1; }
+ # Default settings
+ : ${Security:=none}
+ : ${WPADriver:=nl80211,wext}
+ : ${TimeoutWPA:=15}
+
+ if [[ $RFKill ]]; then
+ enable_rf "$Interface" "$RFKill" || return 1
+ fi
- # Kill any lingering wpa_supplicants.
- stop_wpa "$INTERFACE" &> /dev/null
+ # Kill any lingering WPA supplicants
+ WPAConfigFile= wpa_stop "$Interface" &> /dev/null
- # Start wpa_supplicant
- if [[ "$SECURITY" = "wpa-config" ]]; then
- WPA_CONF="${WPA_CONF:-/etc/wpa_supplicant.conf}"
+ if [[ $Security == "wpa-config" ]]; then
+ : ${WPAConfigFile:=/etc/wpa_supplicant.conf}
+ config_file=$WPAConfigFile
else
- WPA_CONF=$(make_wpa_config_file $INTERFACE)
+ config_file=$(wpa_make_config_file "$Interface")
+ if [[ -z $config_file ]]; then
+ report_error "Could not create a wpa config file for interface '$Interface'"
+ bring_interface_down "$Interface"
+ return 1
+ fi
+ printf "%s\n" "network={" "$(wpa_make_config_block)" "}" >> "$config_file"
fi
- report_debug wireless_up start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_DRIVER" "$WPA_OPTS"
- if ! start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_DRIVER" "$WPA_OPTS"; then
- report_fail "wpa_supplicant did not start, possible configuration error"
+
+ # Start the WPA supplicant
+ if ! do_debug wpa_start "$Interface" "$WPADriver" "$config_file"; then
+ report_error "The WPA supplicant did not start for interface '$Interface'"
+ bring_interface_down "$Interface"
return 1
fi
- # Scan for network's existence first
- if checkyesno "${SCAN:-no}"; then
- report_debug wireless_up scanning
- local OLDESSID="$ESSID"
- if [[ -n "$AP" ]]; then
- BSSID=$(wpa_find_ap "$INTERFACE" "$AP")
- else
- ESSID=$(wpa_find_essid "$INTERFACE" "$ESSID")
- fi
- if [[ $? -gt 0 ]]; then
- report_fail "Wireless network \"$OLDESSID\" not present."
- report_debug wireless_up stop_wpa "$INTERFACE"
- stop_wpa "$INTERFACE"
+ if is_yes "${Scan:-no}"; then
+ if ! wpa_wait_while_state "$TimeoutWPA" "$Interface" "DISCONNECTED" "SCANNING"; then
+ report_error "Wireless network '$ESSID' (or access point) not present"
+ wpa_stop "$Interface"
+ bring_interface_down "$interface"
return 1
fi
fi
-
- # Build configuration file
- case "$SECURITY" in
- wpa-config)
- ;;
- none|wep|wpa|wpa-configsection)
- printf "%s\n" "network={" "$(make_wpa_config)" "}" >> "$WPA_CONF"
- report_debug wireless_up "Configuration generated at $WPA_CONF"
- report_debug wireless_up wpa_reconfigure "$INTERFACE"
- if ! wpa_reconfigure "$INTERFACE"; then
- report_fail "WPA configuration failed!"
- stop_wpa "$INTERFACE"
- return 1
- fi
- ;;
- *)
- report_fail "Invalid SECURITY setting: $SECURITY"
- ;;
- esac
-
+
# Bring interface up after starting wpa_supplicant
# This is important since cards such as iwl3945 do not support
# mode switching when they are already up.
- report_debug wireless_up ifup
- bring_interface up "$INTERFACE" || return 1
+ bring_interface_up "$Interface" || return 1
- report_debug wireless_up wpa_check
- if ! wpa_check "$INTERFACE" "$TIMEOUT"; then
- report_fail "WPA Authentication/Association Failed"
+ if ! wpa_wait_until_state "$TimeoutWPA" "$Interface" "COMPLETED"; then
+ report_error "WPA association/authentication failed for interface '$Interface'"
+ wpa_stop "$Interface"
+ bring_interface_down "$Interface"
return 1
fi
- if ! "$CONN_DIR/ethernet" up "$PROFILE"; then
- wireless_down "$PROFILE" YES
+ if ! ip_set; then
+ wpa_stop "$Interface"
+ bring_interface_down "$Interface"
return 1
fi
}
-# wireless_down PROFILE [ LEAVE ifconfig up? default no ]
wireless_down() {
- local PROFILE="$1"
- load_profile "$PROFILE"
-
- "$CONN_DIR/ethernet" down "$PROFILE"
-
- # The config file can contain a non-standard control socket path
- if [[ "$SECURITY" = "wpa-config" ]]; then
- WPA_CONF="${WPA_CONF:-/etc/wpa_supplicant.conf}"
+ ip_unset
+ if [[ $Security == "wpa-config" ]]; then
+ : ${WPAConfigFile:=/etc/wpa_supplicant.conf}
fi
- report_debug wireless_down stop_wpa "$INTERFACE"
- stop_wpa "$INTERFACE"
- rm -rf "$STATE_DIR/wpa.$INTERFACE"
-
- bring_interface down "$INTERFACE"
-
- # Handle wireless kill switches
- # Any reason why a hardware switch should be considered on interface down?
- if [[ "$RFKILL" == "soft" ]]; then
- set_rf_state "$INTERFACE" disabled $RFKILL_NAME || return 1
+ wpa_stop "$Interface"
+ bring_interface_down "$Interface" || return 1
+ if [[ $RFKill ]]; then
+ disable_rf "$Interface" "$RFKill"
fi
}
-wireless_$1 "$2" "$3"
-exit $?
# vim: ft=sh ts=4 et sw=4 tw=0:
-
diff --git a/src/lib/globals b/src/lib/globals
index 491f9d6..8277a40 100644
--- a/src/lib/globals
+++ b/src/lib/globals
@@ -1,136 +1,121 @@
-# /usr/lib/networks/globals
-#
-# All +x files in /usr/lib/network/hooks will be sourced when this file is.
-# Hook files can override any of the utility functions defined here for custom
-# behavior (such as logging error messages to syslog). This lets us keep netcfg
-# simple but gives it the flexibility for users to make modular use of it to do
-# more complex things
-
-
-### Globals
PROFILE_DIR="/etc/network.d"
-IFACE_DIR="$PROFILE_DIR/interfaces"
SUBR_DIR="/usr/lib/network"
-HOOKS_DIR="$SUBR_DIR/hooks"
CONN_DIR="$SUBR_DIR/connections"
STATE_DIR="/run/network"
-
+STATE_FILE="${NETCTL_STATE_FILE:-/var/lib/netctl/netctl.state}"
### Logging/Error reporting
-function report_err {
+report_notice() {
echo "$*"
}
-function report_notice {
+report_error() {
echo "$*"
}
-function report_debug {
- checkyesno "$NETCFG_DEBUG" && echo "DEBUG: $*" >&2
+report_debug() {
+ is_yes "${NETCTL_DEBUG:-no}" && echo "DEBUG: $*" >&2
}
-function report_try {
- # This needs -n and a trailing space.
- echo -n ":: $* "
- REPORT_TRYING=1
+exit_error() {
+ report_error "$@" >&2
+ exit 1
}
-function report_fail {
- if [[ -n "$*" ]]; then
- if (( REPORT_TRYING )); then
- echo "- $* [fail]"
- REPORT_TRYING=
- else
- echo "$*"
- fi
- elif (( REPORT_TRYING )); then
- echo "[fail]"
- REPORT_TRYING=
- fi
-}
-function report_success {
- if [[ -n "$*" ]]; then
- # This needs -n and a trailing space.
- echo -n "- $* "
- fi
- echo "[done]"
- REPORT_TRYING=
+### Variable management
+
+## Check if a variable occurs in an array
+# $1: the variable to find
+# $2...: the array elements
+in_array() {
+ local hay needle=$1
+ shift
+ for hay; do
+ [[ $hay == "$needle" ]] && return 0
+ done
+ return 1
}
-### For calling scripts only; don't use in library functions
-function exit_stderr { echo "$*" >&2; exit 1; }
-function exit_err { report_err "$*"; exit 1; }
-function exit_fail { report_fail "$*"; exit 1; }
-
-
-### From FreeBSD's /etc/rc.subr
-##
-# checkyesno var
-# Test $1 variable, and warn if not set to YES or NO.
-# Return 0 if it's "yes" (et al), nonzero otherwise.
-# To default to yes, do: "checkyesno ${VAR:-yes}".
-#
-function checkyesno() {
- local _value="$1"
- #debug "checkyesno: $1 is set to $_value."
- case "$_value" in
-
- # "yes", "true", "on", or "1"
- [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
+## Check if a variable denotes a positive truth value
+# $1: the variable to check, use is_yes ${VAR:-yes} to set a default
+is_yes() {
+ case ${1,,} in
+ yes|true|on|1)
return 0
;;
-
- # "no", "false", "off", or "0"
- [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
+ no|false|off|0)
return 1
;;
- *)
- #warn "\$${1} is not set properly - see rc.conf(5)."
+ *)
+ report_error "Not a valid truth value: '$1'"
return 1
;;
esac
}
-## Check if variable is a member of an array
-# $1: the variable to find
-# $2...: the array elements
-function inarray() {
- local item search="$1"
- shift
- for item in "$@"; do
- if [[ "$item" == "$search" ]]; then
- return 0
- fi
- done
- return 1
+
+### Control flow
+
+## Show what we evaluate when debugging, but always evaluate
+do_debug() {
+ report_debug "${FUNCNAME[1]}:" "$@"
+ "$@"
+}
+
+## Exit if we are not effectively root
+# $1: program name (optional)
+ensure_root() {
+ (( EUID == 0 )) || exit_error "${1-$0} needs root privileges"
}
## Waits until a statement succeeds or a timeout occurs
# $1: timeout in seconds
# $2...: condition command
-function timeout_wait() {
- local timeout="$1"
- (( timeout *= 10 ))
+timeout_wait() {
+ local timeout=$1
+ (( timeout *= 5 ))
shift
while ! eval "$*"; do
(( timeout-- > 0 )) || return 1
- sleep 0.1
+ sleep 0.2
done
return 0
}
-### Load all +x files in $HOOKS_DIR
-function load_hooks() {
+### Profile management
+
+## List all acceptable profiles names (assume they don't contain newlines)
+list_profiles() {
+ # JP: follow aliases with -L, also skip profiles that end with '.conf' (so
+ # profile.conf can be the wpa.conf file for profile)
+ find -L "$PROFILE_DIR/" -maxdepth 1 -type f -not -name '.*' -not -name '*~' -not -name '*.conf' -not -name '*.service' -printf "%f\n"
+}
+
+## Sources all hooks, a profile and any interface hook
+# $1: profile name
+load_profile() {
local hook
- for hook in $(find -L "$HOOKS_DIR/" -maxdepth 1 -type f -executable | sort -u); do
+ if [[ ! -r "$PROFILE_DIR/$1" ]]; then
+ exit_error "Profile '$1' does not exist or is not readable"
+ fi
+ while read -r hook; do
source "$hook"
- done
+ done < <(find -L "$PROFILE_DIR/hooks" -maxdepth 1 -type f -executable -not -name '.*' -not -name '*~' | sort -u)
+ source "$PROFILE_DIR/$1"
+ if [[ -z $Interface ]]; then
+ exit_error "Profile '$1' does not specify an interface"
+ fi
+ if [[ ! -r "$CONN_DIR/${Connection:-/dev/null/nonexistent}" ]]; then
+ exit_error "Profile '$1' does not specify a valid connection"
+ fi
+ if [[ -x "$PROFILE_DIR/interfaces/$Interface" ]]; then
+ source "$PROFILE_DIR/interfaces/$Interface"
+ fi
}
-load_hooks
# vim: ft=sh ts=4 et sw=4:
diff --git a/src/lib/ip b/src/lib/ip
new file mode 100644
index 0000000..02d99f4
--- /dev/null
+++ b/src/lib/ip
@@ -0,0 +1,215 @@
+## /usr/lib/network/globals needs to be sourced before this file
+
+
+## Add resolv.conf entries for an interface
+# $1: interface name
+# $2...: entries, one line per variable
+resolvconf_add() {
+ local interface="$1"
+ shift
+ printf "%s\n" "$@" | resolvconf -a "$interface"
+}
+
+
+## Set up an IP configuration
+# $Interface: interface name
+# $IP: type of IPv4 configuration
+# $IP6: type of IPv6 configuration
+ip_set() {
+ local addr line route interface_sysctl=${Interface/.//}
+
+ if [[ -z $IP && -z $IP6 ]]; then
+ report_error "Neither IP, nor IP6 was specified"
+ return 1
+ fi
+
+ case $IP in
+ dhcp)
+ case ${DHCPClient:-dhcpcd} in
+ dhcpcd)
+ rm -f "/run/dhcpcd-$Interface".{pid,cache}
+ # If using own dns, tell dhcpcd to NOT replace resolv.conf
+ [[ $DNS ]] && DhcpcdOptions+=" -C resolv.conf"
+ do_debug dhcpcd -qL -t "${TimeoutDHCP:-10}" $DHCPOptions "$Interface" 2>&1 | report_debug "$(cat)"
+ # The first array value of PIPESTATUS is the exit status of dhcpcd
+ if (( PIPESTATUS != 0 )); then
+ report_error "DHCP IP lease attempt failed on interface '$Interface'"
+ return 1
+ fi
+ ;;
+ dhclient)
+ rm -f "/run/dhclient-${Interface}.pid"
+ if ! do_debug dhclient -q -e "TIMEOUT=${TimeoutDHCP:-10}" -pf "/run/dhclient-$Interface.pid" $DhclientOptions "$Interface"; then
+ report_error "DHCP IP lease attempt failed on interface '$Interface'"
+ return 1
+ fi
+ ;;
+ *)
+ report_error "Unsupported DHCP client: '$DHCPClient'"
+ return 1
+ ;;
+ esac
+ ;;
+ static)
+ if [[ $Address ]]; then
+ for addr in "${Address[@]}"; do
+ [[ $addr == */* ]] || addr+="/24"
+ if ! do_debug ip addr add "$addr" brd + dev "$Interface"; then
+ report_error "Could not add address '$addr' to interface '$Interface'"
+ return 1
+ fi
+ done
+ fi
+ if [[ $Gateway ]]; then
+ if ! do_debug ip route add default via "$Gateway" dev "$Interface"; then
+ report_error "Could not set gateway '$Gateway' on interface '$Interface'"
+ return 1
+ fi
+ fi
+ ;;
+ ""|no)
+ ;;
+ *)
+ report_error "IP must be either 'dhcp', 'static' or 'no'"
+ return 1
+ ;;
+ esac
+
+ # Add static IP routes
+ if [[ $IP && $Routes ]]; then
+ for route in "${Routes[@]}"; do
+ if ! do_debug ip route add $route dev "$Interface"; then
+ report_error "Could not add route '$route' to interface '$Interface'"
+ return 1
+ fi
+ done
+ fi
+
+ # Load ipv6 module if necessary
+ case "$IP6" in
+ dhcp*|stateless|static)
+ [[ -d "/proc/sys/net/ipv6" ]] || modprobe ipv6
+ ;;
+ no)
+ [[ -d "/proc/sys/net/ipv6" ]] && sysctl -q -w "net.ipv6.conf.$interface_sysctl.accept_ra=0"
+ ;;
+ "") # undefined IP6 does not prevent RA's from being received -> nop
+ ;;
+ *)
+ report_error "IP6 must be 'dhcp', 'dhcp-noaddr', 'stateless', 'static' or 'no'"
+ return 1
+ ;;
+ esac
+
+ case "$IP6" in
+ dhcp*)
+ if ! type dhclient &>/dev/null; then
+ report_error "You need to install dhclient to use DHCPv6"
+ return 1
+ fi
+ sysctl -q -w "net.ipv6.conf.$interface_sysctl.accept_ra=1"
+ [[ $IP6 == "dhcp-noaddr" ]] && Dhclient6Options+=" -S"
+ rm -f "/run/dhclient6-${Interface}.pid"
+ if ! do_debug dhclient -6 -q -e "TIMEOUT=${TimeoutDHCP:-10}" -pf "$Pidfile" $Dhclient6Options "$Interface"; then
+ report_error "DHCPv6 IP lease attempt failed on interface '$Interface'"
+ return 1
+ fi
+ ;;
+ stateless)
+ sysctl -q -w "net.ipv6.conf.$interface_sysctl.accept_ra=1"
+ ;;
+ static)
+ sysctl -q -w "net.ipv6.conf.$interface_sysctl.accept_ra=0"
+ if [[ -n $Address6 ]]; then
+ for addr in "${Address6[@]}"; do
+ if ! do_debug ip -6 addr add $addr dev "$Interface"; then
+ report_error "Could not add address '$addr' to interface '$Interface'"
+ fi
+ done
+ fi
+ ;;
+ esac
+
+ if [[ $IP6 ]]; then
+ # Wait for Duplicate Address Detection to finish
+ if ! timeout_wait "${TimeoutDAD:-3}" '[[ -z "$(ip -6 addr show dev "$Interface" tentative)" ]]'; then
+ report_error "Duplicate Address Detection is taking too long on interface '$Interface'"
+ return 1
+ fi
+
+ # Add static IPv6 routes
+ if [[ $Routes6 ]]; then
+ for route in "${Routes6[@]}"; do
+ if ! do_debug ip -6 route add $route dev "$Interface"; then
+ report_error "Could not add route '$route' to interface '$Interface'"
+ return 1
+ fi
+ done
+ fi
+
+ # Set a custom gateway after DAD has finished
+ if [[ $IP6 == "static" && $Gateway6 ]]; then
+ if ! do_debug ip -6 route replace default via "$Gateway6" dev "$Interface"; then
+ report_error "Could not set gateway '$Gateway6' on interface '$Interface'"
+ return 1
+ fi
+ fi
+ fi
+
+ if [[ $IPCustom ]]; then
+ for line in "${IPCustom[@]}"; do
+ if ! do_debug ip $line; then
+ report_error "Could not configure interface ($line)"
+ return 1
+ fi
+ done
+ fi
+
+ if [[ $Hostname ]]; then
+ if ! do_debug hostnamectl set-hostname "$Hostname"; then
+ report_error "Cannot set the hostname to '$Hostname'"
+ return 1
+ fi
+ fi
+
+ if [[ $DNS ]]; then
+ resolvconf_add "$Interface" \
+ "${DNSDomain/#/domain }" \
+ "${DNSSearch/#/search }" \
+ "${DNS[@]/#/nameserver }" \
+ "${DNSOptions[@]/#/options }"
+ fi
+}
+
+
+## Clean up the dynamic part of an IP configuration
+# $Interface: interface name
+# $IP: type of IPv4 configuration
+# $IP6: type of IPv6 configuration
+ip_unset() {
+ if [[ "$IP" == "dhcp" ]]; then
+ case $DHCPClient in
+ dhcpcd)
+ if [[ -f "/run/dhcpcd-$Interface.pid" ]]; then
+ do_debug dhcpcd -qk "$Interface" >/dev/null
+ fi
+ ;;
+ dhclient)
+ if [[ -f "/run/dhclient-$Interface.pid" ]]; then
+ # Alternatively, use -r instead of -x to also release the lease
+ do_debug dhclient -q -x "$Interface" -pf "/run/dhclient-$Interface.pid" >/dev/null
+ fi
+ ;;
+ esac
+ fi
+ if [[ "$IP6" == dhcp* ]]; then
+ if [[ -f "/run/dhclient6-$Interface.pid" ]]; then
+ do_debug dhclient -6 -q -x "$Interface" -pf "/run/dhclient6-$Interface.pid" >/dev/null
+ fi
+ fi
+
+ [[ $DNS ]] && resolvconf -d "$Interface"
+}
+
+
+# vim: ft=sh ts=4 et sw=4:
diff --git a/src/lib/network b/src/lib/network
index 1aa384c..1117737 100644..100755
--- a/src/lib/network
+++ b/src/lib/network
@@ -1,368 +1,95 @@
-### Globals
-. /usr/lib/network/globals
-# will load hooks
-
-## Loads a profile.
-# $1: profile name
-load_profile()
-{
- unset ROUTES
- [[ -z "$1" ]] && return 1
- if [[ ! -f "$PROFILE_DIR/$1" ]]; then
- report_err "Profile \"$1\" does not exist"
- return 1
- fi
- report_debug "Loading profile $1"
- INTERFACE=$(. "$PROFILE_DIR/$1"; echo "$INTERFACE")
- report_debug "Configuring interface $INTERFACE"
- if [[ -z "$INTERFACE" ]]; then
- report_err "Profile missing an interface to configure"
- return 1
- fi
- if [[ -f "$IFACE_DIR/$INTERFACE" ]]; then
- report_debug "Interface level configuration enabled: $IFACE_DIR/$INTERFACE"
- . "$IFACE_DIR/$INTERFACE"
- fi
- . "$PROFILE_DIR/$1" # we want profile settings to override, so need to source profile again
- if [[ ! -f "$CONN_DIR/$CONNECTION" ]]; then
- report_err "$CONNECTION is not a valid connection, check spelling or look at examples"
- return 1
- fi
-}
-
-##################
-# Profile up/down
-##################
-
-## Take all registered profiles down.
-all_down()
-{
- find "$STATE_DIR/profiles/" -maxdepth 1 -type f -printf '%f\n' \
- | while read prof; do
- profile_down "$prof"
- done
-}
+#! /bin/bash
-## Create the state dir and sub directories if they don't already exist.
-check_make_state_dir()
-{
- [[ ! -d "$STATE_DIR" ]] && mkdir -p "$STATE_DIR"/{interfaces,profiles}
- for d in interfaces profiles suspend; do
- [[ ! -d "$STATE_DIR/$d" ]] && mkdir "$STATE_DIR/$d"
- done
-}
+. /usr/lib/network/globals
-## Save the list of running profiles and take them down if needed
-# $1: interface name or "all"
-# $2: take associated profiles down (optional, default="yes")
-interface_suspend()
-{
- report_debug interface_suspend "$@"
- check_make_state_dir
- find "$STATE_DIR/profiles/" -maxdepth 1 -type f -printf '%f\n' \
- | while read prof; do
- # the pipe to "while read" will create a subshell
- INTERFACE=$(. "$STATE_DIR/profiles/$prof"; echo "$INTERFACE")
- if [[ "$1" == all || "$1" == "$INTERFACE" ]]; then
- report_notice "suspending interface $INTERFACE with profile $prof"
- cp "$STATE_DIR/profiles/$prof" "$STATE_DIR/suspend/"
- if checkyesno "${2:-yes}"; then
- profile_down "$prof"
- fi
- fi
- done
-}
-
-## Save the list of all running profiles and take them down
-all_suspend() {
- interface_suspend all
+## Check if a string represents a network interface
+# $1: potential interface name
+is_interface() {
+ # Strip any old school alias specifier
+ [[ -d "/sys/class/net/${1%%:?*}" ]]
}
-## Restore saved profiles (for resume purposes).
-# $@: a list of interfaces not to resume (e.g., because they're disabled)
-all_resume()
-{
- report_debug all_resume "$@"
- find "$STATE_DIR/suspend/" -maxdepth 1 -type f -printf '%f\n' \
- | while read prof; do
- # the pipe to "while read" will create a subshell
- INTERFACE=$(. "$STATE_DIR/suspend/$prof"; echo "$INTERFACE")
- if [[ $# -eq 0 || ! " $* " =~ " $INTERFACE " ]]; then
- report_notice "resuming interface $INTERFACE with profile $prof"
- profile_up "$prof"
- rm -f "$STATE_DIR/suspend/$prof" # if profile_up succeeds, it will have already removed this
- fi
- done
+## Check if an interface is up
+# $1: interface name
+interface_is_up() {
+ local flags
+ read flags < "/sys/class/net/${1%%:?*}/flags"
+ # IFF_UP is defined as 0x1 in linux/if.h
+ (( flags & 0x1 ))
}
-## Puts up a profile.
-# $1: the profile name
-profile_up()
-{
- (
- # Keep inside subshell so that options from one profile don't cross to others
- # exit 1 used in a subshell is effectively exiting a new process
- check_make_state_dir
-
- local status PROFILE="$1" # save PROFILE in a variable so that it's available to PRE_UP/POST_DOWN etc hooks
-
- load_profile "$PROFILE" || exit 1
-
- if check_profile "$PROFILE"; then
- report_err "$PROFILE already connected"
+## Activate an interface
+# $1: interface name
+bring_interface_up() {
+ local interface=$1
+ ip link set dev "$interface" up &>/dev/null
+ timeout_wait "${TimeoutUp:-5}" 'interface_is_up "$interface"'
+}
+
+## Deactivate an interface
+# $1: interface name
+bring_interface_down() {
+ local interface=$1
+ ip addr flush dev "$interface" &>/dev/null
+ ip link set dev "$interface" down &>/dev/null
+ # We reuse the up timeout (down normally is faster)
+ timeout_wait "${TimeoutUp:-5}" '! interface_is_up "$interface"'
+}
+
+
+if [[ $# -ne 2 || $1 != @(start|stop) ]]; then
+ exit_error "Usage: $0 {start|stop} <profile>"
+fi
+ensure_root netctl
+# Ensure we are not in a transient directory
+cd /
+
+# Expose the profile name
+Profile=$2
+load_profile "$Profile"
+source "$CONN_DIR/$Connection"
+case $1 in
+ start)
+ report_notice "Starting network profile '$Profile'..."
+ if is_interface "$Interface" && interface_is_up "$Interface" && \
+ ! is_yes "${ForceConnect:-no}"; then
+ report_error "The interface of network profile '$Profile' is already up"
exit 1
fi
-
- # EXCLUSIVE, network.d/profile: Individual profile is mutually exclusive
- if checkyesno "$EXCLUSIVE"; then
- all_down
- fi
-
- report_try "$PROFILE up"
-
- status=$(check_iface "$INTERFACE")
- report_debug "status reported to profile_up as: $status"
- case "$status" in
- external)
- report_fail "Interface $INTERFACE externally controlled"
- exit 1
- ;;
- disabled)
- report_fail "Interface $INTERFACE is disabled"
- exit 1
- ;;
- "")
- ;;
- *)
- if checkyesno "$CHECK"; then
- report_fail "Interface $INTERFACE already in use"
- exit 1
-
- # not necessary to sandbox this call or reload PROFILE afterwards
- elif ! interface_down "$INTERFACE"; then
- report_fail
- exit 1
- fi
- ;;
- esac
-
- if ! ( eval $PRE_UP ); then # JP: sandbox the eval so variables don't bleed into current function
- report_debug profile_up "PRE_UP failed"
- report_fail
+ if ! "${Connection}_up"; then
+ report_error "Failed to bring the network up for profile '$Profile'"
exit 1
fi
-
- if ! "$CONN_DIR/$CONNECTION" up "$PROFILE"; then
- report_debug profile_up "connect failed"
- report_fail
- # "$CONN_DIR/$CONNECTION" down "$PROFILE" # JP: should we do this to make sure?
+ # JP: sandbox the eval
+ if ! ( eval $ExecUpPost ); then
+ report_error "ExecUpPost failed for network profile '$Profile'"
+ # Failing ExecUpPost will take the connection down
+ "${Connection}_down"
exit 1
fi
-
- if ! ( eval $POST_UP ); then # JP: sandbox the eval
- report_debug profile_up "POST_UP failed"
- report_fail
- # failing POST_UP will take interface down
- "$CONN_DIR/$CONNECTION" down "$PROFILE"
+ report_notice "Started network profile '$Profile'"
+ ;;
+ stop)
+ report_notice "Stopping network profile '$Profile'..."
+ # JP: sandbox the eval
+ if ! ( eval $ExecDownPre ); then
+ report_error "ExecDownPre failed for network profile '$Profile'"
+ # Failing ExecDownPre will leave the profile active
exit 1
fi
-
- set_profile up "$PROFILE"
- unset EXCLUSIVE
-
- # Successfully running a new profile; erase any suspended profiles on this interface
- local iface="$INTERFACE"
- find "$STATE_DIR/suspend/" -maxdepth 1 -type f -printf '%f\n' \
- | while read prof; do
- # the pipe to "while read" will create a subshell
- INTERFACE=$(. "$STATE_DIR/suspend/$prof"; echo "$INTERFACE")
- if [[ "$iface" == "$INTERFACE" ]]; then
- rm "$STATE_DIR/suspend/$prof"
- fi
- done
-
- report_success
- ); return $?
-}
-
-## Puts a profile down.
-# $1: the profile name
-profile_down()
-{
- (
- check_make_state_dir
-
- local status PROFILE="$1" # save PROFILE in a variable so that it's available to PRE_UP/POST_DOWN etc hooks
-
- load_profile "$PROFILE" || exit 1
-
- status=$(check_iface "$INTERFACE")
- report_debug "status reported to profile_down as: $status"
-
- if [[ "$status" != "$PROFILE" ]]; then
- # if interface not available to be controlled by netcfg, then
- # any profiles should have been removed by check_iface
- # else we get here if another profile is running
- report_err "Profile not connected"
+ if ! "${Connection}_down"; then
+ report_error "Failed to bring the network down for profile '$Profile'"
exit 1
fi
-
- report_try "$PROFILE down"
- if [[ "$(check_iface "$INTERFACE")" == "external" ]]; then
- report_fail "$interface was connected by another application"
+ if is_interface "$Interface" && interface_is_up "$Interface" && \
+ ! is_yes "${ForceConnect:-no}"; then
+ report_error "The interface of network profile '$Profile' did not go down"
exit 1
fi
+ report_notice "Stopped network profile '$Profile'"
+ ;;
+esac
- if ! ( eval $PRE_DOWN ); then # JP: sandbox the eval
- report_debug profile_down "PRE_DOWN failed"
- # true # JP: did we want failing PRE_DOWN to leave the profile active?
- report_fail
- exit 1
- fi
-
- if ! "$CONN_DIR/$CONNECTION" down "$PROFILE"; then
- report_debug profile_up "disconnect failed"
- report_fail
- exit 1
- fi
-
- if ! ( eval $POST_DOWN ); then # JP: sandbox the eval
- report_debug profile_down "POST_DOWN failed"
- report_fail
- exit 1
- fi
-
- set_profile down "$PROFILE"
- report_success
- ); return $?
-}
-
-# interface_down interface
-# take interface down
-#
-interface_down()
-{
- local profile=$(check_iface "$1")
- case "$profile" in
- ""|disabled) return 0 ;;
- external) return 1 ;;
- *) profile_down "$profile" ;;
- esac
-}
-
-# interface_reconnect interface
-# reconnects the profile active on interface
-interface_reconnect()
-{
- local profile=$(check_iface "$1")
- case "$profile" in
- ""|disabled|external)
- return 1
- ;;
- *)
- profile_down "$profile"
- profile_up "$profile"
- ;;
- esac
-}
-
-##
-# check_iface interface
-# Return 0 if interface unavailable (in use by a profile or externally, or disabled)
-# Return 1 if interface down and available to be used
-#
-check_iface() {
- if [[ -f "$STATE_DIR/interfaces/$1" ]]; then
- cat "$STATE_DIR/interfaces/$1"
- return 0
- else
- return 1
- fi
-}
-
-# list_profiles
-# Outputs a list of all profiles
-list_profiles() {
- # JP: follow aliases with -L, also skip profiles that start with '.' or end with '~' or '.conf' (so profile.conf can be the wpa.conf file for profile)
- find -L "$PROFILE_DIR/" -maxdepth 1 -type f -not -name '*~' -not -name '*.conf' -not -name '.*' -printf "%f\n"
-}
-
-# check_profile profile
-# Return 0 if profile registered as being up
-# Return 1 if profile not registered
-#
-check_profile() {
- [[ -f "$STATE_DIR/profiles/$1" && ! -f "$STATE_DIR/suspend/$1" ]] && return 0
- return 1
-}
-
-### Status setting functions
-##
-# set_profile up/down profile
-# Set profile state, either up or down
-#
-set_profile() {
- local INTERFACE
- if [[ "$1" == "up" ]]; then
- INTERFACE=$(. "$PROFILE_DIR/$2"; echo "$INTERFACE")
- cp "$PROFILE_DIR/$2" "$STATE_DIR/profiles/"
- set_iface up "$INTERFACE" "$2"
- elif [[ "$1" == "down" && -f "$STATE_DIR/profiles/$2" ]]; then # JP: skip if profile not already up
- INTERFACE=$(. "$STATE_DIR/profiles/$2"; echo "$INTERFACE")
- rm "$STATE_DIR/profiles/$2"
- set_iface down "$INTERFACE" "$2"
- fi
-}
-
-# set_iface up/down interface [profile]
-# Set interface status to up/down
-# optionally link it to a profile.
-#
-set_iface() {
- local PROFILE="${3:-external}"
- if [[ "$1" == "up" ]]; then
- echo "$PROFILE" > "$STATE_DIR/interfaces/$2"
- elif [[ "$1" == "down" ]]; then
- rm -f "$STATE_DIR/interfaces/$2" # JP: add -f so we don't complain if the interface isn't up
- fi
-}
-
-is_interface() {
- local INTERFACE="$1"
- if [[ ! -e "/sys/class/net/$INTERFACE" ]]; then
- if ! echo "$INTERFACE" | grep -F -q ":"; then
- return 1
- fi
- fi
- return 0
-}
-
-interface_is_up() {
- local flags
- read flags < "/sys/class/net/$1/flags"
- # IFF_UP is defined as 0x1 in linux/if.h
- (( flags & 0x1 ))
-}
-
-## Changes a network interface state.
-# $1: up, flush, or down.
-# $2: the interface name
-bring_interface()
-{
- local INTERFACE="$2"
- case "$1" in
- up)
- ip link set dev "$INTERFACE" up &>/dev/null
- timeout_wait "${UP_TIMEOUT:-5}" 'interface_is_up "$INTERFACE"' || return 1
- ;;
- flush|down)
- ip addr flush dev "$INTERFACE" &>/dev/null
- ;;&
- down)
- ip link set dev "$INTERFACE" down &>/dev/null
- ;;
- esac
-}
# vim: ft=sh ts=4 et sw=4:
diff --git a/src/lib/rfkill b/src/lib/rfkill
index 1832dc1..996e463 100644
--- a/src/lib/rfkill
+++ b/src/lib/rfkill
@@ -1,61 +1,60 @@
-set_rf_state() {
- local INTERFACE="$1" state="$2" RFKILL_NAME="$3"
+## /usr/lib/network/globals needs to be sourced before this file
- if [[ "$RFKILL" == "hard" ]]; then
- report_fail "Cannot set state on hardware rfkill switch"
- return 1
- fi
- local path=$(get_rf_path "$INTERFACE" "$RFKILL_NAME") || return 1
- case "$state" in
- enabled)
- echo 0 > "$path/soft"
- ;;
- disabled)
- echo 1 > "$path/soft"
- ;;
- esac
-}
+## Determine the system interface of an rfkill device
+# $1: interface name
+# $2: rfkill name
get_rf_path() {
- local INTERFACE="$1" RFKILL_NAME="$2" path
+ local interface=$1 rfkill_name=${2:-auto} path
- if [[ -n "$RFKILL_NAME" ]]; then
+ if [[ $rfkill_name == "auto" ]]; then
+ path=$(find -L "/sys/class/net/$interface/" -maxdepth 2 -type d -name "rfkill*" 2> /dev/null | head -n 1)
+ if [[ $path ]]; then
+ echo "$path"
+ return 0
+ fi
+ report_error "No rfkill switch available on interface '$interface'"
+ else
for path in /sys/class/rfkill/*; do
- if [[ "$(< "$path/name")" == "$RFKILL_NAME" ]]; then
+ if [[ $(< "$path/name") == "$rfkill_name" ]]; then
echo "$path"
return 0
fi
done
- report_fail "no rfkill switch with name $RFKILL_NAME"
- else
- path=$(find -L "/sys/class/net/$INTERFACE/" -maxdepth 2 -type d -name "rfkill*" 2> /dev/null | head -n 1)
- if [[ -n "$path" ]]; then
- echo "$path"
- return 0
- fi
- report_fail "no rfkill switch available on interface $INTERFACE"
+ report_error "No rfkill switch with name '$rfkill_name'"
fi
return 1
}
+## Unblock transmission through a wireless device
+# $1: interface name
+# $2: rfkill name
enable_rf() {
- local INTERFACE="$1" RFKILL="$2" RFKILL_NAME="$3" path hard soft
-
- # Enable rfkill if necessary, or fail if it is hardware
- if [[ -n "$RFKILL" ]]; then
- path=$(get_rf_path "$INTERFACE" "$RFKILL_NAME") || return 1
- read hard < "$path/hard"
- read soft < "$path/soft"
-
- if (( hard )); then
- report_fail "radio is disabled on $INTERFACE"
- return 1
- elif (( soft )); then
- set_rf_state "$INTERFACE" enabled "$RFKILL_NAME" || return 1
- timeout_wait 1 "(( ! \$(< \"$path/soft\") ))"
- fi
+ local interface=$1 rfkill=$2 path hard soft
+
+ path=$(get_rf_path "$interface" "$rfkill") || return 1
+ read hard < "$path/hard"
+ read soft < "$path/soft"
+
+ if (( hard )); then
+ report_error "Transmission is hard-blocked on interface '$interface'"
+ return 1
+ elif (( soft )); then
+ do_debug echo 0 > "$path/soft"
+ timeout_wait 1 '(( ! $(< "$path/soft") ))'
fi
}
-# vim: ft=sh ts=4 et sw=4:
+## Block transmission through a wireless device
+# $1: interface name
+# $2: rfkill name
+disable_rf() {
+ local interface=$1 rfkill=$2 path
+
+ path=$(get_rf_path "$interface" "$rfkill") || return 1
+ do_debug echo 1 > "$path/soft"
+ timeout_wait 1 '(( $(< "$path/soft") ))'
+}
+
+# vim: ft=sh ts=4 et sw=4:
diff --git a/src/netctl b/src/netctl
index f1d79e8..0a82f89 100755
--- a/src/netctl
+++ b/src/netctl
@@ -1,106 +1,150 @@
-#!/bin/bash
+#! /bin/bash
-. /usr/lib/network/network
+. /usr/lib/network/globals
-NETCFG_VER=2-notpackaged
+NETCTL_VERSION=notpackaged
-version()
-{
- echo "netcfg v$NETCFG_VER"
-}
-usage()
-{
- version
+usage() {
cat << END
-Usage:
- Start specified profile: netcfg profile
- Other functions: netcfg argument profile
-Arguments:
- current Report currently running profiles
--a, all-down Take all active profiles down
--c, check-iface Do not start profile if interface is already up
--d, down Take specified profile down
--D, iface-down Take down profile active on specified interface
--h, help This help message
--l, list List all available profiles
--r, reconnect Disconnect and reconnect specified profile
--R, iface-recon Reconnect profile active on specified interface
--u, up Start specified profile
--v, version Output version information and exit
- all-resume Resume previously suspended profiles and reconnect them
- all-suspend Store a list of current running profiles and suspend them
+Usage: netctl {COMMAND} [PROFILE]
+ [--help|--version]
+
+Commands:
+ list List available profiles
+ store Save which profiles are active
+ restore Load saved profiles
+ stop-all Stops all profiles.
+ start [PROFILE] Start a profile
+ stop [PROFILE] Stop a profile
+ restart [PROFILE] Restart a profile
+ switch-to [PROFILE] Switch to a profile
+ status [PROFILE] Show runtime status of a profile
+ enable [PROFILE] Enable the systemd unit for a profile
+ disable [PROFILE] Disable the systemd unit for a profile
+ reenable [PROFILE] Reenable the systemd unit for a profile
END
}
-# TODO: Re-add ROOT check and rewrite with getopts from BashFAQ
-
-case "$1" in
- --version|-v|version)
- version
- exit 0;;
- --help|-h|help)
- usage
- exit 0;;
- list|-l)
- list_profiles
- exit 0;;
- current|-s|status)
- if [[ -d "$STATE_DIR/profiles/" ]]; then
- ls "$STATE_DIR/profiles/"
- exit 0
- else
- exit_stderr "No active profiles."
- fi;;
-esac
+list() {
+ local indicators=( '*' ' ' )
+ list_profiles | while read -r Profile; do
+ systemctl is-active --quiet "netctl@$Profile.service" &> /dev/null
+ # Make the return variable boolean
+ [[ $? -eq 0 ]]; printf '%s %s\n' "${indicators[$?]}" "$Profile"
+ done
+}
+
+store() {
+ systemctl list-units --type=service --full --no-legend --no-pager | \
+ cut -d\ -f1 | grep "^netctl@" > "$STATE_FILE"
+}
+
+restore() {
+ if [[ ! -r $STATE_FILE ]]; then
+ exit_error "Could not read state file '$STATE_FILE'"
+ fi
+ mapfile -t Units < "$STATE_FILE"
+ do_debug systemctl start "${Units[@]}"
+}
+
+stop_all() {
+ # We cannot pipe to mapfile, as the end of a pipe is inside a subshell
+ mapfile -t Profiles < <(list_profiles)
+ do_debug systemctl stop "${Profiles[@]/#/netctl@}" 2> \
+ >(grep -Fv "not loaded" >&2)
+}
+
+switch_to() {
+ cd "$PROFILE_DIR"
+ if [[ ! -r $1 ]]; then
+ exit_error "Profile '$1' does not exist or is not readable"
+ fi
+ # We assume interface names are not quoted
+ # Using read removes leading whitespace
+ read InterfaceLine < \
+ <(grep -om1 "^[[:space:]]*Interface=[[:alnum:]:._-]\+" "$1")
+ if [[ -z $InterfaceLine ]]; then
+ exit_error "Profile '$1' does not specify an interface"
+ fi
+ mapfile -t AllProfiles < <(list_profiles)
+ mapfile -t Profiles < <(grep -Fl "$InterfaceLine" "${AllProfiles[@]}")
+ do_debug systemctl stop "${Profiles[@]/#/netctl@}" 2> \
+ >(grep -Fv "not loaded" >&2)
+ do_debug systemctl start "netctl@$1"
+}
+
+unit_enable() {
+ local unit="/etc/systemd/system/netctl@$1.service"
+ if [[ -e $unit ]]; then
+ report_error "A unit file for profile '$1' already exists"
+ return 1
+ fi
+ load_profile "$1"
+ echo ".include /usr/lib/systemd/system/netctl@.service" > "$unit"
+ echo -e "\n[Unit]" >> "$unit"
+ [[ -n $Description ]] && echo "Description=$Description" >> "$unit"
+ : ${BindsToInterfaces=$Interface}
+ printf 'BindsTo=sys-subsystem-net-devices-%s.device\n' \
+ "${BindsToInterfaces[@]}" >> "$unit"
+ if [[ -n $After ]]; then
+ printf 'After="netctl@%s.service"\n' "${After[@]//\"/\\\"}" >> "$unit"
+ fi
+ systemctl daemon-reload
+ systemctl reenable "netctl@$1.service"
+}
-if [[ $(id -u) -gt 0 ]]; then
- exit_stderr "This script should be run as root."
-fi
-
-# Ensure cwd is not in a transient directory, which may prevent unmounting due to netcfg children
-cd /
-
-case "$1" in
- -c|check-iface|-u|up)
- CHECK="YES"
- profile_up "$2";;
- -d|down)
- profile_down "$2";;
- -D|iface-down)
- interface_down "$2";;
- -a|all-down)
- all_down;;
- -r|reconnect)
- profile_down "$2"
- profile_up "$2";;
- -R|iface-recon)
- interface_reconnect "$2";;
- all-resume)
- all_resume;;
- all-suspend)
- all_suspend;;
- clean)
- rm "$STATE_DIR/interfaces"/* 2> /dev/null
- rm "$STATE_DIR/profiles"/* 2> /dev/null
- rm "$STATE_DIR/suspend"/* 2> /dev/null
- rm "$STATE_DIR/netcfg-daemon" 2> /dev/null
- killall wpa_supplicant 2> /dev/null
- killall dhcpcd 2> /dev/null
- killall dhclient 2> /dev/null
- ;;
- -*|--*)
- usage
- exit 1;;
- *)
- if [[ -n "$1" ]]; then
- profile_up "$1"
- else
- usage
- exit 1
- fi
- ;;
+unit_disable() {
+ local unit="/etc/systemd/system/netctl@$1.service"
+ if systemctl is-enabled --quiet "netctl@$1.service"; then
+ systemctl disable "netctl@$1.service"
+ fi
+ if [[ ! -f $unit ]]; then
+ report_error "No regular unit file found for profile '$1'"
+ return 1
+ fi
+ do_debug rm "$unit"
+ systemctl daemon-reload
+}
+
+
+case $# in
+ 1)
+ case $1 in
+ --version)
+ report_notice "netctl version $NETCTL_VERSION";;
+ --help)
+ usage;;
+ list)
+ list;;
+ store|restore)
+ ensure_root "$(basename "$0")"
+ "$1";;
+ stop-all)
+ stop_all;;
+ *)
+ exit_error "$(usage)";;
+ esac;;
+ 2)
+ case $1 in
+ start|stop|restart|status)
+ systemctl $1 "netctl@$2";;
+ switch-to)
+ ensure_root "$(basename "$0")"
+ switch_to "$2";;
+ enable|disable)
+ ensure_root "$(basename "$0")"
+ "unit_$1" "$2";;
+ reenable)
+ ensure_root "$(basename "$0")"
+ unit_disable "$2"
+ unit_enable "$2";;
+ *)
+ exit_error "$(usage)";;
+ esac;;
+ *)
+ exit_error "$(usage)";;
esac
-exit $?
+
# vim: ft=sh ts=4 et sw=4:
diff --git a/src/netctl-auto b/src/netctl-auto
index c6aaf67..3452969 100755
--- a/src/netctl-auto
+++ b/src/netctl-auto
@@ -1,87 +1,74 @@
#! /bin/bash
-. /usr/lib/network/network
+
+. /usr/lib/network/globals
. "$SUBR_DIR/8021x"
. "$SUBR_DIR/rfkill"
-. /etc/conf.d/netcfg
AUTOWIFI="/usr/sbin/wpa_actiond -p /run/wpa_supplicant"
-ACTION_SCRIPT="/usr/bin/netcfg-wpa_actiond-action"
+ACTION_SCRIPT="/usr/lib/network/auto.action"
-case $1 in
- help)
- echo "netcfg-wpa_actiond <interface>"
- echo "netcfg-wpa_actiond stop <interface>"
- exit
- ;;
- stop)
- [[ -z $2 ]] && echo "Please specify an interface to stop" && exit 1
- interface=$2
- PIDFILE="/run/wpa_actiond_${interface}.pid"
- [[ -f "$IFACE_DIR/$interface" ]] && source "$IFACE_DIR/$interface"
- netcfg -D "$interface"
- timeout_wait 1 '[[ ! -f "$PIDFILE" ]]' || kill "$(< "$PIDFILE")"
- # only try to disable software rfkill switches (FS#25514)
- if [[ "$RFKILL" == "soft" ]]; then
- set_rf_state "$interface" disabled $RFKILL_NAME || exit $?
- fi
- exit
- ;;
- *)
- interface=$1; shift
- PIDFILE="/run/wpa_actiond_${interface}.pid"
- EXTRA_AUTOWIFI_OPTIONS="$*"
- ;;
-esac
-
-if [[ -z $interface ]]; then
- echo "No interface specified"
- exit 1
+if [[ $# != 2 || $1 != @(start|stop) ]]; then
+ exit_error "Usage: netctl-auto [start|stop] <interface>"
fi
-# Load interface specific config
-[[ -f "$IFACE_DIR/$interface" ]] && source "$IFACE_DIR/$interface"
-
-if [[ -f "$CONN_DIR/interfaces/$interface" ]]; then
- netcfg -D "$interface"
-fi
-
-if [[ -n "$RFKILL" ]]; then # Enable radio if necessary
- enable_rf "$interface" "$RFKILL" "$RFKILL_NAME" || exit $?
-fi
-
-WPA_CONF="$(make_wpa_config_file "$interface")"
-
-if [[ -n "${AUTO_PROFILES}" ]]; then
- for prof in "${AUTO_PROFILES[@]}"; do echo "$prof"; done
-else
- list_profiles
-fi | while read profile; do
- echo "$profile"
- (
- load_profile "$profile"
-
- [[ $CONNECTION != "wireless" ]] && exit 1
- [[ $INTERFACE != $interface ]] && exit 1
- # Exclude wpa-config, the wpa_conf is 'complete' and doesn't fit in this scheme
- [[ -z "$SECURITY" ]] && SECURITY="none"
- [[ $SECURITY == "wpa-config" ]] && exit 1
+INTERFACE=$2
+PIDFILE="$STATE_DIR/wpa_actiond_$INTERFACE.pid"
+PROFILE_FILE="$STATE_DIR/wpa_actiond_$INTERFACE.profile"
+shift 2
- printf "%s\n" "network={" "$(make_wpa_config)" "id_str=\"$profile\"" "}" >> "$WPA_CONF"
- )
-done
-
-
-[[ -z $WPA_DRIVER ]] && WPA_DRIVER="nl80211,wext"
-WPA_OPTS="-W $WPA_OPTS"
-
-# Kill any existing wpa_supplicant on this interface
-stop_wpa "$interface" &> /dev/null
-
-if start_wpa "$interface" "$WPA_CONF" "$WPA_DRIVER" $WPA_OPTS; then
- if $AUTOWIFI -i "$interface" -P "$PIDFILE" -a "$ACTION_SCRIPT" $EXTRA_AUTOWIFI_OPTIONS; then
- exit 0
+case $1 in
+ start)
+ if [[ -e "/run/wpa_supplicant_$INTERFACE.pid" ]]; then
+ exit_error "The interface ($INTERFACE) is already in use"
fi
-fi
+ if [[ -x "$PROFILE_DIR/interfaces/$INTERFACE" ]]; then
+ source "$PROFILE_DIR/interfaces/$INTERFACE"
+ fi
+ [[ $RFKill ]] && enable_rf "$INTERFACE" "$RFKill" || exit 1
+
+ WPA_CONF=$(wpa_make_config_file "$INTERFACE")
+ list_profiles | while read -r profile; do
+ report_notice "$profile"
+ (
+ source "$PROFILE_DIR/$profile"
+ is_yes "${ExcludeAuto:-no}"&& exit 1
+ : ${Security:=none}
+ [[ $Interface != "$INTERFACE" ]] && exit 1
+ [[ $Connection != "wireless" ]] && exit 1
+ # Exclude wpa-config, the wpa_conf is 'complete' and doesn't fit in this scheme
+ [[ $Security == "wpa-config" ]] && exit 1
+
+ printf "%s\n" "network={" "$(wpa_make_config_block)" "id_str=\"$profile\"" "}" >> "$WPA_CONF"
+ )
+ done
+
+ # Kill any lingering WPA supplicants
+ WPAConfigFile= wpa_stop "$INTERFACE" &> /dev/null
+
+ # Start the WPA supplicant
+ : ${WPADriver:=nl80211,wext}
+ WPAOptions+=" -W"
+ if wpa_start "$INTERFACE" "$WPADriver" "$WPA_CONF"; then
+ if $AUTOWIFI -i "$INTERFACE" -P "$PIDFILE" -a "$ACTION_SCRIPT" "$@"; then
+ exit 0
+ fi
+ fi
+ exit 1
+ ;;
+ stop)
+ if [[ -e $PROFILE_FILE ]]; then
+ "$SUBR_DIR/network" stop "$(< "$PROFILE_FILE")" && rm -f "$PROFILE_FILE"
+ else
+ if [[ -x "$PROFILE_DIR/interfaces/$INTERFACE" ]]; then
+ source "$PROFILE_DIR/interfaces/$INTERFACE"
+ fi
+ wpa_stop "$INTERFACE"
+ ip link set dev "$INTERFACE" down
+ [[ $RFKill ]] && disable_rf "$INTERFACE" "$RFKill"
+ fi
+ timeout_wait 1 '[[ ! -f "$PIDFILE" ]]' || kill "$(< "$PIDFILE")"
+ ;;
+esac
-exit 1
+# vim: ft=sh ts=4 et sw=4:
diff --git a/src/wifi-menu b/src/wifi-menu
index f46db0d..8c8189a 100755
--- a/src/wifi-menu
+++ b/src/wifi-menu
@@ -1,24 +1,21 @@
#! /bin/bash
-. /usr/lib/network/network
+. /usr/lib/network/globals
. "$SUBR_DIR/8021x"
-. /etc/conf.d/netcfg
+
usage()
{
cat << END
-Usage: wifi-menu [-o | --obscure] [-h | --help] [interface]
+Usage: wifi-menu [-h | --help] [-o | --obscure] [interface]
Interactively connect to a wireless network.
Arguments:
+ -h, --help Show this help.
-o, --obscure Show asterisks for the characters of the password
and store the password as a hexadecimal string.
- -h, --help Show this help.
- interface The wireless interface to use.
- (default: WIRELESS_INTERFACE from /etc/conf.d/netcfg)
-
-For choosing from all available profiles, use netcfg-menu.
+ interface The wireless interface to use (default: wlan0).
END
}
@@ -30,10 +27,10 @@ init_profiles()
while read profile; do
essid=$(
unset INTERFACE ESSID
- . "$PROFILE_DIR/$profile" &> /dev/null
- if [[ "$INTERFACE" = "$1" && -n "$ESSID" ]]; then
+ source "$PROFILE_DIR/$profile" > /dev/null
+ if [[ "$Interface" = "$1" && -n "$ESSID" ]]; then
printf "%s" "$ESSID"
- if [[ "$DESCRIPTION" =~ "Automatically generated" ]]; then
+ if [[ "$Description" =~ "Automatically generated" ]]; then
return 2
else
return 1
@@ -61,8 +58,8 @@ init_entries()
while IFS=$'\t' read signal flags ssid; do
ENTRIES[i++]="--" # $ssid might look like an option to dialog.
ENTRIES[i++]=$ssid
- if inarray "$ssid" "${ESSIDS[@]}"; then
- if inarray "$(ssid_to_profile "$ssid")" "${GENERATED[@]}"; then
+ if in_array "$ssid" "${ESSIDS[@]}"; then
+ if in_array "$(ssid_to_profile "$ssid")" "${GENERATED[@]}"; then
ENTRIES[i]="+" # Automatically generated
else
ENTRIES[i]="*" # Handmade
@@ -124,13 +121,13 @@ create_profile()
fi
fi
cat << EOF > "$PROFILE_DIR/$PROFILE"
-CONNECTION='wireless'
-DESCRIPTION='Automatically generated profile by wifi-menu'
-INTERFACE='$INTERFACE'
-SECURITY='$security'
+Description='Automatically generated profile by wifi-menu'
+Interface=$INTERFACE
+Connection=wireless
+Security=$security
ESSID=$(printf "%q" "$1")
IP='dhcp'
-${key+KEY=$key}
+${key+Key=$key}
EOF
printf "%s" "$PROFILE"
return 0
@@ -142,17 +139,14 @@ connect_to_ssid()
{
local msg
PROFILE=$(ssid_to_profile "$1")
- if [[ $? -eq 0 ]]; then
- clear
- check_profile "$PROFILE" && profile_down "$PROFILE"
- else
+ if [[ $? -ne 0 ]]; then
PROFILE=$(create_profile "$1")
RETURN=$?
(( RETURN == 0 )) || return $RETURN
SPAWNED_PROFILE=1
- clear
fi
- if ! profile_up "$PROFILE"; then
+ clear
+ if ! netctl restart "$PROFILE"; then
if (( SPAWNED_PROFILE )); then
msg=" CONNECTING FAILED
@@ -183,40 +177,35 @@ while [[ "$1" = -* ]]; do
esac
done
if [[ $# -gt 1 ]]; then
- report_err "Too many arguments"
+ report_error "Too many arguments"
usage
exit 255
fi
-if [[ $(id -u) -ne 0 ]]; then
- exit_stderr "This script needs to be run with root privileges"
-fi
+ensure_root "$(basename "$0")"
if ! type dialog &> /dev/null; then
- exit_stderr "Please install 'dialog' to use wifi-menu"
+ exit_error "Please install 'dialog' to use wifi-menu"
fi
-INTERFACE=${1-$WIRELESS_INTERFACE}
+INTERFACE=${1-wlan0}
if [[ -z "$INTERFACE" ]]; then
- report_err "Missing interface specification"
+ report_error "Missing interface specification"
usage
exit 255
fi
cd / # We do not want to spawn anything that can block unmounting
-is_interface "$INTERFACE" || exit_fail "No such interface: $INTERFACE"
-if ! interface_is_up "$INTERFACE"; then
- [[ -f "$IFACE_DIR/$INTERFACE" ]] && . "$IFACE_DIR/$INTERFACE"
- bring_interface up "$INTERFACE" || exit_fail "Interface unavailable"
- SPAWNED_INTERFACE=1
+if [[ ! -d "/sys/class/net/$INTERFACE" ]]; then
+ exit_error "No such interface: $INTERFACE"
fi
-report_try "Scanning for networks"
+echo -n "Scanning for networks... "
CONNECTION=$(wpa_call "$INTERFACE" status 2> /dev/null | grep -m 1 "^ssid=")
CONNECTION=${CONNECTION#ssid=}
NETWORKS=$(wpa_supplicant_scan "$INTERFACE" 3,4,5)
if [[ $? -eq 0 ]]; then
trap 'rm -f "$NETWORKS"' EXIT
- report_success
+ echo "done"
init_profiles "$INTERFACE"
init_entries "$NETWORKS"
MSG="Select the network you wish to use
@@ -233,7 +222,7 @@ Flags description:
RETURN=$?
fi
else
- report_fail
+ echo "failed"
RETURN=3
fi
@@ -244,20 +233,19 @@ case $RETURN in
clear
;;
3) # No networks found
- report_err "No networks found"
+ report_error "No networks found"
;;
4) # Invalid passphrase length (WEP keys have tighter restrictions)
clear
- report_err "Passphrase must be 8..63 characters"
+ report_error "Passphrase must be 8..63 characters"
;;
255) # ESC or error
clear
- report_err "Aborted"
+ report_error "Aborted"
;;
*) # Should not happen
- report_err "Unexpected return code from dialog: $RETURN"
+ report_error "Unexpected return code from dialog: $RETURN"
RETURN=7
;;
esac
-(( RETURN && SPAWNED_INTERFACE )) && bring_interface down "$INTERFACE"
exit $RETURN