/[baselayout]/branches/baselayout-1_12/sbin/runscript.sh
Gentoo

Contents of /branches/baselayout-1_12/sbin/runscript.sh

Parent Directory Parent Directory | Revision Log Revision Log


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