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

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

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.20