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

Contents of /trunk/sbin/runscript.sh

Parent Directory Parent Directory | Revision Log Revision Log


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