#!/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";; STOPPED) # This reason should never be processed exit 0;; *) ifsuffix=;; esac ifname="$interface$ifsuffix${ifclass+.}$ifclass" 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=/var/run/dhcpcd _detected_init=false : ${if_up:=false} : ${if_down:=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 [ -e "$1/$i" ] && ifaces="$ifaces${ifaces:+ }$i" done for x in "$1"/*; do [ -e "$x" ] || continue for i in $interface_order; do if [ $i = "${x##*/}" ]; then unset x break fi done [ -n "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}" done echo "$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" ] || return 1 [ -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 "$2" >"$1" 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" [ -n "$lvl" ] && shift if [ -n "$*" ]; then if type logger >/dev/null 2>&1; then logger -t dhcpcd -p daemon."$lvl" -is "$interface: $*" fi 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="" _service_cmd="" _service_status="" [ -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. _service_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 [ -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 1>/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" 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 1>/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 \ /etc/dhcpcd.enter-hook \ /libexec/dhcpcd-hooks/* \ /etc/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