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