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
31 activity=false
32
33 EMI_SERVICE="svc:/system/early-manifest-import:default"
34 PROFILE_DIR_SITE="/etc/svc/profile/site"
35
36 X=
37 ALT_REPOSITORY=
38 ALT_MFST_DIR=
39 early=false
40 [ "$SMF_FMRI" == "$EMI_SERVICE" ] && early=true
41
42 usage()
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
53 while 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
60 done
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
68 function 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 #
79 function 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 #
108 function 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 #
200 function 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 #
269 function 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 #
321 function 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 #
353 function 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 #
365 if [ "$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
380 fi
381
382 SVCCFG_CHECKHASH=1 export SVCCFG_CHECKHASH
383
384 #
385 # 0c Clean up repository
386 #
387 if [ "$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
429 fi
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 #
436 if [ -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
441 fi
442
443 #
444 # Call import and apply profiles here
445 #
446 if [ "$early" = "true" ]; then
447 import_manifests "/lib/svc/manifest" true
448 apply_profile
449 apply_site_profile "/etc/svc/profile"
450 else
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"
471 fi
472
473
474 #
475 # 6. Final actions.
476 #
477
478 if $activity; then
479 /usr/sbin/svcadm _smf_backup "manifest_import" || true
480 fi
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 #
488 touch /etc/svc/smf_rwtest.$$ > /dev/null 2>&1
489 if [ $? -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 }
497 fi
498
499 if $activity; then
500 /usr/sbin/svccfg cleanup | /usr/bin/tee /dev/msglog
501 else
502 cleanup_needwork
503 if [ $? -ne 0 ]; then
504 /usr/sbin/svccfg cleanup -a | /usr/bin/tee /dev/msglog
505 fi
506 fi
507
508 exit 0