/[baselayout]/trunk/sbin/runscript.sh
Gentoo

Contents of /trunk/sbin/runscript.sh

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1814 - (show annotations) (download) (as text)
Thu Jan 12 17:13:55 2006 UTC (8 years, 9 months ago) by uberlord
File MIME type: text/x-sh
File size: 17405 byte(s)
Exit with the correct code
1 #!/bin/bash
2 # Copyright 1999-2006 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4
5 # Common functions
6 [[ ${RC_GOT_FUNCTIONS} != "yes" ]] && source /sbin/functions.sh
7
8 # User must be root to run most script stuff (except status)
9 if [[ ${EUID} != 0 ]] && ! [[ $2 == "status" && $# -eq 2 ]] ; then
10 eerror "$0: must be root to run init scripts"
11 exit 1
12 fi
13
14 # State variables
15 svcpause="no"
16 svcrestart="no"
17
18 myscript="$1"
19 if [[ -L $1 && ! -L "/etc/init.d/${1##*/}" ]] ; then
20 myservice="$(readlink $1)"
21 else
22 myservice="$1"
23 fi
24
25 myservice="${myservice##*/}"
26 export SVCNAME="${myservice}"
27 mylevel="$(<${svcdir}/softlevel)"
28
29 svc_trap() {
30 trap 'eerror "ERROR: \"${myservice}\" caught an interrupt"; exit 1' \
31 INT QUIT TSTP
32 }
33
34 # Setup a default trap
35 svc_trap
36
37 # Functions to handle dependencies and services
38 [[ ${RC_GOT_SERVICES} != "yes" ]] && source "${svclib}/sh/rc-services.sh"
39 # Functions to control daemons
40 [[ ${RC_GOT_DAEMON} != "yes" ]] && source "${svclib}/sh/rc-daemon.sh"
41
42 # Set $IFACE to the name of the network interface if it is a 'net.*' script
43 if [[ ${myservice%%.*} == "net" && ${myservice##*.} != "${myservice}" ]] ; then
44 IFACE="${myservice##*.}"
45 NETSERVICE="yes"
46 else
47 IFACE=
48 NETSERVICE=
49 fi
50
51 # Check if the textdomain is non-default
52 search_lang="${LC_ALL:-${LC_MESSAGES:-${LANG}}}"
53 [[ -f ${TEXTDOMAINDIR}/${search_lang%.*}/LC_MESSAGES/${myservice}.mo ]] \
54 && TEXTDOMAIN="${myservice}"
55
56 # Source configuration files.
57 # (1) Source /etc/conf.d/net if it is a net.* service
58 # (2) Source /etc/conf.d/${myservice} to get initscript-specific
59 # configuration (if it exists).
60 # (3) Source /etc/rc.conf to pick up potentially overriding
61 # configuration, if the system administrator chose to put it
62 # there (if it exists).
63 if [[ ${NETSERVICE} == "yes" ]] ; then
64 conf="$(add_suffix /etc/conf.d/net)"
65 [[ -e ${conf} ]] && source "${conf}"
66 fi
67 conf="$(add_suffix /etc/conf.d/${myservice})"
68 [[ -e ${conf} ]] && source "${conf}"
69 conf="$(add_suffix /etc/rc.conf)"
70 [[ -e ${conf} ]] && source "${conf}"
71
72 # Call svc_quit if we abort AND we have obtained a lock
73 svcbegun=1
74 service_started "${myservice}"
75 svcstarted=$?
76 service_inactive "${myservice}"
77 svcinactive=$?
78 svc_quit() {
79 eerror "ERROR: \"${myservice}\" caught an interrupt"
80 if [[ ${svcbegun} == 0 ]] ; then
81 end_service "${myservice}"
82 svcbegun=1
83 fi
84 if service_inactive "${myservice}" || [[ ${svcinactive} == 0 ]] ; then
85 mark_service_inactive "${myservice}"
86 elif [[ ${svcstarted} == 0 ]] ; then
87 mark_service_started "${myservice}"
88 else
89 mark_service_stopped "${myservice}"
90 fi
91 exit 1
92 }
93
94 usage() {
95 local IFS="|"
96 myline="Usage: ${myservice} { $* "
97 echo
98 eerror "${myline}}"
99 eerror " ${myservice} without arguments for full help"
100 }
101
102 stop() {
103 # Return success so the symlink gets removed
104 return 0
105 }
106
107 start() {
108 eerror "ERROR: \"${myservice}\" does not have a start function."
109 # Return failure so the symlink doesn't get created
110 return 1
111 }
112
113 restart() {
114 svc_restart || return $?
115 }
116
117 status() {
118 # Dummy function
119 return 0
120 }
121
122 svc_stop() {
123 local x= mydep= mydeps= retval=0
124 local -a servicelist=()
125
126 # Do not try to stop if it had already failed to do so on runlevel change
127 if is_runlevel_stop && service_failed "${myservice}" ; then
128 return 1
129 fi
130
131 if service_stopped "${myservice}" ; then
132 ewarn "WARNING: \"${myservice}\" has not yet been started."
133 return 0
134 fi
135
136 if ! mark_service_stopping "${myservice}" ; then
137 ewarn "WARNING: \"${myservice}\" is already stopping."
138 return 0
139 fi
140 # Lock service starting too ...
141 mark_service_starting "${myservice}"
142
143 # Ensure that we clean up if we abort for any reason
144 trap "svc_quit" INT QUIT TSTP
145
146 begin_service "${myservice}"
147 svcbegun=$?
148
149 service_message "Stopping service ${myservice}"
150
151 if in_runlevel "${myservice}" "${BOOTLEVEL}" && \
152 [[ ${SOFTLEVEL} != "reboot" && ${SOFTLEVEL} != "shutdown" && \
153 ${SOFTLEVEL} != "single" ]] ; then
154 ewarn "WARNING: you are stopping a boot service."
155 fi
156
157 if [[ ${svcpause} != "yes" ]] ; then
158 if [[ ${NETSERVICE} == "yes" ]] ; then
159 # A net.* service
160 if in_runlevel "${myservice}" "${BOOTLEVEL}" || \
161 in_runlevel "${myservice}" "${mylevel}" ; then
162 # Only worry about net.* services if this is the last one running,
163 # or if RC_NET_STRICT_CHECKING is set ...
164 if ! is_net_up ; then
165 mydeps="net"
166 fi
167 fi
168
169 mydeps="${mydeps} ${myservice}"
170 else
171 mydeps="${myservice}"
172 fi
173 fi
174
175 # Save the IN_BACKGROUND var as we need to clear it for stopping depends
176 local ib_save="${IN_BACKGROUND}"
177 unset IN_BACKGROUND
178
179 for mydep in ${mydeps} ; do
180 for x in $(needsme "${mydep}") ; do
181 # Service not currently running, continue
182 if service_started "${x}" ; then
183 stop_service "${x}"
184 service_list=( "${service_list[@]}" "${x}" )
185 fi
186 done
187 done
188
189 for x in "${service_list[@]}" ; do
190 # We need to test if the service has been marked stopped
191 # as the fifo may still be around if called by custom code
192 # such as postup from a net script.
193 service_stopped "${mynetservice}" && continue
194
195 wait_service "${x}"
196 if ! service_stopped "${x}" ; then
197 retval=1
198 break
199 fi
200 done
201
202 IN_BACKGROUND="${ib_save}"
203
204 if [[ ${retval} != 0 ]] ; then
205 eerror "ERROR: problems stopping dependent services."
206 eerror " \"${myservice}\" is still up."
207 else
208 # Now that deps are stopped, stop our service
209 (
210 exit() {
211 RC_QUIET_STDOUT="no"
212 eerror "DO NOT USE EXIT IN INIT.D SCRIPTS"
213 eerror "This IS a bug, please fix your broken init.d"
214 unset -f exit
215 exit $@
216 }
217 # Stop einfo/ebegin/eend from working as parallel messes us up
218 [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && RC_QUIET_STDOUT="yes"
219 stop
220 )
221 retval=$?
222
223 # If a service has been marked inactive, exit now as something
224 # may attempt to start it again later
225 if service_inactive "${myservice}" ; then
226 svcinactive=0
227 [[ ${svcbegun} == 0 ]] && end_service "${myservice}" 0
228 return 0
229 fi
230 fi
231
232 if [[ ${retval} != 0 ]] ; then
233 # Did we fail to stop? create symlink to stop multible attempts at
234 # runlevel change. Note this is only used at runlevel change ...
235 is_runlevel_stop && mark_service_failed "${myservice}"
236
237 # If we are halting the system, do it as cleanly as possible
238 if [[ ${SOFTLEVEL} != "reboot" && ${SOFTLEVEL} != "shutdown" ]] ; then
239 if [[ ${svcinactive} == 0 ]] ; then
240 mark_service_inactive "${myservice}"
241 else
242 mark_service_started "${myservice}"
243 fi
244 fi
245
246 service_message "eerror" "FAILED to stop service ${myservice}!"
247 else
248 # If we're stopped from a daemon that sets ${IN_BACKGROUND} such as
249 # wpa_monitor when we mark as inactive instead of taking the down
250 svcstarted=1
251 if service_inactive "${myservice}" ; then
252 svcinactive=0
253 else
254 mark_service_stopped "${myservice}"
255 fi
256 service_message "Stopped service ${myservice}"
257 fi
258
259 if [[ ${svcbegun} == 0 ]] ; then
260 end_service "${myservice}" "${retval}"
261 svcbegun=1
262 fi
263
264 # Reset the trap
265 svc_trap
266
267 return "${retval}"
268 }
269
270 svc_start() {
271 local x= y= retval=0 startfail="no"
272
273 # Do not try to start if i have done so already on runlevel change
274 if is_runlevel_start && service_failed "${myservice}" ; then
275 return 1
276 fi
277
278 if service_started "${myservice}" ; then
279 ewarn "WARNING: \"${myservice}\" has already been started."
280 return 0
281 elif service_stopping "${myservice}" ; then
282 eerror "ERROR: please wait for \"${myservice}\" to stop first."
283 return 1
284 elif service_inactive "${myservice}" ; then
285 if [[ ${IN_BACKGROUND} != "true" ]] ; then
286 ewarn "WARNING: \"${myservice}\" has already been started."
287 return 0
288 fi
289 fi
290
291 if ! mark_service_starting "${myservice}" ; then
292 ewarn "WARNING: \"${myservice}\" is already starting."
293 return 0
294 fi
295
296 # Ensure that we clean up if we abort for any reason
297 trap "svc_quit" INT QUIT TSTP
298
299 begin_service "${myservice}"
300 svcbegun=$?
301
302 service_message "Starting service ${myservice}"
303
304 # Save the IN_BACKGROUND var as we need to clear it for starting depends
305 local ib_save="${IN_BACKGROUND}"
306 unset IN_BACKGROUND
307
308 local startupservices="$(trace_dependencies $(ineed "${myservice}") \
309 $(valid_iuse ${myservice}))"
310 local netservices="$(dolisting "/etc/runlevels/${BOOTLEVEL}/net.*") \
311 $(dolisting "/etc/runlevels/${mylevel}/net.*")"
312 local startupnetservices=
313
314 # Start dependencies, if any.
315 # We don't handle "after" deps here as it's the job of rc to start them.
316 for x in ${startupservices} ; do
317 if [[ ${x} == "net" && ${NETSERVICE} != "yes" ]] && ! is_net_up ; then
318 for y in ${netservices} ; do
319 local mynetservice="${y##*/}"
320 if service_stopped "${mynetservice}" ; then
321 start_service "${mynetservice}"
322 startupnetservices="${startupnetservices}${mynetservice} "
323 fi
324 done
325 elif [[ ${x} != "net" ]] ; then
326 if service_stopped "${x}" ; then
327 start_service "${x}"
328 fi
329 fi
330 done
331
332 # We also wait for any services we're after to finish incase they
333 # have a "before" dep but we don't dep on them.
334 if is_runlevel_start ; then
335 startupservices="${startupservices} $(valid_iafter ${myservice})"
336 fi
337
338 # Wait for dependencies to finish.
339 for x in ${startupservices} ; do
340 if [[ ${x} == "net" && ${NETSERVICE} != "yes" ]] ; then
341 for y in ${startupnetservices} ; do
342 # Don't wait if it's already been started
343 service_started "${y}" && continue
344 wait_service "${y}"
345 if ! service_started "${y}" ; then
346 # A 'need' dependency is critical for startup
347 if ineed -t "${myservice}" "${x}" >/dev/null ; then
348 if ! is_net_up ; then
349 startfail="yes"
350 break
351 fi
352 fi
353 fi
354 done
355 elif [[ ${x} != "net" ]] ; then
356 # Don't wait if it's already been started
357 service_started "${x}" && continue
358 wait_service "${x}"
359 if ! service_started "${x}" ; then
360 # A 'need' dependacy is critical for startup
361 if ineed -t "${myservice}" "${x}" >/dev/null ; then
362 startfail="yes"
363 break
364 fi
365 fi
366 fi
367 done
368
369 if [[ ${startfail} == "yes" ]] ; then
370 eerror "ERROR: Problem starting needed services."
371 eerror " \"${myservice}\" was not started."
372 retval=1
373 elif broken "${myservice}" ; then
374 eerror "ERROR: Some services needed are missing. Run"
375 eerror " './${myservice} broken' for a list of those"
376 eerror " services. \"${myservice}\" was not started."
377 retval=1
378 else
379 IN_BACKGROUND="${ib_save}"
380 (
381 exit() {
382 RC_QUIET_STDOUT="no"
383 eerror "DO NOT USE EXIT IN INIT.D SCRIPTS"
384 eerror "This IS a bug, please fix your broken init.d"
385 unset -f exit
386 exit $@
387 }
388 # Stop einfo/ebegin/eend from working as parallel messes us up
389 [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && RC_QUIET_STDOUT="yes"
390 start
391 )
392 retval=$?
393
394 # If a service has been marked inactive, exit now as something
395 # may attempt to start it again later
396 if service_inactive "${myservice}" ; then
397 svcinactive=0
398 [[ ${svcbegun} == 0 ]] && end_service "${myservice}" 1
399 return 1
400 fi
401 fi
402
403 if [[ ${retval} != 0 ]] ; then
404 is_runlevel_start && mark_service_failed "${myservice}"
405
406 # Remove link if service didn't start; but only if we're not booting
407 # If we're booting, we need to continue and do our best to get the
408 # system up.
409 if [[ ${SOFTLEVEL} != "${BOOTLEVEL}" ]] ; then
410 if [[ ${svcinactive} == 0 ]] ; then
411 mark_service_inactive "${myservice}"
412 else
413 mark_service_stopped "${myservice}"
414 fi
415 fi
416
417 service_message "eerror" "FAILED to start service ${myservice}!"
418 else
419 svcstarted=0
420 mark_service_started "${myservice}"
421
422 service_message "Service ${myservice} started OK"
423 fi
424
425 if [[ ${svcbegun} == 0 ]] ; then
426 end_service "${myservice}" "${retval}"
427 svcbegun=1
428 fi
429
430 # Reset the trap
431 svc_trap
432
433 return "${retval}"
434 }
435
436 svc_restart() {
437 if ! service_stopped "${myservice}" ; then
438 svc_stop || return "$?"
439 fi
440 svc_start || return "$?"
441 }
442
443 svc_status() {
444 # The basic idea here is to have some sort of consistent
445 # output in the status() function which scripts can use
446 # as an generic means to detect status. Any other output
447 # should thus be formatted in the custom status() function
448 # to work with the printed " * status: foo".
449 local efunc="" state=""
450
451 # If we are effectively root, check to see if required daemons are running
452 # and update our status accordingly
453 [[ ${EUID} == 0 ]] && update_service_status "${myservice}"
454
455 if service_stopping "${myservice}" ; then
456 efunc="eerror"
457 state="stopping"
458 elif service_starting "${myservice}" ; then
459 efunc="einfo"
460 state="starting"
461 elif service_inactive "${myservice}" ; then
462 efunc="ewarn"
463 state="inactive"
464 elif service_started "${myservice}" ; then
465 efunc="einfo"
466 state="started"
467 else
468 efunc="eerror"
469 state="stopped"
470 fi
471 [[ ${RC_QUIET_STDOUT} != "yes" ]] \
472 && ${efunc} "status: ${state}"
473
474 status
475 # Return 0 if started, otherwise 1
476 [[ ${state} == "started" ]]
477 }
478
479 rcscript_errors="$(bash -n ${myscript} 2>&1)" || {
480 [[ -n ${rcscript_errors} ]] && echo "${rcscript_errors}" >&2
481 eerror "ERROR: \"${myscript}\" has syntax errors in it; aborting ..."
482 exit 1
483 }
484
485 # set *after* wrap_rcscript, else we get duplicates.
486 opts="start stop restart"
487
488 source "${myscript}"
489
490 # make sure whe have valid $opts
491 if [[ -z ${opts} ]] ; then
492 opts="start stop restart"
493 fi
494
495 svc_homegrown() {
496 local x arg="$1"
497 shift
498
499 # Walk through the list of available options, looking for the
500 # requested one.
501 for x in ${opts} ; do
502 if [[ ${x} == "${arg}" ]] ; then
503 if typeset -F "${x}" &>/dev/null ; then
504 # Run the homegrown function
505 "${x}"
506
507 return $?
508 fi
509 fi
510 done
511 x=""
512
513 # If we're here, then the function wasn't in $opts.
514 [[ -n $* ]] && x="/ $* "
515 eerror "ERROR: wrong args ( "${arg}" ${x})"
516 # Do not quote this either ...
517 usage ${opts}
518 exit 1
519 }
520
521 shift
522 if [[ $# -lt 1 ]] ; then
523 eerror "ERROR: not enough args."
524 usage ${opts}
525 exit 1
526 fi
527 for arg in $* ; do
528 case "${arg}" in
529 --quiet)
530 RC_QUIET_STDOUT="yes"
531 ;;
532 # We check this in functions.sh ...
533 # --nocolor)
534 # RC_NOCOLOR="yes"
535 # ;;
536 --verbose)
537 RC_VERBOSE="yes"
538 ;;
539 esac
540 done
541 for arg in $* ; do
542 case "${arg}" in
543 stop)
544 if [[ -e "${svcdir}/restart/${myservice}" ]] ; then
545 rm -f "${svcdir}/restart/${myservice}"
546 fi
547
548 # Stoped from the background - treat this as a restart so that
549 # stopped services come back up again when started.
550 if [[ ${IN_BACKGROUND} == "true" ]] ; then
551 rm -rf "${svcdir}/snapshot/$$"
552 mkdir -p "${svcdir}/snapshot/$$"
553 cp -pP "${svcdir}"/started/* "${svcdir}/snapshot/$$/"
554 fi
555
556 svc_stop
557 retval="$?"
558
559 if [[ ${IN_BACKGROUND} == "true" ]] ; then
560 res=
561 for x in $(dolisting "${svcdir}/snapshot/$$/") ; do
562 if service_stopped "${x##*/}" ; then
563 res="${res}${x##*/} "
564 fi
565 done
566 [[ -n ${res} ]] && echo "${res}" > "${svcdir}/restart/${myservice}"
567 fi
568
569 exit "${retval}"
570 ;;
571 start)
572 svc_start
573 retval=$?
574 if ! is_runlevel_start && [[ -s "${svcdir}/restart/${myservice}" ]] ; then
575 for x in $(trace_dependencies $(< "${svcdir}/restart/${myservice}")) ; do
576 service_stopped "${x}" && start_service "${x}"
577 done
578 fi
579 if [[ -e "${svcdir}/restart/${myservice}" ]] ; then
580 rm -f "${svcdir}/restart/${myservice}"
581 fi
582 exit "${retval}"
583 ;;
584 needsme|ineed|usesme|iuse|broken)
585 trace_dependencies "-${arg}"
586 ;;
587 status)
588 svc_status
589 ;;
590 zap)
591 if [[ -e "${svcdir}/restart/${myservice}" ]] ; then
592 rm -f "${svcdir}/restart/${myservice}"
593 fi
594 if ! service_stopped "${myservice}" ; then
595 einfo "Manually resetting ${myservice} to stopped state."
596 mark_service_stopped "${myservice}"
597 fi
598 end_service "${myservice}"
599 ;;
600 restart)
601 svcrestart="yes"
602
603 # We don't kill child processes if we're restarting
604 # This is especically important for sshd ....
605 RC_KILL_CHILDREN="no"
606
607 # Create a snapshot of started services
608 rm -rf "${svcdir}/snapshot/$$"
609 mkdir -p "${svcdir}/snapshot/$$"
610 cp -pP "${svcdir}"/started/* "${svcdir}/snapshot/$$/"
611
612 # Simple way to try and detect if the service use svc_{start,stop}
613 # to restart if it have a custom restart() funtion.
614 if [[ -n $(egrep '^[[:space:]]*restart[[:space:]]*()' "/etc/init.d/${myservice}") ]] ; then
615 if [[ -z $(egrep 'svc_stop' "/etc/init.d/${myservice}") || \
616 -z $(egrep 'svc_start' "/etc/init.d/${myservice}") ]] ; then
617 echo
618 ewarn "Please use 'svc_stop; svc_start' and not 'stop; start' to"
619 ewarn "restart the service in its custom 'restart()' function."
620 ewarn "Run ${myservice} without arguments for more info."
621 echo
622 svc_restart
623 else
624 restart
625 fi
626 else
627 restart
628 fi
629
630 # Restart dependencies as well
631 if service_started "${myservice}" ; then
632 for x in $(trace_dependencies \
633 $(dolisting "${svcdir}/snapshot/$$/") ) ; do
634 if service_stopped "${x##*/}" ; then
635 start_service "${x##*/}"
636 fi
637 done
638 elif service_inactive "${myservice}" ; then
639 res=
640 for x in $(dolisting "${svcdir}/snapshot/$$/") ; do
641 if service_stopped "${x##*/}" ; then
642 res="${res}${x##*/} "
643 fi
644 done
645 [[ -n ${res} ]] && echo "${res}" > "${svcdir}/restart/${myservice}"
646 fi
647
648 # Wait for any services that may still be running ...
649 [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && wait
650
651 rm -rf "${svcdir}/snapshot/$$"
652 svcrestart="no"
653 ;;
654 pause)
655 svcpause="yes"
656 svc_stop
657 svcpause="no"
658 ;;
659 --quiet|--nocolor)
660 ;;
661 help)
662 exec "${svclib}"/sh/rc-help.sh "${myscript}" help
663 ;;
664 *)
665 # Allow for homegrown functions
666 svc_homegrown ${arg}
667 ;;
668 esac
669 done
670
671 # vim:ts=4

Properties

Name Value
svn:eol-style native
svn:executable *
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.20