xref: /illumos-gate/usr/src/cmd/svc/milestone/net-svc (revision d7ddd43c70ebe97a1118be9f663a54d0d1d89fe6)
1#!/sbin/sh
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22#
23# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26# ident	"%Z%%M%	%I%	%E% SMI"
27
28#
29# This is third phase of TCP/IP startup/configuration.  This script
30# runs after the NIS/NIS+ startup script.  We run things here that may
31# depend on NIS/NIS+ maps.
32#
33
34. /lib/svc/share/smf_include.sh
35
36case "$1" in
37'start')
38	#
39	# In a shared-IP zone we need this service to be up, but all of the
40	# work it tries to do is irrelevant (and will actually lead to the
41	# service failing if we try to do it), so just bail out.
42	# In the global zone and exclusive-IP zones we proceed.
43	#
44	smf_configure_ip || exit 0
45	;; # Fall through -- rest of script is the initialization code
46
47'stop')
48	exit 0
49	;;
50
51*)
52	echo "Usage: $0 { start | stop }"
53	exit 1
54	;;
55esac
56
57NWAM_FMRI="svc:/network/physical:nwam"
58NETSVC_FMRI="svc:/network/service:default"
59
60interface=$2
61
62# If boot variables are not set, set variables we use
63[ -z "$_INIT_UTS_NODENAME" ] && _INIT_UTS_NODENAME=`/usr/bin/uname -n`
64
65#
66# This function removes the instance portion of the passed-in FMRI; for
67# example, 'svc:/network/service:default' becomes 'svc:/network/service'.
68#
69remove_fmri_inst () {
70	echo $1 | awk -F: ' { printf "%s:%s", $1, $2 } '
71}
72
73#
74# This function returns true if this script was *not* invoked
75# by an instance of svc:/network/service.
76#
77fmri_is_not_netsvc () {
78	FMRI_1=`remove_fmri_inst $SMF_FMRI`
79	FMRI_2=`remove_fmri_inst $NETSVC_FMRI`
80	[ "$FMRI_1" = "$FMRI_2" ] && return 1
81	return 0
82}
83
84#
85# This function returns true if this script was *not* invoked
86# by the nwam instance of the network/physical service.
87#
88fmri_is_not_nwam () {
89	[ "&SMF_FMRI" = "$NWAM_FMRI" ] && return 1
90	return 0
91}
92
93#
94# This function returns true if the nwam service is not running, false
95# if it is.  "running" is defined as "current state is online or next
96# state is online".
97#
98nwam_is_not_running() {
99	state=`/usr/bin/svcprop -p restarter/state $NWAM_FMRI`
100	nstate=`/usr/bin/svcprop -p restarter/next_state $NWAM_FMRI`
101
102	[ "$state" = "online" -o "$nextstate" = "online" ] && return 1
103	return 0
104}
105
106#
107# wait_nis
108# Wait up to 5 seconds for ypbind to obtain a binding.
109#
110wait_nis ()
111{
112	for i in 1 2 3 4 5; do
113		server=`/usr/bin/ypwhich 2>/dev/null`
114		[ $? -eq 0 -a -n "$server" ] && return 0 || sleep 1
115	done
116	return 1
117}
118
119#
120# This function takes two file names and the file mode as input. The two
121# files are compared for differences (using cmp(1)) and if different, the
122# second file is over written with the first. A chmod is done with the file
123# mode passed in. If the files are equal, the first file passed
124# in (the /tmp file) is deleted.
125#
126mv_file ()
127{
128	/usr/bin/cmp -s $1 $2
129	if [ $? -eq 1 ]; then
130		/usr/bin/mv $1 $2
131		#
132		# The umask during boot is configurable, which requires
133		# explicit setting of file permission modes when we
134		# create files.
135		#
136		/usr/bin/chmod $3 $2
137	else
138		/usr/bin/rm $1
139	fi
140}
141
142#
143# This function takes a DHCP parameter (as defined in /etc/dhcp/inittab)
144# and returns the value for that parameter returned by the DHCP server.
145# If the global 'interface' is defined, it will request the value learned
146# on that interface, else it will request the value learned on the primary
147# interface.
148#
149get_dhcp_var ()
150{
151	if [ -n "$interface" ]; then
152		/sbin/dhcpinfo -i $interface $1
153	else
154		/sbin/dhcpinfo $1
155	fi
156}
157
158#
159# This function returns true if the string "# Added by DHCP$" occurs in
160# the passed-in file, false otherwise.
161#
162dhcp_edits ()
163{
164	/usr/bin/grep '# Added by DHCP$' $1 >/dev/null 2>&1
165	return $?
166}
167
168#
169# update_resolv()
170# Go through /etc/resolv.conf and replace any existing domain or
171# nameserver entries with new ones derived from DHCP.  Note that
172# it is important to preserve order of domain entries vs. search
173# entries; the search entries are reserved for administrator
174# customization and if placed after the domain entry will override
175# it.  See resolv.conf(4).
176#
177# The first arg should be the dns servers string, the second
178# should be the dns domain.
179#
180update_resolv ()
181{
182	dnsservers=$1
183	dnsdomain=$2
184
185	if [ ! -f /etc/resolv.conf ]; then
186		/usr/bin/touch /etc/resolv.conf
187	fi
188	export dnsservers dnsdomain
189	/usr/bin/nawk </etc/resolv.conf >/tmp/resolv.conf.$$ '
190		function writedomain() {
191			if (updated == 0) {
192			    	# Use only first domain, not a search list
193			    	split(ENVIRON["dnsdomain"], d)
194				if(length(d[1]) != 0)
195					printf("domain %s\n", d[1])
196			}
197			++updated
198		}
199		$1 == "domain" { writedomain(); next }
200		$1 != "nameserver" { print $0 }
201		END {
202			writedomain()
203			n = split(ENVIRON["dnsservers"], s)
204			for (i = 1; i <= n; ++i)
205				printf("nameserver %s\n", s[i])
206		}'
207	unset dnsservers dnsdomain
208	mv_file /tmp/resolv.conf.$$ /etc/resolv.conf 644
209}
210
211#
212# update_nss
213# This routine takes as a parameter, the name of the respective policy
214# to change in the nsswitch.conf (hosts or ipnodes) to update with dns.
215#
216update_nss ()
217{
218	policy=$1;
219	# Add dns to the nsswitch file, if it isn't already there.
220	/usr/bin/awk ' $1 ~ /^'${policy}':/ {
221		n = split($0, a);
222		newl = a[1];
223		if ($0 !~ /dns/) {
224			printf("#%s # Commented out by DHCP\n", $0);
225			updated = 0;
226			for (i = 2; i <= n; i++) {
227				if (updated == 0 && index(a[i], "[") == 1) {
228					newl = newl" dns";
229					updated++;
230				}
231				newl = newl" "a[i];
232			}
233			if (updated == 0) {
234				newl = newl" dns";
235				updated++;
236			}
237			if (updated != 0)
238				newl = newl" # Added by DHCP";
239			else
240				newl = $0;
241			printf("%s\n", newl);
242		} else
243			printf("%s\n", $0);
244	} $1 !~ /^'${policy}':/ { printf("%s\n", $0); }' /etc/nsswitch.conf \
245	    >/tmp/nsswitch.conf.$$
246
247	mv_file /tmp/nsswitch.conf.$$ /etc/nsswitch.conf 644
248}
249
250#
251# Remove any lines with the "# Added by DHCP" tag from /etc/nsswitch.conf;
252# also uncomment hosts and ipnodes entries which were previously commented
253# out by this script.
254#
255cleanup_nss ()
256{
257	/usr/bin/sed \
258	    -e '/# Added by DHCP$/d' \
259	    -e 's/^\(#hosts:\)\(.*[^#]\)\(#.*\)$/hosts: \2/' \
260	    -e 's/^\(#ipnodes:\)\(.*[^#]\)\(#.*\)$/ipnodes: \2/' \
261	    /etc/nsswitch.conf >/tmp/nsswitch.conf.$$
262
263	mv_file /tmp/nsswitch.conf.$$ /etc/nsswitch.conf 644
264}
265
266#
267# Remove any lines with the "# Added by DHCP" tag from /etc/inet/hosts.
268#
269cleanup_hosts ()
270{
271	/usr/bin/nawk '{
272		if (index($0, "# Added by DHCP") == 0 ||
273		    $1 == "127.0.0.1" || $1 == "::1") {
274			print $0
275		}
276	}' /etc/inet/hosts > /tmp/hosts.$$
277	mv_file /tmp/hosts.$$ /etc/inet/hosts 444
278}
279
280#
281# We now need to reset the netmask and broadcast address for our network
282# interfaces.  Since this may result in a name service lookup, we want to
283# now wait for NIS to come up if we previously started it.
284#
285# Only do this in the non-nwam case.
286#
287if fmri_is_not_nwam; then
288	domain=`/usr/bin/domainname 2>/dev/null`
289
290	[ -z "$domain" ] || [ ! -d /var/yp/binding/$domain ] || wait_nis || \
291    		echo "WARNING: Timed out waiting for NIS to come up" >& 2
292
293	#
294	# Re-set the netmask and broadcast addr for all IP interfaces.  This
295	# ifconfig is run here, after waiting for name services, so that
296	# "netmask +" will find the netmask if it lives in a NIS map. The 'D'
297	# in -auD tells ifconfig NOT to mess with the interface if it is
298	# under DHCP control
299	#
300	/usr/sbin/ifconfig -auD4 netmask + broadcast +
301fi
302
303# Uncomment these lines to print complete network interface configuration
304# echo "network interface configuration:"
305# /usr/sbin/ifconfig -a
306
307#
308# If our network configuration strategy is DHCP, check for DNS
309# configuration parameters obtained from the DHCP server.
310#
311# If NWAM is enabled, it will invoke this script to do this configuration
312# whenever a DHCP lease is obtained; in that case, this configuration
313# should *not* happen when svc:network/service is starting, as it will
314# interfere with the configuration performed by NWAM.
315#
316if nwam_is_not_running || fmri_is_not_netsvc; then
317
318	smf_netstrategy
319
320	if [ "$_INIT_NET_STRATEGY" = "dhcp" ]; then
321		dnsservers=`get_dhcp_var DNSserv`
322		dnsdomain=`get_dhcp_var DNSdmain`
323	else
324		dnsservers=""
325		dnsdomain=""
326	fi
327
328	if [ -n "$dnsservers" ]; then
329		#
330		# add settings retrieved from dhcp server to /etc/resolv.conf
331		#
332		update_resolv "$dnsservers" "$dnsdomain"
333
334		#
335		# Add dns to the nsswitch file, if it isn't already there.
336		#
337		update_nss hosts
338		update_nss ipnodes
339
340	elif dhcp_edits /etc/nsswitch.conf; then
341		# If we added DNS to the hosts and ipnodes
342		# policy in the nsswitch, remove it.
343		cleanup_nss
344	fi
345fi
346
347if dhcp_edits /etc/inet/hosts; then
348	# Clean up any old DHCP-added entries
349	# (except loopback) in the hosts file.
350	cleanup_hosts
351fi
352
353#
354# If we were invoked by NWAM, can exit now (skipping the ipqos config)
355#
356if [ -z "$SMF_FMRI" ] || [ "$SMF_FMRI" = "$NWAM_FMRI" ]; then
357        exit 0
358fi
359
360#
361# Load the IPQoS configuration.
362# This is backgrounded so that any remote hostname lookups it performs
363# don't unduely delay startup. Any messages go via syslog.
364#
365
366if [ -f /usr/sbin/ipqosconf -a -f /etc/inet/ipqosinit.conf ]; then
367        /usr/sbin/ipqosconf -s -a /etc/inet/ipqosinit.conf &
368fi
369