/[baselayout]/trunk/sbin/rc-daemon.sh
Gentoo

Contents of /trunk/sbin/rc-daemon.sh

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1583 - (show annotations) (download) (as text)
Thu Oct 20 11:59:02 2005 UTC (12 years, 9 months ago) by uberlord
File MIME type: text/x-sh
File size: 10825 byte(s)
Fixed stopping when no process to stop
1 # Copyright 1999-2005 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3
4 # RC functions to work with daemons
5 # Basically we're a fancy wrapper for start-stop-daemon
6 # and should be called as such. This means that our init scripts
7 # should work as is with zero modification :)
8
9 # Actually, the above is a small as lie we have some init scripts which try to
10 # get start-stop-daemon to launch a shell script. While this does work with
11 # the start-stop-daemon program in /sbin, it does cause a problem for us
12 # when we're testing for the daemon to be running. I (Roy Marples) view this
13 # as behaviour by design as start-stop-daemon should not be used to run shell
14 # scripts!
15 # At the time of writing, the only culprit I know of is courier-imap.
16 # There may be others!
17
18 RC_GOT_DAEMON="yes"
19
20 [[ ${RC_GOT_FUNCTIONS} != "yes" ]] && source /sbin/functions.sh
21 [[ ${RC_GOT_SERVICES} != "yes" ]] && source "${svclib}/sh/rc-services.sh"
22
23 RC_RETRY_KILL="no"
24 RC_RETRY_TIMEOUT=1
25 RC_RETRY_COUNT=5
26 RC_FAIL_ON_ZOMBIE="no"
27 RC_KILL_CHILDREN="no"
28 RC_WAIT_ON_START="0.1"
29
30 # Override default settings with user settings ...
31 [[ -f /etc/conf.d/rc ]] && source /etc/conf.d/rc
32
33 # void rc_shift_args(void)
34 #
35 # Proccess vars - makes things easier by using the shift command
36 # and indirect variables
37 rc_shift_args() {
38 while [[ $# != "0" ]]; do
39 if [[ $1 != "-"* && -n ${addvar} ]]; then
40 if [[ -z ${!addvar} ]]; then
41 eval "${addvar}=\"$1\""
42 else
43 eval "${addvar}=\"${!addvar} $1\""
44 fi
45 shift
46 continue
47 fi
48 unset addvar
49 case "$1" in
50 -S|--start)
51 stopping=false
52 ;;
53 -K|--stop)
54 stopping=true
55 ;;
56 -n|--name)
57 addvar="name"
58 ;;
59 -x|--exec|-a|--startas)
60 addvar="cmd"
61 ;;
62 -p|--pidfile)
63 addvar="pidfile"
64 ;;
65 --pidfile=*)
66 pidfile="${1##--pidfile=}"
67 ;;
68 --pid=*)
69 pidfile="${1##--pid=}"
70 ;;
71 -R|--retry)
72 unset RC_RETRY_COUNT
73 addvar="RC_RETRY_COUNT"
74 ;;
75 -s|--signal)
76 addvar="signal"
77 ;;
78 -t|--test|-o|--oknodo)
79 nothing=true
80 ;;
81 esac
82 shift
83 done
84
85 [[ -z ${RC_RETRY_COUNT} ]] && RC_RETRY_COUNT=5
86 }
87
88 # void rc_setup_daemon_vars(void)
89 #
90 # Setup our vars based on the start-stop-daemon command
91 rc_setup_daemon_vars() {
92 local name i
93 local -a sargs=( "${args%% \'--\' *}" )
94 local -a eargs
95 local x="${args// \'--\' /}"
96 [[ ${x} != "${args}" ]] && eargs=( "${args##* \'--\' }" )
97
98 rc_shift_args ${sargs[@]}
99
100 [[ -z ${cmd} ]] && cmd="${name}"
101
102 # We may want to launch the daemon with a custom command
103 # This is mainly useful for debugging with apps like valgrind, strace
104 local bash_service=$( bash_variable "${myservice}" )
105 eval x=\"\$\{RC_DAEMON_${bash_service}\}\"
106 if [[ -n ${x} ]]; then
107 local -a d=( ${x} )
108 if ${stopping}; then
109 args="--stop"
110 else
111 args="--start"
112 fi
113
114 # Add -- or - arguments as s-s-d options
115 j=${#d[@]}
116 for (( i=0; i<j; i++ )); do
117 [[ ${d[i]:0:1} != "-" ]] && break
118 args="${args} ${d[i]}"
119 unset d[i]
120 done
121 d=$( "${d[@]}" )
122
123 eval args=\"${args} --exec '${d[0]}' -- ${d[@]:1} '${cmd}' ${eargs[@]}\"
124 ! ${stopping} && cmd="${d[0]}"
125 fi
126
127 return 0
128 }
129
130 # bool rc_try_kill_pid(int pid, char* signal, bool session)
131 #
132 # Repeatedly kill the pid with the given signal until it dies
133 # If session is true then we use tread pid as session and send it
134 # via pkill
135 # Returns 0 if successfuly otherwise 1
136 rc_try_kill_pid() {
137 local pid="$1" signal="${2:-TERM}" session="${3:-false}" i s p e
138
139 # We split RC_RETRY_TIMEOUT into tenths of seconds
140 # So we return as fast as possible
141 s=$(( ${RC_RETRY_TIMEOUT}/10 )).$(( ${RC_RETRY_TIMEOUT}%10 ))
142
143 for (( i=0; i<RC_RETRY_COUNT*10; i++ )); do
144 if ${session} ; then
145 if [[ -x /usr/bin/pkill ]]; then
146 pkill "-${signal}" -s "${pid}"
147 pgrep -s "${pid}" >/dev/null || return 0
148 else
149 local pids=$(ps -eo pid,sid | sed -n 's/'${pid}'$//p')
150 [[ -z ${pids} ]] && return 0
151 kill -s "${signal}" ${pids} 2>/dev/null
152 e=false
153 for p in ${pids}; do
154 if [[ -d "/proc/${p}" ]]; then
155 e=true
156 break
157 fi
158 done
159 ${e} || return 0
160 fi
161 else
162 kill -s "${signal}" "${pid}" 2>/dev/null
163 [[ ! -d "/proc/${pid}" ]] && return 0
164 fi
165 LC_ALL=C /bin/sleep "${s}"
166 done
167
168 return 1
169 }
170
171 # bool rc_kill_pid(int pid, bool session)
172 #
173 # Kills the given pid/session
174 # Returns 1 if we fail to kill the pid (if it's valid) otherwise 0
175 rc_kill_pid() {
176 local pid="$1" session="${2:-false}"
177
178 rc_try_kill_pid "${pid}" "${signal}" "${session}" && return 0
179
180 [[ ${RC_RETRY_KILL} == "yes" ]] \
181 && rc_try_kill_pid "${pid}" KILL "${session}" && return 0
182
183 return 1
184 }
185
186 # char* pidof(char* cmd, ...)
187 #
188 # Returns a space seperated list of pids associated with the command
189 # This is to handle the rpc.nfsd program which acts weird
190 pidof() {
191 local arg args
192
193 for arg in "$@"; do
194 [[ ${arg##*/} == "rpc.nfsd" ]] && arg="${arg%/*}/nfsd"
195 args="${args} '"${arg}"'"
196 done
197
198 eval /bin/pidof -x ${args}
199 }
200
201 # bool is_daemon_running(char* cmd, char* pidfile)
202 #
203 # Returns 0 if the given daemon is running, otherwise 1
204 # If a pidfile is supplied, the pid inside it must match
205 # a pid in the list of pidof ${cmd}
206 is_daemon_running() {
207 local cmd pidfile pids pid
208
209 if [[ $# == "1" ]]; then
210 cmd="$1"
211 else
212 local i j="$#"
213 for (( i=0; i<j-1; i++ )); do
214 cmd="${cmd} $1"
215 shift
216 done
217 pidfile="$1"
218 fi
219
220 pids=$( pidof ${cmd} )
221 [[ -z ${pids} ]] && return 1
222
223 [[ -s ${pidfile} ]] || return 0
224
225 read pid < "${pidfile}"
226 pids=" ${pids} "
227 [[ ${pids// ${pid} } != "${pids}" ]]
228 }
229
230 # int rc_start_daemon(void)
231 #
232 # We don't do anyting fancy - just pass the given options
233 # to start-stop-daemon and return the value
234 rc_start_daemon() {
235 eval /sbin/start-stop-daemon "${args}"
236 local retval="$?"
237
238 [[ ${retval} != "0" ]] && return "${retval}"
239 [[ ${RC_WAIT_ON_START} == "0" ]] && return "${retval}"
240
241 # We pause for RC_WAIT_ON_START seconds and then
242 # check if the daemon is still running - this is mainly
243 # to handle daemons who launch and then fail due to invalid
244 # configuration files
245 LC_ALL=C /bin/sleep "${RC_WAIT_ON_START}"
246 is_daemon_running ${cmd} "${pidfile}"
247 retval="$?"
248 [[ ${retval} == "0" ]] && return 0
249
250 # Stop if we can to clean things up
251 if [[ $( type -t stop ) == "function" ]]; then
252 stop >/dev/null # We don't want to echo ebegin/eend
253 elif [[ -n ${pidfile} ]]; then
254 rc_stop_daemon
255 fi
256 return "${retval}"
257 }
258
259 # bool rc_stop_daemon(void)
260 #
261 # Instead of calling start-stop-daemon we instead try and
262 # kill the process ourselves and any children left over
263 # Returns 0 if everything was successful otherwise 1
264 rc_stop_daemon() {
265 local pid pids retval="0"
266
267 if [[ -n ${cmd} ]]; then
268 if ! is_daemon_running ${cmd} "${pidfile}" ; then
269 [[ ${RC_FAIL_ON_ZOMBIE} == "yes" ]] && return 1
270 fi
271 pids=$( pidof ${cmd} )
272 fi
273
274 if [[ -s ${pidfile} ]]; then
275 read pid < "${pidfile}"
276 # Check that the given program is actually running the pid
277 if [[ -n ${pids} ]]; then
278 pids=" ${pids} "
279 [[ ${pids// ${pid} } == ${pids} ]] && return 1
280 fi
281 pids=${pid}
282 fi
283
284 # If there's nothing to kill then return without error
285 [[ -z ${pids} ]] && return 0
286
287 # We may not have pgrep to find our children, so we provide
288 # two methods
289 if [[ ${RC_KILL_CHILDREN} == "yes" ]]; then
290 if [[ -x /usr/bin/pgrep ]]; then
291 pids="${pids} $(pgrep -P ${pids// /,})"
292 else
293 local npids
294 for pid in ${pids} ; do
295 npids="${npids} $(ps -eo pid,ppid | sed -n 's/'${pid}'$//p')"
296 done
297 pids="${pids} ${npids}"
298 fi
299 fi
300
301 for pid in ${pids}; do
302 if [[ ${RC_FAIL_ON_ZOMBIE} == "yes" ]]; then
303 ps -p "${pid}" &>/dev/null || return 1
304 fi
305
306 if rc_kill_pid "${pid}" false ; then
307 # Remove the pidfile if the process didn't
308 [[ -f ${pidfile} ]] && rm -f "${pidfile}"
309 else
310 retval=1
311 fi
312
313 if [[ ${RC_KILL_CHILDREN} == "yes" ]]; then
314 rc_kill_pid "${pid}" true || retval=1
315 fi
316 done
317
318 return "${retval}"
319 }
320
321 # void update_service_status(char *service)
322 #
323 # Loads the service state file and ensures that all listed daemons are still
324 # running - hopefully on their correct pids too
325 # If not, we stop the service
326 update_service_status() {
327 local service="$1" daemonfile="${svcdir}/daemons/$1" i
328 local -a RC_DAEMONS=() RC_PIDFILES=()
329
330 # We only care about marking started services as stopped if the daemon(s)
331 # for it are no longer running
332 ! service_started "${service}" && return
333 [[ ! -f ${daemonfile} ]] && return
334
335 # OK, now check that every daemon launched is active
336 # If the --start command was any good a pidfile was specified too
337 source "${daemonfile}"
338 for (( i=0; i<${#RC_DAEMONS[@]}; i++ )); do
339 if ! is_daemon_running ${RC_DAEMONS[i]} "${RC_PIDFILES[i]}" ; then
340 if [[ -e "/etc/init.d/${service}" ]]; then
341 ( /etc/init.d/"${service}" stop &>/dev/null )
342 break
343 fi
344 fi
345 done
346 }
347
348 # int start-stop-daemon(...)
349 #
350 # Provide a wrapper to start-stop-daemon
351 # Return the result of start_daemon or stop_daemon depending on
352 # how we are called
353 start-stop-daemon() {
354 local args=$( requote "$@" ) result i
355 local cmd pidfile pid stopping signal nothing=false
356 local daemonfile="${svcdir}/daemons/${myservice}"
357 local -a RC_DAEMONS=() RC_PIDFILES=()
358
359 [[ -e ${daemonfile} ]] && source "${daemonfile}"
360
361 rc_setup_daemon_vars
362
363 # We pass --oknodo and --test directly to start-stop-daemon and return
364 if ${nothing}; then
365 eval /sbin/start-stop-daemon "${args}"
366 return "$?"
367 fi
368
369 if ${stopping}; then
370 rc_stop_daemon
371 result="$?"
372 if [[ ${result} == "0" ]]; then
373 # We stopped the daemon successfully
374 # so we remove it from our state
375 for (( i=0; i<${#RC_DAEMONS[@]}; i++ )); do
376 # We should really check for valid cmd AND pidfile
377 # But most called to --stop only set the pidfile
378 if [[ ${RC_DAEMONS[i]} == "{cmd}" \
379 || ${RC_PIDFILES[i]}="${pidfile}" ]]; then
380 unset RC_DAEMONS[i] RC_PIDFILES[i]
381 RC_DAEMONS=( "${RC_DAEMONS[@]}" )
382 RC_PIDFILES=( "${RC_PIDFILES[@]}" )
383 break
384 fi
385 done
386 fi
387 else
388 rc_start_daemon
389 result="$?"
390 if [[ ${result} == "0" ]]; then
391 # We started the daemon sucessfully
392 # so we add it to our state
393 local max="${#RC_DAEMONS[@]}"
394 for (( i=0; i<${max}; i++ )); do
395 if [[ ${RC_DAEMONS[i]} == "{cmd}" \
396 && ${RC_PIDFILES[i]}="${pidfile}" ]]; then
397 break
398 fi
399 done
400
401 if [[ ${i} == "${max}" ]]; then
402 RC_DAEMONS[max]="${cmd}"
403 RC_PIDFILES[max]="${pidfile}"
404 fi
405 fi
406 fi
407
408 # Write the new list of daemon states for this service
409 if [[ ${#RC_DAEMONS[@]} == "0" ]]; then
410 [[ -f ${daemonfile} ]] && rm -f "${daemonfile}"
411 else
412 echo "RC_DAEMONS[0]=\"${RC_DAEMONS[0]}\"" > "${daemonfile}"
413 echo "RC_PIDFILES[0]=\"${RC_PIDFILES[0]}\"" >> "${daemonfile}"
414
415 for (( i=1; i<${#RC_DAEMONS[@]}; i++ )); do
416 echo "RC_DAEMONS[${i}]=\"${RC_DAEMONS[i]}\"" >> "${daemonfile}"
417 echo "RC_PIDFILES[${i}]=\"${RC_PIDFILES[i]}\"" >> "${daemonfile}"
418 done
419 fi
420
421 return "${result}"
422 }
423
424 # vim:ts=4

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.20