Write your own init script

Most developers who've written web software know that when they install something like httpd they can typically call service httpd restart and they'll restart their server. Similarly, they could call /etc/init.d/httpd start to start, or change start to stop and they'll shut off the server. All of this is typically web-dev 101.

But what happens when you write your own server? And how does that service call work?

On a linux machine there's a concept of runlevels. These indicate the state of your machine. And when you transition into one of these states there are scripts that can be ran automatically. To manage these you can use chkconfig. If you call chkconfig --list you'll see a list of various services and which run levels they're active on. I won't attempt to go fully in depth on run levels, but you should read about them here and then come back to this post once you're finished.

Back? Alright, now that we know all about run levels, and we've discovered that we only need to write one script that will be symlinked like crazy from all those rcN.d directories. So what goes into this script?

Well, the template is pretty simple to follow. It goes like this:

#!/bin/sh
#
# /etc/init.d/myservice
# init script for "MyService" server
#
# chkconfig: 036 95 05
# description: MyServer server daemon
#
# processname: MyServer
# pidfile: /var/run/MyServer.pid

RETVAL=0
prog="MyServer"

start() {
	echo -n $"Starting $prog:"
	nohup MyServer &
	echo $! > /var/run/MyServer.pid
	echo
}

stop() {	(6)
	echo -n $"Stopping $prog:"
	if [ -f /var/www/run/MyServer.pid ]; then 
		kill `cat /var/www/run/MyServer.pid`
		rm /var/www/run/MyServer.pid
	fi
	echo
}

case "$1" in
	start)
		start
		;;
	stop)
		stop
		;;
	restart)
		stop
		start
		;;
	*)	(10)
		echo $"Usage: $0 {start|stop|restart}"
		RETVAL=1
esac
exit $RETVAL

The first part of this script consists of a large block of comments. These are known as tags for the init system to read. The chkconfig: and description: tags are the only required ones and have an important role to play. The description tag tells you what this script is all about (documentation is important you know?). The chkconfig is special, those three numbers set the run levels this script is called from, the priority in which the script is ran when started, and the priority when the script is called with stop. These last two numbers should add up to 100.

For a description of each of the tags you can use, you can read more here. I've chosen run levels 0,3 and 6 so that the service is called whenever the machine is stopped or rebooted, and when we've acquired networking capabilities.

The one fancy trick here is the following:

nohup MyServer &
echo $! > /var/run/MyServer.pid

The $! (dollarsign bang), within a bash shell, recieves the process id of the program which was pushed to the background last. Don't ask me how to google for that symbol (it's hard), but that's what it does, and when combined with the nohup command, it makes for an easy way to grab the process ID of your new service.

Make sure your script doesn't have any syntax errors and move it to the /etc/init.d/ directory. Make sure it's executable via chmod +x scriptname and give it a couple of goes. Depending on what your service is capable of responding to, you may add in other options like status, reload, etc. If you want to see all the options for what you can use in the case statement, you can read more here.

Once the script is in place simply run chkconfig using the name of the script in the init.d directory like so:

chkconfig --add myservice
chkconfig --list myservice
myservice   0:on   1:off   2:off   3:on    4:off   5:off    6:on

And that's it! If you change the runlevels in the tags of the script you'll want to do a quick chkconfig --del myservice && chkconfig --add myservice to update the run levels. Now go forth! Write your own services!