1#!/bin/bash 2# 3# /etc/init.d/xendomains 4# Start / stop domains automatically when domain 0 boots / shuts down. 5# 6# chkconfig: 345 99 00 7# description: Start / stop Xen domains. 8# 9# This script offers fairly basic functionality. It should work on Redhat 10# but also on LSB-compliant SuSE releases and on Debian with the LSB package 11# installed. (LSB is the Linux Standard Base) 12# 13# Based on the example in the "Designing High Quality Integrated Linux 14# Applications HOWTO" by Avi Alkalay 15# <http://www.tldp.org/HOWTO/HighQuality-Apps-HOWTO/> 16# 17### BEGIN INIT INFO 18# Provides: xendomains 19# Required-Start: $syslog $remote_fs xenstored xenconsoled 20# Should-Start: xend 21# Required-Stop: $syslog $remote_fs xenstored xenconsoled 22# Should-Stop: xend 23# Default-Start: 2 3 5 24# Default-Stop: 0 1 6 25# Short-Description: Start/stop secondary xen domains 26# Description: Start / stop domains automatically when domain 0 27# boots / shuts down. 28### END INIT INFO 29 30. @XEN_SCRIPT_DIR@/hotplugpath.sh 31 32CMD=${sbindir}/xl 33HEADCOMP="Xen saved domain" 34$CMD list &> /dev/null 35if test $? -ne 0 36then 37 exit $? 38fi 39 40$CMD list &> /dev/null 41if test $? -ne 0 42then 43 exit 0; 44fi 45 46# Correct exit code would probably be 5, but it's enough 47# if xend complains if we're not running as privileged domain 48if [ ! -e /dev/xen/privcmd ] && [ ! -e /proc/xen/privcmd ]; then 49 exit 0 50fi 51 52# RHEL-based systems only shutdown a service if they find a lockfile 53# in /var/lock/subsys 54if [[ -d ${XEN_LOCK_DIR}/subsys ]] ; then 55 LOCKFILE=${XEN_LOCK_DIR}/subsys/xendomains 56else 57 LOCKFILE=${XEN_LOCK_DIR}/xendomains 58fi 59 60XENDOM_CONFIG=@CONFIG_DIR@/@CONFIG_LEAF_DIR@/xendomains 61 62test -r $XENDOM_CONFIG || { echo "$XENDOM_CONFIG not existing"; 63 if [ "$1" = "stop" ]; then exit 0; 64 else exit 6; fi; } 65 66. $XENDOM_CONFIG 67 68# Use the SUSE rc_ init script functions; 69# emulate them on LSB, RH and other systems 70if test -e /etc/rc.status; then 71 # SUSE rc script library 72 . /etc/rc.status 73else 74 _cmd=$1 75 declare -a _SMSG 76 if test "${_cmd}" = "status"; then 77 _SMSG=(running dead dead unused unknown) 78 _RC_UNUSED=3 79 else 80 _SMSG=(done failed failed missed failed skipped unused failed failed) 81 _RC_UNUSED=6 82 fi 83 if test -e /etc/init.d/functions; then 84 # REDHAT 85 . /etc/init.d/functions 86 echo_rc() 87 { 88 #echo -n " [${_SMSG[${_RC_RV}]}] " 89 if test ${_RC_RV} = 0; then 90 success " [${_SMSG[${_RC_RV}]}] " 91 else 92 failure " [${_SMSG[${_RC_RV}]}] " 93 fi 94 } 95 elif test -e /lib/lsb/init-functions; then 96 # LSB 97 . /lib/lsb/init-functions 98 if alias log_success_msg >/dev/null 2>/dev/null; then 99 echo_rc() 100 { 101 echo " [${_SMSG[${_RC_RV}]}] " 102 } 103 else 104 echo_rc() 105 { 106 if test ${_RC_RV} = 0; then 107 log_success_msg " [${_SMSG[${_RC_RV}]}] " 108 else 109 log_failure_msg " [${_SMSG[${_RC_RV}]}] " 110 fi 111 } 112 fi 113 else 114 # emulate it 115 echo_rc() 116 { 117 echo " [${_SMSG[${_RC_RV}]}] " 118 } 119 fi 120 rc_reset() { _RC_RV=0; } 121 rc_failed() 122 { 123 if test -z "$1"; then 124 _RC_RV=1; 125 elif test "$1" != "0"; then 126 _RC_RV=$1; 127 fi 128 return ${_RC_RV} 129 } 130 rc_check() 131 { 132 return rc_failed $? 133 } 134 rc_status() 135 { 136 rc_failed $? 137 if test "$1" = "-r"; then _RC_RV=0; shift; fi 138 if test "$1" = "-s"; then rc_failed 5; echo_rc; rc_failed 3; shift; fi 139 if test "$1" = "-u"; then rc_failed ${_RC_UNUSED}; echo_rc; rc_failed 3; shift; fi 140 if test "$1" = "-v"; then echo_rc; shift; fi 141 if test "$1" = "-r"; then _RC_RV=0; shift; fi 142 return ${_RC_RV} 143 } 144 rc_exit() { exit ${_RC_RV}; } 145 rc_active() 146 { 147 if test -z "$RUNLEVEL"; then read RUNLEVEL REST < <(/sbin/runlevel); fi 148 if test -e /etc/init.d/S[0-9][0-9]${1}; then return 0; fi 149 return 1 150 } 151fi 152 153if ! which usleep >&/dev/null 154then 155 usleep() 156 { 157 if [ -n "$1" ] 158 then 159 sleep $(( $1 / 1000000 )) 160 fi 161 } 162fi 163 164# Reset status of this service 165rc_reset 166 167## 168# Returns 0 (success) if the given parameter names a directory, and that 169# directory is not empty. 170# 171contains_something() 172{ 173 if [ -d "$1" ] && [ `/bin/ls $1 | wc -l` -gt 0 ] 174 then 175 return 0 176 else 177 return 1 178 fi 179} 180 181# read name from xen config file 182rdname() 183{ 184 NM=$($CMD create --quiet --dryrun --defconfig "$1" | 185 sed -n 's/^.*(name \(.*\))$/\1/p;s/^.*"name": "\(.*\)",$/\1/p') 186} 187 188rdnames() 189{ 190 NAMES= 191 if ! contains_something "$XENDOMAINS_AUTO" 192 then 193 return 194 fi 195 for dom in $XENDOMAINS_AUTO/*; do 196 rdname $dom 197 if test -z $NAMES; then 198 NAMES=$NM; 199 else 200 NAMES="$NAMES|$NM" 201 fi 202 done 203} 204 205# get xenstore domain id (or 0 if no xenstore domain) 206get_xsdomid() 207{ 208 XS_DOMID=`${bindir}/xenstore-read /tool/xenstored/domid 2>/dev/null` 209 if test $? -ne 0; then 210 XS_DOMID=0 211 fi 212} 213 214LIST_GREP='(domain\|(domid\|(name\|^ {$\|"name":\|^ "domid":' 215parseln() 216{ 217 if [[ "$1" =~ '(domain' ]] || [[ "$1" = "{" ]]; then 218 name=;id= 219 elif [[ "$1" =~ '(name' ]]; then 220 name=$(echo $1 | sed -e 's/^.*(name \(.*\))$/\1/') 221 elif [[ "$1" =~ '(domid' ]]; then 222 id=$(echo $1 | sed -e 's/^.*(domid \(.*\))$/\1/') 223 elif [[ "$1" =~ '"name":' ]]; then 224 name=$(echo $1 | sed -e 's/^.*"name": "\(.*\)",$/\1/') 225 elif [[ "$1" =~ '"domid":' ]]; then 226 id=$(echo $1 | sed -e 's/^.*"domid": \(.*\),$/\1/') 227 fi 228 229 [ -n "$name" -a -n "$id" ] && return 0 || return 1 230} 231 232is_running() 233{ 234 get_xsdomid 235 rdname $1 236 RC=1 237 name=;id= 238 while read LN; do 239 parseln "$LN" || continue 240 if test $id = 0; then continue; fi 241 if test $id = $XS_DOMID; then continue; fi 242 case $name in 243 ($NM) 244 RC=0 245 ;; 246 esac 247 done < <($CMD list -l | grep "$LIST_GREP") 248 return $RC 249} 250 251start() 252{ 253 if [ -f $LOCKFILE ]; then 254 echo -e "xendomains already running (lockfile exists)" 255 return; 256 fi 257 258 mkdir -p $(dirname "$LOCKFILE") 259 touch $LOCKFILE 260 261 saved_domains=" " 262 if [ "$XENDOMAINS_RESTORE" = "true" ] && 263 contains_something "$XENDOMAINS_SAVE" 264 then 265 echo -n "Restoring Xen domains:" 266 saved_domains=`ls $XENDOMAINS_SAVE` 267 for dom in $XENDOMAINS_SAVE/*; do 268 if [ -f $dom ] ; then 269 HEADER=`head -c 16 $dom | head -n 1 2> /dev/null` 270 if [ "$HEADER" = "$HEADCOMP" ]; then 271 echo -n " ${dom##*/}" 272 XMR=`$CMD restore $dom 2>&1 1>/dev/null` 273 #$CMD restore $dom 274 if [ $? -ne 0 ]; then 275 echo -e "\nAn error occurred while restoring domain ${dom##*/}:\n$XMR" 276 rc_failed $? 277 echo -e '!' 278 else 279 # mv $dom ${dom%/*}/.${dom##*/} 280 rm $dom 281 fi 282 fi 283 fi 284 done 285 echo -e 286 fi 287 288 if contains_something "$XENDOMAINS_AUTO" 289 then 290 echo -n "Starting auto Xen domains:" 291 # We expect config scripts for auto starting domains to be in 292 # XENDOMAINS_AUTO - they could just be symlinks to files elsewhere 293 294 # Create all domains with config files in XENDOMAINS_AUTO. 295 # TODO: We should record which domain name belongs 296 # so we have the option to selectively shut down / migrate later 297 # If a domain statefile from $XENDOMAINS_SAVE matches a domain name 298 # in $XENDOMAINS_AUTO, do not try to start that domain; if it didn't 299 # restore correctly it requires administrative attention. 300 for dom in $XENDOMAINS_AUTO/*; do 301 echo -n " ${dom##*/}" 302 shortdom=$(echo $dom | sed -n 's/^.*\/\(.*\)$/\1/p') 303 echo $saved_domains | grep -w $shortdom > /dev/null 304 if [ $? -eq 0 ] || is_running $dom; then 305 echo -n "(skip)" 306 else 307 XMC=`$CMD create --quiet --defconfig $dom` 308 if [ $? -ne 0 ]; then 309 echo -e "\nAn error occurred while creating domain ${dom##*/}: $XMC\n" 310 rc_failed $? 311 echo -e '!' 312 else 313 usleep $XENDOMAINS_CREATE_USLEEP 314 fi 315 fi 316 done 317 fi 318} 319 320all_zombies() 321{ 322 get_xsdomid 323 name=;id= 324 while read LN; do 325 parseln "$LN" || continue 326 if test $id = 0; then continue; fi 327 if test $id = $XS_DOMID; then continue; fi 328 if test "$state" != "-b---d" -a "$state" != "-----d"; then 329 return 1; 330 fi 331 done < <($CMD list -l | grep "$LIST_GREP") 332 return 0 333} 334 335# Wait for max $XENDOMAINS_STOP_MAXWAIT for $CMD $1 to finish; 336# if it has not exited by that time kill it, so the init script will 337# succeed within a finite amount of time; if $2 is nonnull, it will 338# kill the command as well as soon as no domain (except for zombies) 339# are left (used for shutdown --all). Third parameter, if any, suppresses 340# output of dots per working state (formatting issues) 341watchdog_xencmd() 342{ 343 if test -z "$XENDOMAINS_STOP_MAXWAIT" -o "$XENDOMAINS_STOP_MAXWAIT" = "0"; then 344 exit 345 fi 346 347 usleep 20000 348 for no in `seq 0 $XENDOMAINS_STOP_MAXWAIT`; do 349 # exit if $CMD save/migrate/shutdown is finished 350 PSAX=`ps axlw | grep "$CMD $1" | grep -v grep` 351 if test -z "$PSAX"; then exit; fi 352 if ! test -n "$3"; then echo -n '.'; fi 353 sleep 1 354 # go to kill immediately if there's only zombies left 355 if all_zombies && test -n "$2"; then break; fi 356 done 357 sleep 1 358 read PSF PSUID PSPID PSPPID < <(echo "$PSAX") 359 # kill $CMD $1 360 kill $PSPID >/dev/null 2>&1 361 362 echo -e . 363} 364 365stop() 366{ 367 exec 3>&2 2> /dev/null 368 369 # Collect list of domains to shut down 370 if test "$XENDOMAINS_AUTO_ONLY" = "true"; then 371 rdnames 372 fi 373 get_xsdomid 374 echo -n "Shutting down Xen domains:" 375 name=;id= 376 while read LN; do 377 parseln "$LN" || continue 378 if test $id = 0; then continue; fi 379 if test $id = $XS_DOMID; then continue; fi 380 echo -n " $name" 381 if test "$XENDOMAINS_AUTO_ONLY" = "true"; then 382 eval " 383 case \"\$name\" in 384 ($NAMES) 385 # nothing 386 ;; 387 (*) 388 echo -e '(skip)' 389 continue 390 ;; 391 esac 392 " 393 fi 394 # XENDOMAINS_SYSRQ chould be something like just "s" 395 # or "s e i u" or even "s e s i u o" 396 # for the latter, you should set XENDOMAINS_USLEEP to 1200000 or so 397 if test -n "$XENDOMAINS_SYSRQ"; then 398 for sysrq in $XENDOMAINS_SYSRQ; do 399 echo -n "(SR-$sysrq)" 400 XMR=`$CMD sysrq $id $sysrq 2>&1 1>/dev/null` 401 if test $? -ne 0; then 402 echo -e "\nAn error occurred while doing sysrq on domain:\n$XMR\n" 403 rc_failed $? 404 echo -n '!' 405 fi 406 # usleep just ignores empty arg 407 usleep $XENDOMAINS_USLEEP 408 done 409 fi 410 if test "$state" = "-b---d" -o "$state" = "-----d"; then 411 echo -n "(zomb)" 412 continue 413 fi 414 if test -n "$XENDOMAINS_MIGRATE"; then 415 echo -n "(migr)" 416 watchdog_xencmd migrate & 417 WDOG_PID=$! 418 XMR=`$CMD migrate $id $XENDOMAINS_MIGRATE 2>&1 1>/dev/null` 419 if test $? -ne 0; then 420 echo -e "\nAn error occurred while migrating domain:\n$XMR\n" 421 rc_failed $? 422 echo -e '!' 423 424 kill $WDOG_PID >/dev/null 2>&1 425 else 426 kill $WDOG_PID >/dev/null 2>&1 427 428 echo -e . 429 usleep 1000 430 continue 431 fi 432 fi 433 if test -n "$XENDOMAINS_SAVE"; then 434 echo -n "(save)" 435 watchdog_xencmd save & 436 WDOG_PID=$! 437 mkdir -p "$XENDOMAINS_SAVE" 438 XMR=`$CMD save $id $XENDOMAINS_SAVE/$name 2>&1 1>/dev/null` 439 if test $? -ne 0; then 440 echo -e "\nAn error occurred while saving domain:\n$XMR\n" 441 rc_failed $? 442 echo -e '!' 443 kill $WDOG_PID >/dev/null 2>&1 444 else 445 kill $WDOG_PID >/dev/null 2>&1 446 echo -e . 447 usleep 1000 448 continue 449 fi 450 fi 451 if test -n "$XENDOMAINS_SHUTDOWN"; then 452 # XENDOMAINS_SHUTDOWN should be "--wait" 453 echo -n "(shut)" 454 watchdog_xencmd shutdown & 455 WDOG_PID=$! 456 XMR=`$CMD shutdown $XENDOMAINS_SHUTDOWN $id 2>&1 1>/dev/null` 457 if test $? -ne 0; then 458 echo -e "\nAn error occurred while shutting down domain:\n$XMR\n" 459 rc_failed $? 460 echo -e '!' 461 fi 462 kill $WDOG_PID >/dev/null 2>&1 463 fi 464 done < <($CMD list -l | grep "$LIST_GREP") 465 466 # NB. this shuts down ALL Xen domains (politely), not just the ones in 467 # AUTODIR/* 468 # This is because it's easier to do ;-) but arguably if this script is run 469 # on system shutdown then it's also the right thing to do. 470 if ! all_zombies && test -n "$XENDOMAINS_SHUTDOWN_ALL"; then 471 # XENDOMAINS_SHUTDOWN_ALL should be "--all --wait" 472 echo -n " SHUTDOWN_ALL " 473 watchdog_xencmd shutdown 1 false & 474 WDOG_PID=$! 475 XMR=`$CMD shutdown $XENDOMAINS_SHUTDOWN_ALL 2>&1 1>/dev/null` 476 if test $? -ne 0; then 477 echo -e "\nAn error occurred while shutting down all domains: $XMR\n" 478 rc_failed $? 479 echo -e '!' 480 fi 481 kill $WDOG_PID >/dev/null 2>&1 482 fi 483 484 # Unconditionally delete lock file 485 rm -f $LOCKFILE 486 487 exec 2>&3 488} 489 490check_domain_up() 491{ 492 name=;id= 493 while read LN; do 494 parseln "$LN" || continue 495 if test $id = 0; then continue; fi 496 case $name in 497 ($1) 498 return 0 499 ;; 500 esac 501 done < <($CMD list -l | grep "$LIST_GREP") 502 return 1 503} 504 505check_all_auto_domains_up() 506{ 507 if ! contains_something "$XENDOMAINS_AUTO" 508 then 509 return 0 510 fi 511 missing= 512 for nm in $XENDOMAINS_AUTO/*; do 513 rdname $nm 514 found=0 515 if check_domain_up "$NM"; then 516 echo -n " $name" 517 else 518 missing="$missing $NM" 519 fi 520 done 521 if test -n "$missing"; then 522 echo -n " MISS AUTO:$missing" 523 return 1 524 fi 525 return 0 526} 527 528check_all_saved_domains_up() 529{ 530 if ! contains_something "$XENDOMAINS_SAVE" 531 then 532 return 0 533 fi 534 missing=`/bin/ls $XENDOMAINS_SAVE` 535 echo -n " MISS SAVED: " $missing 536 return 1 537} 538 539# This does NOT necessarily restart all running domains: instead it 540# stops all running domains and then boots all the domains specified in 541# AUTODIR. If other domains have been started manually then they will 542# not get restarted. 543# Commented out to avoid confusion! 544 545restart() 546{ 547 stop 548 start 549} 550 551reload() 552{ 553 restart 554} 555 556 557case "$1" in 558 start) 559 start 560 rc_status 561 if test -f $LOCKFILE; then rc_status -v; fi 562 ;; 563 564 stop) 565 stop 566 rc_status -v 567 ;; 568 569 restart) 570 restart 571 ;; 572 reload) 573 reload 574 ;; 575 576 status) 577 echo -n "Checking for xendomains:" 578 if test ! -f $LOCKFILE; then 579 rc_failed 3 580 else 581 check_all_auto_domains_up 582 rc_status 583 check_all_saved_domains_up 584 rc_status 585 fi 586 rc_status -v 587 ;; 588 589 *) 590 echo "Usage: $0 {start|stop|restart|reload|status}" 591 rc_failed 3 592 rc_status -v 593 ;; 594esac 595 596rc_exit 597