xref: /netbsd-src/external/bsd/dhcpcd/dist/hooks/dhcpcd-run-hooks (revision 794dfa7744c76b94d06f96c66c5309dbba49b631)
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