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