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