xref: /illumos-gate/usr/src/cmd/svc/milestone/manifest-import (revision 5bbb4db2c3f208d12bf0fd11769728f9e5ba66a2)
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 2009 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. /lib/svc/share/manifest_cleanup.ksh
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
45function svccfg_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
52function svccfg_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
60function prophist_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
77function prophist_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
91function prophist_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
112function prophist_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
129function prophist_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
139function prophist_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
165function prophist_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
192function prophist_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
222function prophist_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
246function instance_refresh {
247	echo $1 >> /etc/svc/volatile/refreshes
248}
249
250function refresh_instances {
251	[ -r /etc/svc/volatile/refreshes ] && {
252		sort -u /etc/svc/volatile/refreshes | xargs -l svcadm refresh
253	}
254}
255
256function instance_clear {
257	echo $1 >> /etc/svc/volatile/clears
258}
259
260function clear_conditionally {
261	[ "`/usr/bin/svcprop -p restarter/state $1`" = "maintenance" ] && \
262	    /usr/sbin/svcadm clear $1
263}
264
265function clear_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
273function prepare_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
341#
342# 0b Cleanup deathrow
343#
344deathrow=/etc/svc/deathrow
345if [ -s $deathrow ];then
346	#
347	# svc.startd has unconfigured the services found in deathrow,
348	# clean them now.
349	#
350	while read fmri mfst pkgname; do
351		# Delete services and instances from the deathrow file.
352		/usr/sbin/svccfg delete -f $fmri >/dev/null 2>&1
353		# Remove deathrow manifest hash.
354		/usr/sbin/svccfg delhash -d $mfst >/dev/null 2>&1
355	done < $deathrow
356	/usr/bin/mv $deathrow $deathrow.old
357fi
358SVCCFG_CHECKHASH=1 export SVCCFG_CHECKHASH
359
360#
361# 0c Clean up repository
362#
363if [ -z "$X" ] && /usr/bin/svcprop smf/manifest 2>/dev/null |
364    /usr/bin/grep '^ar_svc_[^/]*/md5sum opaque ' >/dev/null
365then
366	set -- `
367		/usr/bin/svcprop smf/manifest 2>/dev/null |
368		    /usr/bin/grep '^ar_svc[^/]*/md5sum opaque ' |
369		    /usr/bin/tr '/' ' ' |
370		    while read pg prop type value; do
371			echo "$pg/$value"
372		done
373	`
374	backup=`echo "$#/$#" | sed 's/.//g'`
375	fwidth=`echo "$#\c" | wc -c`
376
377	echo "Converting obsolete repository entries: \c" > /dev/msglog
378	i=1; n=$#
379	while [ $# -gt 0 ]; do
380		printf "%${fwidth}s/%${fwidth}s" $i $n > /dev/msglog
381		echo $1 | sed 's:/: :' | (
382			read pg value
383
384			(echo "select /smf/manifest"; echo "delpg v$pg") |
385			    /usr/sbin/svccfg 2>/dev/null >/dev/null
386			(echo "select /smf/manifest"; echo "delpg $pg") |
387			    /usr/sbin/svccfg 2>/dev/null >/dev/null
388			(echo "select /smf/manifest";
389			    echo "addpg v$pg framework") |
390			    /usr/sbin/svccfg 2>/dev/null >/dev/null
391			(echo "select /smf/manifest";
392			    echo "setprop v$pg/md5sum = opaque: $value") |
393			    /usr/sbin/svccfg 2>/dev/null >/dev/null
394		)
395		i=`expr $i + 1`
396		shift
397		echo "$backup\c" > /dev/msglog
398	done
399	echo > /dev/msglog
400	echo "Converted $n obsolete repository entries"
401	activity=true
402fi
403
404#
405# If no last-import snapshots are present on critical services, then we are
406# creating the last-import snapshots for the first time post upgrade.
407#
408create_last_import=1
409for svc in single-user multi-user multi-user-server; do
410	if /usr/bin/svcprop -s last-import svc:/milestone/$svc:default \
411	    >/dev/null 2>&1
412	then
413		create_last_import=
414		break
415	fi
416done
417
418if [ $create_last_import ]; then
419	echo "Last import snapshots absent; preparing for re-import"
420	prepare_last_import
421
422	#
423	# Apply property history files.
424	#
425	echo "Upgrade detected; applying property history"
426	for phist in /var/svc/profile/prophist.*; do
427		/lib/svc/bin/prophist hash $phist
428		if [ $? = 3 ]; then
429			echo "Sourcing $phist"
430			. $phist
431		fi
432	done
433
434	/usr/bin/rm -f /var/svc/profile/.upgrade_prophist
435fi
436
437#
438# 2.  Manifest import.  Application directories first, then
439# site-specific manifests.
440#
441nonsite_dirs=`/usr/bin/find /var/svc/manifest/* -name site -prune -o -type d \
442	-print -prune`
443
444nonsite_manifests=`/lib/svc/bin/mfstscan $nonsite_dirs`
445site_manifests=`/lib/svc/bin/mfstscan /var/svc/manifest/site`
446
447manifests="$nonsite_manifests $site_manifests"
448
449[ -n "$_MFST_DEBUG" ] && {
450	echo "Changed manifests to import:"
451	for m in $manifests; do echo "  $m"; done
452}
453
454#
455# 2b.  Import the manifests while giving a running display of imports on
456# console, and a final count in the logfile.
457#
458if [ -n "$nonsite_manifests" -o -n "$site_manifests" ]; then
459	rm -f /tmp/manifest_import.$$
460
461	set -- $manifests
462	cleanup=""
463	backup=`echo "$#/$#" | sed 's/.//g'`
464	fwidth=`echo "$#\c" | wc -c`
465
466	echo "Loading smf(5) service descriptions: \c" > /dev/msglog
467
468	#
469	# Attempt of moving the repository to tmpfs.  If that doesn't
470	# work, reset doswitch so we don't attempt switching back.
471	#
472	/usr/sbin/svcadm _smf_repository_switch fast
473	doswitch=$?
474
475	i=1; n=$#
476	svcprop smf/manifest > /etc/svc/volatile/smf_manifest_svcprop 2>&1
477	while [ $# -gt 0 ]; do
478		printf "%${fwidth}s/%${fwidth}s" $i $n > /dev/msglog
479		grep $1 /etc/svc/volatile/smf_manifest_svcprop > /dev/null 2>&1
480		if [ $? -eq 0 ]; then
481			cleanup="$cleanup $1"
482		fi
483		svccfg_import $1
484		i=`expr $i + 1`
485		shift
486		echo "$backup\c" > /dev/msglog
487	done
488	rm -f /etc/svc/volatile/smf_manifest_svcprop
489
490	#
491	# If switch back fails, exit with the fatal error code.
492	# Normally the failure indicates that there is a serious
493	# problem on the root file system such as file operation
494	# failure or repository access failure.
495	#
496	if [ $doswitch -eq 0 ]; then
497		/usr/sbin/svcadm _smf_repository_switch perm || { \
498		    echo "Repository switch back operation failed, \c"
499		    echo "please check the system log for the"
500		    echo "possible fatal error messages."
501		    exit $SMF_EXIT_ERR_FATAL
502                    }
503	fi
504
505	echo > /dev/msglog
506	echo "Loaded $n smf(5) service descriptions"
507	activity=true
508
509	if [ -s /tmp/manifest_import.$$ ]; then
510		echo "svccfg warnings:"
511		cat /tmp/manifest_import.$$
512
513		msg="svccfg import warnings.  See"
514		msg="$msg /var/svc/log/system-manifest-import:default.log ."
515		echo $msg > /dev/msglog
516	fi
517	rm -f /tmp/manifest_import.$$
518fi
519
520#
521# 3.  Profile application.  We must create the platform profile upon
522# first boot, as we may be a diskless client of a platform or
523# architecture distinct from our NFS server.
524#
525svccfg_apply /var/svc/profile/generic.xml
526
527if [ ! -f /var/svc/profile/platform.xml ]; then
528	this_karch=`uname -m`
529	this_plat=`uname -i`
530
531	if [ -f /var/svc/profile/platform_$this_plat.xml ]; then
532		platform_profile=platform_$this_plat.xml
533	elif [ -f /var/svc/profile/platform_$this_karch.xml ]; then
534		platform_profile=platform_$this_karch.xml
535	else
536		platform_profile=platform_none.xml
537	fi
538
539	ln -s $platform_profile /var/svc/profile/platform.xml
540fi
541
542svccfg_apply /var/svc/profile/platform.xml
543
544#
545# 4.  Upgrade handling.  The upgrade file generally consists of a series
546# of svcadm(1M) and svccfg(1M) commands.
547#
548(
549	unset SVCCFG_CHECKHASH
550
551	if [ -f /var/svc/profile/upgrade ]; then
552		. /var/svc/profile/upgrade
553
554		/usr/bin/mv /var/svc/profile/upgrade \
555		    /var/svc/profile/upgrade.app.`date +\%Y\%m\%d\%H\%M\%S`
556		activity=true
557	fi
558
559	#
560	# Rename the datalink upgrade script file. This script is used in the
561	# network/physical service to upgrade datalink configuration, but
562	# the file cannot be renamed until now (when the file system becomes
563	# read-write).
564	#
565	datalink_script=/var/svc/profile/upgrade_datalink
566	if [ -f "${datalink_script}" ]; then
567		/usr/bin/mv "${datalink_script}" \
568		    "${datalink_script}".app.`date +\%Y\%m\%d\%H\%M\%S`
569	fi
570)
571
572#
573# 5.  Site profile is applied last to give administrator the final say.
574#
575if [ -f /var/svc/profile/site.xml ]; then
576	svccfg_apply /var/svc/profile/site.xml
577fi
578
579#
580# 6.  Final actions.
581#
582refresh_instances
583clear_instances
584
585if $activity; then
586	svcadm _smf_backup "manifest_import" || true
587fi
588
589manifest_cleanup $activity $cleanup
590
591exit 0
592