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