]>
Commit | Line | Data |
---|---|---|
f4c7726e | 1 | #!/bin/bash |
ce2a536c AM |
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 xend | |
20 | # Should-Start: | |
21 | # Required-Stop: $syslog $remote_fs xend | |
22 | # Should-Stop: | |
23 | # Default-Start: 3 4 5 | |
24 | # Default-Stop: 0 1 2 6 | |
f4c7726e | 25 | # Default-Enabled: yes |
ce2a536c | 26 | # Short-Description: Start/stop secondary xen domains |
f4c7726e | 27 | # Description: Start / stop domains automatically when domain 0 |
ce2a536c AM |
28 | # boots / shuts down. |
29 | ### END INIT INFO | |
30 | ||
f4c7726e | 31 | # Correct exit code would probably be 5, but it's enough |
32 | # if xend complains if we're not running as privileged domain | |
ce2a536c AM |
33 | if ! [ -e /proc/xen/privcmd ]; then |
34 | exit 0 | |
35 | fi | |
36 | ||
ce2a536c | 37 | LOCKFILE=/var/lock/subsys/xendomains |
f4c7726e | 38 | XENDOM_CONFIG=/etc/sysconfig/xendomains |
39 | ||
40 | test -r $XENDOM_CONFIG || { echo "$XENDOM_CONFIG not existing"; | |
41 | if [ "$1" = "stop" ]; then exit 0; | |
42 | else exit 6; fi; } | |
43 | ||
44 | . $XENDOM_CONFIG | |
45 | ||
46 | # Use the SUSE rc_ init script functions; | |
47 | # emulate them on LSB, RH and other systems | |
48 | if test -e /etc/rc.status; then | |
49 | # SUSE rc script library | |
50 | . /etc/rc.status | |
51 | else | |
52 | _cmd=$1 | |
53 | declare -a _SMSG | |
54 | if test "${_cmd}" = "status"; then | |
55 | _SMSG=(running dead dead unused unknown) | |
56 | _RC_UNUSED=3 | |
57 | else | |
58 | _SMSG=(done failed failed missed failed skipped unused failed failed) | |
59 | _RC_UNUSED=6 | |
60 | fi | |
61 | if test -e /lib/lsb/init-functions; then | |
62 | # LSB | |
63 | . /lib/lsb/init-functions | |
64 | echo_rc() | |
65 | { | |
66 | if test ${_RC_RV} = 0; then | |
67 | log_success_msg " [${_SMSG[${_RC_RV}]}] " | |
68 | else | |
69 | log_failure_msg " [${_SMSG[${_RC_RV}]}] " | |
70 | fi | |
71 | } | |
72 | elif test -e /etc/init.d/functions; then | |
73 | # REDHAT | |
74 | . /etc/init.d/functions | |
75 | echo_rc() | |
76 | { | |
77 | #echo -n " [${_SMSG[${_RC_RV}]}] " | |
78 | if test ${_RC_RV} = 0; then | |
79 | success " [${_SMSG[${_RC_RV}]}] " | |
80 | else | |
81 | failure " [${_SMSG[${_RC_RV}]}] " | |
82 | fi | |
83 | } | |
84 | else | |
85 | # emulate it | |
86 | echo_rc() | |
87 | { | |
88 | echo " [${_SMSG[${_RC_RV}]}] " | |
89 | } | |
90 | fi | |
91 | rc_reset() { _RC_RV=0; } | |
92 | rc_failed() | |
ce2a536c | 93 | { |
f4c7726e | 94 | if test -z "$1"; then |
95 | _RC_RV=1; | |
96 | elif test "$1" != "0"; then | |
97 | _RC_RV=$1; | |
98 | fi | |
99 | return ${_RC_RV} | |
ce2a536c | 100 | } |
f4c7726e | 101 | rc_check() |
ce2a536c | 102 | { |
f4c7726e | 103 | return rc_failed $? |
104 | } | |
105 | rc_status() | |
106 | { | |
107 | rc_failed $? | |
108 | if test "$1" = "-r"; then _RC_RV=0; shift; fi | |
109 | if test "$1" = "-s"; then rc_failed 5; echo_rc; rc_failed 3; shift; fi | |
110 | if test "$1" = "-u"; then rc_failed ${_RC_UNUSED}; echo_rc; rc_failed 3; shift; fi | |
111 | if test "$1" = "-v"; then echo_rc; shift; fi | |
112 | if test "$1" = "-r"; then _RC_RV=0; shift; fi | |
113 | return ${_RC_RV} | |
ce2a536c | 114 | } |
f4c7726e | 115 | rc_exit() { exit ${_RC_RV}; } |
116 | rc_active() | |
ce2a536c | 117 | { |
f4c7726e | 118 | if test -z "$RUNLEVEL"; then read RUNLEVEL REST < <(/sbin/runlevel); fi |
119 | if test -e /etc/init.d/S[0-9][0-9]${1}; then return 0; fi | |
120 | return 1 | |
ce2a536c AM |
121 | } |
122 | fi | |
123 | ||
f4c7726e | 124 | if ! which usleep >&/dev/null |
125 | then | |
126 | usleep() | |
127 | { | |
128 | if [ -n "$1" ] | |
129 | then | |
130 | sleep $(( $1 / 1000000 )) | |
131 | fi | |
132 | } | |
133 | fi | |
134 | ||
135 | # Reset status of this service | |
136 | rc_reset | |
137 | ||
138 | ## | |
139 | # Returns 0 (success) if the given parameter names a directory, and that | |
140 | # directory is not empty. | |
141 | # | |
142 | contains_something() | |
143 | { | |
144 | if [ -d "$1" ] && [ `/bin/ls $1 | wc -l` -gt 0 ] | |
145 | then | |
146 | return 0 | |
147 | else | |
148 | return 1 | |
149 | fi | |
150 | } | |
151 | ||
152 | # read name from xen config file | |
153 | rdname() | |
154 | { | |
155 | NM=$(xm create --quiet --dryrun --defconfig "$1" | | |
156 | sed -n 's/^.*(name \(.*\))$/\1/p') | |
157 | } | |
158 | ||
159 | rdnames() | |
160 | { | |
161 | NAMES= | |
162 | if ! contains_something "$XENDOMAINS_AUTO" | |
163 | then | |
164 | return | |
165 | fi | |
166 | for dom in $XENDOMAINS_AUTO/*; do | |
167 | rdname $dom | |
168 | if test -z $NAMES; then | |
169 | NAMES=$NM; | |
170 | else | |
171 | NAMES="$NAMES|$NM" | |
172 | fi | |
173 | done | |
174 | } | |
ce2a536c | 175 | |
f4c7726e | 176 | parseln() |
177 | { | |
178 | name=`echo "$1" | cut -c0-17` | |
179 | name=${name%% *} | |
180 | rest=`echo "$1" | cut -c18- ` | |
181 | read id mem cpu vcpu state tm < <(echo "$rest") | |
182 | } | |
ce2a536c | 183 | |
f4c7726e | 184 | is_running() |
185 | { | |
186 | rdname $1 | |
187 | RC=1 | |
188 | while read LN; do | |
189 | parseln "$LN" | |
190 | if test $id = 0; then continue; fi | |
191 | case $name in | |
192 | ($NM) | |
193 | RC=0 | |
194 | ;; | |
195 | esac | |
196 | done < <(xm list | grep -v '^Name') | |
197 | return $RC | |
198 | } | |
ce2a536c | 199 | |
f4c7726e | 200 | start() |
201 | { | |
202 | if [ -f $LOCKFILE ]; then | |
203 | echo -n "xendomains already running (lockfile exists)" | |
204 | return; | |
205 | fi | |
ce2a536c | 206 | |
f4c7726e | 207 | if [ "$XENDOMAINS_RESTORE" = "true" ] && |
208 | contains_something "$XENDOMAINS_SAVE" | |
209 | then | |
210 | mkdir -p $(dirname "$LOCKFILE") | |
ce2a536c | 211 | touch $LOCKFILE |
f4c7726e | 212 | echo -n "Restoring Xen domains:" |
213 | for dom in $XENDOMAINS_SAVE/*; do | |
214 | echo -n " ${dom##*/}" | |
215 | xm restore $dom | |
ce2a536c | 216 | if [ $? -ne 0 ]; then |
f4c7726e | 217 | rc_failed $? |
218 | echo -n '!' | |
219 | else | |
220 | # mv $dom ${dom%/*}/.${dom##*/} | |
221 | rm $dom | |
ce2a536c AM |
222 | fi |
223 | done | |
f4c7726e | 224 | echo . |
ce2a536c AM |
225 | fi |
226 | ||
f4c7726e | 227 | if contains_something "$XENDOMAINS_AUTO" |
228 | then | |
229 | touch $LOCKFILE | |
230 | echo -n "Starting auto Xen domains:" | |
231 | # We expect config scripts for auto starting domains to be in | |
232 | # XENDOMAINS_AUTO - they could just be symlinks to files elsewhere | |
233 | ||
234 | # Create all domains with config files in XENDOMAINS_AUTO. | |
235 | # TODO: We should record which domain name belongs | |
236 | # so we have the option to selectively shut down / migrate later | |
237 | for dom in $XENDOMAINS_AUTO/*; do | |
238 | echo -n " ${dom##*/}" | |
239 | if is_running $dom; then | |
240 | echo -n "(skip)" | |
241 | else | |
242 | xm create --quiet --defconfig $dom | |
243 | if [ $? -ne 0 ]; then | |
244 | rc_failed $? | |
245 | echo -n '!' | |
246 | else | |
247 | usleep $XENDOMAINS_CREATE_USLEEP | |
248 | fi | |
249 | fi | |
250 | done | |
251 | fi | |
252 | } | |
253 | ||
254 | all_zombies() | |
255 | { | |
256 | while read LN; do | |
257 | parseln "$LN" | |
258 | if test $id = 0; then continue; fi | |
259 | if test "$state" != "-b---d" -a "$state" != "-----d"; then | |
260 | return 1; | |
261 | fi | |
262 | done < <(xm list | grep -v '^Name') | |
263 | return 0 | |
264 | } | |
265 | ||
266 | # Wait for max $XENDOMAINS_STOP_MAXWAIT for xm $1 to finish; | |
267 | # if it has not exited by that time kill it, so the init script will | |
268 | # succeed within a finite amount of time; if $2 is nonnull, it will | |
269 | # kill the command as well as soon as no domain (except for zombies) | |
270 | # are left (used for shutdown --all). | |
271 | watchdog_xm() | |
272 | { | |
273 | if test -z "$XENDOMAINS_STOP_MAXWAIT" -o "$XENDOMAINS_STOP_MAXWAIT" = "0"; then | |
274 | exit | |
275 | fi | |
276 | usleep 20000 | |
277 | for no in `seq 0 $XENDOMAINS_STOP_MAXWAIT`; do | |
278 | # exit if xm save/migrate/shutdown is finished | |
279 | PSAX=`ps axlw | grep "xm $1" | grep -v grep` | |
280 | if test -z "$PSAX"; then exit; fi | |
281 | echo -n "."; sleep 1 | |
282 | # go to kill immediately if there's only zombies left | |
283 | if all_zombies && test -n "$2"; then break; fi | |
284 | done | |
285 | sleep 1 | |
286 | read PSF PSUID PSPID PSPPID < <(echo "$PSAX") | |
287 | # kill xm $1 | |
288 | kill $PSPID >/dev/null 2>&1 | |
ce2a536c AM |
289 | } |
290 | ||
291 | stop() | |
292 | { | |
f4c7726e | 293 | # Collect list of domains to shut down |
294 | if test "$XENDOMAINS_AUTO_ONLY" = "true"; then | |
295 | rdnames | |
296 | fi | |
297 | echo -n "Shutting down Xen domains:" | |
298 | while read LN; do | |
299 | parseln "$LN" | |
300 | if test $id = 0; then continue; fi | |
301 | echo -n " $name" | |
302 | if test "$XENDOMAINS_AUTO_ONLY" = "true"; then | |
303 | case $name in | |
304 | ($NAMES) | |
305 | # nothing | |
306 | ;; | |
307 | (*) | |
308 | echo -n "(skip)" | |
309 | continue | |
310 | ;; | |
311 | esac | |
312 | fi | |
313 | # XENDOMAINS_SYSRQ chould be something like just "s" | |
314 | # or "s e i u" or even "s e s i u o" | |
315 | # for the latter, you should set XENDOMAINS_USLEEP to 1200000 or so | |
316 | if test -n "$XENDOMAINS_SYSRQ"; then | |
317 | for sysrq in $XENDOMAINS_SYSRQ; do | |
318 | echo -n "(SR-$sysrq)" | |
319 | xm sysrq $id $sysrq | |
320 | if test $? -ne 0; then | |
321 | rc_failed $? | |
322 | echo -n '!' | |
323 | fi | |
324 | # usleep just ignores empty arg | |
325 | usleep $XENDOMAINS_USLEEP | |
326 | done | |
327 | fi | |
328 | if test "$state" = "-b---d" -o "$state" = "-----d"; then | |
329 | echo -n "(zomb)" | |
330 | continue | |
331 | fi | |
332 | if test -n "$XENDOMAINS_MIGRATE"; then | |
333 | echo -n "(migr)" | |
334 | watchdog_xm migrate & | |
335 | WDOG_PID=$! | |
336 | xm migrate $id $XENDOMAINS_MIGRATE | |
337 | if test $? -ne 0; then | |
338 | rc_failed $? | |
339 | echo -n '!' | |
340 | kill $WDOG_PID >/dev/null 2>&1 | |
341 | else | |
342 | kill $WDOG_PID >/dev/null 2>&1 | |
343 | continue | |
344 | fi | |
345 | fi | |
346 | if test -n "$XENDOMAINS_SAVE"; then | |
347 | echo -n "(save)" | |
348 | watchdog_xm save & | |
349 | WDOG_PID=$! | |
350 | mkdir -p "$XENDOMAINS_SAVE" | |
351 | xm save $id $XENDOMAINS_SAVE/$name | |
352 | if test $? -ne 0; then | |
353 | rc_failed $? | |
354 | echo -n '!' | |
355 | kill $WDOG_PIG >/dev/null 2>&1 | |
356 | else | |
357 | kill $WDOG_PIG >/dev/null 2>&1 | |
358 | continue | |
359 | fi | |
360 | fi | |
361 | if test -n "$XENDOMAINS_SHUTDOWN"; then | |
362 | # XENDOMAINS_SHUTDOWN should be "--halt --wait" | |
363 | echo -n "(shut)" | |
364 | watchdog_xm shutdown & | |
365 | WDOG_PID=$! | |
366 | xm shutdown $id $XENDOMAINS_SHUTDOWN | |
367 | if test $? -ne 0; then | |
368 | rc_failed $? | |
369 | echo -n '!' | |
370 | fi | |
371 | kill $WDOG_PIG >/dev/null 2>&1 | |
372 | fi | |
373 | done < <(xm list | grep -v '^Name') | |
374 | ||
ce2a536c AM |
375 | # NB. this shuts down ALL Xen domains (politely), not just the ones in |
376 | # AUTODIR/* | |
377 | # This is because it's easier to do ;-) but arguably if this script is run | |
378 | # on system shutdown then it's also the right thing to do. | |
f4c7726e | 379 | if ! all_zombies && test -n "$XENDOMAINS_SHUTDOWN_ALL"; then |
380 | # XENDOMAINS_SHUTDOWN_ALL should be "--all --halt --wait" | |
381 | echo -n " SHUTDOWN_ALL " | |
382 | watchdog_xm shutdown 1 & | |
383 | WDOG_PID=$! | |
384 | xm shutdown $XENDOMAINS_SHUTDOWN_ALL | |
385 | if test $? -ne 0; then | |
386 | rc_failed $? | |
387 | echo -n '!' | |
388 | fi | |
389 | kill $WDOG_PID >/dev/null 2>&1 | |
390 | fi | |
106c001c | 391 | |
f4c7726e | 392 | # Unconditionally delete lock file |
393 | rm -f $LOCKFILE | |
394 | } | |
ce2a536c | 395 | |
f4c7726e | 396 | check_domain_up() |
397 | { | |
398 | while read LN; do | |
399 | parseln "$LN" | |
400 | if test $id = 0; then continue; fi | |
401 | case $name in | |
402 | ($1) | |
403 | return 0 | |
404 | ;; | |
405 | esac | |
406 | done < <(xm list | grep -v "^Name") | |
407 | return 1 | |
408 | } | |
ce2a536c | 409 | |
f4c7726e | 410 | check_all_auto_domains_up() |
411 | { | |
412 | if ! contains_something "$XENDOMAINS_AUTO" | |
413 | then | |
414 | return 0 | |
415 | fi | |
416 | missing= | |
417 | for nm in $XENDOMAINS_AUTO/*; do | |
418 | rdname $nm | |
419 | found=0 | |
420 | if check_domain_up "$NM"; then | |
421 | echo -n " $name" | |
422 | else | |
423 | missing="$missing $NM" | |
424 | fi | |
425 | done | |
426 | if test -n "$missing"; then | |
427 | echo -n " MISS AUTO:$missing" | |
428 | return 1 | |
429 | fi | |
430 | return 0 | |
431 | } | |
ce2a536c | 432 | |
f4c7726e | 433 | check_all_saved_domains_up() |
434 | { | |
435 | if ! contains_something "$XENDOMAINS_SAVE" | |
436 | then | |
437 | return 0 | |
438 | fi | |
439 | missing=`/bin/ls $XENDOMAINS_SAVE` | |
440 | echo -n " MISS SAVED: " $missing | |
441 | return 1 | |
ce2a536c AM |
442 | } |
443 | ||
444 | # This does NOT necessarily restart all running domains: instead it | |
445 | # stops all running domains and then boots all the domains specified in | |
446 | # AUTODIR. If other domains have been started manually then they will | |
447 | # not get restarted. | |
448 | # Commented out to avoid confusion! | |
ce2a536c | 449 | |
f4c7726e | 450 | restart() |
451 | { | |
452 | stop | |
453 | start | |
454 | } | |
455 | ||
456 | reload() | |
457 | { | |
458 | restart | |
459 | } | |
ce2a536c AM |
460 | |
461 | ||
462 | case "$1" in | |
463 | start) | |
464 | start | |
f4c7726e | 465 | rc_status |
466 | if test -f $LOCKFILE; then rc_status -v; fi | |
ce2a536c AM |
467 | ;; |
468 | ||
469 | stop) | |
470 | stop | |
f4c7726e | 471 | rc_status -v |
ce2a536c AM |
472 | ;; |
473 | ||
f4c7726e | 474 | restart) |
475 | restart | |
476 | ;; | |
477 | reload) | |
478 | reload | |
479 | ;; | |
ce2a536c AM |
480 | |
481 | status) | |
f4c7726e | 482 | echo -n "Checking for xendomains:" |
483 | if test ! -f $LOCKFILE; then | |
484 | rc_failed 3 | |
485 | else | |
486 | check_all_auto_domains_up | |
487 | rc_status | |
488 | check_all_saved_domains_up | |
489 | rc_status | |
490 | fi | |
491 | rc_status -v | |
ce2a536c AM |
492 | ;; |
493 | ||
494 | *) | |
f4c7726e | 495 | echo "Usage: $0 {start|stop|restart|reload|status}" |
496 | rc_failed 3 | |
497 | rc_status -v | |
ce2a536c AM |
498 | ;; |
499 | esac | |
500 | ||
f4c7726e | 501 | rc_exit |