Running arbitrary program as daemon from init script
I need to install a program as a service in Red Hat. It doesn't background itself, manage its PID file, or manage its own logs. It just runs and prints to STDOUT and STDERR.
Using the standard init scripts as guides, I've developed the following:
#!/bin/bash
#
# /etc/rc.d/init.d/someprog
#
# Starts the someprog daemon
#
# chkconfig: 345 80 20
# description: the someprog daemon
# processname: someprog
# config: /etc/someprog.conf
# Source function library.
. /etc/rc.d/init.d/functions
prog="someprog"
exec="/usr/local/bin/$prog"
[ -e "/etc/sysconfig/$prog" ] && . "/etc/sysconfig/$prog"
lockfile="/var/lock/subsys/$prog"
RETVAL=0
check() {
[ `id -u` = 0 ] || exit 4
test -x "$exec" || exit 5
}
start() {
check
if [ ! -f "$lockfile" ]; then
echo -n $"Starting $prog: "
daemon --user someproguser "$exec"
RETVAL=$?
[ $RETVAL -eq 0 ] && touch "$lockfile"
echo
fi
return $RETVAL
}
stop() {
check
echo -n $"Stopping $prog: "
killproc "exec"
RETVAL=$?
[ $RETVAL -eq 0 ] && rm -f "$lockfile"
echo
return $RETVAL
}
restart() {
stop
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
status)
status "$prog"
RETVAL=$?
;;
*)
echo $"Usage: $0 {start|stop|restart|status}"
RETVAL=2
esac
exit $RETVAL
It may be that my mistake was to copy-paste and modify some of the existing scripts in /etc/init.d. In any case, the resulting service behaves strangely:
- when I start it with
service someprog start
the program prints to the terminal and the command doesn't complete. - if I CTRL-C, it prints "Session terminated, killing shell... ...killed. FAILED". I have to do this to get my shell prompt back again.
- now when I run
service someprog status
it says it's running and lists its PID. I can see it inps
so it is running. - now when I run
service someprog stop
it fails to stop. I can verify that it's still running withps
.
What do I need to change so that someprog
is sent to the background and managed as a service?
Edit: I have now found a couple of related questions, neither of them with an actual answer other than "do something else":
- Call to daemon in a /etc/init.d script is blocking, not running in background
- Getting shell script to run as a daemon on CentOS?
Edit: this answer on double-forking might have solved my problem, but now my program itself double-forks and that works: https://stackoverflow.com/a/9646251/898699
Solution 1:
The command "doesn't complete" because the daemon
function does not run your application in the background for you. You will need to add an &
to the end of your daemon
command like so:
daemon --user someproguser $exec &
If someprog
doesn't handle SIGHUP
, you should run the command with nohup
to ensure that your process won't receive SIGHUP
which tells your process to exit when the parent shell exits. That would look like this:
daemon --user someproguser "nohup $exec" &
In your stop
function, killproc "exec"
isn't doing anything to stop your program. It should read like so:
killproc $exec
killproc
requires the full path to your application to stop it properly. I've had some trouble with killproc
in the past, so you can also just kill the PID in the PIDFILE you should be writing someprog
's PID to with something like this:
cat $pidfile | xargs kill
You can write the PIDFILE like this:
ps aux | grep $exec | grep -v grep | tr -s " " | cut -d " " -f2 > $pidfile
where $pidfile
points to /var/run/someprog.pid
.
If you want [OK] or [FAILED] on your stop
function, you should use the success
and failure
functions from /etc/rc.d/init.d/functions
. You don't need these in the start
function because daemon
calls the appropriate one for you.
You also only need quotes around strings with spaces. It's a style choice, though, so it's up to you.
All these changes look like this:
#!/bin/bash
#
# /etc/rc.d/init.d/someprog
#
# Starts the someprog daemon
#
# chkconfig: 345 80 20
# description: the someprog daemon
# processname: someprog
# config: /etc/someprog.conf
# Source function library.
. /etc/rc.d/init.d/functions
prog=someprog
exec=/usr/local/bin/$prog
[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog
lockfile=/var/lock/subsys/$prog
pidfile=/var/run/$prog
RETVAL=0
check() {
[ `id -u` = 0 ] || exit 4
test -x $exec || exit 5
}
start() {
check
if [ ! -f $lockfile ]; then
echo -n $"Starting $prog: "
daemon --user someproguser "nohup $exec" &
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
touch $lockfile
ps aux | grep $exec | grep -v grep | tr -s " " | cut -d " " -f2 > $pidfile
fi
echo
fi
return $RETVAL
}
stop() {
check
echo -n $"Stopping $prog: "
killproc $exec && cat $pidfile | kill
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
rm -f $lockfile
rm -f $pidfile
success; echo
else
failure; echo
fi
echo
return $RETVAL
}
restart() {
stop
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
status)
status $prog
RETVAL=$?
;;
*)
echo $"Usage: $0 {start|stop|restart|status}"
RETVAL=2
esac
exit $RETVAL