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