When dealing with programs that weren't designed as daemons (those that don't background themselves, manage PID files, or handle their own logging), we face several technical hurdles in init scripts:
- Process doesn't detach from the controlling terminal
- Output continues to stream to STDOUT/STDERR
- Lack of proper PID management makes service control unreliable
The key problems in the provided init script:
# Main issues in the original approach:
1. Using daemon function with a non-detaching process
2. killproc tries to kill "exec" literally instead of $prog
3. No output redirection handling
Here's a properly modified version that handles the daemonization properly:
#!/bin/bash
#
# /etc/rc.d/init.d/someprog
#
# chkconfig: 345 80 20
# description: someprog service wrapper
. /etc/rc.d/init.d/functions
prog="someprog"
exec="/usr/local/bin/$prog"
user="someproguser"
logfile="/var/log/${prog}.log"
pidfile="/var/run/${prog}.pid"
start() {
echo -n $"Starting $prog: "
# Key modifications:
daemon --user $user --pidfile $pidfile \
"{ $exec &>> $logfile & }; echo \$! > $pidfile"
RETVAL=$?
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/$prog
echo
return $RETVAL
}
stop() {
echo -n $"Stopping $prog: "
killproc -p "$pidfile" "$exec"
RETVAL=$?
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$prog
echo
return $RETVAL
}
The solution works because:
- We force backgrounding with &
- Redirect all output to a log file with &>>
- Properly capture and store the PID
- Use the correct process name with killproc
For programs that resist even the above method:
start() {
echo -n $"Starting $prog: "
nohup $exec &>> $logfile &
echo $! > $pidfile
RETVAL=$?
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/$prog
echo
}
For enterprise environments, consider adding:
- Log rotation configuration
- Resource limits (ulimit)
- Startup dependency management
- Pre-start validation checks
When dealing with programs that don't background themselves, the main issue lies in their interaction with the controlling terminal. The standard daemon
function from /etc/rc.d/init.d/functions
might not properly handle processes that:
- Maintain STDOUT/STDERR connections
- Don't create their own PID files
- Don't detach from the terminal session
The behavior you're seeing occurs because:
daemon --user someproguser "$exec"
This command doesn't fully daemonize the process when:
- The program maintains terminal connections
- No proper PID file management exists
- The process isn't properly disowned from the shell
Here's a modified version that properly handles foreground processes:
start() {
check
if [ ! -f "$lockfile" ]; then
echo -n $"Starting $prog: "
# Use nohup with output redirection
nohup daemon --user someproguser "$exec" > /var/log/someprog.log 2>&1 &
# Store the PID properly
echo $! > /var/run/someprog.pid
RETVAL=$?
[ $RETVAL -eq 0 ] && touch "$lockfile"
echo
fi
return $RETVAL
}
stop() {
check
echo -n $"Stopping $prog: "
# Read PID from our custom file
[ -f /var/run/someprog.pid ] && kill -9 $(cat /var/run/someprog.pid)
RETVAL=$?
[ $RETVAL -eq 0 ] && rm -f "$lockfile" /var/run/someprog.pid
echo
return $RETVAL
}
For a production-ready solution:
#!/bin/bash
#
# /etc/rc.d/init.d/someprog
#
# chkconfig: 345 80 20
# description: Custom daemon management for foreground processes
. /etc/rc.d/init.d/functions
prog="someprog"
exec="/usr/local/bin/$prog"
pidfile="/var/run/$prog.pid"
logfile="/var/log/$prog.log"
lockfile="/var/lock/subsys/$prog"
[ -e "/etc/sysconfig/$prog" ] && . "/etc/sysconfig/$prog"
start() {
[ -x $exec ] || exit 5
echo -n $"Starting $prog: "
# Full daemonization with output redirection
nohup $exec >> $logfile 2>&1 &
retval=$?
pid=$!
[ $retval -eq 0 ] && {
echo $pid > $pidfile
touch $lockfile
}
echo
return $retval
}
stop() {
echo -n $"Stopping $prog: "
[ -f $pidfile ] && killproc -p $pidfile $exec
retval=$?
[ $retval -eq 0 ] && {
rm -f $lockfile
rm -f $pidfile
}
echo
return $retval
}
case "$1" in
start) start ;;
stop) stop ;;
restart)
stop
start
;;
status)
status -p $pidfile $prog
;;
*)
echo $"Usage: $0 {start|stop|restart|status}"
exit 2
esac
exit $?
For more complex scenarios, consider:
- Using
start-stop-daemon
if available - Implementing proper log rotation
- Adding resource limit controls
- Setting process priority with
nice
After implementing changes:
chkconfig --add someprog
service someprog start
- Verify with
ps aux | grep someprog
- Check log output in
/var/log/someprog.log