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