xref: /illumos-gate/usr/src/cmd/svc/milestone/manifest-import (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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
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
35X=
36while getopts n opt; do
37	case $opt in
38		n)	X=echo;;
39		?)	echo "Usage: /lib/svc/method/manifest-import [-n]\n"
40		exit 2;;
41	esac
42done
43
44svccfg_apply () {
45	$X /usr/sbin/svccfg apply $1
46	if [ $? -ne 0 ]; then
47		echo "WARNING: svccfg apply $1 failed" | tee /dev/msglog
48	fi
49}
50
51svccfg_import () {
52	$X /usr/sbin/svccfg import $1 2>>/tmp/manifest_import.$$
53	if [ $? -ne 0 ]; then
54		echo > /dev/msglog
55		echo "WARNING: svccfg import $1 failed" | tee /dev/msglog
56	fi
57}
58
59prophist_upgrade () {
60	#
61	# A property has changed in the manifest that we wish to propagate into
62	# the repository during manifest import.  We don't want to pollute
63	# manifests with overrides, so handle explicitly here.
64	#
65	fmri=$1
66	pgrp=$2
67	prop=$3
68	nval=$4
69	shift 4
70
71	/lib/svc/bin/prophist upgrade -e $fmri -g $pgrp -p $prop -n "$nval" \
72	    "$@"
73	[ $? = 0 ] && instance_refresh $fmri
74}
75
76prophist_override () {
77	#
78	# A property has changed in the manifest that we wish to propagate
79	# into the repository during manifest import.
80	#
81	fmri=$1
82	pgrp=$2
83	prop=$3
84	nval=$4
85
86	/lib/svc/bin/prophist overwrite -e $fmri -g $pgrp -p $prop -n "$nval"
87	[ $? = 0 ] && instance_refresh $fmri
88}
89
90prophist_delete_svc_pg () {
91	#
92	# Certain property groups have migrated from the service level to the
93	# instance level.  We don't care if they are at both, as the instance
94	# level will trump.  But having neither could be bad.  So check and if
95	# the given pg exists at both levels, delete the service-level one only.
96	#
97	service=$1
98	instance=$2
99	property_group=$3
100
101	/usr/bin/svcprop -q -p $property_group $service
102	res1=$?
103	/usr/bin/svcprop -q -c -p $property_group $service:$instance
104	res2=$?
105	if [ $res1 -eq 0 -a $res2 -eq 0 ]; then
106		/lib/svc/bin/prophist delete -e $service -g $property_group
107		instance_refresh $service:$instance
108	fi
109}
110
111prophist_delete_dependency () {
112	#
113	# Some services have stale dependencies that need to be removed.
114	# This is done by removing the dependency property group.
115	#
116	fmri=$1
117	property_group=$2
118
119	/usr/bin/svcprop -q -c -p $property_group $fmri
120	if [ $? -eq 0 ]; then
121		/lib/svc/bin/prophist delete -e $fmri -g $property_group
122	else
123		[ -n "$_MFST_DEBUG" ] && \
124		    echo "Dependency $property_group not defined on $fmri"
125	fi
126}
127
128prophist_delete_pg () {
129	# Delete obsolete property groups from old manifests.  Instances
130	# should be refreshed for changes to take effect.
131	fmri=$1
132	pg=$2
133
134	/usr/bin/svcprop -Cqp $pg $fmri &&
135	    /lib/svc/bin/prophist delete -e $fmri -g $pg
136}
137
138prophist_addprop () {
139	#
140	# If a property doesn't exist, create it.  Instances should be
141	# refreshed for changes to take effect.
142	#
143	if [ $# -lt 6 ]; then
144		echo "prophist_addprop(): Insufficient arguments ($*)."
145		exit 1
146	fi
147
148	fmri=$1
149	/usr/bin/svcprop -q $fmri || return
150
151	pg=$2
152	pgtype=$3
153	prop=$4
154
155	/usr/bin/svcprop -Cqp $pg/$prop $fmri && return
156
157	shift 4
158
159	/usr/bin/svcprop -Cqp $pg $fmri || \
160	    /usr/sbin/svccfg -s $fmri addpg $pg $pgtype
161	/usr/sbin/svccfg -s $fmri setprop $pg/$prop = $*
162}
163
164prophist_addmeth () {
165	#
166	# If a method doesn't exist, create it.  Instances should be refreshed
167	# for changes to take effect.
168	#
169	if [ $# -ne 4 ]; then
170		echo "prophist_addmeth(): Insufficient arguments ($*)"
171		exit 1
172	fi
173
174	fmri=$1
175	/usr/bin/svcprop -q $fmri || return
176
177	name=$2
178	/usr/bin/svcprop -Cqp $name $fmri && return
179
180	exec=$3
181	to=$4
182
183	/usr/sbin/svccfg -s $fmri <<END
184	    addpg $name method
185	    setprop $name/type = astring: method
186	    setprop $name/exec = astring: "$exec"
187	    setprop $name/timeout_seconds = count: $to
188END
189}
190
191prophist_adddep () {
192	#
193	# If a dependency doesn't exist, create it.  Instances should be
194	# refreshed for changes to take effect.
195	#
196	if [ $# -lt 6 ]; then
197		echo "prophist_adddep(): Insufficient arguments ($*)"
198		exit 1
199	fi
200
201	fmri=$1
202	/usr/bin/svcprop -q $fmri || return
203
204	name=$2
205	/usr/bin/svcprop -Cqp $name $fmri && return
206
207	type=$3
208	group=$4
209	ro=$5
210	shift 5
211
212	/usr/sbin/svccfg -s $fmri <<END
213	    addpg $name dependency
214	    setprop $name/type = astring: $type
215	    setprop $name/grouping = astring: $group
216	    setprop $name/restart_on = astring: $ro
217	    setprop $name/entities = fmri: $*
218END
219}
220
221prophist_adddpt () {
222	#
223	# If a dependent doesn't exist, create it.  Instances should be
224	# refresh for changes to take effect.
225	#
226	if [ $# -ne 5 ]; then
227		echo "prophist_adddpt(): Incorrect arguments ($*).\n"
228		exit 1
229	fi
230
231	fmri=$1
232	/usr/bin/svcprop -q $fmri || return
233
234	name=$2
235	/usr/bin/svcprop -Cqp dependents/$name $fmri && return
236
237	group=$3
238	ro=$4
239	target=$5
240
241	prophist_addprop $fmri dependents framework $name fmri: $target
242	prophist_adddep $target $name service $group $ro $fmri
243}
244
245instance_refresh () {
246	echo $1 >> /etc/svc/volatile/refreshes
247}
248
249refresh_instances () {
250	[ -r /etc/svc/volatile/refreshes ] && {
251		sort -u /etc/svc/volatile/refreshes | xargs -l svcadm refresh
252	}
253}
254
255instance_clear () {
256	echo $1 >> /etc/svc/volatile/clears
257}
258
259clear_conditionally () {
260	[ "`/usr/bin/svcprop -p restarter/state $1`" = "maintenance" ] && \
261	    /usr/sbin/svcadm clear $1
262}
263
264clear_instances () {
265	[ -r /etc/svc/volatile/clears ] && {
266		for inst in `/usr/bin/sort -u /etc/svc/volatile/clears`; do
267			clear_conditionally $inst
268		done
269	}
270}
271
272prepare_last_import () {
273	# Preserve the five hashes for the profiles: generic (two
274	# cases), platform (uname -i, uname -m outputs), and site.
275
276	gn="var_svc_profile_generic_open_xml"
277	gh=`/usr/bin/svcprop -p ${gn}/md5sum smf/manifest 2>/dev/null`
278	[ $? = 0 ] || gh=""
279
280	gln="var_svc_profile_generic_limited_net_xml"
281	glh=`/usr/bin/svcprop -p ${gln}/md5sum smf/manifest 2>/dev/null`
282	[ $? = 0 ] || glh=""
283
284	LC_ALL=C pl=`/usr/bin/uname -i | /usr/bin/tr , _`
285	pln="var_svc_profile_platform_${pl}_xml"
286	plh=`/usr/bin/svcprop -p ${pln}/md5sum smf/manifest 2>/dev/null`
287	[ $? = 0 ] || plh=""
288
289	LC_ALL=C plm=`/usr/bin/uname -m | /usr/bin/tr , _`
290	if [ $plm != $pl ]; then
291		plmn="var_svc_profile_platform_${plm}_xml"
292		plmh=`/usr/bin/svcprop -p ${plmn}/md5sum smf/manifest \
293		    2>/dev/null`
294		[ $? = 0 ] || plmh=""
295	else
296		plmh=""
297	fi
298
299	sn="var_svc_profile_site_xml"
300	sh=`/usr/bin/svcprop -p $sn/md5sum smf/manifest 2>/dev/null`
301	[ $? = 0 ] || sh=""
302
303	# Remove all manifest hashes.
304	/usr/sbin/svccfg delete smf/manifest
305
306	# Restore smf/manifest and hash values.
307	/usr/sbin/svccfg add smf/manifest
308	[ -n "$gh" ] && {
309		echo "Preserving generic hash ($gh)."
310		/usr/sbin/svccfg -s smf/manifest addpg ${gn} framework
311		/usr/sbin/svccfg -s smf/manifest setprop ${gn}/md5sum = \
312		    opaque: $gh
313	}
314	[ -n "$glh" ] && {
315		echo "Preserving generic_limited hash ($glh)."
316		/usr/sbin/svccfg -s smf/manifest addpg ${gln} framework
317		/usr/sbin/svccfg -s smf/manifest setprop ${gln}/md5sum = \
318		    opaque: $glh
319	}
320	[ -n "$plh" ] && {
321		echo "Preserving platform hash ($plh)."
322		/usr/sbin/svccfg -s smf/manifest addpg $pln framework
323		/usr/sbin/svccfg -s smf/manifest setprop $pln/md5sum = \
324		    opaque: $plh
325	}
326	[ -n "$plmh" ] && {
327		echo "Preserving platform hash ($plmh)."
328		/usr/sbin/svccfg -s smf/manifest addpg $plmn framework
329		/usr/sbin/svccfg -s smf/manifest setprop $plmn/md5sum = \
330		    opaque: $plmh
331	}
332	[ -n "$sh" ] && {
333		echo "Preserving site hash ($sh)."
334		/usr/sbin/svccfg -s smf/manifest addpg $sn framework
335		/usr/sbin/svccfg -s smf/manifest setprop $sn/md5sum = \
336		    opaque: $sh
337	}
338}
339
340#
341# 0b Cleanup deathrow
342#
343deathrow=/etc/svc/deathrow
344if [ -s $deathrow ];then
345	#
346	# svc.startd has unconfigured the services found in deathrow,
347	# clean them now.
348	#
349	while read fmri mfst pkgname; do
350		# Delete services and instances from the deathrow file.
351		/usr/sbin/svccfg delete -f $fmri >/dev/null 2>&1
352		# Remove deathrow manifest hash.
353		/usr/sbin/svccfg delhash -d $mfst >/dev/null 2>&1
354	done < $deathrow
355	/usr/bin/mv $deathrow $deathrow.old
356fi
357SVCCFG_CHECKHASH=1 export SVCCFG_CHECKHASH
358
359#
360# 0c Clean up repository
361#
362if [ -z "$X" ] && /usr/bin/svcprop smf/manifest 2>/dev/null |
363    /usr/bin/grep '^ar_svc_[^/]*/md5sum opaque ' >/dev/null
364then
365	set -- `
366		/usr/bin/svcprop smf/manifest 2>/dev/null |
367		    /usr/bin/grep '^ar_svc[^/]*/md5sum opaque ' |
368		    /usr/bin/tr '/' ' ' |
369		    while read pg prop type value; do
370			echo "$pg/$value"
371		done
372	`
373	backup=`echo "$#/$#" | sed 's/.//g'`
374	fwidth=`echo "$#\c" | wc -c`
375
376	echo "Converting obsolete repository entries: \c" > /dev/msglog
377	i=1; n=$#
378	while [ $# -gt 0 ]; do
379		printf "%${fwidth}s/%${fwidth}s" $i $n > /dev/msglog
380		echo $1 | sed 's:/: :' | (
381			read pg value
382
383			(echo "select /smf/manifest"; echo "delpg v$pg") |
384			    /usr/sbin/svccfg 2>/dev/null >/dev/null
385			(echo "select /smf/manifest"; echo "delpg $pg") |
386			    /usr/sbin/svccfg 2>/dev/null >/dev/null
387			(echo "select /smf/manifest";
388			    echo "addpg v$pg framework") |
389			    /usr/sbin/svccfg 2>/dev/null >/dev/null
390			(echo "select /smf/manifest";
391			    echo "setprop v$pg/md5sum = opaque: $value") |
392			    /usr/sbin/svccfg 2>/dev/null >/dev/null
393		)
394		i=`expr $i + 1`
395		shift
396		echo "$backup\c" > /dev/msglog
397	done
398	echo > /dev/msglog
399	echo "Converted $n obsolete repository entries"
400	activity=true
401fi
402
403#
404# If no last-import snapshots are present on critical services, then we are
405# creating the last-import snapshots for the first time post upgrade.
406#
407create_last_import=1
408for svc in single-user multi-user multi-user-server; do
409	if /usr/bin/svcprop -s last-import svc:/milestone/$svc:default \
410	    >/dev/null 2>&1
411	then
412		create_last_import=
413		break
414	fi
415done
416
417if [ $create_last_import ]; then
418	echo "Last import snapshots absent; preparing for re-import"
419	prepare_last_import
420
421	#
422	# Apply property history files.
423	#
424	echo "Upgrade detected; applying property history"
425	for phist in /var/svc/profile/prophist.*; do
426		/lib/svc/bin/prophist hash $phist
427		if [ $? = 3 ]; then
428			echo "Sourcing $phist"
429			. $phist
430		fi
431	done
432
433	/usr/bin/rm -f /var/svc/profile/.upgrade_prophist
434fi
435
436#
437# 2.  Manifest import.  Application directories first, then
438# site-specific manifests.
439#
440nonsite_dirs=`/usr/bin/find /var/svc/manifest/* -name site -prune -o -type d \
441	-print -prune`
442
443nonsite_manifests=`/lib/svc/bin/mfstscan $nonsite_dirs`
444site_manifests=`/lib/svc/bin/mfstscan /var/svc/manifest/site`
445
446manifests="$nonsite_manifests $site_manifests"
447
448[ -n "$_MFST_DEBUG" ] && {
449	echo "Changed manifests to import:"
450	for m in $manifests; do echo "  $m"; done
451}
452
453#
454# 2b.  Import the manifests while giving a running display of imports on
455# console, and a final count in the logfile.
456#
457if [ -n "$nonsite_manifests" -o -n "$site_manifests" ]; then
458	rm -f /tmp/manifest_import.$$
459
460	set -- $manifests
461	backup=`echo "$#/$#" | sed 's/.//g'`
462	fwidth=`echo "$#\c" | wc -c`
463
464	echo "Loading smf(5) service descriptions: \c" > /dev/msglog
465
466	#
467	# Attempt of moving the repository to tmpfs.  If that doesn't
468	# work, reset doswitch so we don't attempt switching back.
469	#
470	/usr/sbin/svcadm _smf_repository_switch fast
471	doswitch=$?
472
473	i=1; n=$#
474	while [ $# -gt 0 ]; do
475		printf "%${fwidth}s/%${fwidth}s" $i $n > /dev/msglog
476		svccfg_import $1
477		i=`expr $i + 1`
478		shift
479		echo "$backup\c" > /dev/msglog
480	done
481
482	#
483	# If switch back fails, exit with the fatal error code.
484	# Normally the failure indicates that there is a serious
485	# problem on the root file system such as file operation
486	# failure or repository access failure.
487	#
488	if [ $doswitch -eq 0 ]; then
489		/usr/sbin/svcadm _smf_repository_switch perm || { \
490		    echo "Repository switch back operation failed, \c"
491		    echo "please check the system log for the"
492		    echo "possible fatal error messages."
493		    exit $SMF_EXIT_ERR_FATAL
494                    }
495	fi
496
497	echo > /dev/msglog
498	echo "Loaded $n smf(5) service descriptions"
499	activity=true
500
501	if [ -s /tmp/manifest_import.$$ ]; then
502		echo "svccfg warnings:"
503		cat /tmp/manifest_import.$$
504
505		msg="svccfg import warnings.  See"
506		msg="$msg /var/svc/log/system-manifest-import:default.log ."
507		echo $msg > /dev/msglog
508	fi
509	rm -f /tmp/manifest_import.$$
510fi
511
512#
513# 3.  Profile application.  We must create the platform profile upon
514# first boot, as we may be a diskless client of a platform or
515# architecture distinct from our NFS server.
516#
517svccfg_apply /var/svc/profile/generic.xml
518
519if [ ! -f /var/svc/profile/platform.xml ]; then
520	this_karch=`uname -m`
521	this_plat=`uname -i`
522
523	if [ -f /var/svc/profile/platform_$this_plat.xml ]; then
524		platform_profile=platform_$this_plat.xml
525	elif [ -f /var/svc/profile/platform_$this_karch.xml ]; then
526		platform_profile=platform_$this_karch.xml
527	else
528		platform_profile=platform_none.xml
529	fi
530
531	ln -s $platform_profile /var/svc/profile/platform.xml
532fi
533
534svccfg_apply /var/svc/profile/platform.xml
535
536#
537# 4.  Upgrade handling.  The upgrade file generally consists of a series
538# of svcadm(1M) and svccfg(1M) commands.
539#
540(
541	unset SVCCFG_CHECKHASH
542
543	if [ -f /var/svc/profile/upgrade ]; then
544		. /var/svc/profile/upgrade
545
546		/usr/bin/mv /var/svc/profile/upgrade \
547		    /var/svc/profile/upgrade.app.`date +\%Y\%m\%d\%H\%M\%S`
548		activity=true
549	fi
550
551	#
552	# Rename the datalink upgrade script file. This script is used in the
553	# network/physical service to upgrade datalink configuration, but
554	# the file cannot be renamed until now (when the file system becomes
555	# read-write).
556	#
557	datalink_script=/var/svc/profile/upgrade_datalink
558	if [ -f "${datalink_script}" ]; then
559		/usr/bin/mv "${datalink_script}" \
560		    "${datalink_script}".app.`date +\%Y\%m\%d\%H\%M\%S`
561	fi
562)
563
564#
565# 5.  Site profile is applied last to give administrator the final say.
566#
567if [ -f /var/svc/profile/site.xml ]; then
568	svccfg_apply /var/svc/profile/site.xml
569fi
570
571#
572# 6.  Final actions.
573#
574refresh_instances
575clear_instances
576
577if $activity; then
578	svcadm _smf_backup "manifest_import" || true
579fi
580
581exit 0
582