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 [ -f /lib/svc/share/smf_include.sh ] || exit 1 28 29 . /lib/svc/share/smf_include.sh 30 31 SVCADM=/usr/sbin/svcadm 32 SVCCFG=/usr/sbin/svccfg 33 SVCPROP=/bin/svcprop 34 SVCS=/usr/bin/svcs 35 MFSTPG=manifestfiles 36 MFSTSCAN=/lib/svc/bin/mfstscan 37 MCLEANUPFILE=/etc/svc/volatile/mcleanup.$$ 38 IGNORELIST="system/install-discovery smf/manifest" 39 MFSTHISTORY=/lib/svc/share/mfsthistory 40 UPLIST=0 41 42 # 43 # Create a list of service to manifest pairs for the upgrade 44 # process to determine what files are associated with a service 45 # 46 function create_list { 47 for cl_mfile in `find /var/svc/manifest -name "*.xml"` 48 do 49 for cl_invent in `svccfg inventory $cl_mfile` 50 do 51 cl_invent=${cl_invent#svc:/*} 52 53 cl_instance=${cl_invent#*:} 54 cl_instance=${cl_instance##*/*} 55 [ $cl_instance ] && continue 56 57 cl_invent=${cl_invent%:*} 58 cl_invent=`echo $cl_invent | sed -e 's/[-\/\,]/_/g'` 59 60 61 eval $cl_invent=\"\$$cl_invent $cl_mfile\" 62 done 63 done 64 UPLIST=1 65 } 66 67 # 68 # Inventory the instances listed with a manifest file 69 # 70 function get_instances { 71 gi_mfile=$1 72 73 lst="" 74 for gi_invent in `svccfg inventory $gi_mfile` 75 do 76 gi_tmp=${gi_invent#svc:/*} 77 gi_tmp=${gi_tmp#*:} 78 gi_tmp=${gi_tmp##*/*} 79 80 [ $gi_tmp ] && lst="$lst $gi_invent" 81 done 82 83 echo $lst 84 } 85 86 function pid_timeout { 87 pt_pid=$1 88 89 pt_cnt=0 90 while [ `ps -p $pt_pid -o pid | grep -v PID` -a $pt_cnt -lt 30 ] 91 do 92 sleep 1 93 cnt=`expr $pt_cnt + 1` 94 done 95 if [ $pt_cnt -eq 30 -a "`ps -p $pt_pid -o pid | grep -v PID`" ]; then 96 return 1 97 else 98 return 0 99 fi 100 } 101 102 # 103 # Process a service to ensure that it's manifests exist 104 # and are in sync with the service. 105 # 106 function process_service { 107 ps_service=$1 108 109 # 110 # Throw away unsupported services, if there is a false listing 111 # for manifestfiles support 112 # 113 $SVCPROP -p $MFSTPG/support $ps_service 2>/dev/null | grep false > /dev/null 114 [ $? -eq 0 ] && return 115 116 # 117 # Create the list of instances for this service. 118 # 119 $SVCPROP -p $MFSTPG $ps_service > $MCLEANUPFILE 120 set -A ps_mfiles `grep astring $MCLEANUPFILE | awk '{print $3}'` 121 122 # 123 # Check to see if the manifest files associated with the service are 124 # missing, or if the manifest file has changed, either caught here 125 # or by the caller. 126 # 127 ps_x=`$MFSTSCAN ${ps_mfiles[@]} 2>&1` 128 if [ $? -eq 0 ]; then 129 if [ "$force" != "true" -a ! "$ps_x" ]; then 130 ps_ret=0 131 for ps_f in ${ps_mfiles[@]} 132 do 133 echo "$force" | grep -v $ps_f > /dev/null 2>&1 134 ps_ret=`expr $ps_ret + $?` 135 done 136 [ $ps_ret -eq 0 ] && return 137 fi 138 fi 139 140 ps_refresh=0 141 ps_mfiles_tmp="" 142 ps_mfiles_cnt=${#ps_mfiles[@]} 143 ps_instances=`$SVCS -H -oFMRI $ps_service 2>/dev/null` 144 145 # 146 # For each manifest file that is listed by the service 147 # check for its existance. If it exists, then check that 148 # the instances of the service are supported by at least 149 # one of the manifest files listed. 150 # 151 for mf in ${ps_mfiles[@]} 152 do 153 # 154 # This is an unsupported service just return 155 # skipping the service. 156 # 157 [ ${mf%/var/svc/manifest*} ] && return 158 159 if [ ! -f $mf ]; then 160 ps_mfiles_tmp="$ps_mfiles_tmp $mf" 161 continue 162 fi 163 164 inst=`get_instances $mf` 165 166 set -A ps_inst_list 167 for i in $inst 168 do 169 ps_inst_tmp="" 170 for j in $ps_instances 171 do 172 if [ "$i" == "$j" ]; then 173 set -A ps_inst_list ${ps_inst_list[*]} $j 174 continue 175 else 176 ps_inst_tmp="$ps_inst_tmp $j" 177 fi 178 done 179 # 180 # If there are any instances not accounted for add 181 # them to the list to be cleaned up. 182 # 183 ps_instances=$ps_inst_tmp 184 done 185 done 186 # 187 # If there are any manifest files set them to the list 188 # to be cleaned up. 189 # 190 set -A ps_mfiles $ps_mfiles_tmp 191 192 # 193 # For each manifest file that was not found remove it from 194 # the service's list of manifest files. 195 # 196 for mf in ${ps_mfiles[@]} 197 do 198 # 199 # Need to remove the file from the smf/manifest 200 # list. 201 # 202 ps_refresh=1 203 mf_nw=`echo "$needwork" | grep -v $mf` 204 needwork="$mf_nw" 205 mf_srch=`echo $mf | sed -e 's/\./\\\./g'` 206 mf_pg=`grep "$mf_srch" $MCLEANUPFILE | awk '{print $1}'` 207 [ $ps_mfiles_cnt -ne ${#ps_mfiles[@]} ] && \ 208 $SVCCFG -s $ps_service delprop $mf_pg > /dev/null 2>&1 209 mf_pg=`echo $mf_pg | awk -F'/' '{print $2}'` 210 $SVCCFG -s smf/manifest delpg $mf_pg > /dev/null 2>&1 211 done 212 213 # 214 # If all the manifest files that were listed in the service have now 215 # been removed, delete the service. 216 # 217 if [ $ps_mfiles_cnt -eq ${#ps_mfiles[@]} ]; then 218 # 219 # Disable each of the instances for the service 220 # then delete the service. 221 # 222 # If the restarter is not startd then the service 223 # will not be online at this point and we need 224 # to not wait on the disable. 225 # 226 # Set the delete opt to -f if the disable is not 227 # synchronous. 228 # 229 $SVCPROP -q -p general/restarter $ps_service 230 if [ $? -ne 0 ]; then 231 DISOPT="-s" 232 DELOP="" 233 else 234 DISOPT="" 235 DELOP="-f" 236 fi 237 238 for i in `$SVCS -H -oFMRI $ps_service` 239 do 240 $SVCADM disable $DISOPT $i & 241 CPID=$! 242 243 pid_timeout $CPID 244 if [ $? -ne 0 ]; then 245 DELOPT="-f" 246 kill $CPID 247 fi 248 done 249 250 echo "$SVCCFG delete $ps_service" 251 $SVCCFG delete $DELOPT $ps_service 252 return 253 fi 254 255 # 256 # Need to only cleanup instances that are no longer supported 257 # by the manifest files associated with the service. 258 # 259 for i in $ps_instances 260 do 261 # 262 # Ignore any instances that are hand created 263 # 264 ps_refresh=1 265 $SVCCFG -s $i selectsnap last-import > /dev/null 2>&1 266 [ $? -ne 0 ] && continue 267 268 # 269 # If the restarter is not startd then the service 270 # will not be online at this point and we need 271 # to not wait on the disable. 272 # 273 $SVCPROP -q -p general/restarter $ps_service 274 if [ $? -ne 0 ]; then 275 DELOP="" 276 $SVCADM disable -s $i & 277 CPID=$! 278 279 pid_timeout $CPID 280 if [ $? -ne 0 ]; then 281 DELOPT="-f" 282 kill $CPID 283 fi 284 else 285 DELOP="-f" 286 $SVCADM disable $i 287 fi 288 289 echo "$SVCCFG delete $i" 290 $SVCCFG delete $DELOP $i 291 done 292 293 # 294 # If instances of the services were removed, refresh the 295 # additional instances, or cleanup any leftover services. 296 # 297 if [ $ps_refresh -ne 0 ]; then 298 if [ ${#ps_inst_list[@]} -gt 0 ]; then 299 for i in ${ps_inst_list[@]} 300 do 301 $SVCCFG -s $i refresh 302 done 303 else 304 ps_support=0 305 for ps_mfile in `awk '{print $3}' $MCLEANUPFILE` 306 do 307 $SVCCFG inventory $ps_mfile | grep $ps_service > /dev/null 2>&1 308 [ $? -eq 0 ] && ps_supprt=1 309 done 310 [ $ps_support -eq 0 ] && $SVCCFG delete $ps_service 311 fi 312 fi 313 } 314 315 # 316 # Upgrade a service to have the manifest files associated with 317 # listed in the manifestfiles property group. 318 # 319 # If the first argument is FALSE, then check to see if the service 320 # has any previous import indications. If so then delete the 321 # service, otherwise set the service as a non-supported service 322 # for the automated manifest deletion process. 323 # 324 function add_manifest { 325 am_service=$1 326 shift 327 328 $SVCCFG -s $am_service addpg $MFSTPG framework 329 330 if [ "$1" == "FALSE" ]; then 331 am_lisnap=1 332 am_inst=`svcs -H -oFMRI $am_service 2>/dev/null` 333 334 # 335 # Check for a last-import snapshot, if there is not 336 # one then the service was hand crafted and the support 337 # should be set to false. 338 # 339 if [ $? -eq 0 ]; then 340 for i in $am_inst 341 do 342 $SVCCFG -s $i selectsnap last-import > /dev/null 2>&1 343 [ $? -eq 0 ] && am_lisnap=0 344 done 345 fi 346 347 if [ $am_lisnap -ne 0 ]; then 348 $SVCCFG -s $am_service setprop $MFSTPG/support = boolean: 0 349 350 return 351 fi 352 353 # 354 # If the service was not hand crafted then check to see if 355 # the service has ever been installed in the /var/svc/manifest 356 # directory and therefore a known removed service. 357 # 358 grep "$am_service " $MFSTHISTORY | grep -v "^#" > /dev/null 2>&1 359 if [ $? -eq 0 ]; then 360 echo "$SVCCFG delete $am_service" 361 $SVCCFG delete -f $am_service 362 else 363 # 364 # Do not know where the service came from so set 365 # it to false. 366 # 367 $SVCCFG -s $am_service setprop $MFSTPG/support = boolean: 0 368 fi 369 else 370 for am_mfile in $@ 371 do 372 CF=${am_mfile#/*} 373 CF=`echo $CF | sed -e 's/[\/\,\.]/_/g'` 374 $SVCCFG -s $am_service setprop $MFSTPG/$CF = astring: $am_mfile 375 done 376 fi 377 } 378 379 # 380 # upgrade the entries in the smf/manifest table to have 381 # a pointer to the actual manifest file. 382 # 383 function upgrade_smfmanifest { 384 us_unfnd="" 385 386 for us_E in `$SVCPROP smf/manifest | grep md5sum | grep var_svc_manifest | awk '{print $1}' | awk -F'/' '{print $1}'` 387 do 388 $SVCPROP -q -p $us_E/manifestfile smf/manifest 389 [ $? -eq 0 ] && continue 390 391 us_S=`echo $us_E | sed -e 's/_xml/.xml/'` 392 us_S=`echo $us_S | sed -e 's/var_svc_manifest_/var\/svc\/manifest\//'` 393 394 us_R="" 395 while [ ! -f $us_S -a ! "$us_R" ] 396 do 397 us_S=`echo $us_S | sed -e 's/_/\//'` 398 us_R=${us_S##*_*} 399 done 400 401 us_S="/$us_S" 402 if [ -f $us_S ]; then 403 us_R=`$MFSTSCAN $us_S` 404 [ ! "$R" ] && \ 405 $SVCCFG -s smf/manifest setprop ${us_E}/manifestfile = astring: $us_S 406 else 407 us_unfnd="$us_unfnd $us_E" 408 fi 409 done 410 411 echo "$us_unfnd" 412 } 413 414 function manifest_cleanup { 415 # 416 # If manifest-import had activity then need to make checks to override 417 # a mfstscan that returns no modifications. This is because the hash 418 # table will already have been updated by the manifest-import run, 419 # therefor manifest-cleanup will not see those changes in the mfstscan 420 # call. 421 # 422 # activity indicates changes and overrides the needwork check. 423 # force can be a list of files that will only be processed 424 # or force can be set to true, so that all files are checked 425 # regardless. 426 # 427 arg1=$1 428 activity=${arg1:-true} 429 [ "$1" ] && shift 430 argrest=$@ 431 force=${argrest:-false} 432 433 # 434 # Check the smf/manifest table to see if it needs upgrading 435 # 436 md5c=`$SVCPROP smf/manifest | grep var_svc_manifest | grep -c md5sum` 437 mfc=`$SVCPROP smf/manifest | grep var_svc_manifest | grep -cw manifestfile` 438 if [ $md5c -ne $mfc ]; then 439 unfnd_upgrade=`upgrade_smfmanifest` 440 if [ "$force" == false ]; then 441 activity="true" 442 force="true" 443 fi 444 fi 445 446 smfmfiles=`svcprop smf/manifest | grep manifestfile | grep astring | awk '{print $3}'` 447 needwork=`/lib/svc/bin/mfstscan $smfmfiles 2>&1 1>/dev/null` 448 if [ ! "$needwork" ]; then 449 [ "$activity" == false ] && return 450 451 [ "$activity" == true -a "$force" == false ] && return 452 fi 453 454 # 455 # Walk the list of services... 456 # 457 export SVCCFG_CHECKHASH=1 458 for service in `$SVCCFG list` 459 do 460 svcprop -q -p $MFSTPG $service 461 if [ $? -ne 0 ]; then 462 mc_igchk=`eval expr \"$IGNORELIST \" : "'.*\($service \)'"` 463 if [[ -n $mc_igchk ]]; then 464 echo "add_manifest $service FALSE" 465 add_manifest $service FALSE 466 continue 467 fi 468 469 [ $UPLIST -eq 0 ] && create_list 470 471 CS=`echo $service | sed -e 's/[-\/\,]/_/g'` 472 473 eval manifestlist=\$$CS 474 if [ -n "$manifestlist" ]; then 475 echo "add_manifest $service $manifestlist" 476 add_manifest $service $manifestlist 477 else 478 echo "add_manifest $service FALSE" 479 add_manifest $service FALSE 480 fi 481 else 482 process_service $service 483 fi 484 done 485 486 rm -f $MCLEANUPFILE 487 unset SVCCFG_CHECKHASH 488 489 # 490 # Check to make sure all work was processed and 491 # that all the files were removed correctly from 492 # the smf/manifest table. 493 # 494 leftover=`echo "$needwork" | grep "cannot stat" | awk '{print $4}'` 495 for f in $leftover $unfnd_upgrade 496 do 497 f_srch=`echo $f | sed -e 's/\./\\\./g; s/:$//'` 498 f_entry=`$SVCPROP smf/manifest | grep "$f_srch" | awk -F'/' '{print $1}'` 499 [ "$f_entry" ] && $SVCCFG -s smf/manifest delpg $f_entry 500 done 501 } 502