Sometimes you have an executable which does not fork to the background, but you need to control it with init scripts, so that it does indeed run in the background. Here’s a pretty generic init script for that. It allows you to configure these:
1 2 3 4 5 6 7 |
DAEMON_NAME="My Little Daemon" DAEMON_EXECUTABLE="/opt/my_daemon/my_daemon" DAEMON_OPTIONS="" DAEMON_HOMEDIR="/opt/my_daemon" DAEMON_PIDFILE="/var/run/my_daemon.pid" DAEMON_LOGFILE="/var/log/my_daemon.log" INIT_SLEEPTIME="2" |
The script changes directory to the DAEMON_HOMEDIR, runs DAEMON_EXECUTABLE with DAEMON_OPTIONS and saves the new process id to the DAEMON_PIDFILE file. Remember to use different pidfile for every daemon.
The script also checks whether the process is up and running after INIT_SLEEPTIME seconds. If not, it will fail. It will do the check after stopping as well.
All stdout/stderr output is sent to DAEMON_LOGFILE. If you don’t want to log the output, set it to “/dev/null”.
You can control init scripts with this part in the beginning of the file:
1 2 3 4 5 6 7 8 |
### BEGIN INIT INFO # Provides: my_daemon # Required-Start: $network # Required-Stop: $network # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Runs the non-forking program in the background ### END INIT INFO |
Ubuntu/Debian update-rc.d will use those defaults to install it. So after you drop the script under /etc/init.d with the name my_daemon, you can install it using this:
1 |
sudo update-rc.d my_daemon defaults |
To disable temporarily:
1 |
sudo update-rc.d my_daemon disable |
To re-enable:
1 |
sudo update-rc.d my_daemon enable |
To remove:
1 |
sudo update-rc.d -f my_daemon remove |
This script does not change running user id from root to something else, so be careful with it.
To start up the daemon, run:
1 |
sudo service my_daemon start |
To stop:
1 |
sudo service my_daemon stop |
Restart:
1 |
sudo service my_daemon restart |
See status:
1 |
sudo service my_daemon status |
The Script
Enough explanation. Here’s the script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
#!/bin/sh ### BEGIN INIT INFO # Provides: my_daemon # Required-Start: $network # Required-Stop: $network # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Runs the non-forking program in the background ### END INIT INFO # Defaults DAEMON_NAME="My Little Daemon" DAEMON_EXECUTABLE="/opt/my_daemon/my_daemon" DAEMON_OPTIONS="" DAEMON_HOMEDIR="/opt/my_daemon" DAEMON_PIDFILE="/var/run/my_daemon.pid" DAEMON_LOGFILE="/var/log/my_daemon.log" INIT_SLEEPTIME="2" # Defaults can be overridden in this file DAEMON_DEFAULTS_FILE="/etc/default/my_daemon" PATH=/sbin:/bin:/usr/sbin:/usr/bin # Load alternate configuration if exists test -f $DAEMON_DEFAULTS_FILE && . $DAEMON_DEFAULTS_FILE . /lib/lsb/init-functions # Usually no need to edit below this point. Just have these ready: # # * DAEMON_EXECUTABLE - full path to the executable # * DAEMON_OPTIONS - options to pass to the executable # * DAEMON_NAME - a decriptive name # * DAEMON_HOMEDIR - place where to cd before running # * DAEMON_PIDFILE - pid file name # * DAEMON_LOGFILE - log file name # * INIT_SLEEPTIME - how long to wait for startup and shutdown # # The rest will be taken care of. Executable is run with "nohup", so no # need to fork. is_running () { # Test whether pid file exists or not test -f $DAEMON_PIDFILE || return 1 # Test whether process is running or not read PID < "$DAEMON_PIDFILE" ps -p $PID >/dev/null 2>&1 || return 1 # Is running return 0 } root_only () { if [ "$(id -u)" != "0" ]; then echo "Only root should run this operation" exit 1 fi } run () { if is_running; then PID="$(cat $DAEMON_PIDFILE)" echo "Daemon is already running as PID $PID" return 1 fi cd $DAEMON_HOMEDIR nohup $DAEMON_EXECUTABLE $DAEMON_OPTIONS >>$DAEMON_LOGFILE 2>&1 & echo $! > $DAEMON_PIDFILE read PID < "$DAEMON_PIDFILE" sleep $INIT_SLEEPTIME if ! is_running; then echo "Daemon died immediately after starting. Please check your logs and configurations." return 1 fi echo "Daemon is running as PID $PID" return 0 } stop () { if is_running; then read PID < "$DAEMON_PIDFILE" kill $PID fi sleep $INIT_SLEEPTIME if is_running; then while is_running; do echo "waiting for daemon to die (PID $PID)" sleep $INIT_SLEEPTIME done fi rm -f "$DAEMON_PIDFILE" return 0 } case "$1" in start) root_only log_daemon_msg "Starting $DAEMON_NAME" run log_end_msg $? ;; stop) root_only log_daemon_msg "Stopping $DAEMON_NAME" stop log_end_msg $? ;; restart) root_only $0 stop && $0 start ;; status) status_of_proc \ -p "$DAEMON_PIDFILE" \ "$DAEMON_EXECUTABLE" \ "$DAEMON_NAME" \ && exit 0 \ || exit $? ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 ;; esac |