summaryrefslogtreecommitdiffstats
path: root/hooks
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2017-03-16 09:54:30 +0000
committerRoy Marples <roy@marples.name>2017-03-16 09:54:30 +0000
commit5bfdb2ea4d393006a71a0bfe35c977ba3d098c46 (patch)
tree9dc6a209a44c7c34a9c39b78dda54b359c80060b /hooks
parent579ef7ab845d1c10096b18d17da042ce13bc2f0a (diff)
downloaddhcpcd-5bfdb2ea4d393006a71a0bfe35c977ba3d098c46.tar.xz
Move dhcpcd-hooks dir to hooks
Diffstat (limited to 'hooks')
-rw-r--r--hooks/01-test8
-rw-r--r--hooks/02-dump8
-rw-r--r--hooks/10-wpa_supplicant119
-rw-r--r--hooks/15-timezone48
-rw-r--r--hooks/20-resolv.conf204
-rw-r--r--hooks/29-lookup-hostname40
-rw-r--r--hooks/30-hostname165
-rw-r--r--hooks/50-dhcpcd-compat41
-rw-r--r--hooks/50-ntp.conf141
-rw-r--r--hooks/50-yp.conf56
-rw-r--r--hooks/50-ypbind.in86
-rw-r--r--hooks/Makefile63
-rw-r--r--hooks/dhcpcd-run-hooks.8.in217
-rw-r--r--hooks/dhcpcd-run-hooks.in387
14 files changed, 1583 insertions, 0 deletions
diff --git a/hooks/01-test b/hooks/01-test
new file mode 100644
index 00000000..d4cf8281
--- /dev/null
+++ b/hooks/01-test
@@ -0,0 +1,8 @@
+# Echo the interface flags, reason and message options
+
+if [ "$reason" = "TEST" ]; then
+ set | grep "^\(interface\|pid\|reason\|profile\|skip_hooks\)=" | sort
+ set | grep "^if\(carrier\|flags\|mtu\|wireless\|ssid\)=" | sort
+ set | grep "^\(new_\|old_\|nd[0-9]*_\)" | sort
+ exit 0
+fi
diff --git a/hooks/02-dump b/hooks/02-dump
new file mode 100644
index 00000000..0d515f78
--- /dev/null
+++ b/hooks/02-dump
@@ -0,0 +1,8 @@
+# Just echo our DHCP options we have
+
+case "$reason" in
+DUMP|DUMP6)
+ set | sed -ne 's/^new_//p' | sort
+ exit 0
+ ;;
+esac
diff --git a/hooks/10-wpa_supplicant b/hooks/10-wpa_supplicant
new file mode 100644
index 00000000..9eec0c1f
--- /dev/null
+++ b/hooks/10-wpa_supplicant
@@ -0,0 +1,119 @@
+# Start, reconfigure and stop wpa_supplicant per wireless interface.
+# This is needed because wpa_supplicant lacks hotplugging of any kind
+# and the user should not be expected to have to wire it into their system
+# if the base system doesn't do this itself.
+
+if [ -z "$wpa_supplicant_conf" ]; then
+ for x in \
+ /etc/wpa_supplicant/wpa_supplicant-"$interface".conf \
+ /etc/wpa_supplicant/wpa_supplicant.conf \
+ /etc/wpa_supplicant-"$interface".conf \
+ /etc/wpa_supplicant.conf \
+ ; do
+ if [ -s "$x" ]; then
+ wpa_supplicant_conf="$x"
+ break
+ fi
+ done
+fi
+: ${wpa_supplicant_conf:=/etc/wpa_supplicant.conf}
+
+wpa_supplicant_ctrldir()
+{
+ local dir
+
+ dir=$(key_get_value "[[:space:]]*ctrl_interface=" \
+ "$wpa_supplicant_conf")
+ dir=$(trim "$dir")
+ case "$dir" in
+ DIR=*)
+ dir=${dir##DIR=}
+ dir=${dir%%[[:space:]]GROUP=*}
+ dir=$(trim "$dir")
+ ;;
+ esac
+ printf %s "$dir"
+}
+
+wpa_supplicant_start()
+{
+ local dir err errn
+
+ # If the carrier is up, don't bother checking anything
+ [ "$ifcarrier" = "up" ] && return 0
+
+ # Pre flight checks
+ if [ ! -s "$wpa_supplicant_conf" ]; then
+ syslog warn \
+ "$wpa_supplicant_conf does not exist"
+ syslog warn "not interacting with wpa_supplicant(8)"
+ return 1
+ fi
+ dir=$(wpa_supplicant_ctrldir)
+ if [ -z "$dir" ]; then
+ syslog warn \
+ "ctrl_interface not defined in $wpa_supplicant_conf"
+ syslog warn "not interacting with wpa_supplicant(8)"
+ return 1
+ fi
+
+ wpa_cli -p "$dir" -i "$interface" status >/dev/null 2>&1 && return 0
+ syslog info "starting wpa_supplicant"
+ driver=${wpa_supplicant_driver:+-D}$wpa_supplicant_driver
+ err=$(wpa_supplicant -B -c"$wpa_supplicant_conf" -i"$interface" \
+ "$driver" 2>&1)
+ errn=$?
+ if [ $errn != 0 ]; then
+ syslog err "failed to start wpa_supplicant"
+ syslog err "$err"
+ fi
+ return $errn
+}
+
+wpa_supplicant_reconfigure()
+{
+ local dir err errn
+
+ dir=$(wpa_supplicant_ctrldir)
+ [ -z "$dir" ] && return 1
+ if ! wpa_cli -p "$dir" -i "$interface" status >/dev/null 2>&1; then
+ wpa_supplicant_start
+ return $?
+ fi
+ syslog info "reconfiguring wpa_supplicant"
+ err=$(wpa_cli -p "$dir" -i "$interface" reconfigure 2>&1)
+ errn=$?
+ if [ $errn != 0 ]; then
+ syslog err "failed to reconfigure wpa_supplicant"
+ syslog err "$err"
+ fi
+ return $errn
+}
+
+wpa_supplicant_stop()
+{
+ local dir err errn
+
+ dir=$(wpa_supplicant_ctrldir)
+ [ -z "$dir" ] && return 1
+ wpa_cli -p "$dir" -i "$interface" status >/dev/null 2>&1 || return 0
+ syslog info "stopping wpa_supplicant"
+ err=$(wpa_cli -i"$interface" terminate 2>&1)
+ errn=$?
+ if [ $errn != 0 ]; then
+ syslog err "failed to start wpa_supplicant"
+ syslog err "$err"
+ fi
+ return $errn
+}
+
+if [ "$ifwireless" = "1" ] && \
+ type wpa_supplicant >/dev/null 2>&1 && \
+ type wpa_cli >/dev/null 2>&1
+then
+ case "$reason" in
+ PREINIT) wpa_supplicant_start;;
+ RECONFIGURE) wpa_supplicant_reconfigure;;
+ DEPARTED) wpa_supplicant_stop;;
+ esac
+fi
diff --git a/hooks/15-timezone b/hooks/15-timezone
new file mode 100644
index 00000000..0ccdc45b
--- /dev/null
+++ b/hooks/15-timezone
@@ -0,0 +1,48 @@
+# Configure timezone
+
+: ${localtime:=/etc/localtime}
+
+set_zoneinfo()
+{
+ local zoneinfo_dir= zone_file=
+
+ [ -z "$new_tzdb_timezone" ] && return 0
+
+ for d in \
+ /usr/share/zoneinfo \
+ /usr/lib/zoneinfo \
+ /var/share/zoneinfo \
+ /var/zoneinfo \
+ ; do
+ if [ -d "$d" ]; then
+ zoneinfo_dir="$d"
+ break
+ fi
+ done
+
+ if [ -z "$zoneinfo_dir" ]; then
+ syslog warning "timezone directory not found"
+ return 1
+ fi
+
+ zone_file="$zoneinfo_dir/$new_tzdb_timezone"
+ if [ ! -e "$zone_file" ]; then
+ syslog warning "no timezone definition for $new_tzdb_timezone"
+ return 1
+ fi
+
+ if copy_file "$zone_file" "$localtime"; then
+ syslog info "timezone changed to $new_tzdb_timezone"
+ fi
+}
+
+# For ease of use, map DHCP6 names onto our DHCP4 names
+case "$reason" in
+BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
+ new_tzdb_timezone="$new_dhcp6_tzdb_timezone"
+ ;;
+esac
+
+if $if_up; then
+ set_zoneinfo
+fi
diff --git a/hooks/20-resolv.conf b/hooks/20-resolv.conf
new file mode 100644
index 00000000..e4db368d
--- /dev/null
+++ b/hooks/20-resolv.conf
@@ -0,0 +1,204 @@
+# Generate /etc/resolv.conf
+# Support resolvconf(8) if available
+# We can merge other dhcpcd resolv.conf files into one like resolvconf,
+# but resolvconf is preferred as other applications like VPN clients
+# can readily hook into it.
+# Also, resolvconf can configure local nameservers such as bind
+# or dnsmasq. This is important as the libc resolver isn't that powerful.
+
+resolv_conf_dir="$state_dir/resolv.conf"
+NL="
+"
+: ${resolvconf:=resolvconf}
+
+build_resolv_conf()
+{
+ local cf="$state_dir/resolv.conf.$ifname"
+ local interfaces= header= search= srvs= servers= x=
+
+ # Build a list of interfaces
+ interfaces=$(list_interfaces "$resolv_conf_dir")
+
+ # Build the resolv.conf
+ if [ -n "$interfaces" ]; then
+ # Build the header
+ for x in ${interfaces}; do
+ header="$header${header:+, }$x"
+ done
+
+ # Build the search list
+ domain=$(cd "$resolv_conf_dir"; \
+ key_get_value "domain " ${interfaces})
+ search=$(cd "$resolv_conf_dir"; \
+ key_get_value "search " ${interfaces})
+ set -- ${domain}
+ domain="$1"
+ [ -n "$2" ] && search="$search $*"
+ [ -n "$search" ] && search="$(uniqify $search)"
+ [ "$domain" = "$search" ] && search=
+ [ -n "$domain" ] && domain="domain $domain$NL"
+ [ -n "$search" ] && search="search $search$NL"
+
+ # Build the nameserver list
+ srvs=$(cd "$resolv_conf_dir"; \
+ key_get_value "nameserver " ${interfaces})
+ for x in $(uniqify ${srvs}); do
+ servers="${servers}nameserver $x$NL"
+ done
+ fi
+ header="$signature_base${header:+ $from }$header"
+
+ # Assemble resolv.conf using our head and tail files
+ [ -f "$cf" ] && rm -f "$cf"
+ [ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
+ echo "$header" > "$cf"
+ if [ -f /etc/resolv.conf.head ]; then
+ cat /etc/resolv.conf.head >> "$cf"
+ else
+ echo "# /etc/resolv.conf.head can replace this line" >> "$cf"
+ fi
+ printf %s "$domain$search$servers" >> "$cf"
+ if [ -f /etc/resolv.conf.tail ]; then
+ cat /etc/resolv.conf.tail >> "$cf"
+ else
+ echo "# /etc/resolv.conf.tail can replace this line" >> "$cf"
+ fi
+ if change_file /etc/resolv.conf "$cf"; then
+ chmod 644 /etc/resolv.conf
+ fi
+ rm -f "$cf"
+}
+
+# Extract any ND DNS options from the RA
+# For now, we ignore the lifetime of the DNS options unless they
+# are absent or zero.
+# In this case they are removed from consideration.
+# See draft-gont-6man-slaac-dns-config-issues-01 for issues
+# regarding DNS option lifetime in ND messages.
+eval_nd_dns()
+{
+
+ eval ltime=\$nd${i}_rdnss${j}_lifetime
+ if [ -z "$ltime" -o "$ltime" = 0 ]; then
+ rdnss=
+ else
+ eval rdnss=\$nd${i}_rdnss${j}_servers
+ fi
+ eval ltime=\$nd${i}_dnssl${j}_lifetime
+ if [ -z "$ltime" -o "$ltime" = 0 ]; then
+ dnssl=
+ else
+ eval dnssl=\$nd${i}_dnssl${j}_search
+ fi
+
+ [ -z "$rdnss" -a -z "$dnssl" ] && return 1
+
+ [ -n "$rdnss" ] && new_rdnss="$new_rdnss${new_rdnss:+ }$rdnss"
+ [ -n "$dnssl" ] && new_dnssl="$new_dnssl${new_dnssl:+ }$dnssl"
+ j=$(($j + 1))
+ return 0
+}
+
+add_resolv_conf()
+{
+ local x= conf="$signature$NL" warn=true
+ local i j ltime rdnss dnssl new_rdnss new_dnssl
+
+ # Loop to extract the ND DNS options using our indexed shell values
+ i=1
+ j=1
+ while true; do
+ while true; do
+ eval_nd_dns || break
+ done
+ i=$(($i + 1))
+ j=1
+ eval_nd_dns || break
+ done
+ [ -n "$new_rdnss" ] && \
+ new_domain_name_servers="$new_domain_name_servers${new_domain_name_servers:+ }$new_rdnss"
+ [ -n "$new_dnssl" ] && \
+ new_domain_search="$new_domain_search${new_domain_search:+ }$new_dnssl"
+
+ # Derive a new domain from our various hostname options
+ if [ -z "$new_domain_name" ]; then
+ if [ "$new_dhcp6_fqdn" != "${new_dhcp6_fqdn#*.}" ]; then
+ new_domain_name="${new_dhcp6_fqdn#*.}"
+ elif [ "$new_fqdn" != "${new_fqdn#*.}" ]; then
+ new_domain_name="${new_fqdn#*.}"
+ elif [ "$new_host_name" != "${new_host_name#*.}" ]; then
+ new_domain_name="${new_host_name#*.}"
+ fi
+ fi
+
+ # If we don't have any configuration, remove it
+ if [ -z "$new_domain_name_servers" -a \
+ -z "$new_domain_name" -a \
+ -z "$new_domain_search" ]; then
+ remove_resolv_conf
+ return $?
+ fi
+
+ if [ -n "$new_domain_name" ]; then
+ set -- $new_domain_name
+ if valid_domainname "$1"; then
+ conf="${conf}domain $1$NL"
+ else
+ syslog err "Invalid domain name: $1"
+ fi
+ # If there is no search this, make this one
+ if [ -z "$new_domain_search" ]; then
+ new_domain_search="$new_domain_name"
+ [ "$new_domain_name" = "$1" ] && warn=true
+ fi
+ fi
+ if [ -n "$new_domain_search" ]; then
+ if valid_domainname_list $new_domain_search; then
+ conf="${conf}search $new_domain_search$NL"
+ elif ! $warn; then
+ syslog err "Invalid domain name in list:" \
+ "$new_domain_search"
+ fi
+ fi
+ for x in ${new_domain_name_servers}; do
+ conf="${conf}nameserver $x$NL"
+ done
+ if type "$resolvconf" >/dev/null 2>&1; then
+ [ -n "$ifmetric" ] && export IF_METRIC="$ifmetric"
+ printf %s "$conf" | "$resolvconf" -a "$ifname"
+ return $?
+ fi
+
+ if [ -e "$resolv_conf_dir/$ifname" ]; then
+ rm -f "$resolv_conf_dir/$ifname"
+ fi
+ [ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
+ printf %s "$conf" > "$resolv_conf_dir/$ifname"
+ build_resolv_conf
+}
+
+remove_resolv_conf()
+{
+ if type "$resolvconf" >/dev/null 2>&1; then
+ "$resolvconf" -d "$ifname" -f
+ else
+ if [ -e "$resolv_conf_dir/$ifname" ]; then
+ rm -f "$resolv_conf_dir/$ifname"
+ fi
+ build_resolv_conf
+ fi
+}
+
+# For ease of use, map DHCP6 names onto our DHCP4 names
+case "$reason" in
+BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
+ new_domain_name_servers="$new_dhcp6_name_servers"
+ new_domain_search="$new_dhcp6_domain_search"
+ ;;
+esac
+
+if $if_up || [ "$reason" = ROUTERADVERT ]; then
+ add_resolv_conf
+elif $if_down; then
+ remove_resolv_conf
+fi
diff --git a/hooks/29-lookup-hostname b/hooks/29-lookup-hostname
new file mode 100644
index 00000000..04ad275e
--- /dev/null
+++ b/hooks/29-lookup-hostname
@@ -0,0 +1,40 @@
+# Lookup the hostname in DNS if not set
+
+lookup_hostname()
+{
+ [ -z "$new_ip_address" ] && return 1
+ local h=
+ # Silly ISC programs love to send error text to stdout
+ if type dig >/dev/null 2>&1; then
+ h=$(dig +short -x $new_ip_address)
+ if [ $? = 0 ]; then
+ echo "$h" | sed 's/\.$//'
+ return 0
+ fi
+ elif type host >/dev/null 2>&1; then
+ h=$(host $new_ip_address)
+ if [ $? = 0 ]; then
+ echo "$h" \
+ | sed 's/.* domain name pointer \(.*\)./\1/'
+ return 0
+ fi
+ elif type getent >/dev/null 2>&1; then
+ h=$(getent hosts $new_ip_address)
+ if [ $? = 0 ]; then
+ echo "$h" | sed 's/[^ ]* *\([^ ]*\).*/\1/'
+ return 0
+ fi
+ fi
+ return 1
+}
+
+set_hostname()
+{
+ if [ -z "$new_host_name" -a -z "$new_fqdn_name" ]; then
+ export new_host_name="$(lookup_hostname)"
+ fi
+}
+
+if $if_up; then
+ set_hostname
+fi
diff --git a/hooks/30-hostname b/hooks/30-hostname
new file mode 100644
index 00000000..6f8623f8
--- /dev/null
+++ b/hooks/30-hostname
@@ -0,0 +1,165 @@
+# Set the hostname from DHCP data if required
+
+# A hostname can either be a short hostname or a FQDN.
+# hostname_fqdn=true
+# hostname_fqdn=false
+# hostname_fqdn=server
+
+# A value of server means just what the server says, don't manipulate it.
+# This could lead to an inconsistent hostname on a DHCPv4 and DHCPv6 network
+# where the DHCPv4 hostname is short and the DHCPv6 has an FQDN.
+# DHCPv6 has no hostname option.
+# RFC4702 section 3.1 says FQDN should be prefered over hostname.
+#
+# As such, the default is hostname_fqdn=true so that a consistent hostname
+# is always assigned.
+: ${hostname_fqdn:=true}
+
+# If we used to set the hostname, but relinquish control of it, we should
+# reset to the default value.
+: ${hostname_default=localhost}
+
+# Some systems don't have hostname(1)
+_hostname()
+{
+ local name=
+
+ if [ -z "${1+x}" ]; then
+ if type hostname >/dev/null 2>&1; then
+ hostname
+ elif [ -r /proc/sys/kernel/hostname ]; then
+ read name </proc/sys/kernel/hostname && echo "$name"
+ elif sysctl kern.hostname >/dev/null 2>&1; then
+ sysctl -n kern.hostname
+ elif sysctl kernel.hostname >/dev/null 2>&1; then
+ sysctl -n kernel.hostname
+ else
+ return 1
+ fi
+ return $?
+ fi
+
+ # Always prefer hostname(1) if we have it
+ if type hostname >/dev/null 2>&1; then
+ hostname "$1"
+ elif [ -w /proc/sys/kernel/hostname ]; then
+ echo "$1" >/proc/sys/kernel/hostname
+ elif sysctl kern.hostname >/dev/null 2>&1; then
+ sysctl -w "kern.hostname=$1"
+ elif sysctl kernel.hostname >/dev/null 2>&1; then
+ sysctl -w "kernel.hostname=$1"
+ else
+ # We know this will fail, but it will now fail
+ # with an error to stdout
+ hostname "$1"
+ fi
+}
+
+need_hostname()
+{
+ local hfqdn=false hshort=false
+
+ # Always load the hostname variable for future use
+ hostname="$(_hostname)"
+ case "$hostname" in
+ ""|"(none)"|localhost|localhost.localdomain|"$hostname_default")
+ return 0;;
+ esac
+
+ case "$force_hostname" in
+ [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|1) return 0;;
+ esac
+
+ case "$hostname_fqdn" in
+ [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|1) hfqdn=true;;
+ ""|[Ss][Ee][Rr][Vv][Ee][Rr]) ;;
+ *) hshort=true;;
+ esac
+
+ if [ -n "$old_fqdn" ]; then
+ if ${hfqdn} || ! ${hsort}; then
+ [ "$hostname" = "$old_fqdn" ]
+ else
+ [ "$hostname" = "${old_fqdn%%.*}" ]
+ fi
+ elif [ -n "$old_host_name" ]; then
+ if ${hfqdn}; then
+ if [ -n "$old_domain_name" -a \
+ "$old_host_name" = "${old_host_name#*.}" ]
+ then
+ [ "$hostname" = \
+ "$old_host_name.$old_domain_name" ]
+ else
+ [ "$hostname" = "$old_host_name" ]
+ fi
+ elif ${hshort}; then
+ [ "$hostname" = "${old_host_name%%.*}" ]
+ else
+ [ "$hostname" = "$old_host_name" ]
+ fi
+ else
+ # No old hostname
+ false
+ fi
+}
+
+try_hostname()
+{
+
+ [ "$hostname" = "$1" ] && return 0
+ if valid_domainname "$1"; then
+ syslog info "Setting hostname: $1"
+ _hostname "$1"
+ else
+ syslog err "Invalid hostname: $1"
+ fi
+}
+
+set_hostname()
+{
+ local hfqdn=false hshort=false
+
+ need_hostname || return
+
+ case "$hostname_fqdn" in
+ [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|1) hfqdn=true;;
+ ""|[Ss][Ee][Rr][Vv][Ee][Rr]) ;;
+ *) hshort=true;;
+ esac
+
+ if [ -n "$new_fqdn" ]; then
+ if ${hfqdn} || ! ${hshort}; then
+ try_hostname "$new_fqdn"
+ else
+ try_hostname "${new_fqdn%%.*}"
+ fi
+ elif [ -n "$new_host_name" ]; then
+ if ${hfqdn}; then
+ if [ -n "$new_domain_name" -a \
+ "$new_host_name" = "${new_host_name#*.}" ]
+ then
+ try_hostname "$new_host_name.$new_domain_name"
+ else
+ try_hostname "$new_host_name"
+ fi
+ elif ${hshort}; then
+ try_hostname "${new_host_name%%.*}"
+ else
+ try_hostname "$new_host_name"
+ fi
+ elif [ -n "${hostname_default+x}" ]; then
+ try_hostname "$hostname_default"
+ fi
+}
+
+# For ease of use, map DHCP6 names onto our DHCP4 names
+case "$reason" in
+BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
+ new_fqdn="$new_dhcp6_fqdn"
+ old_fqdn="$old_dhcp6_fqdn"
+ ;;
+esac
+
+if $if_up; then
+ set_hostname
+fi
diff --git a/hooks/50-dhcpcd-compat b/hooks/50-dhcpcd-compat
new file mode 100644
index 00000000..0d6256e6
--- /dev/null
+++ b/hooks/50-dhcpcd-compat
@@ -0,0 +1,41 @@
+# Compat enter hook shim for older dhcpcd versions
+
+IPADDR=$new_ip_address
+INTERFACE=$interface
+NETMASK=$new_subnet_mask
+BROADCAST=$new_broadcast_address
+NETWORK=$new_network_number
+DHCPSID=$new_dhcp_server_identifier
+GATEWAYS=$new_routers
+DNSSERVERS=$new_domain_name_servers
+DNSDOMAIN=$new_domain_name
+DNSSEARCH=$new_domain_search
+NISDOMAIN=$new_nis_domain
+NISSERVERS=$new_nis_servers
+NTPSERVERS=$new_ntp_servers
+
+GATEWAY=
+for x in $new_routers; do
+ GATEWAY="$GATEWAY${GATEWAY:+,}$x"
+done
+DNS=
+for x in $new_domain_name_servers; do
+ DNS="$DNS${DNS:+,}$x"
+done
+
+r="down"
+case "$reason" in
+RENEW) r="up";;
+BOUND|INFORM|REBIND|REBOOT|TEST|TIMEOUT|IPV4LL) r="new";;
+esac
+
+if [ "$r" != "down" ]; then
+ rm -f /var/lib/dhcpcd-"$INTERFACE".info
+ for x in IPADDR INTERFACE NETMASK BROADCAST NETWORK DHCPSID GATEWAYS \
+ DNSSERVERS DNSDOMAIN DNSSEARCH NISDOMAIN NISSERVERS \
+ NTPSERVERS GATEWAY DNS; do
+ eval echo "$x=\'\$$x\'" >> /var/lib/dhcpcd-"$INTERFACE".info
+ done
+fi
+
+set -- /var/lib/dhcpcd-"$INTERFACE".info "$r"
diff --git a/hooks/50-ntp.conf b/hooks/50-ntp.conf
new file mode 100644
index 00000000..74805039
--- /dev/null
+++ b/hooks/50-ntp.conf
@@ -0,0 +1,141 @@
+# Sample dhcpcd hook script for NTP
+# It will configure either one of NTP, OpenNTP or Chrony (in that order)
+# and will default to NTP if no default config is found.
+
+# Like our resolv.conf hook script, we store a database of ntp.conf files
+# and merge into /etc/ntp.conf
+
+# You can set the env var NTP_CONF to override the derived default on
+# systems with >1 NTP client installed.
+# Here is an example for OpenNTP
+# dhcpcd -e NTP_CONF=/usr/pkg/etc/ntpd.conf
+# or by adding this to /etc/dhcpcd.conf
+# env NTP_CONF=/usr/pkg/etc/ntpd.conf
+# or by adding this to /etc/dhcpcd.enter-hook
+# NTP_CONF=/usr/pkg/etc/ntpd.conf
+# To use Chrony instead, simply change ntpd.conf to chrony.conf in the
+# above examples.
+
+: ${ntp_confs:=ntp.conf ntpd.conf chrony.conf}
+: ${ntp_conf_dirs=/etc /usr/pkg/etc /usr/local/etc}
+ntp_conf_dir="$state_dir/ntp.conf"
+
+# If NTP_CONF is not set, work out a good default
+if [ -z "$NTP_CONF" ]; then
+ for d in ${ntp_conf_dirs}; do
+ for f in ${ntp_confs}; do
+ if [ -e "$d/$f" ]; then
+ NTP_CONF="$d/$f"
+ break 2
+ fi
+ done
+ done
+ [ -e "$NTP_CONF" ] || NTP_CONF=/etc/ntp.conf
+fi
+
+# Derive service name from configuration
+if [ -z "$ntp_service" ]; then
+ case "$NTP_CONF" in
+ *chrony.conf) ntp_service=chronyd;;
+ *) ntp_service=ntpd;;
+ esac
+fi
+
+# Debian has a seperate file for DHCP config to avoid stamping on
+# the master.
+if [ "$ntp_service" = ntpd ] && type invoke-rc.d >/dev/null 2>&1; then
+ [ -e /var/lib/ntp ] || mkdir /var/lib/ntp
+ : ${ntp_service:=ntp}
+ : ${NTP_DHCP_CONF:=/var/lib/ntp/ntp.conf.dhcp}
+fi
+
+: ${ntp_restart_cmd:=service_condcommand $ntp_service restart}
+
+ntp_conf=${NTP_CONF}
+NL="
+"
+
+build_ntp_conf()
+{
+ local cf="$state_dir/ntp.conf.$ifname"
+ local interfaces= header= srvs= servers= x=
+
+ # Build a list of interfaces
+ interfaces=$(list_interfaces "$ntp_conf_dir")
+
+ if [ -n "$interfaces" ]; then
+ # Build the header
+ for x in ${interfaces}; do
+ header="$header${header:+, }$x"
+ done
+
+ # Build a server list
+ srvs=$(cd "$ntp_conf_dir";
+ key_get_value "server " $interfaces)
+ if [ -n "$srvs" ]; then
+ for x in $(uniqify $srvs); do
+ servers="${servers}server $x$NL"
+ done
+ fi
+ fi
+
+ # Merge our config into ntp.conf
+ [ -e "$cf" ] && rm -f "$cf"
+ [ -d "$ntp_conf_dir" ] || mkdir -p "$ntp_conf_dir"
+
+ if [ -n "$NTP_DHCP_CONF" ]; then
+ [ -e "$ntp_conf" ] && cp "$ntp_conf" "$cf"
+ ntp_conf="$NTP_DHCP_CONF"
+ elif [ -e "$ntp_conf" ]; then
+ remove_markers "$signature_base" "$signature_base_end" \
+ "$ntp_conf" > "$cf"
+ fi
+
+ if [ -n "$servers" ]; then
+ echo "$signature_base${header:+ $from }$header" >> "$cf"
+ printf %s "$servers" >> "$cf"
+ echo "$signature_base_end${header:+ $from }$header" >> "$cf"
+ else
+ [ -e "$ntp_conf" -a -e "$cf" ] || return
+ fi
+
+ # If we changed anything, restart ntpd
+ if change_file "$ntp_conf" "$cf"; then
+ [ -n "$ntp_restart_cmd" ] && eval $ntp_restart_cmd
+ fi
+}
+
+add_ntp_conf()
+{
+ local cf="$ntp_conf_dir/$ifname" x=
+
+ [ -e "$cf" ] && rm "$cf"
+ [ -d "$ntp_conf_dir" ] || mkdir -p "$ntp_conf_dir"
+ if [ -n "$new_ntp_servers" ]; then
+ for x in $new_ntp_servers; do
+ echo "server $x" >> "$cf"
+ done
+ fi
+ build_ntp_conf
+}
+
+remove_ntp_conf()
+{
+ if [ -e "$ntp_conf_dir/$ifname" ]; then
+ rm "$ntp_conf_dir/$ifname"
+ fi
+ build_ntp_conf
+}
+
+# For ease of use, map DHCP6 names onto our DHCP4 names
+case "$reason" in
+BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
+ new_ntp_servers="$new_dhcp6_sntp_servers"
+;;
+esac
+
+if $if_up; then
+ add_ntp_conf
+elif $if_down; then
+ remove_ntp_conf
+fi
diff --git a/hooks/50-yp.conf b/hooks/50-yp.conf
new file mode 100644
index 00000000..2da68ebc
--- /dev/null
+++ b/hooks/50-yp.conf
@@ -0,0 +1,56 @@
+# Sample dhcpcd hook for ypbind
+# This script is only suitable for the Linux version.
+
+ypbind_pid()
+{
+ [ -s /var/run/ypbind.pid ] && cat /var/run/ypbind.pid
+}
+
+make_yp_conf()
+{
+ [ -z "$new_nis_domain" -a -z "$new_nis_servers" ] && return 0
+ local cf=/etc/yp.conf."$ifname" prefix= x= pid=
+ rm -f "$cf"
+ echo "$signature" > "$cf"
+ if [ -n "$new_nis_domain" ]; then
+ if ! valid_domainname "$new_nis_domain"; then
+ syslog err "Invalid NIS domain name: $new_nis_domain"
+ rm -f "$cf"
+ return 1
+ fi
+ domainname "$new_nis_domain"
+ if [ -n "$new_nis_servers" ]; then
+ prefix="domain $new_nis_domain server "
+ else
+ echo "domain $new_nis_domain broadcast" >> "$cf"
+ fi
+ else
+ prefix="ypserver "
+ fi
+ for x in $new_nis_servers; do
+ echo "$prefix$x" >> "$cf"
+ done
+ save_conf /etc/yp.conf
+ cat "$cf" > /etc/yp.conf
+ rm -f "$cf"
+ pid="$(ypbind_pid)"
+ if [ -n "$pid" ]; then
+ kill -HUP "$pid"
+ fi
+}
+
+restore_yp_conf()
+{
+ [ -n "$old_nis_domain" ] && domainname ""
+ restore_conf /etc/yp.conf || return 0
+ local pid="$(ypbind_pid)"
+ if [ -n "$pid" ]; then
+ kill -HUP "$pid"
+ fi
+}
+
+if $if_up; then
+ make_yp_conf
+elif $if_down; then
+ restore_yp_conf
+fi
diff --git a/hooks/50-ypbind.in b/hooks/50-ypbind.in
new file mode 100644
index 00000000..a9ebbfa6
--- /dev/null
+++ b/hooks/50-ypbind.in
@@ -0,0 +1,86 @@
+# Sample dhcpcd hook for ypbind
+# This script is only suitable for the BSD versions.
+
+: ${ypbind_restart_cmd:=service_command ypbind restart}
+: ${ypbind_stop_cmd:=service_condcommand ypbind stop}
+ypbind_dir="$state_dir/ypbind"
+: ${ypdomain_dir:=@YPDOMAIN_DIR@}
+: ${ypdomain_suffix:=@YPDOMAIN_SUFFIX@}
+
+
+best_domain()
+{
+ local i=
+
+ for i in "$ypbind_dir/$interface_order".*; do
+ if [ -f "$i" ]; then
+ cat "$i"
+ return 0
+ fi
+ done
+ return 1
+}
+
+make_yp_binding()
+{
+ [ -d "$ypbind_dir" ] || mkdir -p "$ypbind_dir"
+ echo "$new_nis_domain" >"$ypbind_dir/$ifname"
+
+ if [ -z "$ypdomain_dir" ]; then
+ false
+ else
+ local cf="$ypdomain_dir/$new_nis_domain$ypdomain_suffix"
+ if [ -n "$new_nis_servers" ]; then
+ local ncf="$cf.$ifname" x=
+ rm -f "$ncf"
+ for x in $new_nis_servers; do
+ echo "$x" >>"$ncf"
+ done
+ change_file "$cf" "$ncf"
+ else
+ [ -e "$cf" ] && rm "$cf"
+ fi
+ fi
+
+ local nd="$(best_domain)"
+ if [ $? = 0 -a "$nd" != "$(domainname)" ]; then
+ domainname "$nd"
+ if [ -n "$ypbind_restart_cmd" ]; then
+ eval $ypbind_restart_cmd
+ fi
+ fi
+}
+
+restore_yp_binding()
+{
+
+ rm -f "$ypbind_dir/$ifname"
+ local nd="$(best_domain)"
+ # We need to stop ypbind if there is no best domain
+ # otherwise it will just stall as we cannot set domainname
+ # to blank :/
+ if [ -z "$nd" ]; then
+ if [ -n "$ypbind_stop_cmd" ]; then
+ eval $ypbind_stop_cmd
+ fi
+ elif [ "$nd" != "$(domainname)" ]; then
+ domainname "$nd"
+ if [ -n "$ypbind_restart_cmd" ]; then
+ eval $ypbind_restart_cmd
+ fi
+ fi
+}
+
+if [ "$reason" = PREINIT ]; then
+ rm -f "$ypbind_dir/$interface".*
+elif $if_up || $if_down; then
+ if [ -n "$new_nis_domain" ]; then
+ if valid_domainname "$new_nis_domain"; then
+ make_yp_binding
+ else
+ syslog err "Invalid NIS domain name: $new_nis_domain"
+ fi
+ elif [ -n "$old_nis_domain" ]; then
+ restore_yp_binding
+ fi
+fi
diff --git a/hooks/Makefile b/hooks/Makefile
new file mode 100644
index 00000000..2043ace0
--- /dev/null
+++ b/hooks/Makefile
@@ -0,0 +1,63 @@
+TOP?= ../
+include ${TOP}/Makefile.inc
+include ${TOP}/iconfig.mk
+
+SCRIPT= dhcpcd-run-hooks
+SCRIPTDIR= ${LIBEXECDIR}
+CLEANFILES= dhcpcd-run-hooks
+MAN8= dhcpcd-run-hooks.8
+CLEANFILES+= dhcpcd-run-hooks.8
+
+SCRIPTSDIR= ${LIBEXECDIR}/dhcpcd-hooks
+SCRIPTS= 01-test 02-dump
+SCRIPTS+= 20-resolv.conf
+SCRIPTS+= 30-hostname
+SCRIPTS+= ${HOOKSCRIPTS}
+
+# Some hooks should not be installed by default
+FILESDIR= ${DATADIR}/dhcpcd/hooks
+FILES= 10-wpa_supplicant
+FILES+= 15-timezone
+FILES+= 29-lookup-hostname
+FILES+= ${EGHOOKSCRIPTS}
+
+.SUFFIXES: .in
+
+.in: Makefile ${TOP}/config.mk
+ ${SED} ${SED_RUNDIR} ${SED_DBDIR} ${SED_LIBDIR} ${SED_HOOKDIR} \
+ ${SED_SYS} ${SED_SCRIPT} ${SED_DATADIR} \
+ ${SED_SERVICEEXISTS} ${SED_SERVICECMD} ${SED_SERVICESTATUS} \
+ ${SED_STATUSARG} \
+ -e 's:@YPDOMAIN_DIR@:${YPDOMAIN_DIR}:g' \
+ -e 's:@YPDOMAIN_SUFFIX@:${YPDOMAIN_SUFFIX}:g' \
+ $< > $@
+
+all: ${SCRIPT} ${MAN8} ${SCRIPTS} ${EGHOOKSCRIPTS}
+
+clean:
+ rm -f ${CLEANFILES} 50-ypbind
+
+depend:
+
+proginstall: ${HOOKSCRIPTS}
+ ${INSTALL} -d ${DESTDIR}${SCRIPTDIR}
+ ${INSTALL} -m ${BINMODE} ${SCRIPT} ${DESTDIR}${SCRIPTDIR}
+ ${INSTALL} -d ${DESTDIR}${SCRIPTSDIR}
+ ${INSTALL} -m ${NONBINMODE} ${SCRIPTS} ${DESTDIR}${SCRIPTSDIR}
+ # We need to remove the old MTU change script if we at all can.
+ rm -f ${DESTDIR}${SCRIPTSDIR}/10-mtu
+
+eginstall: ${EGHOOKSCRIPTS}
+ ${INSTALL} -d ${DESTDIR}${FILESDIR}
+ ${INSTALL} -m ${NONBINMODE} ${FILES} ${DESTDIR}${FILESDIR}
+
+maninstall: ${MAN8}
+ ${INSTALL} -d ${DESTDIR}${MANDIR}/man8
+ ${INSTALL} -m ${MANMODE} ${MAN8} ${DESTDIR}${MANDIR}/man8
+
+install: proginstall eginstall maninstall
+
+import: ${HOOKSCRIPTS}
+ ${INSTALL} -d /tmp/${DISTPREFIX}/dhcpcd-hooks
+ ${INSTALL} -m ${NONBINMODE} ${SCRIPTS} /tmp/${DISTPREFIX}/dhcpcd-hooks
+ ${INSTALL} -m ${NONBINMODE} ${FILES} /tmp/${DISTPREFIX}/dhcpcd-hooks
diff --git a/hooks/dhcpcd-run-hooks.8.in b/hooks/dhcpcd-run-hooks.8.in
new file mode 100644
index 00000000..b4b1d301
--- /dev/null
+++ b/hooks/dhcpcd-run-hooks.8.in
@@ -0,0 +1,217 @@
+.\" Copyright (c) 2006-2017 Roy Marples
+.\" All rights reserved
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd January 23, 2017
+.Dt DHCPCD-RUN-HOOKS 8
+.Os
+.Sh NAME
+.Nm dhcpcd-run-hooks
+.Nd DHCP client configuration script
+.Sh DESCRIPTION
+.Nm
+is used by
+.Xr dhcpcd 8
+to run any system and user defined hook scripts.
+System hook scripts are found in
+.Pa @HOOKDIR@
+and the user defined hooks are
+.Pa @SYSCONFDIR@/dhcpcd.enter-hook .
+and
+.Pa @SYSCONFDIR@/dhcpcd.exit-hook .
+The default install supplies hook scripts for configuring
+.Pa /etc/resolv.conf
+and the hostname.
+Your distribution may have included other hook scripts to say configure
+ntp or ypbind.
+A test hook is also supplied that simply echos the dhcp variables to the
+console from DISCOVER message.
+.Pp
+Each time
+.Nm
+is invoked,
+.Ev $interface
+is set to the interface that
+.Nm dhcpcd
+is run on and
+.Ev $reason
+is to the reason why
+.Nm
+was invoked.
+DHCP information to be configured is held in variables starting with the word
+new_ and old DHCP information to be removed is held in variables starting with
+the word old_.
+.Nm dhcpcd
+can display the full list of variables it knows how about by using the
+.Fl V , -variables
+argument.
+.Pp
+Here's a list of reasons why
+.Nm
+could be invoked:
+.Bl -tag -width EXPIREXXXEXPIRE6
+.It Dv PREINIT
+dhcpcd is starting up and any pre-initialisation should be done.
+.It Dv CARRIER
+dhcpcd has detected the carrier is up.
+This is generally just a notification and no action need be taken.
+.It Dv NOCARRIER
+dhcpcd lost the carrier.
+The cable may have been unplugged or association to the wireless point lost.
+.It Dv INFORM | Dv INFORM6
+dhcpcd informed a DHCP server about it's address and obtained other
+configuration details.
+.It Dv BOUND | Dv BOUND6
+dhcpcd obtained a new lease from a DHCP server.
+.It Dv RENEW | Dv RENEW6
+dhcpcd renewed it's lease.
+.It Dv REBIND | Dv REBIND6
+dhcpcd has rebound to a new DHCP server.
+.It Dv REBOOT | Dv REBOOT6
+dhcpcd successfully requested a lease from a DHCP server.
+.It Dv DELEGATED6
+dhcpcd assigned a delegated prefix to the interface.
+.It Dv IPV4LL
+dhcpcd obtained an IPV4LL address, or one was removed.
+.It Dv STATIC
+dhcpcd has been configured with a static configuration which has not been
+obtained from a DHCP server.
+.It Dv 3RDPARTY
+dhcpcd is monitoring the interface for a 3rd party to give it an IP address.
+.It Dv TIMEOUT
+dhcpcd failed to contact any DHCP servers but was able to use an old lease.
+.It Dv EXPIRE | EXPIRE6
+dhcpcd's lease or state expired and it failed to obtain a new one.
+.It Dv NAK
+dhcpcd received a NAK from the DHCP server.
+This should be treated as EXPIRE.
+.It Dv RECONFIGURE
+dhcpcd has been instructed to reconfigure an interface.
+.It Dv ROUTERADVERT
+dhcpcd has received an IPv6 Router Advertisement, or one has expired.
+.It Dv STOP | Dv STOP6
+dhcpcd stopped running on the interface.
+.It Dv STOPPED
+dhcpcd has stopped entirely.
+.It Dv DEPARTED
+The interface has been removed.
+.It Dv FAIL
+dhcpcd failed to operate on the interface.
+This normally happens when dhcpcd does not support the raw interface, which
+means it cannot work as a DHCP or ZeroConf client.
+Static configuration and DHCP INFORM is still allowed.
+.It Dv DUMP
+dhcpcd has been asked to dump the last lease for the interface.
+.It Dv TEST
+dhcpcd received an OFFER from a DHCP server but will not configure the
+interface.
+This is primarily used to test the variables are filled correctly for the
+script to process them.
+.El
+.Sh ENVIRONMENT
+.Nm dhcpcd
+will clear the environment variables aside from
+.Ev $PATH
+and
+.Ev $RC_SVCNAME .
+The following variables will then be set, along with any protocol supplied
+ones.
+.Bl -tag -width xnew_delegated_dhcp6_prefix
+.It Ev $interface
+the name of the interface.
+.It Ev $reason
+as described above.
+.It Ev $pid
+the pid of
+.Nm dhcpcd .
+.It Ev $ifcarrier
+the link status of
+.Ev $interface :
+.Dv unknown ,
+.Dv up
+or
+.Dv down .
+.It Ev $ifmetric
+.Ev $interface
+preference, lower is better.
+.It Ev $ifwireless
+.Dv 1 if
+.Ev $interface
+is wireless, otherwise
+.Dv 0 .
+.It Ev $ifflags
+.Ev $interface
+flags.
+.It Ev $ifmtu
+.Ev $interface
+MTU.
+.It Ev $ifssid
+the name of the SSID the
+.Ev interface
+is connected to.
+.It Ev $interface_order
+A list of interfaces, in order of preference.
+.It Ev $if_up
+.Dv true
+if the
+.Ev interface
+is up, otherwise
+.Dv false .
+.It Ev $if_down
+.Dv true
+if the
+.Ev interface
+is down, otherwise
+.Dv false .
+.It Ev $af_waiting
+Address family waiting for, as defined in
+.Xr dhcpcd.conf 5 .
+.It Ev $profile
+the name of the profile selected from
+.Xr dhcpcd.conf 5 .
+.It Ev $new_delegated_dhcp6_prefix
+space separated list of delegated prefixes.
+.El
+.Sh FILES
+When
+.Nm
+runs, it loads
+.Pa @SYSCONFDIR@/dhcpcd.enter-hook
+and any scripts found in
+.Pa @HOOKDIR@
+in a lexical order and then finally
+.Pa @SYSCONFDIR@/dhcpcd.exit-hook
+.Sh SEE ALSO
+.Xr dhcpcd 8
+.Sh AUTHORS
+.An Roy Marples Aq Mt roy@marples.name
+.Sh BUGS
+Please report them to
+.Lk http://roy.marples.name/projects/dhcpcd
+.Sh SECURITY CONSIDERATIONS
+.Nm dhcpcd
+will validate the content of each option against its encoding.
+For string, ascii, raw or binhex encoding it's up to the user to validate it
+for the intended purpose.
+.Pp
+When used in a shell script, each variable must be quoted correctly.
diff --git a/hooks/dhcpcd-run-hooks.in b/hooks/dhcpcd-run-hooks.in
new file mode 100644
index 00000000..78448cc6
--- /dev/null
+++ b/hooks/dhcpcd-run-hooks.in
@@ -0,0 +1,387 @@
+#!/bin/sh
+# dhcpcd client configuration script
+
+# Handy variables and functions for our hooks to use
+case "$reason" in
+ ROUTERADVERT)
+ ifsuffix=".ra";;
+ INFORM6|BOUND6|RENEW6|REBIND6|REBOOT6|EXPIRE6|RELEASE6|STOP6)
+ ifsuffix=".dhcp6";;
+ IPV4LL)
+ ifsuffix=".ipv4ll";;
+ *)
+ ifsuffix=".dhcp";;
+esac
+ifname="$interface$ifsuffix"
+
+from=from
+signature_base="# Generated by dhcpcd"
+signature="$signature_base $from $ifname"
+signature_base_end="# End of dhcpcd"
+signature_end="$signature_base_end $from $ifname"
+state_dir=@RUNDIR@/dhcpcd
+_detected_init=false
+
+: ${if_up:=false}
+: ${if_down:=false}
+: ${syslog_debug:=false}
+
+# Ensure that all arguments are unique
+uniqify()
+{
+ local result= i=
+ for i do
+ case " $result " in
+ *" $i "*);;
+ *) result="$result $i";;
+ esac
+ done
+ echo "${result# *}"
+}
+
+# List interface config files in a directory.
+# If dhcpcd is running as a single instance then it will have a list of
+# interfaces in the preferred order.
+# Otherwise we just use what we have.
+list_interfaces()
+{
+ local i= x= ifaces=
+ for i in $interface_order; do
+ for x in "$1"/$i.*; do
+ [ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}"
+ done
+ done
+ for x in "$1"/*; do
+ [ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}"
+ done
+ uniqify $ifaces
+}
+
+# Trim function
+trim()
+{
+ local var="$*"
+
+ var=${var#"${var%%[![:space:]]*}"}
+ var=${var%"${var##*[![:space:]]}"}
+ if [ -z "$var" ]; then
+ # So it seems our shell doesn't support wctype(3) patterns
+ # Fall back to sed
+ var=$(echo "$*" | sed -e 's/^[[:space:]]*//;s/[[:space:]]*$//')
+ fi
+ printf %s "$var"
+}
+
+# We normally use sed to extract values using a key from a list of files
+# but sed may not always be available at the time.
+key_get_value()
+{
+ local key="$1" value= x= line=
+
+ shift
+ if type sed >/dev/null 2>&1; then
+ sed -n "s/^$key//p" $@
+ else
+ for x do
+ while read line; do
+ case "$line" in
+ "$key"*) echo "${line##$key}";;
+ esac
+ done < "$x"
+ done
+ fi
+}
+
+# We normally use sed to remove markers from a configuration file
+# but sed may not always be available at the time.
+remove_markers()
+{
+ local m1="$1" m2="$2" x= line= in_marker=0
+
+ shift; shift
+ if type sed >/dev/null 2>&1; then
+ sed "/^$m1/,/^$m2/d" $@
+ else
+ for x do
+ while read line; do
+ case "$line" in
+ "$m1"*) in_marker=1;;
+ "$m2"*) in_marker=0;;
+ *) [ $in_marker = 0 ] && echo "$line";;
+ esac
+ done < "$x"
+ done
+ fi
+}
+
+# Compare two files.
+comp_file()
+{
+
+ [ -e "$1" -a -e "$2" ] || return 1
+
+ if type cmp >/dev/null 2>&1; then
+ cmp -s "$1" "$2"
+ elif type diff >/dev/null 2>&1; then
+ diff -q "$1" "$2" >/dev/null
+ else
+ # Hopefully we're only working on small text files ...
+ [ "$(cat "$1")" = "$(cat "$2")" ]
+ fi
+}
+
+# Compare two files.
+# If different, replace first with second otherwise remove second.
+change_file()
+{
+
+ if [ -e "$1" ]; then
+ if comp_file "$1" "$2"; then
+ rm -f "$2"
+ return 1
+ fi
+ fi
+ cat "$2" > "$1"
+ rm -f "$2"
+ return 0
+}
+
+# Compare two files.
+# If different, copy or link depending on target type
+copy_file()
+{
+
+ if [ -h "$2" ]; then
+ [ "$(readlink "$2")" = "$1" ] && return 1
+ ln -sf "$1" "$2"
+ else
+ comp_file "$1" "$2" && return 1
+ cat "$1" >"$2"
+ fi
+}
+
+# Save a config file
+save_conf()
+{
+
+ if [ -f "$1" ]; then
+ rm -f "$1-pre.$interface"
+ cat "$1" > "$1-pre.$interface"
+ fi
+}
+
+# Restore a config file
+restore_conf()
+{
+
+ [ -f "$1-pre.$interface" ] || return 1
+ cat "$1-pre.$interface" > "$1"
+ rm -f "$1-pre.$interface"
+}
+
+# Write a syslog entry
+syslog()
+{
+ local lvl="$1"
+
+ if [ "$lvl" = debug ]; then
+ ${syslog_debug} || return 0
+ fi
+ [ -n "$lvl" ] && shift
+ [ -n "$*" ] || return 0
+ case "$lvl" in
+ err|error) echo "$interface: $*" >&2;;
+ *) echo "$interface: $*";;
+ esac
+ if type logger >/dev/null 2>&1; then
+ logger -i -p daemon."$lvl" -t dhcpcd-run-hooks "$interface: $*"
+ fi
+}
+
+# Check for a valid domain name as per RFC1123 with the exception of
+# allowing - and _ as they seem to be widely used.
+valid_domainname()
+{
+ local name="$1" label
+
+ [ -z "$name" -o ${#name} -gt 255 ] && return 1
+
+ while [ -n "$name" ]; do
+ label="${name%%.*}"
+ [ -z "$label" -o ${#label} -gt 63 ] && return 1
+ case "$label" in
+ -*|_*|*-|*_) return 1;;
+ # some sh require - as the first or last character in the class
+ # when matching it
+ *[![:alnum:]_-]*) return 1;;
+ esac
+ [ "$name" = "${name#*.}" ] && break
+ name="${name#*.}"
+ done
+ return 0
+}
+
+valid_domainname_list()
+{
+ local name
+
+ for name do
+ valid_domainname "$name" || return $?
+ done
+ return 0
+}
+
+# Check for a valid path
+valid_path()
+{
+
+ case "$@" in
+ *[![:alnum:]#%+-_:\.,@~\\/\[\]=\ ]*) return 1;;
+ esac
+ return 0
+}
+
+# With the advent of alternative init systems, it's possible to have
+# more than one installed. So we need to try and guess what one we're
+# using unless overriden by configure.
+detect_init()
+{
+ _service_exists="@SERVICEEXISTS@"
+ _service_cmd="@SERVICECMD@"
+ _service_status="@SERVICESTATUS@"
+
+ [ -n "$_service_cmd" ] && return 0
+
+ if ${_detected_init}; then
+ [ -n "$_service_cmd" ]
+ return $?
+ fi
+
+ # Detect the running init system.
+ # As systemd and OpenRC can be installed on top of legacy init
+ # systems we try to detect them first.
+ local status="@STATUSARG@"
+ : ${status:=status}
+ if [ -x /bin/systemctl -a -S /run/systemd/private ]; then
+ _service_exists="/bin/systemctl --quiet is-enabled \$1.service"
+ _service_status="/bin/systemctl --quiet is-active \$1.service"
+ _service_cmd="/bin/systemctl \$2 \$1.service"
+ elif [ -x /usr/bin/systemctl -a -S /run/systemd/private ]; then
+ _service_exists="/usr/bin/systemctl --quiet is-enabled \$1.service"
+ _service_status="/usr/bin/systemctl --quiet is-active \$1.service"
+ _service_cmd="/usr/bin/systemctl \$2 \$1.service"
+ elif [ -x /sbin/rc-service -a \
+ -s /libexec/rc/init.d/softlevel -o -s /run/openrc/softlevel ]
+ then
+ _service_exists="/sbin/rc-service -e \$1"
+ _service_cmd="/sbin/rc-service \$1 -- -D \$2"
+ elif [ -x /usr/sbin/invoke-rc.d ]; then
+ _service_exists="/usr/sbin/invoke-rc.d --query --quiet \$1 start >/dev/null 2>&1 || [ \$? = 104 ]"
+ _service_cmd="/usr/sbin/invoke-rc.d \$1 \$2"
+ elif [ -x /sbin/service ]; then
+ _service_exists="/sbin/service \$1 >/dev/null 2>&1"
+ _service_cmd="/sbin/service \$1 \$2"
+ elif [ -x /usr/sbin/service ]; then
+ _service_exists="/usr/sbin/service \$1 $status >/dev/null 2>&1"
+ _service_cmd="/usr/sbin/service \$1 \$2"
+ elif [ -x /bin/sv ]; then
+ _service_exists="/bin/sv status \$1 >/dev/null 2>&1"
+ _service_cmd="/bin/sv \$2 \$1"
+ elif [ -x /usr/bin/sv ]; then
+ _service_exists="/usr/bin/sv status \$1 >/dev/null 2>&1"
+ _service_cmd="/usr/bin/sv \$2 \$1"
+ elif [ -e /etc/slackware-version -a -d /etc/rc.d ]; then
+ _service_exists="[ -x /etc/rc.d/rc.\$1 ]"
+ _service_cmd="/etc/rc.d/rc.\$1 \$2"
+ _service_status="/etc/rc.d/rc.\$1 status >/dev/null 2>&1"
+ else
+ for x in /etc/init.d/rc.d /etc/rc.d /etc/init.d; do
+ if [ -d $x ]; then
+ _service_exists="[ -x $x/\$1 ]"
+ _service_cmd="$x/\$1 \$2"
+ _service_status="$x/\$1 $status >/dev/null 2>&1"
+ break
+ fi
+ done
+ if [ -e /etc/arch-release ]; then
+ _service_status="[ -e /var/run/daemons/\$1 ]"
+ elif [ "$x" = "/etc/rc.d" -a -e /etc/rc.d/rc.subr ]; then
+ _service_status="$x/\$1 check >/dev/null 2>&1"
+ fi
+ fi
+
+ _detected_init=true
+ if [ -z "$_service_cmd" ]; then
+ syslog err "could not detect a useable init system"
+ return 1
+ fi
+ return 0
+}
+
+# Check a system service exists
+service_exists()
+{
+
+ if [ -z "$_service_exists" ]; then
+ detect_init || return 1
+ fi
+ eval $_service_exists
+}
+
+# Send a command to a system service
+service_cmd()
+{
+
+ if [ -z "$_service_cmd" ]; then
+ detect_init || return 1
+ fi
+ eval $_service_cmd
+}
+
+# Send a command to a system service if it is running
+service_status()
+{
+
+ if [ -z "$_service_cmd" ]; then
+ detect_init || return 1
+ fi
+ if [ -n "$_service_status" ]; then
+ eval $_service_status
+ else
+ service_command $1 status >/dev/null 2>&1
+ fi
+}
+
+# Handy macros for our hooks
+service_command()
+{
+
+ service_exists $1 && service_cmd $1 $2
+}
+service_condcommand()
+{
+
+ service_exists $1 && service_status $1 && service_cmd $1 $2
+}
+
+# We source each script into this one so that scripts run earlier can
+# remove variables from the environment so later scripts don't see them.
+# Thus, the user can create their dhcpcd.enter/exit-hook script to configure
+# /etc/resolv.conf how they want and stop the system scripts ever updating it.
+for hook in \
+ @SYSCONFDIR@/dhcpcd.enter-hook \
+ @HOOKDIR@/* \
+ @SYSCONFDIR@/dhcpcd.exit-hook
+do
+ for skip in $skip_hooks; do
+ case "$hook" in
+ */*~) continue 2;;
+ */"$skip") continue 2;;
+ */[0-9][0-9]"-$skip") continue 2;;
+ */[0-9][0-9]"-$skip.sh") continue 2;;
+ esac
+ done
+ if [ -f "$hook" ]; then
+ . "$hook"
+ fi
+done