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

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