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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.20