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