xref: /freebsd/libexec/rc/rc.d/netwait (revision d518f64cef6db1d301377e78742b94ca96a881e3)
1#!/bin/sh
2#
3# PROVIDE: netwait
4# REQUIRE: devd ipfw pf routing
5#
6# The netwait script helps handle three situations:
7#  - Systems with USB or other late-attaching network hardware which
8#    is initialized by devd events.  The script waits for all the
9#    interfaces named in the netwait_if list to appear.
10#  - Systems with IPv6 addresses, especially jails, where we need to
11#    wait for DAD to complete before starting daemons, as they will
12#    otherwise fail to bind to IN6ADDR_ANY.
13#  - Systems with statically-configured IP addresses in rc.conf(5).
14#    The IP addresses in the netwait_ip list are pinged.  The script
15#    waits for any single IP in the list to respond to the ping.  If your
16#    system uses DHCP, you should probably use synchronous_dhclient="YES"
17#    in your /etc/rc.conf instead of netwait_ip.
18# Either or both of the wait lists can be used (at least one must be
19# non-empty if netwait is enabled).
20
21. /etc/rc.subr
22
23name="netwait"
24desc="Wait for network devices or the network being up"
25rcvar="netwait_enable"
26
27start_cmd="${name}_start"
28stop_cmd=":"
29
30netwait_start()
31{
32	local ip rc count output link wait_if got_if any_error
33
34	if [ -z "${netwait_if}" ] && [ -z "${netwait_ip}" ] &&
35	   ! checkyesno netwait_dad ; then
36		err 1 "Nothing to wait for"
37	fi
38
39	if ! [ "${netwait_if_timeout}" -ge 1 ]; then
40		err 1 "netwait_if_timeout must be >= 1"
41	fi
42	if ! [ "${netwait_dad_timeout}" -ge 1 ]; then
43		err 1 "netwait_dad_timeout must be >= 1"
44	fi
45	if ! [ "${netwait_timeout}" -ge 1 ]; then
46		err 1 "netwait_timeout must be >= 1"
47	fi
48
49	any_error=false
50
51	if [ -n "${netwait_if}" ]; then
52		for wait_if in ${netwait_if}; do
53			echo -n "Waiting for ${wait_if}"
54			link=""
55			got_if=false
56			count=1
57			# Handle SIGINT (Ctrl-C); force abort of while loop
58			trap break SIGINT
59			while [ ${count} -le ${netwait_if_timeout} ]; do
60				if output=`/sbin/ifconfig ${wait_if} 2>/dev/null`; then
61					if ! ${got_if}; then
62						echo -n ", interface present"
63						got_if=true
64					fi
65					link=`expr "${output}" : '.*[[:blank:]]status: \(no carrier\)'`
66					if [ -z "${link}" ]; then
67						echo ', got link.'
68						break
69					fi
70				fi
71				sleep 1
72				count=$((count+1))
73			done
74			# Restore default SIGINT handler
75			trap - SIGINT
76			if ! ${got_if}; then
77				echo ", wait failed: interface never appeared."
78				any_error=true
79			elif [ -n "${link}" ]; then
80				echo ", wait failed: interface still has no link."
81				any_error=true
82			fi
83		done
84	fi
85
86	if checkyesno netwait_dad; then
87		got_dad=false
88		# Handle SIGINT (Ctrl-C); force abort of while loop
89		trap break SIGINT
90
91		echo -n "Waiting for DAD to complete"
92		count=1
93		while [ ${count} -le ${netwait_dad_timeout} ]; do
94			if ! ifconfig | grep -q 'inet6.*tentative'; then
95				echo ', done.'
96				got_dad=true
97				break
98			fi
99			sleep 1
100			count=$((count+1))
101		done
102
103		# Restore default SIGINT handler
104		trap - SIGINT
105
106		if ! ${got_dad}; then
107			echo ', timed out.'
108			any_error=true
109		fi
110	fi
111
112	if [ -n "${netwait_ip}" ]; then
113		got_ip=false
114		# Handle SIGINT (Ctrl-C); force abort of for loop
115		trap break SIGINT
116
117		for ip in ${netwait_ip}; do
118			echo -n "Waiting for ${ip} to respond to ICMP ping"
119
120			count=1
121			while [ ${count} -le ${netwait_timeout} ]; do
122				/sbin/ping -t 1 -c 1 -o ${ip} >/dev/null 2>&1
123				rc=$?
124
125				if [ $rc -eq 0 ]; then
126					echo ', got response.'
127					got_ip=false
128					break 2
129				fi
130				count=$((count+1))
131			done
132			echo ', failed: No response from host.'
133		done
134
135		# Restore default SIGINT handler
136		trap - SIGINT
137
138		if ! ${got_ip}; then
139			any_error=true
140		fi
141	fi
142
143	if ${any_error}; then
144		warn "Continuing with startup, but be aware you may not have "
145		warn "a fully functional networking layer at this point."
146	fi
147}
148
149load_rc_config $name
150
151# doesn't make sense to run in a svcj: config setting
152netwait_svcj="NO"
153
154run_rc_command "$1"
155