10a68f8d2SRoy Marples#!/bin/sh 20a68f8d2SRoy Marples# dhcpcd client configuration script 30a68f8d2SRoy Marples 40a68f8d2SRoy Marples# Handy variables and functions for our hooks to use 50a68f8d2SRoy Marplesifname="$interface${protocol+.}$protocol" 60a68f8d2SRoy Marplesfrom=from 70a68f8d2SRoy Marplessignature_base="# Generated by dhcpcd" 80a68f8d2SRoy Marplessignature="$signature_base $from $ifname" 90a68f8d2SRoy Marplessignature_base_end="# End of dhcpcd" 100a68f8d2SRoy Marplessignature_end="$signature_base_end $from $ifname" 110a68f8d2SRoy Marplesstate_dir=/var/run/dhcpcd/hook-state 120a68f8d2SRoy Marples_detected_init=false 130a68f8d2SRoy Marples 140a68f8d2SRoy Marples: ${if_up:=false} 150a68f8d2SRoy Marples: ${if_down:=false} 160a68f8d2SRoy Marples: ${syslog_debug:=false} 170a68f8d2SRoy Marples 180a68f8d2SRoy Marples# Ensure that all arguments are unique 190a68f8d2SRoy Marplesuniqify() 200a68f8d2SRoy Marples{ 210a68f8d2SRoy Marples result= 220a68f8d2SRoy Marples for i do 230a68f8d2SRoy Marples case " $result " in 240a68f8d2SRoy Marples *" $i "*);; 250a68f8d2SRoy Marples *) result="$result${result:+ }$i";; 260a68f8d2SRoy Marples esac 270a68f8d2SRoy Marples done 280a68f8d2SRoy Marples echo "$result" 290a68f8d2SRoy Marples} 300a68f8d2SRoy Marples 310a68f8d2SRoy Marples# List interface config files in a directory. 320a68f8d2SRoy Marples# If dhcpcd is running as a single instance then it will have a list of 330a68f8d2SRoy Marples# interfaces in the preferred order. 340a68f8d2SRoy Marples# Otherwise we just use what we have. 350a68f8d2SRoy Marpleslist_interfaces() 360a68f8d2SRoy Marples{ 370a68f8d2SRoy Marples ifaces= 380a68f8d2SRoy Marples for i in $interface_order; do 390a68f8d2SRoy Marples for x in "$1"/$i.*; do 400a68f8d2SRoy Marples [ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}" 410a68f8d2SRoy Marples done 420a68f8d2SRoy Marples done 430a68f8d2SRoy Marples for x in "$1"/*; do 440a68f8d2SRoy Marples [ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}" 450a68f8d2SRoy Marples done 460a68f8d2SRoy Marples uniqify $ifaces 470a68f8d2SRoy Marples} 480a68f8d2SRoy Marples 490a68f8d2SRoy Marples# Trim function 500a68f8d2SRoy Marplestrim() 510a68f8d2SRoy Marples{ 520a68f8d2SRoy Marples var="$*" 530a68f8d2SRoy Marples var=${var#"${var%%[![:space:]]*}"} 540a68f8d2SRoy Marples var=${var%"${var##*[![:space:]]}"} 550a68f8d2SRoy Marples if [ -z "$var" ]; then 560a68f8d2SRoy Marples # So it seems our shell doesn't support wctype(3) patterns 570a68f8d2SRoy Marples # Fall back to sed 580a68f8d2SRoy Marples var=$(echo "$*" | sed -e 's/^[[:space:]]*//;s/[[:space:]]*$//') 590a68f8d2SRoy Marples fi 600a68f8d2SRoy Marples printf %s "$var" 610a68f8d2SRoy Marples} 620a68f8d2SRoy Marples 630a68f8d2SRoy Marples# We normally use sed to extract values using a key from a list of files 640a68f8d2SRoy Marples# but sed may not always be available at the time. 650a68f8d2SRoy Marpleskey_get_value() 660a68f8d2SRoy Marples{ 670a68f8d2SRoy Marples key="$1" 680a68f8d2SRoy Marples shift 690a68f8d2SRoy Marples 70*80aa9461SRoy Marples if command -v sed >/dev/null 2>&1; then 710a68f8d2SRoy Marples sed -n "s/^$key//p" $@ 720a68f8d2SRoy Marples else 730a68f8d2SRoy Marples for x do 740a68f8d2SRoy Marples while read line; do 750a68f8d2SRoy Marples case "$line" in 760a68f8d2SRoy Marples "$key"*) echo "${line##$key}";; 770a68f8d2SRoy Marples esac 780a68f8d2SRoy Marples done < "$x" 790a68f8d2SRoy Marples done 800a68f8d2SRoy Marples fi 810a68f8d2SRoy Marples} 820a68f8d2SRoy Marples 830a68f8d2SRoy Marples# We normally use sed to remove markers from a configuration file 840a68f8d2SRoy Marples# but sed may not always be available at the time. 850a68f8d2SRoy Marplesremove_markers() 860a68f8d2SRoy Marples{ 870a68f8d2SRoy Marples m1="$1" 880a68f8d2SRoy Marples m2="$2" 890a68f8d2SRoy Marples in_marker=0 900a68f8d2SRoy Marples 910a68f8d2SRoy Marples shift; shift 92*80aa9461SRoy Marples if command -v sed >/dev/null 2>&1; then 930a68f8d2SRoy Marples sed "/^$m1/,/^$m2/d" $@ 940a68f8d2SRoy Marples else 950a68f8d2SRoy Marples for x do 960a68f8d2SRoy Marples while read line; do 970a68f8d2SRoy Marples case "$line" in 980a68f8d2SRoy Marples "$m1"*) in_marker=1;; 990a68f8d2SRoy Marples "$m2"*) in_marker=0;; 1000a68f8d2SRoy Marples *) [ $in_marker = 0 ] && echo "$line";; 1010a68f8d2SRoy Marples esac 1020a68f8d2SRoy Marples done < "$x" 1030a68f8d2SRoy Marples done 1040a68f8d2SRoy Marples fi 1050a68f8d2SRoy Marples} 1060a68f8d2SRoy Marples 1070a68f8d2SRoy Marples# Compare two files. 1080a68f8d2SRoy Marplescomp_file() 1090a68f8d2SRoy Marples{ 1100a68f8d2SRoy Marples [ -e "$1" ] && [ -e "$2" ] || return 1 1110a68f8d2SRoy Marples 112*80aa9461SRoy Marples if command -v cmp >/dev/null 2>&1; then 1130a68f8d2SRoy Marples cmp -s "$1" "$2" 114*80aa9461SRoy Marples elif command -v diff >/dev/null 2>&1; then 1150a68f8d2SRoy Marples diff -q "$1" "$2" >/dev/null 1160a68f8d2SRoy Marples else 1170a68f8d2SRoy Marples # Hopefully we're only working on small text files ... 1180a68f8d2SRoy Marples [ "$(cat "$1")" = "$(cat "$2")" ] 1190a68f8d2SRoy Marples fi 1200a68f8d2SRoy Marples} 1210a68f8d2SRoy Marples 1220a68f8d2SRoy Marples# Compare two files. 1230a68f8d2SRoy Marples# If different, replace first with second otherwise remove second. 1240a68f8d2SRoy Marpleschange_file() 1250a68f8d2SRoy Marples{ 1260a68f8d2SRoy Marples if [ -e "$1" ]; then 1270a68f8d2SRoy Marples if comp_file "$1" "$2"; then 1280a68f8d2SRoy Marples rm -f "$2" 1290a68f8d2SRoy Marples return 1 1300a68f8d2SRoy Marples fi 1310a68f8d2SRoy Marples fi 1320a68f8d2SRoy Marples cat "$2" > "$1" 1330a68f8d2SRoy Marples rm -f "$2" 1340a68f8d2SRoy Marples return 0 1350a68f8d2SRoy Marples} 1360a68f8d2SRoy Marples 1370a68f8d2SRoy Marples# Compare two files. 1380a68f8d2SRoy Marples# If different, copy or link depending on target type 1390a68f8d2SRoy Marplescopy_file() 1400a68f8d2SRoy Marples{ 1410a68f8d2SRoy Marples if [ -h "$2" ]; then 1420a68f8d2SRoy Marples [ "$(readlink "$2")" = "$1" ] && return 1 1430a68f8d2SRoy Marples ln -sf "$1" "$2" 1440a68f8d2SRoy Marples else 1450a68f8d2SRoy Marples comp_file "$1" "$2" && return 1 1460a68f8d2SRoy Marples cat "$1" >"$2" 1470a68f8d2SRoy Marples fi 1480a68f8d2SRoy Marples} 1490a68f8d2SRoy Marples 1500a68f8d2SRoy Marples# Save a config file 1510a68f8d2SRoy Marplessave_conf() 1520a68f8d2SRoy Marples{ 1530a68f8d2SRoy Marples if [ -f "$1" ]; then 1540a68f8d2SRoy Marples rm -f "$1-pre.$interface" 1550a68f8d2SRoy Marples cat "$1" > "$1-pre.$interface" 1560a68f8d2SRoy Marples fi 1570a68f8d2SRoy Marples} 1580a68f8d2SRoy Marples 1590a68f8d2SRoy Marples# Restore a config file 1600a68f8d2SRoy Marplesrestore_conf() 1610a68f8d2SRoy Marples{ 1620a68f8d2SRoy Marples [ -f "$1-pre.$interface" ] || return 1 1630a68f8d2SRoy Marples cat "$1-pre.$interface" > "$1" 1640a68f8d2SRoy Marples rm -f "$1-pre.$interface" 1650a68f8d2SRoy Marples} 1660a68f8d2SRoy Marples 1670a68f8d2SRoy Marples# Write a syslog entry 1680a68f8d2SRoy Marplessyslog() 1690a68f8d2SRoy Marples{ 1700a68f8d2SRoy Marples lvl="$1" 1710a68f8d2SRoy Marples 1720a68f8d2SRoy Marples if [ "$lvl" = debug ]; then 1730a68f8d2SRoy Marples ${syslog_debug} || return 0 1740a68f8d2SRoy Marples fi 1750a68f8d2SRoy Marples [ -n "$lvl" ] && shift 1760a68f8d2SRoy Marples [ -n "$*" ] || return 0 1770a68f8d2SRoy Marples case "$lvl" in 1780a68f8d2SRoy Marples err|error) echo "$interface: $*" >&2;; 1790a68f8d2SRoy Marples *) echo "$interface: $*";; 1800a68f8d2SRoy Marples esac 181*80aa9461SRoy Marples if command -v logger >/dev/null 2>&1; then 1820a68f8d2SRoy Marples logger -i -p daemon."$lvl" -t dhcpcd-run-hooks "$interface: $*" 1830a68f8d2SRoy Marples fi 1840a68f8d2SRoy Marples} 1850a68f8d2SRoy Marples 1860a68f8d2SRoy Marples# Check for a valid name as per RFC952 and RFC1123 section 2.1 1870a68f8d2SRoy Marplesvalid_domainname() 1880a68f8d2SRoy Marples{ 1890a68f8d2SRoy Marples name="$1" 1900a68f8d2SRoy Marples [ -z "$name" ] || [ ${#name} -gt 255 ] && return 1 1910a68f8d2SRoy Marples 1920a68f8d2SRoy Marples while [ -n "$name" ]; do 1930a68f8d2SRoy Marples label="${name%%.*}" 1940a68f8d2SRoy Marples [ -z "$label" ] || [ ${#label} -gt 63 ] && return 1 1950a68f8d2SRoy Marples case "$label" in 1960a68f8d2SRoy Marples -*|_*|*-|*_) return 1;; 1970a68f8d2SRoy Marples *[![:alnum:]_-]*) return 1;; 1980a68f8d2SRoy Marples "$name") return 0;; 1990a68f8d2SRoy Marples esac 2000a68f8d2SRoy Marples name="${name#*.}" 2010a68f8d2SRoy Marples done 2020a68f8d2SRoy Marples return 0 2030a68f8d2SRoy Marples} 2040a68f8d2SRoy Marples 2050a68f8d2SRoy Marplesvalid_domainname_list() 2060a68f8d2SRoy Marples{ 2070a68f8d2SRoy Marples for name do 2080a68f8d2SRoy Marples valid_domainname "$name" || return $? 2090a68f8d2SRoy Marples done 2100a68f8d2SRoy Marples return 0 2110a68f8d2SRoy Marples} 2120a68f8d2SRoy Marples 2130a68f8d2SRoy Marples# With the advent of alternative init systems, it's possible to have 2140a68f8d2SRoy Marples# more than one installed. So we need to try to guess what one we're 2150a68f8d2SRoy Marples# using unless overridden by configure. 2160a68f8d2SRoy Marplesdetect_init() 2170a68f8d2SRoy Marples{ 2180a68f8d2SRoy Marples _service_exists="" 2190a68f8d2SRoy Marples _service_cmd="" 2200a68f8d2SRoy Marples _service_status="" 2210a68f8d2SRoy Marples 2220a68f8d2SRoy Marples [ -n "$_service_cmd" ] && return 0 2230a68f8d2SRoy Marples 2240a68f8d2SRoy Marples if $_detected_init; then 2250a68f8d2SRoy Marples [ -n "$_service_cmd" ] 2260a68f8d2SRoy Marples return $? 2270a68f8d2SRoy Marples fi 2280a68f8d2SRoy Marples 2290a68f8d2SRoy Marples # Detect the running init system. 2300a68f8d2SRoy Marples # As systemd and OpenRC can be installed on top of legacy init 2310a68f8d2SRoy Marples # systems we try to detect them first. 2320a68f8d2SRoy Marples status="onestatus" 2330a68f8d2SRoy Marples : ${status:=status} 2340a68f8d2SRoy Marples if [ -x /bin/systemctl ] && [ -S /run/systemd/private ]; then 2350a68f8d2SRoy Marples _service_exists="/bin/systemctl --quiet is-enabled \$1.service" 2360a68f8d2SRoy Marples _service_status="/bin/systemctl --quiet is-active \$1.service" 237*80aa9461SRoy Marples _service_cmd="/bin/systemctl \$2 --no-block \$1.service" 2380a68f8d2SRoy Marples elif [ -x /usr/bin/systemctl ] && [ -S /run/systemd/private ]; then 2390a68f8d2SRoy Marples _service_exists="/usr/bin/systemctl --quiet is-enabled \$1.service" 2400a68f8d2SRoy Marples _service_status="/usr/bin/systemctl --quiet is-active \$1.service" 241*80aa9461SRoy Marples _service_cmd="/usr/bin/systemctl \$2 --no-block \$1.service" 2420a68f8d2SRoy Marples elif [ -x /sbin/rc-service ] && 2430a68f8d2SRoy Marples { [ -s /libexec/rc/init.d/softlevel ] || 2440a68f8d2SRoy Marples [ -s /run/openrc/softlevel ]; } 2450a68f8d2SRoy Marples then 2460a68f8d2SRoy Marples _service_exists="/sbin/rc-service -e \$1" 2470a68f8d2SRoy Marples _service_cmd="/sbin/rc-service \$1 -- -D \$2" 2480a68f8d2SRoy Marples elif [ -x /usr/sbin/invoke-rc.d ]; then 2490a68f8d2SRoy Marples _service_exists="/usr/sbin/invoke-rc.d --query --quiet \$1 start >/dev/null 2>&1 || [ \$? = 104 ]" 2500a68f8d2SRoy Marples _service_cmd="/usr/sbin/invoke-rc.d \$1 \$2" 2510a68f8d2SRoy Marples elif [ -x /sbin/service ]; then 2520a68f8d2SRoy Marples _service_exists="/sbin/service \$1 >/dev/null 2>&1" 2530a68f8d2SRoy Marples _service_cmd="/sbin/service \$1 \$2" 2540a68f8d2SRoy Marples elif [ -x /usr/sbin/service ]; then 2550a68f8d2SRoy Marples _service_exists="/usr/sbin/service \$1 $status >/dev/null 2>&1" 2560a68f8d2SRoy Marples _service_cmd="/usr/sbin/service \$1 \$2" 2570a68f8d2SRoy Marples elif [ -x /bin/sv ]; then 2580a68f8d2SRoy Marples _service_exists="/bin/sv status \$1 >/dev/null 2>&1" 2590a68f8d2SRoy Marples _service_cmd="/bin/sv \$2 \$1" 2600a68f8d2SRoy Marples elif [ -x /usr/bin/sv ]; then 2610a68f8d2SRoy Marples _service_exists="/usr/bin/sv status \$1 >/dev/null 2>&1" 2620a68f8d2SRoy Marples _service_cmd="/usr/bin/sv \$2 \$1" 2630a68f8d2SRoy Marples elif [ -e /etc/slackware-version ] && [ -d /etc/rc.d ]; then 2640a68f8d2SRoy Marples _service_exists="[ -x /etc/rc.d/rc.\$1 ]" 2650a68f8d2SRoy Marples _service_cmd="/etc/rc.d/rc.\$1 \$2" 2660a68f8d2SRoy Marples _service_status="/etc/rc.d/rc.\$1 status >/dev/null 2>&1" 2670a68f8d2SRoy Marples else 2680a68f8d2SRoy Marples for x in /etc/init.d/rc.d /etc/rc.d /etc/init.d; do 2690a68f8d2SRoy Marples if [ -d $x ]; then 2700a68f8d2SRoy Marples _service_exists="[ -x $x/\$1 ]" 2710a68f8d2SRoy Marples _service_cmd="$x/\$1 \$2" 2720a68f8d2SRoy Marples _service_status="$x/\$1 $status >/dev/null 2>&1" 2730a68f8d2SRoy Marples break 2740a68f8d2SRoy Marples fi 2750a68f8d2SRoy Marples done 2760a68f8d2SRoy Marples if [ -e /etc/arch-release ]; then 2770a68f8d2SRoy Marples _service_status="[ -e /var/run/daemons/\$1 ]" 2780a68f8d2SRoy Marples elif [ "$x" = "/etc/rc.d" ] && [ -e /etc/rc.d/rc.subr ]; then 2790a68f8d2SRoy Marples _service_status="$x/\$1 check >/dev/null 2>&1" 2800a68f8d2SRoy Marples fi 2810a68f8d2SRoy Marples fi 2820a68f8d2SRoy Marples 2830a68f8d2SRoy Marples _detected_init=true 2840a68f8d2SRoy Marples if [ -z "$_service_cmd" ]; then 2850a68f8d2SRoy Marples syslog err "could not detect a useable init system" 2860a68f8d2SRoy Marples return 1 2870a68f8d2SRoy Marples fi 2880a68f8d2SRoy Marples return 0 2890a68f8d2SRoy Marples} 2900a68f8d2SRoy Marples 2910a68f8d2SRoy Marples# Check a system service exists 2920a68f8d2SRoy Marplesservice_exists() 2930a68f8d2SRoy Marples{ 2940a68f8d2SRoy Marples if [ -z "$_service_exists" ]; then 2950a68f8d2SRoy Marples detect_init || return 1 2960a68f8d2SRoy Marples fi 2970a68f8d2SRoy Marples eval $_service_exists 2980a68f8d2SRoy Marples} 2990a68f8d2SRoy Marples 3000a68f8d2SRoy Marples# Send a command to a system service 3010a68f8d2SRoy Marplesservice_cmd() 3020a68f8d2SRoy Marples{ 3030a68f8d2SRoy Marples if [ -z "$_service_cmd" ]; then 3040a68f8d2SRoy Marples detect_init || return 1 3050a68f8d2SRoy Marples fi 3060a68f8d2SRoy Marples eval $_service_cmd 3070a68f8d2SRoy Marples} 3080a68f8d2SRoy Marples 3090a68f8d2SRoy Marples# Send a command to a system service if it is running 3100a68f8d2SRoy Marplesservice_status() 3110a68f8d2SRoy Marples{ 3120a68f8d2SRoy Marples if [ -z "$_service_cmd" ]; then 3130a68f8d2SRoy Marples detect_init || return 1 3140a68f8d2SRoy Marples fi 3150a68f8d2SRoy Marples if [ -n "$_service_status" ]; then 3160a68f8d2SRoy Marples eval $_service_status 3170a68f8d2SRoy Marples else 3180a68f8d2SRoy Marples service_command $1 status >/dev/null 2>&1 3190a68f8d2SRoy Marples fi 3200a68f8d2SRoy Marples} 3210a68f8d2SRoy Marples 3220a68f8d2SRoy Marples# Handy macros for our hooks 3230a68f8d2SRoy Marplesservice_command() 3240a68f8d2SRoy Marples{ 3250a68f8d2SRoy Marples service_exists $1 && service_cmd $1 $2 3260a68f8d2SRoy Marples} 3270a68f8d2SRoy Marplesservice_condcommand() 3280a68f8d2SRoy Marples{ 3290a68f8d2SRoy Marples service_exists $1 && service_status $1 && service_cmd $1 $2 3300a68f8d2SRoy Marples} 3310a68f8d2SRoy Marples 3320a68f8d2SRoy Marples# We source each script into this one so that scripts run earlier can 3330a68f8d2SRoy Marples# remove variables from the environment so later scripts don't see them. 3340a68f8d2SRoy Marples# Thus, the user can create their dhcpcd.enter/exit-hook script to configure 3350a68f8d2SRoy Marples# /etc/resolv.conf how they want and stop the system scripts ever updating it. 3360a68f8d2SRoy Marplesfor hook in \ 3370a68f8d2SRoy Marples /etc/dhcpcd.enter-hook \ 3380a68f8d2SRoy Marples /usr/libexec/dhcpcd-hooks/* \ 3390a68f8d2SRoy Marples /etc/dhcpcd.exit-hook 3400a68f8d2SRoy Marplesdo 341*80aa9461SRoy Marples case "$hook" in 342*80aa9461SRoy Marples */*~) continue;; 343*80aa9461SRoy Marples esac 3440a68f8d2SRoy Marples for skip in $skip_hooks; do 3450a68f8d2SRoy Marples case "$hook" in 3460a68f8d2SRoy Marples */"$skip") continue 2;; 3470a68f8d2SRoy Marples */[0-9][0-9]"-$skip") continue 2;; 3480a68f8d2SRoy Marples */[0-9][0-9]"-$skip.sh") continue 2;; 3490a68f8d2SRoy Marples esac 3500a68f8d2SRoy Marples done 3510a68f8d2SRoy Marples if [ -f "$hook" ]; then 3520a68f8d2SRoy Marples . "$hook" 3530a68f8d2SRoy Marples fi 3540a68f8d2SRoy Marplesdone 355