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