1#!/bin/ksh
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 2010 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26
27# 0a  Initialization.
28
29[ -f /lib/svc/share/smf_include.sh ] || exit 1
30
31. /lib/svc/share/smf_include.sh
32
33activity=false
34
35EMI_SERVICE="svc:/system/early-manifest-import:default"
36
37X=
38early=false
39[ "$SMF_FMRI" == "$EMI_SERVICE" ] && early=true
40while getopts "n" opt; do
41	case $opt in
42		n)	X=echo;;
43		?)	echo "Usage: /lib/svc/method/manifest-import [-n]\n"
44		exit 2;;
45	esac
46done
47
48function svccfg_apply {
49	$X /usr/sbin/svccfg apply $1
50	if [ $? -ne 0 ]; then
51		echo "WARNING: svccfg apply $1 failed" | tee /dev/msglog
52	fi
53}
54
55#
56# If the smf/manifest table has file entries that are missing
57# then there is work to be done by the cleanup process.
58#
59function cleanup_needwork {
60	if [ "$early" == true ]; then
61		smfmfiles=`/usr/bin/svcprop smf/manifest | \
62		    awk '(/^lib_) && (/\/manifestfile /) {print $3}'`
63	else
64		smfmfiles=`/usr/bin/svcprop smf/manifest | \
65		    awk '/\/manifestfile / {print $3}'`
66	fi
67
68	nw=`/lib/svc/bin/mfstscan $smfmfiles 2>&1 1>/dev/null`
69	[ "$nw" ] && return 1
70
71	return 0
72}
73
74#
75# Upon upgrading to early manifest import code, preserve hashes of system
76# profiles which lived under /var/svc/profile so that svccfg apply would
77# not re-apply the profiles and overwrite user customizations. Simply
78# migrate manifestfile and hash values to new property groups named after
79# profiles under /etc/svc/profile. If the profiles don't really exist,
80# svccfg cleanup will remove the property groups in a later step.
81#
82# Existing generic.xml, inetd_services.xml, and name_service.xml symlinks
83# need to be preserved.
84#
85# Don't process site.xml profile since it is still supported under
86# /var/svc/profile directory.
87#
88function preserve_system_profiles {
89
90	#
91	# If /var is a separate fs, return and let Late Import
92	# preserves the hashes.
93	#
94	[ -d "/var/svc/profile" ] || return 1
95
96	#
97	# Preserve hashes for the following profiles: generic (two
98	# cases) and platform (uname -i, uname -m outputs).
99	#
100	gn="var_svc_profile_generic_open_xml"
101	gh=`/usr/bin/svcprop -p ${gn}/md5sum smf/manifest 2>/dev/null`
102	[ $? = 0 ] || gh=""
103	gn="etc_svc_profile_generic_open_xml"
104
105	gln="var_svc_profile_generic_limited_net_xml"
106	glh=`/usr/bin/svcprop -p ${gln}/md5sum smf/manifest 2>/dev/null`
107	[ $? = 0 ] || glh=""
108	gln="etc_svc_profile_generic_limited_net_xml"
109
110	LC_ALL=C pl=`/usr/bin/uname -i | /usr/bin/tr , _`
111	pln="var_svc_profile_platform_${pl}_xml"
112	plh=`/usr/bin/svcprop -p ${pln}/md5sum smf/manifest 2>/dev/null`
113	[ $? = 0 ] || plh=""
114	pln="etc_svc_profile_platform_${pl}_xml"
115
116	LC_ALL=C plm=`/usr/bin/uname -m | /usr/bin/tr , _`
117	if [ $plm != $pl ]; then
118		plmn="var_svc_profile_platform_${plm}_xml"
119		plmh=`/usr/bin/svcprop -p ${plmn}/md5sum smf/manifest \
120		    2>/dev/null`
121		[ $? = 0 ] || plmh=""
122		plmn="etc_svc_profile_platform_${plm}_xml"
123	else
124		plmh=""
125	fi
126
127	[ -n "$gh" ] && {
128		echo "Preserving generic hash ($gh)."
129		/usr/sbin/svccfg -s smf/manifest addpg ${gn} framework
130		/usr/sbin/svccfg -s smf/manifest setprop ${gn}/md5sum = \
131		    opaque: $gh
132		/usr/sbin/svccfg -s smf/manifest setprop ${gn}/manifestfile = \
133		    astring: "/etc/svc/profile/generic.xml"
134	}
135	[ -n "$glh" ] && {
136		echo "Preserving generic_limited hash ($glh)."
137		/usr/sbin/svccfg -s smf/manifest addpg ${gln} framework
138		/usr/sbin/svccfg -s smf/manifest setprop ${gln}/md5sum = \
139		    opaque: $glh
140		/usr/sbin/svccfg -s smf/manifest setprop ${gln}/manifestfile = \
141		    astring: "/etc/svc/profile/generic.xml"
142	}
143	[ -n "$plh" ] && {
144		echo "Preserving platform hash ($plh)."
145		/usr/sbin/svccfg -s smf/manifest addpg $pln framework
146		/usr/sbin/svccfg -s smf/manifest setprop $pln/md5sum = \
147		    opaque: $plh
148		/usr/sbin/svccfg -s smf/manifest setprop ${pln}/manifestfile = \
149		    astring: "/etc/svc/profile/platform_${pl}_xml"
150	}
151	[ -n "$plmh" ] && {
152		echo "Preserving platform hash ($plmh)."
153		/usr/sbin/svccfg -s smf/manifest addpg $plmn framework
154		/usr/sbin/svccfg -s smf/manifest setprop $plmn/md5sum = \
155		    opaque: $plmh
156		/usr/sbin/svccfg -s smf/manifest setprop \
157		    ${plmn}/manifestfile = \
158		    astring: "/etc/svc/profile/platform_${plm}_xml"
159	}
160
161	#
162	# Move symlinks from /var/svc/profile to /etc/svc/profile
163	#
164	generic_prof="/var/svc/profile/generic.xml"
165	ns_prof="/var/svc/profile/name_service.xml"
166	inetd_prof="/var/svc/profile/inetd_services.xml"
167	[ -L "$generic_prof" ] && mv $generic_prof /etc/svc/profile/
168	[ -L "$ns_prof" ] && mv $ns_prof /etc/svc/profile/
169	[ -L "$inetd_prof" ] && mv $inetd_prof /etc/svc/profile/
170
171	return 0
172}
173
174#
175# 2.  Manifest import.  Application directories first, then
176# site-specific manifests.
177#
178function import_manifests {
179	typeset basedir=$1
180	typeset logf="/etc/svc/volatile/manifest_import.$$"
181
182	rm -f $logf
183
184	nonsite_dirs=`/usr/bin/find $basedir/svc/manifest/* -name site \
185	    -prune -o -type d -print -prune`
186
187	if [ -n "$_MFST_DEBUG" ]; then
188		nonsite_manifests=`/lib/svc/bin/mfstscan $nonsite_dirs`
189		site_manifests=`/lib/svc/bin/mfstscan $basedir/svc/manifest/site`
190
191		manifests="$nonsite_manifests $site_manifests"
192
193		echo "Changed manifests to import:"
194		for m in $manifests; do echo "  $m"; done
195	fi
196
197	#
198	# Attempt of moving the repository to tmpfs.  If that doesn't
199	# work, reset doswitch so we don't attempt switching back.
200	#
201	/usr/sbin/svcadm _smf_repository_switch fast
202	doswitch=$?
203
204	#
205	# Import the manifests while giving a running display of imports on
206	# console, and a final count in the logfile.
207	#
208	dirs="$nonsite_dirs $basedir/svc/manifest/site"
209	$X /usr/sbin/svccfg import -p /dev/msglog $dirs > $logf 2>&1
210
211	grep "Loaded .*. smf(5) service descriptions" $logf > /dev/null 2>&1
212	if [ $? -eq 0 ]; then
213		activity=true
214	fi
215
216	if [ -s $logf ]; then
217		grep "smf(5) service descriptions failed to load" $logf > /dev/null 2>&1
218		failures=$?
219		if [ $failures -eq 0 ]; then
220			echo "svccfg warnings:"
221		fi
222		cat $logf
223
224		if [ $failures -eq 0 ]; then
225			msg="svccfg import warnings.  See"
226			msg="$msg /var/svc/log/system-manifest-import:default.log ."
227			echo $msg > /dev/msglog
228		fi
229	fi
230	rm -f $logf
231}
232
233#
234# 3.  Profile application.  We must create the platform profile upon
235# first boot, as we may be a diskless client of a platform or
236# architecture distinct from our NFS server.
237#
238# Generic and platform profiles are only supported in /etc.
239#
240function apply_profile {
241	#
242	# If smf/manifest doesn't have any profile under /etc/var/profile,
243	# this is very likely an import after upgrade so call
244	# preserve_system_profiles in that case.
245	#
246	LC_ALL=C pl=`/usr/bin/uname -i | /usr/bin/tr , _`
247	pln="etc_svc_profile_platform_${pl}_xml"
248
249	LC_ALL=C plm=`/usr/bin/uname -m | /usr/bin/tr , _`
250	[ $plm != $pl ] && plmn="etc_svc_profile_platform_${plm}_xml"
251
252	preserve_profiles=1
253	for prof in $pln $plmn etc_svc_profile_platform_none_xml \
254	    etc_svc_profile_generic_limited_net_xml \
255	    etc_svc_profile_generic_open_xml; do
256		if /usr/bin/svcprop -p $prof smf/manifest >/dev/null 2>&1
257		then
258			preserve_profiles=0
259			break
260		fi
261	done
262
263	if [ $preserve_profiles -eq 1 ]; then
264		echo "/etc/svc system profiles not found: upgrade system profiles"
265		preserve_system_profiles || return
266	fi
267
268	typeset prefix="/etc/svc/profile"
269	svccfg_apply $prefix/generic.xml
270	if [ ! -f $prefix/platform.xml ]; then
271		this_karch=`uname -m`
272		this_plat=`uname -i`
273
274		if [ -f $prefix/platform_$this_plat.xml ]; then
275			platform_profile=platform_$this_plat.xml
276		elif [ -f $prefix/platform_$this_karch.xml ]; then
277			platform_profile=platform_$this_karch.xml
278		else
279			platform_profile=platform_none.xml
280		fi
281
282		ln -s $platform_profile $prefix/platform.xml
283	fi
284
285	svccfg_apply $prefix/platform.xml
286}
287
288#
289# 4.  Upgrade handling.  The upgrade file generally consists of a series
290# of svcadm(1M) and svccfg(1M) commands.
291#
292function handle_upgrade {
293
294	[ -f /var/svc/profile/upgrade ] && activity=true
295
296	(
297		unset SVCCFG_CHECKHASH
298
299		if [ -f /var/svc/profile/upgrade ]; then
300			. /var/svc/profile/upgrade
301
302			/usr/bin/mv /var/svc/profile/upgrade \
303			    /var/svc/profile/upgrade.app.`date +\%Y\%m\%d\%H\%M\%S`
304		fi
305
306		#
307		# Rename the datalink upgrade script file. This script is used in the
308		# network/physical service to upgrade datalink configuration, but
309		# the file cannot be renamed until now (when the file system becomes
310		# read-write).
311		#
312		datalink_script=/var/svc/profile/upgrade_datalink
313		if [ -f "${datalink_script}" ]; then
314			/usr/bin/mv "${datalink_script}" \
315			    "${datalink_script}".app.`date +\%Y\%m\%d\%H\%M\%S`
316		fi
317	)
318}
319
320#
321# 5.  Site profile is applied last to give administrator the final say.
322#
323function apply_site_profile {
324        typeset prefix="$1/svc/profile"
325	[ -f $prefix/site.xml ] && svccfg_apply $prefix/site.xml
326}
327
328#
329# 0b Cleanup deathrow
330#
331if [ "$early" = "false" ];then
332	deathrow=/etc/svc/deathrow
333	if [ -s $deathrow ];then
334		#
335		# svc.startd has unconfigured the services found in deathrow,
336		# clean them now.
337		#
338		while read fmri mfst pkgname; do
339			# Delete services and instances from the deathrow file.
340			/usr/sbin/svccfg delete -f $fmri >/dev/null 2>&1
341			# Remove deathrow manifest hash.
342			/usr/sbin/svccfg delhash -d $mfst >/dev/null 2>&1
343		done < $deathrow
344		/usr/bin/mv $deathrow $deathrow.old
345	fi
346fi
347
348SVCCFG_CHECKHASH=1 export SVCCFG_CHECKHASH
349
350#
351# 0c Clean up repository
352#
353if [ "$early" = "false" ]; then
354	if [ -z "$X" ] && /usr/bin/svcprop smf/manifest 2>/dev/null |
355	    /usr/bin/grep '^ar_svc_[^/]*/md5sum opaque ' >/dev/null
356	then
357		set -- `
358			/usr/bin/svcprop smf/manifest 2>/dev/null |
359			    /usr/bin/grep '^ar_svc[^/]*/md5sum opaque ' |
360			    /usr/bin/tr '/' ' ' |
361			    while read pg prop type value; do
362				echo "$pg/$value"
363			done
364		`
365		backup=`echo "$#/$#" | sed 's/.//g'`
366		fwidth=`echo "$#\c" | wc -c`
367
368		echo "Converting obsolete repository entries: \c" > /dev/msglog
369		i=1; n=$#
370		while [ $# -gt 0 ]; do
371			printf "%${fwidth}s/%${fwidth}s" $i $n > /dev/msglog
372			echo $1 | sed 's:/: :' | (
373				read pg value
374
375				(echo "select /smf/manifest"; echo "delpg v$pg") |
376				    /usr/sbin/svccfg 2>/dev/null >/dev/null
377				(echo "select /smf/manifest"; echo "delpg $pg") |
378				    /usr/sbin/svccfg 2>/dev/null >/dev/null
379				(echo "select /smf/manifest";
380				    echo "addpg v$pg framework") |
381				    /usr/sbin/svccfg 2>/dev/null >/dev/null
382				(echo "select /smf/manifest";
383				    echo "setprop v$pg/md5sum = opaque: $value") |
384				    /usr/sbin/svccfg 2>/dev/null >/dev/null
385			)
386			i=`expr $i + 1`
387			shift
388			echo "$backup\c" > /dev/msglog
389		done
390		echo > /dev/msglog
391		echo "Converted $n obsolete repository entries"
392		activity=true
393	fi
394
395fi
396
397#
398# Call import and apply profiles here
399#
400if [ "$early" = "true" ]; then
401	import_manifests "/lib"
402	apply_profile
403	apply_site_profile "/etc"
404else
405	#
406	# Process both /lib/svc and /var/svc
407	# during late manifest-import
408	#
409	# First import the manifests
410	#
411	import_manifests "/lib"
412	import_manifests "/var"
413
414	#
415	# Apply profiles
416	#
417	apply_profile
418	apply_site_profile "/etc"
419
420	#
421	# Run the upgrade script
422	#
423	handle_upgrade
424	apply_site_profile "/var"
425fi
426
427
428#
429# 6.  Final actions.
430#
431
432if $activity; then
433	/usr/sbin/svcadm _smf_backup "manifest_import" || true
434fi
435
436#
437# If the filesystem is NOT read only then move the repo back to perm
438# There is no care wether the switch was made or not, but just want
439# to move it.  If it is already perm this does not affect anything
440# at least on the surface.  REALLY want to improve on this...
441#
442touch /etc/svc/smf_rwtest.$$ > /dev/null 2>&1
443if [ $? -eq 0 ]; then
444	rm -f /etc/svc/smf_rwtest.$$
445	/usr/sbin/svcadm _smf_repository_switch perm || { \
446	    echo "Repository switch back operation failed, \c"
447	    echo "please check the system log for the"
448	    echo "possible fatal error messages."
449	    exit $SMF_EXIT_ERR_FATAL
450	    }
451fi
452
453if $activity; then
454	/usr/sbin/svccfg cleanup | /usr/bin/tee /dev/msglog
455else
456	cleanup_needwork
457	if [ $? -ne 0 ]; then
458		/usr/sbin/svccfg cleanup -a | /usr/bin/tee /dev/msglog
459	fi
460fi
461
462exit 0
463