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

Contents of /trunk/sbin/runscript.sh

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1380 - (show annotations) (download) (as text)
Fri Aug 5 05:49:16 2005 UTC (9 years, 1 month ago) by uberlord
File MIME type: text/x-sh
File size: 14459 byte(s)
Rationalise if/then/else login in runscript.sh svc_start() and svc_stop()
1 #!/bin/bash
2 # Copyright 1999-2005 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 # Functions to handle dependencies and services
8 [[ ${RC_GOT_SERVICES} != "yes" ]] && source "${svclib}/sh/rc-services.sh"
9 # Functions to control daemons
10 [[ ${RC_GOT_DAEMON} != "yes" ]] && source "${svclib}/sh/rc-daemon.sh"
11
12 # User must be root to run most script stuff (except status)
13 if [[ ${EUID} != 0 ]] && ! [[ $2 == "status" && $# -eq 2 ]] ; then
14 eerror "$0: must be root to run init scripts"
15 exit 1
16 fi
17
18 # State variables
19 svcpause="no"
20 svcrestart="no"
21
22 myscript=$1
23 if [[ -L $1 ]] && [[ ! -L /etc/init.d/${1##*/} ]] ; then
24 myservice=$(readlink "$1")
25 else
26 myservice=$1
27 fi
28
29 myservice=${myservice##*/}
30 export SVCNAME=${myservice}
31 mylevel=$(<"${svcdir}/softlevel")
32
33 # Set $IFACE to the name of the network interface if it is a 'net.*' script
34 if [[ ${myservice%%.*} == "net" ]] && [[ ${myservice##*.} != ${myservice} ]] ; then
35 IFACE=${myservice##*.}
36 NETSERVICE="yes"
37 else
38 IFACE=
39 NETSERVICE=
40 fi
41
42 # Source configuration files.
43 # (1) Source /etc/conf.d/${myservice} to get initscript-specific
44 # configuration (if it exists).
45 # (2) Source /etc/conf.d/net if it is a net.* service
46 # (3) Source /etc/rc.conf to pick up potentially overriding
47 # configuration, if the system administrator chose to put it
48 # there (if it exists).
49
50 [[ -e $(add_suffix /etc/conf.d/${myservice}) ]] && source "$(add_suffix /etc/conf.d/${myservice})"
51 [[ -e $(add_suffix /etc/conf.d/net) ]] && \
52 [[ ${NETSERVICE} == "yes" ]] && source "$(add_suffix /etc/conf.d/net)"
53 [[ -e $(add_suffix /etc/rc.conf) ]] && source "$(add_suffix /etc/rc.conf)"
54
55
56 usage() {
57 local IFS="|"
58 myline="Usage: ${myservice} { $* "
59 echo
60 eerror "${myline}}"
61 eerror " ${myservice} without arguments for full help"
62 }
63
64 stop() {
65 # Return success so the symlink gets removed
66 return 0
67 }
68
69 start() {
70 eerror "ERROR: \"${myservice}\" does not have a start function."
71 # Return failure so the symlink doesn't get created
72 return 1
73 }
74
75 restart() {
76 svc_restart || return $?
77 }
78
79 status() {
80 # Dummy function
81 return 0
82 }
83
84 svc_stop() {
85 local x=
86 local mydep=
87 local mydeps=
88 local retval=0
89 local ordservice=
90 local was_inactive=false
91
92 if service_stopping "${myservice}" ; then
93 eerror "ERROR: \"${myservice}\" is already stopping."
94 return 0
95 elif service_stopped "${myservice}" ; then
96 eerror "ERROR: \"${myservice}\" has not yet been started."
97 return 0
98 fi
99
100 # Do not try to stop if it had already failed to do so on runlevel change
101 if is_runlevel_stop && service_failed "${myservice}" ; then
102 return 1
103 fi
104
105 service_inactive "${myservice}" && was_inactive=true
106
107 # Remove symlink to prevent recursion
108 mark_service_stopping "${myservice}"
109
110 service_message "Stopping service ${myservice}"
111
112 if in_runlevel "${myservice}" "${BOOTLEVEL}" && \
113 [[ ${SOFTLEVEL} != "reboot" && ${SOFTLEVEL} != "shutdown" && \
114 ${SOFTLEVEL} != "single" ]]
115 then
116 ewarn "WARNING: you are stopping a boot service."
117 fi
118
119 if [[ ${svcpause} != "yes" ]] ; then
120 if [[ ${NETSERVICE} == "yes" ]] ; then
121 # A net.* service
122 if in_runlevel "${myservice}" "${BOOTLEVEL}" || \
123 in_runlevel "${myservice}" "${mylevel}"
124 then
125 # Only worry about net.* services if this is the last one running,
126 # or if RC_NET_STRICT_CHECKING is set ...
127 if ! is_net_up ; then
128 mydeps="net"
129 fi
130 fi
131
132 mydeps="${mydeps} ${myservice}"
133 else
134 mydeps=${myservice}
135 fi
136 fi
137
138 # Save the IN_BACKGROUND var as we need to clear it for stopping depends
139 local ib_save="${IN_BACKGROUND}"
140 unset IN_BACKGROUND
141
142 for mydep in ${mydeps} ; do
143 # If some service 'need' $mydep, stop it first; or if it is a runlevel change,
144 # first stop all services that is started 'after' $mydep.
145 if needsme "${mydep}" >/dev/null || \
146 (is_runlevel_stop && ibefore "${mydep}" >/dev/null)
147 then
148 local servicelist=$(needsme "${mydep}")
149
150 # On runlevel change, stop all services "after $mydep" first ...
151 is_runlevel_stop && servicelist="${servicelist} $(ibefore "${mydep}")"
152
153 for x in ${servicelist} ; do
154 # Make sure we have a relevant rc-script ...
155 if [[ ${x} != "net" ]] && [[ ! -f /etc/init.d/${x} ]] ; then
156 continue
157 fi
158
159 # Service not currently running, continue
160 service_started "${x}" || continue
161
162 if ibefore -t "${mydep}" "${x}" >/dev/null && \
163 [[ -L ${svcdir}/softscripts.new/${x} ]]
164 then
165 # Service do not 'need' $mydep, and is still present in
166 # new runlevel ...
167 continue
168 fi
169
170 stop_service "${x}"
171
172 if ! service_stopped "${x}" ; then
173 # If we are halting the system, try and get it down as
174 # clean as possible, else do not stop our service if
175 # a dependent service did not stop.
176 if needsme -t "${mydep}" "${x}" >/dev/null && \
177 [[ ${SOFTLEVEL} != "reboot" && ${SOFTLEVEL} != "shutdown" ]]
178 then
179 retval=1
180 fi
181
182 break
183 fi
184 done
185 fi
186 done
187
188 IN_BACKGROUND="${ib_save}"
189
190 if [[ ${retval} -ne 0 ]] ; then
191 eerror "ERROR: problems stopping dependent services."
192 eerror " \"${myservice}\" is still up."
193 else
194 # Stop einfo/ebegin/eend from working as parallel messes us up
195 [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && RC_QUIET_STDOUT="yes"
196 # Now that deps are stopped, stop our service
197 ( stop )
198 retval=$?
199
200 # If a service has been marked inactive, exit now as something
201 # may attempt to start it again later
202 service_inactive "${myservice}" && return 0
203 fi
204
205 if [[ ${retval} -ne 0 ]] ; then
206 # Did we fail to stop? create symlink to stop multible attempts at
207 # runlevel change. Note this is only used at runlevel change ...
208 if is_runlevel_stop ; then
209 mark_service_failed "${myservice}"
210 fi
211
212 # If we are halting the system, do it as cleanly as possible
213 if [[ ${SOFTLEVEL} != "reboot" && ${SOFTLEVEL} != "shutdown" ]] ; then
214 if ${was_inactive} ; then
215 mark_service_inactive "${myservice}"
216 else
217 mark_service_started "${myservice}"
218 fi
219 fi
220
221 service_message "eerror" "FAILED to stop service ${myservice}!"
222 else
223 # If we're stopped from a daemon that sets ${IN_BACKGROUND} such as
224 # wpa_monitor when we mark as inactive instead of taking the down
225 if ${IN_BACKGROUND:-false} ; then
226 mark_service_inactive "${myservice}"
227 else
228 mark_service_stopped "${myservice}"
229 fi
230 service_message "Stopped service ${myservice}"
231 fi
232
233 return "${retval}"
234 }
235
236 svc_start() {
237 local retval=0
238 local startfail="no"
239 local x=
240 local y=
241 local myserv=
242 local ordservice=
243
244 if service_starting "${myservice}" ; then
245 ewarn "WARNING: \"${myservice}\" is already starting."
246 return 0
247 elif service_stopping "${myservice}" ; then
248 ewarn "WARNING: please wait for \"${myservice}\" to stop first."
249 return 0
250 elif service_inactive "${myservice}" ; then
251 if [[ ${IN_BACKGROUND} != "true" ]] ; then
252 ewarn "WARNING: \"${myservice}\" has already been started."
253 return 0
254 fi
255 elif service_started "${myservice}" ; then
256 ewarn "WARNING: \"${myservice}\" has already been started."
257 return 0
258 fi
259
260 # Do not try to start if i have done so already on runlevel change
261 if is_runlevel_start && service_failed "${myservice}" ; then
262 return 1
263 fi
264
265 mark_service_starting "${myservice}"
266 service_message "Starting service ${myservice}"
267
268 # On rc change, start all services "before $myservice" first
269 if is_runlevel_start ; then
270 startupservices="$(ineed "${myservice}") \
271 $(valid_iuse "${myservice}") \
272 $(valid_iafter "${myservice}")"
273 else
274 startupservices="$(ineed "${myservice}") \
275 $(valid_iuse "${myservice}")"
276 fi
277
278 # Start dependencies, if any
279 for x in ${startupservices} ; do
280 if [[ ${x} == "net" ]] && [[ ${NETSERVICE} != "yes" ]] && ! is_net_up ; then
281 local netservices="$(dolisting "/etc/runlevels/${BOOTLEVEL}/net.*") \
282 $(dolisting "/etc/runlevels/${mylevel}/net.*")"
283
284 for y in ${netservices} ; do
285 mynetservice=${y##*/}
286 if service_stopped "${mynetservice}" ; then
287 start_service "${mynetservice}"
288 fi
289 done
290 elif [[ ${x} != "net" ]] ; then
291 if service_stopped "${x}"; then
292 start_service "${x}"
293 fi
294 fi
295 done
296
297 # wait for dependencies to finish
298 for x in ${startupservices} ; do
299 if [ "${x}" = "net" -a "${NETSERVICE}" != "yes" ] ; then
300 local netservices="$(dolisting "/etc/runlevels/${BOOTLEVEL}/net.*") \
301 $(dolisting "/etc/runlevels/${mylevel}/net.*")"
302
303 for y in ${netservices} ; do
304 mynetservice="${y##*/}"
305
306 wait_service "${mynetservice}"
307
308 if ! service_started "${mynetservice}" ; then
309 # A 'need' dependency is critical for startup
310 if ineed -t "${myservice}" "${x}" >/dev/null ; then
311 # Only worry about a net.* service if we do not have one
312 # up and running already, or if RC_NET_STRICT_CHECKING
313 # is set ....
314 if ! is_net_up ; then
315 startfail="yes"
316 fi
317 fi
318 fi
319 done
320 elif [ "${x}" != "net" ] ; then
321 wait_service "${x}"
322 if ! service_started "${x}" ; then
323 # A 'need' dependacy is critical for startup
324 if ineed -t "${myservice}" "${x}" >/dev/null ; then
325 startfail="yes"
326 fi
327 fi
328 fi
329 done
330
331 if [[ ${startfail} == "yes" ]] ; then
332 eerror "ERROR: Problem starting needed services."
333 eerror " \"${myservice}\" was not started."
334 retval=1
335 elif broken "${myservice}" ; then
336 eerror "ERROR: Some services needed are missing. Run"
337 eerror " './${myservice} broken' for a list of those"
338 eerror " services. \"${myservice}\" was not started."
339 retval=1
340 else
341 (
342 exit() {
343 RC_QUIET_STDOUT="no"
344 eerror "DO NOT USE EXIT IN INIT.D SCRIPTS"
345 eerror "This IS a bug, please fix your broken init.d"
346 unset -f exit
347 exit $@
348 }
349 # Stop einfo/ebegin/eend from working as parallel messes us up
350 [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && RC_QUIET_STDOUT="yes"
351 start
352 )
353 retval=$?
354
355 # If a service has been marked inactive, exit now as something
356 # may attempt to start it again later
357 service_inactive "${myservice}" && return 1
358 fi
359
360 if [[ ${retval} != 0 ]]; then
361 is_runlevel_start && mark_service_failed "${myservice}"
362
363 # Remove link if service didn't start; but only if we're not booting
364 # If we're booting, we need to continue and do our best to get the
365 # system up.
366 if [[ ${SOFTLEVEL} != "${BOOTLEVEL}" ]]; then
367 mark_service_stopped "${myservice}"
368 fi
369
370 service_message "eerror" "FAILED to start service ${myservice}!"
371 else
372 mark_service_started "${myservice}"
373
374 service_message "Service ${myservice} started OK"
375 fi
376
377 return "${retval}"
378 }
379
380 svc_restart() {
381 if service_started "${myservice}" || service_inactive "${myservice}" ; then
382 svc_stop || return "$?"
383 fi
384 svc_start || return "$?"
385 }
386
387 svc_status() {
388 # The basic idea here is to have some sort of consistent
389 # output in the status() function which scripts can use
390 # as an generic means to detect status. Any other output
391 # should thus be formatted in the custom status() function
392 # to work with the printed " * status: foo".
393 local efunc="" state=""
394
395 if service_starting "${myservice}" ; then
396 efunc="einfo"
397 state="starting"
398 elif service_inactive "${myservice}" ; then
399 efunc="ewarn"
400 state="inactive"
401 elif service_started "${myservice}" ; then
402 efunc="einfo"
403 state="started"
404 elif service_stopping "${myservice}" ; then
405 efunc="eerror"
406 state="stopping"
407 else
408 efunc="eerror"
409 state="stopped"
410 fi
411 [[ ${RC_QUIET_STDOUT} != "yes" ]] \
412 && ${efunc} "status: ${state}"
413
414 status
415 [[ ${efunc} != "eerror" ]]
416 }
417
418 rcscript_errors=$(bash -n "${myscript}" 2>&1) || {
419 [[ -n ${rcscript_errors} ]] && echo "${rcscript_errors}" >&2
420 eerror "ERROR: \"${myscript}\" has syntax errors in it; aborting ..."
421 exit 1
422 }
423
424 # set *after* wrap_rcscript, else we get duplicates.
425 opts="start stop restart"
426
427 source "${myscript}"
428
429 # make sure whe have valid $opts
430 if [[ -z ${opts} ]] ; then
431 opts="start stop restart"
432 fi
433
434 svc_homegrown() {
435 local arg=$1
436 local x=
437
438 # Walk through the list of available options, looking for the
439 # requested one.
440 for x in ${opts} ; do
441 if [[ ${x} == ${arg} ]] ; then
442 if typeset -F "${x}" &>/dev/null ; then
443 # Run the homegrown function
444 "${x}"
445
446 return $?
447 fi
448 fi
449 done
450
451 # If we're here, then the function wasn't in $opts.
452 eerror "ERROR: wrong args. ( "${arg}" / $* )"
453 # Do not quote this either ...
454 usage ${opts}
455 exit 1
456 }
457
458 shift
459 if [[ $# -lt 1 ]] ; then
460 eerror "ERROR: not enough args."
461 usage ${opts}
462 exit 1
463 fi
464 for arg in $* ; do
465 case "${arg}" in
466 --quiet)
467 RC_QUIET_STDOUT="yes"
468 ;;
469 # We check this in functions.sh ...
470 # --nocolor)
471 # RC_NOCOLOR="yes"
472 # ;;
473 --verbose)
474 RC_VERBOSE="yes"
475 ;;
476 esac
477 done
478 for arg in $* ; do
479 case "${arg}" in
480 stop)
481 svc_stop
482 ;;
483 start)
484 svc_start
485 ;;
486 needsme|ineed|usesme|iuse|broken)
487 trace_dependencies "-${arg}"
488 ;;
489 status)
490 svc_status
491 ;;
492 zap)
493 if ! service_stopped "${myservice}" ; then
494 einfo "Manually resetting ${myservice} to stopped state."
495 mark_service_stopped "${myservice}"
496 fi
497 ;;
498 restart)
499 svcrestart="yes"
500
501 # Create a snapshot of started services
502 rm -rf "${svcdir}/snapshot/$$"
503 mkdir -p "${svcdir}/snapshot/$$"
504 cp -a "${svcdir}"/started/* "${svcdir}/snapshot/$$/"
505
506 # Simple way to try and detect if the service use svc_{start,stop}
507 # to restart if it have a custom restart() funtion.
508 if [[ -n $(egrep '^[[:space:]]*restart[[:space:]]*()' "/etc/init.d/${myservice}") ]] ; then
509 if [[ -z $(egrep 'svc_stop' "/etc/init.d/${myservice}") ]] || \
510 [[ -z $(egrep 'svc_start' "/etc/init.d/${myservice}") ]]
511 then
512 echo
513 ewarn "Please use 'svc_stop; svc_start' and not 'stop; start' to"
514 ewarn "restart the service in its custom 'restart()' function."
515 ewarn "Run ${myservice} without arguments for more info."
516 echo
517 svc_restart
518 else
519 restart
520 fi
521 else
522 restart
523 fi
524
525 # Restart dependencies as well
526 if service_started "${myservice}" ; then
527 for x in $(trace_dependencies \
528 $(dolisting "${svcdir}/snapshot/$$/") ) ; do
529 if service_stopped "${x##*/}" ; then
530 start_service "${x##*/}"
531 fi
532 done
533 fi
534
535 # Wait for any services that may still be running ...
536 [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && wait
537
538 rm -rf "${svcdir}/snapshot/$$"
539 svcrestart="no"
540 ;;
541 pause)
542 svcpause="yes"
543 svc_stop
544 svcpause="no"
545 ;;
546 --quiet|--nocolor)
547 ;;
548 *)
549 # Allow for homegrown functions
550 svc_homegrown ${arg}
551 ;;
552 esac
553 done
554
555
556 # 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