1#!/bin/sh 2# $NetBSD: dhcpcd-run-hooks.in,v 1.11 2015/08/21 10:39:00 roy Exp $ 3 4# dhcpcd client configuration script 5 6# Handy variables and functions for our hooks to use 7case "$reason" in 8 ROUTERADVERT) 9 ifsuffix=".ra";; 10 INFORM6|BOUND6|RENEW6|REBIND6|REBOOT6|EXPIRE6|RELEASE6|STOP6) 11 ifsuffix=".dhcp6";; 12 IPV4LL) 13 ifsuffix=".ipv4ll";; 14 *) 15 ifsuffix=".dhcp";; 16esac 17ifname="$interface$ifsuffix" 18 19from=from 20signature_base="# Generated by dhcpcd" 21signature="$signature_base $from $ifname" 22signature_base_end="# End of dhcpcd" 23signature_end="$signature_base_end $from $ifname" 24state_dir=@RUNDIR@/dhcpcd 25_detected_init=false 26 27: ${if_up:=false} 28: ${if_down:=false} 29: ${syslog_debug:=false} 30 31# Ensure that all arguments are unique 32uniqify() 33{ 34 local result= i= 35 for i do 36 case " $result " in 37 *" $i "*);; 38 *) result="$result $i";; 39 esac 40 done 41 echo "${result# *}" 42} 43 44# List interface config files in a directory. 45# If dhcpcd is running as a single instance then it will have a list of 46# interfaces in the preferred order. 47# Otherwise we just use what we have. 48list_interfaces() 49{ 50 local i= x= ifaces= 51 for i in $interface_order; do 52 for x in "$1"/$i.*; do 53 [ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}" 54 done 55 done 56 for x in "$1"/*; do 57 [ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}" 58 done 59 uniqify $ifaces 60} 61 62# Trim function 63trim() 64{ 65 local var="$*" 66 67 var=${var#"${var%%[![:space:]]*}"} 68 var=${var%"${var##*[![:space:]]}"} 69 if [ -z "$var" ]; then 70 # So it seems our shell doesn't support wctype(3) patterns 71 # Fall back to sed 72 var=$(echo "$*" | sed -e 's/^[[:space:]]*//;s/[[:space:]]*$//') 73 fi 74 printf %s "$var" 75} 76 77# We normally use sed to extract values using a key from a list of files 78# but sed may not always be available at the time. 79key_get_value() 80{ 81 local key="$1" value= x= line= 82 83 shift 84 if type sed >/dev/null 2>&1; then 85 sed -n "s/^$key//p" $@ 86 else 87 for x do 88 while read line; do 89 case "$line" in 90 "$key"*) echo "${line##$key}";; 91 esac 92 done < "$x" 93 done 94 fi 95} 96 97# We normally use sed to remove markers from a configuration file 98# but sed may not always be available at the time. 99remove_markers() 100{ 101 local m1="$1" m2="$2" x= line= in_marker=0 102 103 shift; shift 104 if type sed >/dev/null 2>&1; then 105 sed "/^$m1/,/^$m2/d" $@ 106 else 107 for x do 108 while read line; do 109 case "$line" in 110 "$m1"*) in_marker=1;; 111 "$m2"*) in_marker=0;; 112 *) [ $in_marker = 0 ] && echo "$line";; 113 esac 114 done < "$x" 115 done 116 fi 117} 118 119# Compare two files. 120comp_file() 121{ 122 123 [ -e "$1" -a -e "$2" ] || return 1 124 125 if type cmp >/dev/null 2>&1; then 126 cmp -s "$1" "$2" 127 elif type diff >/dev/null 2>&1; then 128 diff -q "$1" "$2" >/dev/null 129 else 130 # Hopefully we're only working on small text files ... 131 [ "$(cat "$1")" = "$(cat "$2")" ] 132 fi 133} 134 135# Compare two files. 136# If different, replace first with second otherwise remove second. 137change_file() 138{ 139 140 if [ -e "$1" ]; then 141 if comp_file "$1" "$2"; then 142 rm -f "$2" 143 return 1 144 fi 145 fi 146 cat "$2" > "$1" 147 rm -f "$2" 148 return 0 149} 150 151# Compare two files. 152# If different, copy or link depending on target type 153copy_file() 154{ 155 156 if [ -h "$2" ]; then 157 [ "$(readlink "$2")" = "$1" ] && return 1 158 ln -sf "$1" "$2" 159 else 160 comp_file "$1" "$2" && return 1 161 cat "$1" >"$2" 162 fi 163} 164 165# Save a config file 166save_conf() 167{ 168 169 if [ -f "$1" ]; then 170 rm -f "$1-pre.$interface" 171 cat "$1" > "$1-pre.$interface" 172 fi 173} 174 175# Restore a config file 176restore_conf() 177{ 178 179 [ -f "$1-pre.$interface" ] || return 1 180 cat "$1-pre.$interface" > "$1" 181 rm -f "$1-pre.$interface" 182} 183 184# Write a syslog entry 185syslog() 186{ 187 local lvl="$1" 188 189 if [ "$lvl" = debug ]; then 190 ${syslog_debug} || return 0 191 fi 192 [ -n "$lvl" ] && shift 193 [ -n "$*" ] || return 0 194 case "$lvl" in 195 err|error) echo "$interface: $*" >&2;; 196 *) echo "$interface: $*";; 197 esac 198 if type logger >/dev/null 2>&1; then 199 logger -i -p daemon."$lvl" -t dhcpcd-run-hooks "$interface: $*" 200 fi 201} 202 203# Check for a valid domain name as per RFC1123 with the exception of 204# allowing - and _ as they seem to be widely used. 205valid_domainname() 206{ 207 local name="$1" label 208 209 [ -z "$name" -o ${#name} -gt 255 ] && return 1 210 211 while [ -n "$name" ]; do 212 label="${name%%.*}" 213 [ -z "$label" -o ${#label} -gt 63 ] && return 1 214 case "$label" in 215 -*|_*|*-|*_) return 1;; 216 # some sh require - as the first or last character in the class 217 # when matching it 218 *[![:alnum:]_-]*) return 1;; 219 esac 220 [ "$name" = "${name#*.}" ] && break 221 name="${name#*.}" 222 done 223 return 0 224} 225 226valid_domainname_list() 227{ 228 local name 229 230 for name do 231 valid_domainname "$name" || return $? 232 done 233 return 0 234} 235 236# Check for a valid path 237valid_path() 238{ 239 240 case "$@" in 241 *[![:alnum:]#%+-_:\.,@~\\/\[\]=\ ]*) return 1;; 242 esac 243 return 0 244} 245 246# With the advent of alternative init systems, it's possible to have 247# more than one installed. So we need to try and guess what one we're 248# using unless overriden by configure. 249detect_init() 250{ 251 _service_exists="@SERVICEEXISTS@" 252 _service_cmd="@SERVICECMD@" 253 _service_status="@SERVICESTATUS@" 254 255 [ -n "$_service_cmd" ] && return 0 256 257 if ${_detected_init}; then 258 [ -n "$_service_cmd" ] 259 return $? 260 fi 261 262 # Detect the running init system. 263 # As systemd and OpenRC can be installed on top of legacy init 264 # systems we try to detect them first. 265 _service_status= 266 if [ -x /bin/systemctl -a -S /run/systemd/private ]; then 267 _service_exists="/bin/systemctl --quiet is-enabled \$1.service" 268 _service_status="/bin/systemctl --quiet is-active \$1.service" 269 _service_cmd="/bin/systemctl \$2 \$1.service" 270 elif [ -x /usr/bin/systemctl -a -S /run/systemd/private ]; then 271 _service_exists="/usr/bin/systemctl --quiet is-enabled \$1.service" 272 _service_status="/usr/bin/systemctl --quiet is-active \$1.service" 273 _service_cmd="/usr/bin/systemctl \$2 \$1.service" 274 elif [ -x /sbin/rc-service -a \ 275 -s /libexec/rc/init.d/softlevel -o -s /run/openrc/softlevel ] 276 then 277 _service_exists="/sbin/rc-service -e \$1" 278 _service_cmd="/sbin/rc-service \$1 -- -D \$2" 279 elif [ -x /usr/sbin/invoke-rc.d ]; then 280 _service_exists="/usr/sbin/invoke-rc.d --query --quiet \$1 start >/dev/null 2>&1 || [ \$? = 104 ]" 281 _service_cmd="/usr/sbin/invoke-rc.d \$1 \$2" 282 elif [ -x /sbin/service ]; then 283 _service_exists="/sbin/service \$1 >/dev/null 2>&1" 284 _service_cmd="/sbin/service \$1 \$2" 285 elif [ -x /bin/sv ]; then 286 _service_exists="/bin/sv status \1 >/dev/null 2>&1" 287 _service_cmd="/bin/sv \$1 \$2" 288 elif [ -x /usr/bin/sv ]; then 289 _service_exists="/usr/bin/sv status \1 >/dev/null 2>&1" 290 _service_cmd="/usr/bin/sv \$1 \$2" 291 elif [ -e /etc/slackware-version -a -d /etc/rc.d ]; then 292 _service_exists="[ -x /etc/rc.d/rc.\$1 ]" 293 _service_cmd="/etc/rc.d/rc.\$1 \$2" 294 _service_status="/etc/rc.d/rc.\$1 status 1>/dev/null 2>&1" 295 else 296 for x in /etc/init.d/rc.d /etc/rc.d /etc/init.d; do 297 if [ -d $x ]; then 298 _service_exists="[ -x $x/\$1 ]" 299 _service_cmd="$x/\$1 \$2" 300 break 301 fi 302 done 303 if [ -e /etc/arch-release ]; then 304 _service_status="[ -e /var/run/daemons/\$1 ]" 305 elif [ "$x" = "/etc/rc.d" -a -e /etc/rc.d/rc.subr ]; then 306 _service_status="$x/\$1 check 1>/dev/null 2>&1" 307 fi 308 fi 309 310 _detected_init=true 311 if [ -z "$_service_cmd" ]; then 312 syslog err "could not detect a useable init system" 313 return 1 314 fi 315 return 0 316} 317 318# Check a system service exists 319service_exists() 320{ 321 322 if [ -z "$_service_exists" ]; then 323 detect_init || return 1 324 fi 325 eval $_service_exists 326} 327 328# Send a command to a system service 329service_cmd() 330{ 331 332 if [ -z "$_service_cmd" ]; then 333 detect_init || return 1 334 fi 335 eval $_service_cmd 336} 337 338# Send a command to a system service if it is running 339service_status() 340{ 341 342 if [ -z "$_service_cmd" ]; then 343 detect_init || return 1 344 fi 345 if [ -n "$_service_status" ]; then 346 eval $_service_status 347 else 348 service_command $1 status >/dev/null 2>&1 349 fi 350} 351 352# Handy macros for our hooks 353service_command() 354{ 355 356 service_exists $1 && service_cmd $1 $2 357} 358service_condcommand() 359{ 360 361 service_exists $1 && service_status $1 && service_cmd $1 $2 362} 363 364# We source each script into this one so that scripts run earlier can 365# remove variables from the environment so later scripts don't see them. 366# Thus, the user can create their dhcpcd.enter/exit-hook script to configure 367# /etc/resolv.conf how they want and stop the system scripts ever updating it. 368for hook in \ 369 @SYSCONFDIR@/dhcpcd.enter-hook \ 370 @HOOKDIR@/* \ 371 @SYSCONFDIR@/dhcpcd.exit-hook 372do 373 for skip in $skip_hooks; do 374 case "$hook" in 375 */*~) continue 2;; 376 */"$skip") continue 2;; 377 */[0-9][0-9]"-$skip") continue 2;; 378 */[0-9][0-9]"-$skip.sh") continue 2;; 379 esac 380 done 381 if [ -f "$hook" ]; then 382 . "$hook" 383 fi 384done 385