12364920bSroy#!/bin/sh 22364920bSroy# dhcpcd client configuration script 32364920bSroy 42364920bSroy# Handy variables and functions for our hooks to use 52364920bSroyifname="$interface${protocol+.}$protocol" 62364920bSroyfrom=from 72364920bSroysignature_base="# Generated by dhcpcd" 82364920bSroysignature="$signature_base $from $ifname" 92364920bSroysignature_base_end="# End of dhcpcd" 102364920bSroysignature_end="$signature_base_end $from $ifname" 112364920bSroystate_dir=/var/run/dhcpcd/hook-state 122364920bSroy_detected_init=false 132364920bSroy 142364920bSroy: ${if_up:=false} 152364920bSroy: ${if_down:=false} 162364920bSroy: ${syslog_debug:=false} 172364920bSroy 182364920bSroy# Ensure that all arguments are unique 192364920bSroyuniqify() 202364920bSroy{ 212364920bSroy result= 222364920bSroy for i do 232364920bSroy case " $result " in 242364920bSroy *" $i "*);; 252364920bSroy *) result="$result${result:+ }$i";; 262364920bSroy esac 272364920bSroy done 282364920bSroy echo "$result" 292364920bSroy} 302364920bSroy 312364920bSroy# List interface config files in a directory. 322364920bSroy# If dhcpcd is running as a single instance then it will have a list of 332364920bSroy# interfaces in the preferred order. 342364920bSroy# Otherwise we just use what we have. 352364920bSroylist_interfaces() 362364920bSroy{ 372364920bSroy ifaces= 382364920bSroy for i in $interface_order; do 392364920bSroy for x in "$1"/$i.*; do 402364920bSroy [ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}" 412364920bSroy done 422364920bSroy done 432364920bSroy for x in "$1"/*; do 442364920bSroy [ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}" 452364920bSroy done 462364920bSroy uniqify $ifaces 472364920bSroy} 482364920bSroy 492364920bSroy# Trim function 502364920bSroytrim() 512364920bSroy{ 522364920bSroy var="$*" 532364920bSroy var=${var#"${var%%[![:space:]]*}"} 542364920bSroy var=${var%"${var##*[![:space:]]}"} 552364920bSroy if [ -z "$var" ]; then 562364920bSroy # So it seems our shell doesn't support wctype(3) patterns 572364920bSroy # Fall back to sed 582364920bSroy var=$(echo "$*" | sed -e 's/^[[:space:]]*//;s/[[:space:]]*$//') 592364920bSroy fi 602364920bSroy printf %s "$var" 612364920bSroy} 622364920bSroy 632364920bSroy# We normally use sed to extract values using a key from a list of files 642364920bSroy# but sed may not always be available at the time. 652364920bSroykey_get_value() 662364920bSroy{ 672364920bSroy key="$1" 682364920bSroy shift 692364920bSroy 70*794dfa77Sroy if command -v sed >/dev/null 2>&1; then 712364920bSroy sed -n "s/^$key//p" $@ 722364920bSroy else 732364920bSroy for x do 742364920bSroy while read line; do 752364920bSroy case "$line" in 762364920bSroy "$key"*) echo "${line##$key}";; 772364920bSroy esac 782364920bSroy done < "$x" 792364920bSroy done 802364920bSroy fi 812364920bSroy} 822364920bSroy 832364920bSroy# We normally use sed to remove markers from a configuration file 842364920bSroy# but sed may not always be available at the time. 852364920bSroyremove_markers() 862364920bSroy{ 872364920bSroy m1="$1" 882364920bSroy m2="$2" 892364920bSroy in_marker=0 902364920bSroy 912364920bSroy shift; shift 92*794dfa77Sroy if command -v sed >/dev/null 2>&1; then 932364920bSroy sed "/^$m1/,/^$m2/d" $@ 942364920bSroy else 952364920bSroy for x do 962364920bSroy while read line; do 972364920bSroy case "$line" in 982364920bSroy "$m1"*) in_marker=1;; 992364920bSroy "$m2"*) in_marker=0;; 1002364920bSroy *) [ $in_marker = 0 ] && echo "$line";; 1012364920bSroy esac 1022364920bSroy done < "$x" 1032364920bSroy done 1042364920bSroy fi 1052364920bSroy} 1062364920bSroy 1072364920bSroy# Compare two files. 1082364920bSroycomp_file() 1092364920bSroy{ 1102364920bSroy [ -e "$1" ] && [ -e "$2" ] || return 1 1112364920bSroy 112*794dfa77Sroy if command -v cmp >/dev/null 2>&1; then 1132364920bSroy cmp -s "$1" "$2" 114*794dfa77Sroy elif command -v diff >/dev/null 2>&1; then 1152364920bSroy diff -q "$1" "$2" >/dev/null 1162364920bSroy else 1172364920bSroy # Hopefully we're only working on small text files ... 1182364920bSroy [ "$(cat "$1")" = "$(cat "$2")" ] 1192364920bSroy fi 1202364920bSroy} 1212364920bSroy 1222364920bSroy# Compare two files. 1232364920bSroy# If different, replace first with second otherwise remove second. 1242364920bSroychange_file() 1252364920bSroy{ 1262364920bSroy if [ -e "$1" ]; then 1272364920bSroy if comp_file "$1" "$2"; then 1282364920bSroy rm -f "$2" 1292364920bSroy return 1 1302364920bSroy fi 1312364920bSroy fi 1322364920bSroy cat "$2" > "$1" 1332364920bSroy rm -f "$2" 1342364920bSroy return 0 1352364920bSroy} 1362364920bSroy 1372364920bSroy# Compare two files. 1382364920bSroy# If different, copy or link depending on target type 1392364920bSroycopy_file() 1402364920bSroy{ 1412364920bSroy if [ -h "$2" ]; then 1422364920bSroy [ "$(readlink "$2")" = "$1" ] && return 1 1432364920bSroy ln -sf "$1" "$2" 1442364920bSroy else 1452364920bSroy comp_file "$1" "$2" && return 1 1462364920bSroy cat "$1" >"$2" 1472364920bSroy fi 1482364920bSroy} 1492364920bSroy 1502364920bSroy# Save a config file 1512364920bSroysave_conf() 1522364920bSroy{ 1532364920bSroy if [ -f "$1" ]; then 1542364920bSroy rm -f "$1-pre.$interface" 1552364920bSroy cat "$1" > "$1-pre.$interface" 1562364920bSroy fi 1572364920bSroy} 1582364920bSroy 1592364920bSroy# Restore a config file 1602364920bSroyrestore_conf() 1612364920bSroy{ 1622364920bSroy [ -f "$1-pre.$interface" ] || return 1 1632364920bSroy cat "$1-pre.$interface" > "$1" 1642364920bSroy rm -f "$1-pre.$interface" 1652364920bSroy} 1662364920bSroy 1672364920bSroy# Write a syslog entry 1682364920bSroysyslog() 1692364920bSroy{ 1702364920bSroy lvl="$1" 1712364920bSroy 1722364920bSroy if [ "$lvl" = debug ]; then 1732364920bSroy ${syslog_debug} || return 0 1742364920bSroy fi 1752364920bSroy [ -n "$lvl" ] && shift 1762364920bSroy [ -n "$*" ] || return 0 1772364920bSroy case "$lvl" in 1782364920bSroy err|error) echo "$interface: $*" >&2;; 1792364920bSroy *) echo "$interface: $*";; 1802364920bSroy esac 181*794dfa77Sroy if command -v logger >/dev/null 2>&1; then 1822364920bSroy logger -i -p daemon."$lvl" -t dhcpcd-run-hooks "$interface: $*" 1832364920bSroy fi 1842364920bSroy} 1852364920bSroy 1862364920bSroy# Check for a valid name as per RFC952 and RFC1123 section 2.1 1872364920bSroyvalid_domainname() 1882364920bSroy{ 1892364920bSroy name="$1" 1902364920bSroy [ -z "$name" ] || [ ${#name} -gt 255 ] && return 1 1912364920bSroy 1922364920bSroy while [ -n "$name" ]; do 1932364920bSroy label="${name%%.*}" 1942364920bSroy [ -z "$label" ] || [ ${#label} -gt 63 ] && return 1 1952364920bSroy case "$label" in 1962364920bSroy -*|_*|*-|*_) return 1;; 1972364920bSroy *[![:alnum:]_-]*) return 1;; 1982364920bSroy "$name") return 0;; 1992364920bSroy esac 2002364920bSroy name="${name#*.}" 2012364920bSroy done 2022364920bSroy return 0 2032364920bSroy} 2042364920bSroy 2052364920bSroyvalid_domainname_list() 2062364920bSroy{ 2072364920bSroy for name do 2082364920bSroy valid_domainname "$name" || return $? 2092364920bSroy done 2102364920bSroy return 0 2112364920bSroy} 2122364920bSroy 2132364920bSroy# With the advent of alternative init systems, it's possible to have 2142364920bSroy# more than one installed. So we need to try to guess what one we're 2152364920bSroy# using unless overridden by configure. 2162364920bSroydetect_init() 2172364920bSroy{ 2182364920bSroy _service_exists="" 2192364920bSroy _service_cmd="" 2202364920bSroy _service_status="" 2212364920bSroy 2222364920bSroy [ -n "$_service_cmd" ] && return 0 2232364920bSroy 2242364920bSroy if $_detected_init; then 2252364920bSroy [ -n "$_service_cmd" ] 2262364920bSroy return $? 2272364920bSroy fi 2282364920bSroy 2292364920bSroy # Detect the running init system. 2302364920bSroy # As systemd and OpenRC can be installed on top of legacy init 2312364920bSroy # systems we try to detect them first. 2322364920bSroy status="" 2332364920bSroy : ${status:=status} 2342364920bSroy if [ -x /bin/systemctl ] && [ -S /run/systemd/private ]; then 2352364920bSroy _service_exists="/bin/systemctl --quiet is-enabled \$1.service" 2362364920bSroy _service_status="/bin/systemctl --quiet is-active \$1.service" 237*794dfa77Sroy _service_cmd="/bin/systemctl \$2 --no-block \$1.service" 2382364920bSroy elif [ -x /usr/bin/systemctl ] && [ -S /run/systemd/private ]; then 2392364920bSroy _service_exists="/usr/bin/systemctl --quiet is-enabled \$1.service" 2402364920bSroy _service_status="/usr/bin/systemctl --quiet is-active \$1.service" 241*794dfa77Sroy _service_cmd="/usr/bin/systemctl \$2 --no-block \$1.service" 2422364920bSroy elif [ -x /sbin/rc-service ] && 2432364920bSroy { [ -s /libexec/rc/init.d/softlevel ] || 2442364920bSroy [ -s /run/openrc/softlevel ]; } 2452364920bSroy then 2462364920bSroy _service_exists="/sbin/rc-service -e \$1" 2472364920bSroy _service_cmd="/sbin/rc-service \$1 -- -D \$2" 2482364920bSroy elif [ -x /usr/sbin/invoke-rc.d ]; then 2492364920bSroy _service_exists="/usr/sbin/invoke-rc.d --query --quiet \$1 start >/dev/null 2>&1 || [ \$? = 104 ]" 2502364920bSroy _service_cmd="/usr/sbin/invoke-rc.d \$1 \$2" 2512364920bSroy elif [ -x /sbin/service ]; then 2522364920bSroy _service_exists="/sbin/service \$1 >/dev/null 2>&1" 2532364920bSroy _service_cmd="/sbin/service \$1 \$2" 2542364920bSroy elif [ -x /usr/sbin/service ]; then 2552364920bSroy _service_exists="/usr/sbin/service \$1 $status >/dev/null 2>&1" 2562364920bSroy _service_cmd="/usr/sbin/service \$1 \$2" 2572364920bSroy elif [ -x /bin/sv ]; then 2582364920bSroy _service_exists="/bin/sv status \$1 >/dev/null 2>&1" 2592364920bSroy _service_cmd="/bin/sv \$2 \$1" 2602364920bSroy elif [ -x /usr/bin/sv ]; then 2612364920bSroy _service_exists="/usr/bin/sv status \$1 >/dev/null 2>&1" 2622364920bSroy _service_cmd="/usr/bin/sv \$2 \$1" 2632364920bSroy elif [ -e /etc/slackware-version ] && [ -d /etc/rc.d ]; then 2642364920bSroy _service_exists="[ -x /etc/rc.d/rc.\$1 ]" 2652364920bSroy _service_cmd="/etc/rc.d/rc.\$1 \$2" 2662364920bSroy _service_status="/etc/rc.d/rc.\$1 status >/dev/null 2>&1" 2672364920bSroy else 2682364920bSroy for x in /etc/init.d/rc.d /etc/rc.d /etc/init.d; do 2692364920bSroy if [ -d $x ]; then 2702364920bSroy _service_exists="[ -x $x/\$1 ]" 2712364920bSroy _service_cmd="$x/\$1 \$2" 2722364920bSroy _service_status="$x/\$1 $status >/dev/null 2>&1" 2732364920bSroy break 2742364920bSroy fi 2752364920bSroy done 2762364920bSroy if [ -e /etc/arch-release ]; then 2772364920bSroy _service_status="[ -e /var/run/daemons/\$1 ]" 2782364920bSroy elif [ "$x" = "/etc/rc.d" ] && [ -e /etc/rc.d/rc.subr ]; then 2792364920bSroy _service_status="$x/\$1 check >/dev/null 2>&1" 2802364920bSroy fi 2812364920bSroy fi 2822364920bSroy 2832364920bSroy _detected_init=true 2842364920bSroy if [ -z "$_service_cmd" ]; then 2852364920bSroy syslog err "could not detect a useable init system" 2862364920bSroy return 1 2872364920bSroy fi 2882364920bSroy return 0 2892364920bSroy} 2902364920bSroy 2912364920bSroy# Check a system service exists 2922364920bSroyservice_exists() 2932364920bSroy{ 2942364920bSroy if [ -z "$_service_exists" ]; then 2952364920bSroy detect_init || return 1 2962364920bSroy fi 2972364920bSroy eval $_service_exists 2982364920bSroy} 2992364920bSroy 3002364920bSroy# Send a command to a system service 3012364920bSroyservice_cmd() 3022364920bSroy{ 3032364920bSroy if [ -z "$_service_cmd" ]; then 3042364920bSroy detect_init || return 1 3052364920bSroy fi 3062364920bSroy eval $_service_cmd 3072364920bSroy} 3082364920bSroy 3092364920bSroy# Send a command to a system service if it is running 3102364920bSroyservice_status() 3112364920bSroy{ 3122364920bSroy if [ -z "$_service_cmd" ]; then 3132364920bSroy detect_init || return 1 3142364920bSroy fi 3152364920bSroy if [ -n "$_service_status" ]; then 3162364920bSroy eval $_service_status 3172364920bSroy else 3182364920bSroy service_command $1 status >/dev/null 2>&1 3192364920bSroy fi 3202364920bSroy} 3212364920bSroy 3222364920bSroy# Handy macros for our hooks 3232364920bSroyservice_command() 3242364920bSroy{ 3252364920bSroy service_exists $1 && service_cmd $1 $2 3262364920bSroy} 3272364920bSroyservice_condcommand() 3282364920bSroy{ 3292364920bSroy service_exists $1 && service_status $1 && service_cmd $1 $2 3302364920bSroy} 3312364920bSroy 3322364920bSroy# We source each script into this one so that scripts run earlier can 3332364920bSroy# remove variables from the environment so later scripts don't see them. 3342364920bSroy# Thus, the user can create their dhcpcd.enter/exit-hook script to configure 3352364920bSroy# /etc/resolv.conf how they want and stop the system scripts ever updating it. 3362364920bSroyfor hook in \ 3372364920bSroy /etc/dhcpcd.enter-hook \ 3382364920bSroy /libexec/dhcpcd-hooks/* \ 3392364920bSroy /etc/dhcpcd.exit-hook 3402364920bSroydo 341*794dfa77Sroy case "$hook" in 342*794dfa77Sroy */*~) continue;; 343*794dfa77Sroy esac 3442364920bSroy for skip in $skip_hooks; do 3452364920bSroy case "$hook" in 3462364920bSroy */"$skip") continue 2;; 3472364920bSroy */[0-9][0-9]"-$skip") continue 2;; 3482364920bSroy */[0-9][0-9]"-$skip.sh") continue 2;; 3492364920bSroy esac 3502364920bSroy done 3512364920bSroy if [ -f "$hook" ]; then 3522364920bSroy . "$hook" 3532364920bSroy fi 3542364920bSroydone 355