]>
Commit | Line | Data |
---|---|---|
2e8b91a6 JR |
1 | #!/bin/sh |
2 | # | |
3 | # xendomains Start / stop domains automatically when domain 0 boots / shuts down. | |
4 | # | |
5 | # chkconfig: 345 99 00 | |
6 | # description: Start / stop Xen domains. | |
7 | # | |
8 | # This script offers fairly basic functionality. It should work on Redhat | |
9 | # but also on LSB-compliant SuSE releases and on Debian with the LSB package | |
10 | # installed. (LSB is the Linux Standard Base) | |
11 | # | |
12 | # Based on the example in the "Designing High Quality Integrated Linux | |
13 | # Applications HOWTO" by Avi Alkalay | |
14 | # <http://www.tldp.org/HOWTO/HighQuality-Apps-HOWTO/> | |
15 | # | |
16 | ### BEGIN INIT INFO | |
17 | # Provides: xendomains | |
18 | # Required-Start: $syslog $remote_fs xenstored xenconsoled | |
19 | # Should-Start: xend | |
20 | # Required-Stop: $syslog $remote_fs xenstored xenconsoled | |
21 | # Should-Stop: xend | |
22 | # Default-Start: 2 3 4 5 | |
23 | # Default-Stop: 0 1 6 | |
24 | # Short-Description: Start/stop secondary xen domains | |
25 | # Description: Start / stop domains automatically when domain 0 | |
26 | # boots / shuts down. | |
27 | ### END INIT INFO | |
28 | ||
29 | . /etc/rc.d/init.d/functions | |
30 | ||
31 | CMD=xm | |
32 | $CMD list >/dev/null 2>/dev/null || CMD=xl | |
33 | $CMD list >/dev/null 2>/dev/null || exit 0 | |
34 | ||
35 | [ -e /proc/xen/privcmd ] || exit 0 | |
36 | ||
37 | if [ -r /etc/sysconfig/xendomains ]; then | |
38 | . /etc/sysconfig/xendomains | |
39 | else | |
40 | echo "/etc/sysconfig/xendomains does not exist" | |
41 | if [ "$1" = "stop" ]; then | |
42 | exit 0 | |
43 | else | |
44 | exit 6 | |
45 | fi | |
46 | fi | |
47 | ||
48 | ## | |
49 | # Returns 0 (success) if the given parameter names a directory, and that | |
50 | # directory is not empty. | |
51 | # | |
52 | contains_something() { | |
53 | if [ -d "$1" ] && [ `/bin/ls $1 | wc -l` -gt 0 ]; then | |
54 | return 0 | |
55 | else | |
56 | return 1 | |
57 | fi | |
58 | } | |
59 | ||
60 | # read name from xen config file | |
61 | rdname() { | |
62 | NM=$($CMD create --quiet --dryrun --defconfig "$1" | sed -n 's/^.*(name \(.*\))$/\1/p') | |
63 | } | |
64 | ||
65 | rdnames() { | |
66 | NAMES= | |
67 | if ! contains_something "$XENDOMAINS_AUTO"; then | |
68 | return | |
69 | fi | |
70 | for dom in $XENDOMAINS_AUTO/*; do | |
71 | rdname $dom | |
72 | if test -z $NAMES; then | |
73 | NAMES=$NM; | |
74 | else | |
75 | NAMES="$NAMES|$NM" | |
76 | fi | |
77 | done | |
78 | } | |
79 | ||
80 | parseln() { | |
81 | if [[ "$1" =~ '(domain' ]]; then | |
82 | name=;id= | |
83 | else if [[ "$1" =~ '(name' ]]; then | |
84 | name=$(echo $1 | sed -e 's/^.*(name \(.*\))$/\1/') | |
85 | else if [[ "$1" =~ '(domid' ]]; then | |
86 | id=$(echo $1 | sed -e 's/^.*(domid \(.*\))$/\1/') | |
87 | fi; fi; fi | |
88 | ||
89 | [ -n "$name" -a -n "$id" ] && return 0 || return 1 | |
90 | } | |
91 | ||
92 | is_running() { | |
93 | rdname $1 | |
94 | RC=1 | |
95 | name=;id= | |
96 | while read LN; do | |
97 | parseln "$LN" || continue | |
98 | [ $id = 0 ] && continue | |
99 | case $name in | |
100 | ($NM) | |
101 | RC=0 | |
102 | ;; | |
103 | esac | |
104 | done < <($CMD list -l | grep '(\(domain\|domid\|name\)') | |
105 | return $RC | |
106 | } | |
107 | ||
108 | start() { | |
109 | if [ -f /var/lock/subsys/xendomains ]; then | |
110 | echo -e "xendomains already running (lockfile exists)" | |
111 | return | |
112 | fi | |
113 | ||
114 | saved_domains=" " | |
115 | if [ "$XENDOMAINS_RESTORE" = "true" ] && contains_something "$XENDOMAINS_SAVE"; then | |
116 | mkdir -p $(dirname "/var/lock/subsys/xendomains") | |
117 | touch /var/lock/subsys/xendomains | |
118 | echo -n "Restoring Xen domains:" | |
119 | saved_domains=`ls $XENDOMAINS_SAVE` | |
120 | for dom in $XENDOMAINS_SAVE/*; do | |
121 | if [ -f $dom ] ; then | |
122 | HEADER=`head -c 16 $dom | head -n 1 2> /dev/null` | |
123 | if [ $HEADER = "LinuxGuestRecord" ]; then | |
124 | echo -n " ${dom##*/}" | |
125 | XMR=`$CMD restore $dom 2>&1 1>/dev/null` | |
126 | #$CMD restore $dom | |
127 | if [ $? -ne 0 ]; then | |
128 | echo -e "\nAn error occurred while restoring domain ${dom##*/}:\n$XMR" | |
129 | echo -e '!' | |
130 | else | |
131 | # mv $dom ${dom%/*}/.${dom##*/} | |
132 | rm $dom | |
133 | fi | |
134 | fi | |
135 | fi | |
136 | done | |
137 | echo -e | |
138 | fi | |
139 | ||
140 | if contains_something "$XENDOMAINS_AUTO" ; then | |
141 | touch /var/lock/subsys/xendomains | |
142 | echo -n "Starting auto Xen domains:" | |
143 | # We expect config scripts for auto starting domains to be in | |
144 | # XENDOMAINS_AUTO - they could just be symlinks to files elsewhere | |
145 | ||
146 | # Create all domains with config files in XENDOMAINS_AUTO. | |
147 | # TODO: We should record which domain name belongs | |
148 | # so we have the option to selectively shut down / migrate later | |
149 | # If a domain statefile from $XENDOMAINS_SAVE matches a domain name | |
150 | # in $XENDOMAINS_AUTO, do not try to start that domain; if it didn't | |
151 | # restore correctly it requires administrative attention. | |
152 | for dom in $XENDOMAINS_AUTO/*; do | |
153 | echo -n " ${dom##*/}" | |
154 | shortdom=$(echo $dom | sed -n 's/^.*\/\(.*\)$/\1/p') | |
155 | echo $saved_domains | grep -w $shortdom > /dev/null | |
156 | if [ $? -eq 0 ] || is_running $dom; then | |
157 | echo -n "(skip)" | |
158 | else | |
159 | XMC=`$CMD create --quiet --defconfig $dom` | |
160 | if [ $? -ne 0 ]; then | |
161 | echo -e "\nAn error occurred while creating domain ${dom##*/}: $XMC\n" | |
162 | echo -e '!' | |
163 | else | |
164 | usleep $XENDOMAINS_CREATE_USLEEP | |
165 | fi | |
166 | fi | |
167 | done | |
168 | fi | |
169 | } | |
170 | ||
171 | all_zombies() { | |
172 | name=;id= | |
173 | while read LN; do | |
174 | parseln "$LN" || continue | |
175 | if test $id = 0; then continue; fi | |
176 | if test "$state" != "-b---d" -a "$state" != "-----d"; then | |
177 | return 1; | |
178 | fi | |
179 | done < <($CMD list -l | grep '(\(domain\|domid\|name\)') | |
180 | return 0 | |
181 | } | |
182 | ||
183 | # Wait for max $XENDOMAINS_STOP_MAXWAIT for $CMD $1 to finish; | |
184 | # if it has not exited by that time kill it, so the init script will | |
185 | # succeed within a finite amount of time; if $2 is nonnull, it will | |
186 | # kill the command as well as soon as no domain (except for zombies) | |
187 | # are left (used for shutdown --all). Third parameter, if any, suppresses | |
188 | # output of dots per working state (formatting issues) | |
189 | watchdog_xencmd() { | |
190 | if test -z "$XENDOMAINS_STOP_MAXWAIT" -o "$XENDOMAINS_STOP_MAXWAIT" = "0"; then | |
191 | exit | |
192 | fi | |
193 | ||
194 | usleep 20000 | |
195 | for no in `seq 0 $XENDOMAINS_STOP_MAXWAIT`; do | |
196 | # exit if $CMD save/migrate/shutdown is finished | |
197 | PSAX=`ps axlw | grep "$CMD $1" | grep -v grep` | |
198 | if test -z "$PSAX"; then exit; fi | |
199 | if ! test -n "$3"; then echo -n '.'; fi | |
200 | sleep 1 | |
201 | # go to kill immediately if there's only zombies left | |
202 | if all_zombies && test -n "$2"; then break; fi | |
203 | done | |
204 | sleep 1 | |
205 | read PSF PSUID PSPID PSPPID < <(echo "$PSAX") | |
206 | # kill $CMD $1 | |
207 | kill $PSPID >/dev/null 2>&1 | |
208 | ||
209 | echo -e . | |
210 | } | |
211 | ||
212 | stop() { | |
213 | # Collect list of domains to shut down | |
214 | if test "$XENDOMAINS_AUTO_ONLY" = "true"; then | |
215 | rdnames | |
216 | fi | |
217 | echo -n "Shutting down Xen domains:" | |
218 | name=;id= | |
219 | while read LN; do | |
220 | parseln "$LN" || continue | |
221 | if test $id = 0; then continue; fi | |
222 | echo -n " $name" | |
223 | if test "$XENDOMAINS_AUTO_ONLY" = "true"; then | |
224 | eval " | |
225 | case \"\$name\" in | |
226 | ($NAMES) | |
227 | # nothing | |
228 | ;; | |
229 | (*) | |
230 | echo -e '(skip)' | |
231 | continue | |
232 | ;; | |
233 | esac | |
234 | " | |
235 | fi | |
236 | # XENDOMAINS_SYSRQ chould be something like just "s" | |
237 | # or "s e i u" or even "s e s i u o" | |
238 | # for the latter, you should set XENDOMAINS_USLEEP to 1200000 or so | |
239 | if test -n "$XENDOMAINS_SYSRQ"; then | |
240 | for sysrq in $XENDOMAINS_SYSRQ; do | |
241 | echo -n "(SR-$sysrq)" | |
242 | XMR=`$CMD sysrq $id $sysrq 2>&1 1>/dev/null` | |
243 | if test $? -ne 0; then | |
244 | echo -e "\nAn error occurred while doing sysrq on domain:\n$XMR\n" | |
245 | echo -n '!' | |
246 | fi | |
247 | # usleep just ignores empty arg | |
248 | usleep $XENDOMAINS_USLEEP | |
249 | done | |
250 | fi | |
251 | if test "$state" = "-b---d" -o "$state" = "-----d"; then | |
252 | echo -n "(zomb)" | |
253 | continue | |
254 | fi | |
255 | if test -n "$XENDOMAINS_MIGRATE"; then | |
256 | echo -n "(migr)" | |
257 | watchdog_xencmd migrate & | |
258 | WDOG_PID=$! | |
259 | XMR=`$CMD migrate $id $XENDOMAINS_MIGRATE 2>&1 1>/dev/null` | |
260 | if test $? -ne 0; then | |
261 | echo -e "\nAn error occurred while migrating domain:\n$XMR\n" | |
262 | echo -e '!' | |
263 | ||
264 | kill $WDOG_PID >/dev/null 2>&1 | |
265 | else | |
266 | kill $WDOG_PID >/dev/null 2>&1 | |
267 | ||
268 | echo -e . | |
269 | usleep 1000 | |
270 | continue | |
271 | fi | |
272 | fi | |
273 | if test -n "$XENDOMAINS_SAVE"; then | |
274 | echo -n "(save)" | |
275 | watchdog_xencmd save & | |
276 | WDOG_PID=$! | |
277 | mkdir -p "$XENDOMAINS_SAVE" | |
278 | XMR=`$CMD save $id $XENDOMAINS_SAVE/$name 2>&1 1>/dev/null` | |
279 | if test $? -ne 0; then | |
280 | echo -e "\nAn error occurred while saving domain:\n$XMR\n" | |
281 | echo -e '!' | |
282 | kill $WDOG_PID >/dev/null 2>&1 | |
283 | else | |
284 | kill $WDOG_PID >/dev/null 2>&1 | |
285 | echo -e . | |
286 | usleep 1000 | |
287 | continue | |
288 | fi | |
289 | fi | |
290 | if test -n "$XENDOMAINS_SHUTDOWN"; then | |
291 | # XENDOMAINS_SHUTDOWN should be "--halt --wait" | |
292 | echo -n "(shut)" | |
293 | watchdog_xencmd shutdown & | |
294 | WDOG_PID=$! | |
295 | XMR=`$CMD shutdown $id $XENDOMAINS_SHUTDOWN 2>&1 1>/dev/null` | |
296 | if test $? -ne 0; then | |
297 | echo -e "\nAn error occurred while shutting down domain:\n$XMR\n" | |
298 | echo -e '!' | |
299 | fi | |
300 | kill $WDOG_PID >/dev/null 2>&1 | |
301 | fi | |
302 | done < <($CMD list -l | grep '(\(domain\|domid\|name\)') | |
303 | ||
304 | # NB. this shuts down ALL Xen domains (politely), not just the ones in | |
305 | # AUTODIR/* | |
306 | # This is because it's easier to do ;-) but arguably if this script is run | |
307 | # on system shutdown then it's also the right thing to do. | |
308 | if ! all_zombies && test -n "$XENDOMAINS_SHUTDOWN_ALL"; then | |
309 | # XENDOMAINS_SHUTDOWN_ALL should be "--all --halt --wait" | |
310 | echo -n " SHUTDOWN_ALL " | |
311 | watchdog_xencmd shutdown 1 false & | |
312 | WDOG_PID=$! | |
313 | XMR=`$CMD shutdown $XENDOMAINS_SHUTDOWN_ALL 2>&1 1>/dev/null` | |
314 | if test $? -ne 0; then | |
315 | echo -e "\nAn error occurred while shutting down all domains: $XMR\n" | |
316 | echo -e '!' | |
317 | fi | |
318 | kill $WDOG_PID >/dev/null 2>&1 | |
319 | fi | |
320 | ||
321 | # Unconditionally delete lock file | |
322 | rm -f /var/lock/subsys/xendomains | |
323 | } | |
324 | ||
325 | check_domain_up() | |
326 | { | |
327 | name=;id= | |
328 | while read LN; do | |
329 | parseln "$LN" || continue | |
330 | if test $id = 0; then continue; fi | |
331 | case $name in | |
332 | ($1) | |
333 | return 0 | |
334 | ;; | |
335 | esac | |
336 | done < <($CMD list -l | grep '(\(domain\|domid\|name\)') | |
337 | return 1 | |
338 | } | |
339 | ||
340 | check_all_auto_domains_up() | |
341 | { | |
342 | if ! contains_something "$XENDOMAINS_AUTO"; then | |
343 | return 0 | |
344 | fi | |
345 | missing= | |
346 | for nm in $XENDOMAINS_AUTO/*; do | |
347 | rdname $nm | |
348 | found=0 | |
349 | if check_domain_up "$NM"; then | |
350 | echo -n " $name" | |
351 | else | |
352 | missing="$missing $NM" | |
353 | fi | |
354 | done | |
355 | if test -n "$missing"; then | |
356 | echo -n " MISS AUTO:$missing" | |
357 | return 1 | |
358 | fi | |
359 | return 0 | |
360 | } | |
361 | ||
362 | check_all_saved_domains_up() | |
363 | { | |
364 | if ! contains_something "$XENDOMAINS_SAVE"; then | |
365 | return 0 | |
366 | fi | |
367 | missing=`/bin/ls $XENDOMAINS_SAVE` | |
368 | echo -n " MISS SAVED: " $missing | |
369 | return 1 | |
370 | } | |
371 | ||
372 | RETVAL=0 | |
373 | # See how we were called. | |
374 | case "$1" in | |
375 | start) | |
376 | start | |
377 | ;; | |
378 | stop) | |
379 | stop | |
380 | ;; | |
381 | restart|reload) | |
382 | # This does NOT necessarily restart all running domains: instead it | |
383 | # stops all running domains and then boots all the domains specified in | |
384 | # AUTODIR. If other domains have been started manually then they will | |
385 | # not get restarted. | |
386 | stop | |
387 | start | |
388 | ;; | |
389 | status) | |
390 | if [ -f /var/lock/subsys/xendomains; then | |
391 | echo -n "Checking for xendomains:" | |
392 | check_all_auto_domains_up | |
393 | check_all_saved_domains_up | |
394 | fi | |
395 | ;; | |
396 | *) | |
397 | msg_usage "$0 {start|stop|restart|reload|status}" | |
398 | ;; | |
399 | esac | |
400 | ||
401 | exit $RETVAL |