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