-#!/bin/sh
+#!/bin/bash
#
-# xendomains Start / stop domains automatically when domain 0 boots / shuts down.
+# xendomains Start / stop domains automatically when domain 0 boots / shuts down.
#
-# chkconfig: 345 99 00
-# description: Start / stop Xen domains.
+# chkconfig: 345 99 00
+# description: Start / stop Xen domains.
#
-# This script offers fairly basic functionality. It should work on Redhat
-# but also on LSB-compliant SuSE releases and on Debian with the LSB package
-# installed. (LSB is the Linux Standard Base)
-#
-# Based on the example in the "Designing High Quality Integrated Linux
-# Applications HOWTO" by Avi Alkalay
-# <http://www.tldp.org/HOWTO/HighQuality-Apps-HOWTO/>
-#
-### BEGIN INIT INFO
-# Provides: xendomains
-# Required-Start: $syslog $remote_fs xenstored xenconsoled
-# Should-Start: xend
-# Required-Stop: $syslog $remote_fs xenstored xenconsoled
-# Should-Stop: xend
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Start/stop secondary xen domains
-# Description: Start / stop domains automatically when domain 0
-# boots / shuts down.
-### END INIT INFO
. /etc/rc.d/init.d/functions
-CMD=xm
-$CMD list >/dev/null 2>/dev/null || CMD=xl
-$CMD list >/dev/null 2>/dev/null || exit 0
+if ! [ -e /proc/xen/privcmd ]; then
+ exit 0
+fi
-[ -e /proc/xen/privcmd ] || exit 0
+TOOLSTACK=$(/usr/libexec/xen/bin/xen-toolstack toolstack 2>/dev/null)
+if [ $? -ne 0 ]; then
+ echo "No usable Xen toolstack selected"
+ exit 0
+fi
+if [ "$(basename "$TOOLSTACK")" != xl ] && [ "$(basename "$TOOLSTACK")" != xm ]; then
+ exit 0
+fi
-if [ -r /etc/sysconfig/xendomains ]; then
- . /etc/sysconfig/xendomains
-else
- echo "/etc/sysconfig/xendomains does not exist"
- if [ "$1" = "stop" ]; then
- exit 0
- else
- exit 6
- fi
+if ! /usr/libexec/xen/bin/xen-toolstack list >/dev/null 2>&1 ; then
+ exit 0;
fi
-##
-# Returns 0 (success) if the given parameter names a directory, and that
-# directory is not empty.
-#
-contains_something() {
- if [ -d "$1" ] && [ `/bin/ls $1 | wc -l` -gt 0 ]; then
- return 0
- else
- return 1
- fi
+[ -r /etc/sysconfig/xendomains ] && . /etc/sysconfig/xendomains
+
+shopt -s nullglob
+
+check_config_name()
+{
+ /usr/libexec/xen/bin/xen-toolstack create --quiet --dryrun --defconfig "$1" | sed -n 's/^.*(name \(.*\))$/\1/p;s/^.*"name": "\(.*\)",$/\1/p'
}
-# read name from xen config file
-rdname() {
- NM=$($CMD create --quiet --dryrun --defconfig "$1" | sed -n 's/^.*(name \(.*\))$/\1/p')
+check_running()
+{
+ /usr/libexec/xen/bin/xen-toolstack domid "$1" >/dev/null 2>&1
+ return $?
}
-rdnames() {
- NAMES=
- if ! contains_something "$XENDOMAINS_AUTO"; then
- return
- fi
- for dom in $XENDOMAINS_AUTO/*; do
- rdname $dom
- if test -z $NAMES; then
- NAMES=$NM;
+timeout_coproc()
+{
+ local TIMEOUT=$1
+ shift
+
+ coproc "$@" >/dev/null 2>&1
+
+ local COPROC_OUT
+ exec {COPROC_OUT}<&"${COPROC[0]}"
+ local PID="$COPROC_PID"
+
+ for no in $(seq 0 $TIMEOUT); do
+ if [ -z "$COPROC_PID" ]; then break; fi
+ sleep 1
+ done
+
+ kill -INT "$COPROC_PID" >/dev/null 2>&1
+ wait $PID
+ local rc=$?
+ if [ $rc -eq 0 ]; then
+ ok
else
- NAMES="$NAMES|$NM"
+ fail
fi
- done
-}
-parseln() {
- if [[ "$1" =~ '(domain' ]]; then
- name=;id=
- else if [[ "$1" =~ '(name' ]]; then
- name=$(echo $1 | sed -e 's/^.*(name \(.*\))$/\1/')
- else if [[ "$1" =~ '(domid' ]]; then
- id=$(echo $1 | sed -e 's/^.*(domid \(.*\))$/\1/')
- fi; fi; fi
+ [ $rc -gt 0 ] && cat <&$COPROC_OUT
+ exec <&$COPROC_OUT-
+}
- [ -n "$name" -a -n "$id" ] && return 0 || return 1
+timeout_domain()
+{
+ name="$1"
+ TIMEOUT="$2"
+ for no in $(seq 0 $TIMEOUT); do
+ if ! check_running "$name"; then return 0; fi
+ sleep 1
+ done
+ return 1
}
-is_running() {
- rdname $1
- RC=1
- name=;id=
- while read LN; do
- parseln "$LN" || continue
- [ $id = 0 ] && continue
- case $name in
- ($NM)
- RC=0
- ;;
- esac
- done < <($CMD list -l | grep '(\(domain\|domid\|name\)')
- return $RC
+do_start_restore()
+{
+ [ -n "$XENDOMAINS_SAVE" ] || return
+ [ -d "$XENDOMAINS_SAVE" ] || return
+ [ -n "$XENDOMAINS_RESTORE" ] || return
+
+ for file in $XENDOMAINS_SAVE/*; do
+ if [ -f $file ] ; then
+ name="${file##*/}"
+ show "Restoring Xen domain $name (from $file)"
+ busy
+
+ out=$(/usr/libexec/xen/bin/xen-toolstack restore "$file" >/dev/null 2>&1)
+ case "$?" in
+ 0)
+ rm "$file"
+ domains[$name]='started'
+ ok
+ ;;
+ *)
+ domains[$name]='failed'
+ fail
+ echo "$out"
+ ;;
+ esac
+ fi
+ done
}
-start() {
- if [ -f /var/lock/subsys/xendomains ]; then
- echo -e "xendomains already running (lockfile exists)"
- return
- fi
+do_start_auto()
+{
+ [ -n "$XENDOMAINS_AUTO" ] || return
+ [ -d "$XENDOMAINS_AUTO" ] || return
- saved_domains=" "
- if [ "$XENDOMAINS_RESTORE" = "true" ] && contains_something "$XENDOMAINS_SAVE"; then
- mkdir -p $(dirname "/var/lock/subsys/xendomains")
- touch /var/lock/subsys/xendomains
- echo -n "Restoring Xen domains:"
- saved_domains=`ls $XENDOMAINS_SAVE`
- for dom in $XENDOMAINS_SAVE/*; do
- if [ -f $dom ] ; then
- HEADER=`head -c 16 $dom | head -n 1 2> /dev/null`
- if [ $HEADER = "LinuxGuestRecord" ]; then
- echo -n " ${dom##*/}"
- XMR=`$CMD restore $dom 2>&1 1>/dev/null`
- #$CMD restore $dom
- if [ $? -ne 0 ]; then
- echo -e "\nAn error occurred while restoring domain ${dom##*/}:\n$XMR"
- echo -e '!'
- else
- # mv $dom ${dom%/*}/.${dom##*/}
- rm $dom
- fi
- fi
- fi
- done
- echo -e
- fi
-
- if contains_something "$XENDOMAINS_AUTO" ; then
- touch /var/lock/subsys/xendomains
- echo -n "Starting auto Xen domains:"
- # We expect config scripts for auto starting domains to be in
- # XENDOMAINS_AUTO - they could just be symlinks to files elsewhere
-
- # Create all domains with config files in XENDOMAINS_AUTO.
- # TODO: We should record which domain name belongs
- # so we have the option to selectively shut down / migrate later
- # If a domain statefile from $XENDOMAINS_SAVE matches a domain name
- # in $XENDOMAINS_AUTO, do not try to start that domain; if it didn't
- # restore correctly it requires administrative attention.
- for dom in $XENDOMAINS_AUTO/*; do
- echo -n " ${dom##*/}"
- shortdom=$(echo $dom | sed -n 's/^.*\/\(.*\)$/\1/p')
- echo $saved_domains | grep -w $shortdom > /dev/null
- if [ $? -eq 0 ] || is_running $dom; then
- echo -n "(skip)"
- else
- XMC=`$CMD create --quiet --defconfig $dom`
- if [ $? -ne 0 ]; then
- echo -e "\nAn error occurred while creating domain ${dom##*/}: $XMC\n"
- echo -e '!'
+ for file in $XENDOMAINS_AUTO/*; do
+ name="$(check_config_name $file)"
+
+ if [ "${domains[$name]}" = started ]; then
+ :
+ elif check_running "$name"; then
+ echo "Xen domain $name already running"
else
- usleep $XENDOMAINS_CREATE_USLEEP
+ show "Starting Xen domain $name (from $file)"
+ busy
+
+ if [ "${domains[$name]}" = failed ]; then
+ fail
+ else
+ out=$(/usr/libexec/xen/bin/xen-toolstack create --quiet --defconfig "$file" >/dev/null 2>&1)
+ case "$?" in
+ 0)
+ ok
+ ;;
+ *)
+ fail
+ echo "$out"
+ ;;
+ esac
+ fi
fi
- fi
done
- fi
}
-all_zombies() {
- name=;id=
- while read LN; do
- parseln "$LN" || continue
- if test $id = 0; then continue; fi
- if test "$state" != "-b---d" -a "$state" != "-----d"; then
- return 1;
+do_start()
+{
+ declare -A domains
+
+ if [ -f /var/lock/subsys/xendomains ]; then
+ msg_already_running "xendomains"
+ return
fi
- done < <($CMD list -l | grep '(\(domain\|domid\|name\)')
- return 0
-}
-# Wait for max $XENDOMAINS_STOP_MAXWAIT for $CMD $1 to finish;
-# if it has not exited by that time kill it, so the init script will
-# succeed within a finite amount of time; if $2 is nonnull, it will
-# kill the command as well as soon as no domain (except for zombies)
-# are left (used for shutdown --all). Third parameter, if any, suppresses
-# output of dots per working state (formatting issues)
-watchdog_xencmd() {
- if test -z "$XENDOMAINS_STOP_MAXWAIT" -o "$XENDOMAINS_STOP_MAXWAIT" = "0"; then
- exit
- fi
-
- usleep 20000
- for no in `seq 0 $XENDOMAINS_STOP_MAXWAIT`; do
- # exit if $CMD save/migrate/shutdown is finished
- PSAX=`ps axlw | grep "$CMD $1" | grep -v grep`
- if test -z "$PSAX"; then exit; fi
- if ! test -n "$3"; then echo -n '.'; fi
- sleep 1
- # go to kill immediately if there's only zombies left
- if all_zombies && test -n "$2"; then break; fi
- done
- sleep 1
- read PSF PSUID PSPID PSPPID < <(echo "$PSAX")
- # kill $CMD $1
- kill $PSPID >/dev/null 2>&1
-
- echo -e .
+ do_start_restore
+ do_start_auto
+
+ touch /var/lock/subsys/xendomains
}
-stop() {
- # Collect list of domains to shut down
- if test "$XENDOMAINS_AUTO_ONLY" = "true"; then
- rdnames
- fi
- echo -n "Shutting down Xen domains:"
- name=;id=
- while read LN; do
- parseln "$LN" || continue
- if test $id = 0; then continue; fi
- echo -n " $name"
- if test "$XENDOMAINS_AUTO_ONLY" = "true"; then
- eval "
- case \"\$name\" in
- ($NAMES)
- # nothing
- ;;
- (*)
- echo -e '(skip)'
- continue
- ;;
- esac
- "
- fi
- # XENDOMAINS_SYSRQ chould be something like just "s"
- # or "s e i u" or even "s e s i u o"
- # for the latter, you should set XENDOMAINS_USLEEP to 1200000 or so
- if test -n "$XENDOMAINS_SYSRQ"; then
- for sysrq in $XENDOMAINS_SYSRQ; do
- echo -n "(SR-$sysrq)"
- XMR=`$CMD sysrq $id $sysrq 2>&1 1>/dev/null`
- if test $? -ne 0; then
- echo -e "\nAn error occurred while doing sysrq on domain:\n$XMR\n"
- echo -n '!'
- fi
- # usleep just ignores empty arg
- usleep $XENDOMAINS_USLEEP
- done
- fi
- if test "$state" = "-b---d" -o "$state" = "-----d"; then
- echo -n "(zomb)"
- continue
- fi
- if test -n "$XENDOMAINS_MIGRATE"; then
- echo -n "(migr)"
- watchdog_xencmd migrate &
- WDOG_PID=$!
- XMR=`$CMD migrate $id $XENDOMAINS_MIGRATE 2>&1 1>/dev/null`
- if test $? -ne 0; then
- echo -e "\nAn error occurred while migrating domain:\n$XMR\n"
- echo -e '!'
-
- kill $WDOG_PID >/dev/null 2>&1
- else
- kill $WDOG_PID >/dev/null 2>&1
-
- echo -e .
- usleep 1000
- continue
- fi
- fi
- if test -n "$XENDOMAINS_SAVE"; then
- echo -n "(save)"
- watchdog_xencmd save &
- WDOG_PID=$!
- mkdir -p "$XENDOMAINS_SAVE"
- XMR=`$CMD save $id $XENDOMAINS_SAVE/$name 2>&1 1>/dev/null`
- if test $? -ne 0; then
- echo -e "\nAn error occurred while saving domain:\n$XMR\n"
- echo -e '!'
- kill $WDOG_PID >/dev/null 2>&1
- else
- kill $WDOG_PID >/dev/null 2>&1
- echo -e .
- usleep 1000
- continue
- fi
- fi
- if test -n "$XENDOMAINS_SHUTDOWN"; then
- # XENDOMAINS_SHUTDOWN should be "--halt --wait"
- echo -n "(shut)"
- watchdog_xencmd shutdown &
- WDOG_PID=$!
- XMR=`$CMD shutdown $id $XENDOMAINS_SHUTDOWN 2>&1 1>/dev/null`
- if test $? -ne 0; then
- echo -e "\nAn error occurred while shutting down domain:\n$XMR\n"
- echo -e '!'
- fi
- kill $WDOG_PID >/dev/null 2>&1
- fi
- done < <($CMD list -l | grep '(\(domain\|domid\|name\)')
-
- # NB. this shuts down ALL Xen domains (politely), not just the ones in
- # AUTODIR/*
- # This is because it's easier to do ;-) but arguably if this script is run
- # on system shutdown then it's also the right thing to do.
- if ! all_zombies && test -n "$XENDOMAINS_SHUTDOWN_ALL"; then
- # XENDOMAINS_SHUTDOWN_ALL should be "--all --halt --wait"
- echo -n " SHUTDOWN_ALL "
- watchdog_xencmd shutdown 1 false &
- WDOG_PID=$!
- XMR=`$CMD shutdown $XENDOMAINS_SHUTDOWN_ALL 2>&1 1>/dev/null`
- if test $? -ne 0; then
- echo -e "\nAn error occurred while shutting down all domains: $XMR\n"
- echo -e '!'
- fi
- kill $WDOG_PID >/dev/null 2>&1
- fi
+do_stop_migrate()
+{
+ [ -n "$XENDOMAINS_MIGRATE" ] || return
- # Unconditionally delete lock file
- rm -f /var/lock/subsys/xendomains
+ while read id name rest; do
+ show "Migrating Xen domain $name ($id)"
+ busy
+ (timeout_coproc "$XENDOMAINS_STOP_MAXWAIT" /usr/libexec/xen/bin/xen-toolstack migrate $id $XENDOMAINS_MIGRATE)
+ done < <(/usr/libexec/xen/bin/xen-init-list)
}
-check_domain_up()
+do_stop_save()
{
- name=;id=
- while read LN; do
- parseln "$LN" || continue
- if test $id = 0; then continue; fi
- case $name in
- ($1)
- return 0
- ;;
- esac
- done < <($CMD list -l | grep '(\(domain\|domid\|name\)')
- return 1
+ [ -n "$XENDOMAINS_SAVE" ] || return
+ [ -d "$XENDOMAINS_SAVE" ] || mkdir -m 0700 -p "$XENDOMAINS_SAVE"
+
+ while read id name rest; do
+ show "Saving Xen domain $name ($id)"
+ busy
+ (timeout_coproc "$XENDOMAINS_STOP_MAXWAIT" /usr/libexec/xen/bin/xen-toolstack save $id $XENDOMAINS_SAVE/$name)
+ done < <(/usr/libexec/xen/bin/xen-init-list)
}
-check_all_auto_domains_up()
+do_stop_shutdown()
{
- if ! contains_something "$XENDOMAINS_AUTO"; then
- return 0
- fi
- missing=
- for nm in $XENDOMAINS_AUTO/*; do
- rdname $nm
- found=0
- if check_domain_up "$NM"; then
- echo -n " $name"
- else
- missing="$missing $NM"
- fi
- done
- if test -n "$missing"; then
- echo -n " MISS AUTO:$missing"
- return 1
- fi
- return 0
+ while read id name rest; do
+ show "Shutting down Xen domain $name ($id)"
+ busy
+ /usr/libexec/xen/bin/xen-toolstack shutdown $id >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ ok
+ else
+ fail
+ fi
+ done < <(/usr/libexec/xen/bin/xen-init-list)
+ while read id name rest; do
+ show "Waiting for Xen domain $name ($id) to shut down"
+ busy
+ timeout_domain "$name" "$XENDOMAINS_STOP_MAXWAIT"
+ if [ $? -eq 0 ]; then
+ ok
+ else
+ fail
+ fi
+ done < <(/usr/libexec/xen/bin/xen-init-list)
}
-check_all_saved_domains_up()
+do_stop()
{
- if ! contains_something "$XENDOMAINS_SAVE"; then
- return 0
- fi
- missing=`/bin/ls $XENDOMAINS_SAVE`
- echo -n " MISS SAVED: " $missing
- return 1
+ if [ ! -f /var/lock/subsys/xendomains ]; then
+ msg_not_running "xendomains"
+ return
+ fi
+
+ do_stop_migrate
+ do_stop_save
+ do_stop_shutdown
+
+ rm -f /var/lock/subsys/xendomains
}
-RETVAL=0
-# See how we were called.
case "$1" in
- start)
- start
- ;;
- stop)
- stop
- ;;
- restart|reload)
-# This does NOT necessarily restart all running domains: instead it
-# stops all running domains and then boots all the domains specified in
-# AUTODIR. If other domains have been started manually then they will
-# not get restarted.
- stop
- start
- ;;
- status)
- if [ -f /var/lock/subsys/xendomains; then
- echo -n "Checking for xendomains:"
- check_all_auto_domains_up
- check_all_saved_domains_up
- fi
- ;;
- *)
- msg_usage "$0 {start|stop|restart|reload|status}"
- ;;
+ start)
+ do_start
+ ;;
+ stop)
+ do_stop
+ ;;
+ restart)
+ do_stop
+ do_start
+ ;;
+ reload|force-reload)
+ do_stop
+ do_start
+ ;;
+ status)
+ if [ -f /var/lock/subsys/xendomains ]; then
+ /usr/libexec/xen/bin/xen-toolstack list -v
+ fi
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|status|restart|reload|force-reload}"
+ exit 3
+ ;;
esac
-exit $RETVAL
+exit 0