aboutsummaryrefslogtreecommitdiff
path: root/libexec/rc/rc.d/netwait
blob: 05874552cf1c0201a2d8cf557a6a715288585d05 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/bin/sh
#
# PROVIDE: netwait
# REQUIRE: devd ipfw pf routing
#
# The netwait script helps handle three situations:
#  - Systems with USB or other late-attaching network hardware which
#    is initialized by devd events.  The script waits for all the
#    interfaces named in the netwait_if list to appear.
#  - Systems with IPv6 addresses, especially jails, where we need to
#    wait for DAD to complete before starting daemons, as they will
#    otherwise fail to bind to IN6ADDR_ANY.
#  - Systems with statically-configured IP addresses in rc.conf(5).
#    The IP addresses in the netwait_ip list are pinged.  The script
#    waits for any single IP in the list to respond to the ping.  If your
#    system uses DHCP, you should probably use synchronous_dhclient="YES"
#    in your /etc/rc.conf instead of netwait_ip.
# Either or both of the wait lists can be used (at least one must be
# non-empty if netwait is enabled).

. /etc/rc.subr

name="netwait"
desc="Wait for network devices or the network being up"
rcvar="netwait_enable"

start_cmd="${name}_start"
stop_cmd=":"

netwait_start()
{
	local ip rc count output link wait_if got_if any_error

	if [ -z "${netwait_if}" ] && [ -z "${netwait_ip}" ] &&
	   ! checkyesno netwait_dad ; then
		err 1 "Nothing to wait for"
	fi

	if ! [ "${netwait_if_timeout:=0}" -ge 1 ]; then
		err 1 "netwait_if_timeout must be >= 1"
	fi
	if ! check_kern_features inet6; then
		netwait_dad="NO"
	elif ! [ "${netwait_dad_timeout:=0}" -ge 1 ]; then
		netwait_dad_timeout=$(($(sysctl -n net.inet6.ip6.dad_count)+1))
	fi
	if ! [ "${netwait_timeout:=0}" -ge 1 ]; then
		err 1 "netwait_timeout must be >= 1"
	fi

	any_error=false

	if [ -n "${netwait_if}" ]; then
		for wait_if in ${netwait_if}; do
			echo -n "Waiting for ${wait_if}"
			link=""
			got_if=false
			count=1
			# Handle SIGINT (Ctrl-C); force abort of while loop
			trap break SIGINT
			while [ ${count} -le ${netwait_if_timeout} ]; do
				if output=`/sbin/ifconfig ${wait_if} 2>/dev/null`; then
					if ! ${got_if}; then
						echo -n ", interface present"
						got_if=true
					fi
					link=`expr "${output}" : '.*[[:blank:]]status: \(no carrier\)'`
					if [ -z "${link}" ]; then
						echo ', got link.'
						break
					fi
				fi
				sleep 1
				count=$((count+1))
			done
			# Restore default SIGINT handler
			trap - SIGINT
			if ! ${got_if}; then
				echo ", wait failed: interface never appeared."
				any_error=true
			elif [ -n "${link}" ]; then
				echo ", wait failed: interface still has no link."
				any_error=true
			fi
		done
	fi
	
	if checkyesno netwait_dad; then
		got_dad=false
		# Handle SIGINT (Ctrl-C); force abort of while loop
		trap break SIGINT

		echo -n "Waiting for DAD to complete"
		count=1
		while [ ${count} -le ${netwait_dad_timeout} ]; do
			if ! ifconfig | grep -q 'inet6.*tentative'; then
				echo ', done.'
				got_dad=true
				break
			fi
			sleep 1
			count=$((count+1))
		done

		# Restore default SIGINT handler
		trap - SIGINT

		if ! ${got_dad}; then
			echo ', timed out.'
			any_error=true
		fi
	fi

	if [ -n "${netwait_ip}" ]; then
		got_ip=false
		# Handle SIGINT (Ctrl-C); force abort of for loop
		trap break SIGINT

		for ip in ${netwait_ip}; do
			echo -n "Waiting for ${ip} to respond to ICMP ping"

			count=1
			while [ ${count} -le ${netwait_timeout} ]; do
				/sbin/ping -t 1 -c 1 -o ${ip} >/dev/null 2>&1
				rc=$?

				if [ $rc -eq 0 ]; then
					echo ', got response.'
					got_ip=false
					break 2
				fi
				count=$((count+1))
			done
			echo ', failed: No response from host.'
		done

		# Restore default SIGINT handler
		trap - SIGINT

		if ! ${got_ip}; then
			any_error=true
		fi
	fi

	if ${any_error}; then
		warn "Continuing with startup, but be aware you may not have "
		warn "a fully functional networking layer at this point."
	fi
}

load_rc_config $name

# doesn't make sense to run in a svcj: config setting
netwait_svcj="NO"

run_rc_command "$1"