Home | History | Annotate | Download | only in dhcpcd-6.8.2
      1 #!/bin/sh
      2 # dhcpcd client configuration script 
      3 
      4 # Handy variables and functions for our hooks to use
      5 case "$reason" in
      6 	ROUTERADVERT)
      7 		ifsuffix=".ra";;
      8 	INFORM6|BOUND6|RENEW6|REBIND6|REBOOT6|EXPIRE6|RELEASE6|STOP6)
      9 		ifsuffix=".dhcp6";;
     10 	*)
     11 		ifsuffix=".dhcp";;
     12 esac
     13 ifname="$interface$ifsuffix${ifclass+.}$ifclass"
     14 
     15 from=from
     16 signature_base="# Generated by dhcpcd"
     17 signature="$signature_base $from $ifname"
     18 signature_base_end="# End of dhcpcd"
     19 signature_end="$signature_base_end $from $ifname"
     20 state_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
     28 uniqify()
     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.
     44 list_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
     59 trim()
     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.
     75 key_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.
     95 remove_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.
    116 comp_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.
    134 change_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
    150 copy_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
    163 save_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
    173 restore_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
    182 syslog()
    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.
    202 valid_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 
    223 valid_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
    234 valid_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.
    246 detect_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 
    316 service_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
    326 service_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
    336 service_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
    350 service_command()
    351 {
    352 
    353 	service_exists $1 && service_cmd $1 $2
    354 }
    355 service_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.
    365 for hook in \
    366 	@SYSCONFDIR@/dhcpcd.enter-hook \
    367 	@HOOKDIR@/* \
    368 	@SYSCONFDIR@/dhcpcd.exit-hook
    369 do
    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
    381 done
    382