Creating a Custom init.d Script on Fedora

20, Apr 2012

Contents

In the Linux world there are many times when it is necessary to start a program at boot, and have it running until the computer shuts down. Standard examples of these types of programs are server deamons, such as mysqld, httpd, sshd, and various others. Most programs that you'll install that need to have a deamon come with one already created and setup. There may come a time however, when a program that you want to run as a deamon does not have a boot script already, and you have to create your own.

When Should My Script Run?

Before you can begin to write your own init scripts, you need at least a rudimentary understanding of runlevels in Linux. A run level tells the computer what mode it should boot into, thus enabling or deactivating certain features on the system. Red Hat/Fedora Linux has 6 different runlevels:

Note that different distributions may have different numbers representing their runlevels.

These runlevels are NOT executed sequentially: a system is booted into a specific level, according to the default specified in /etc/inittab. Obviously, one does not want to set that default to either 0 or 6, as the system would then boot up and either turn itself off, or constantly reboot.

All the init scripts are stored in /etc/int.d and from there they then propagated out to the respective /etc/rc[0-6].d/ (rc stands for run command) directory - the system reads through whichever rc directory is specified in the /etc/inittab file on boot, calling all the contents of that directory. Because a script may need to be started in multiple different run levels, using symlinks is the most sensible way of managing this. Red Hat and Fedora use the chkconfig command to manage all the scripts stored in the /etc/init.d/ directory, however on other distributions you can do this manually, or write your own script to handle it. Basically, what chkconfig does is automatically place symlinks in each of the /etc/rc[0-6].d/ directories specified in the command. It also provides ways of easily deleting, modifying and listing what scripts are being run on each run level.

Writing Your Own Init Script

If you're going to be using chkconfig to manage your new service, there is a specific format that you must follow when constructing your script file. Below is a basic structure of the file:

#!/bin/bash
#
# <service> <Brief Description>
#
# chkconfig: <runlevels> <start_number> <kill_number>
# description: <More detailed description of the service>
# processname: <process_name>

case "$1" in
    start)
    stop)
    status)
    restart)
    *)
esac

Where the following holds true:

service : The name of the service you're creating

runlevels : Number or number of each of the runlevels that you want this script to be started on, for example, 35 means that this script is to be run on runlevels 3 and 5.

start_number : What order the script should start in on each runlevel. For non essential scripts, you want this to be relatively high so that it is started after most other programs (99 is the largest number possible).

kill_number : What order the script should stop when leaving the runlevel. For non essential scripts, you want this to be relatively low so that it is killed before programs it may depend upon (01 is the lowest possible - note the leading 0).

process_name : The name that this process is running under

You will then need to fill in each of the methods in the case statement as needed to start and stop your service. When you're done, make the file executable, and then run chkconfig on it:

sudo chmod a+x /etc/init.d/<service_name>
sudo chkconfig --level <desired_runlevels> <service_name> on

Next time you start your machine your new service will be called when the computer enters any of the run levels specified.

Code Snippits

Here's a couple useful snippits of code that will help when developing your service:

#source function library
. /etc/rc.d/init.d/functions

This will source some helpful functions that already exist on the machine that you can use, including:

Here it is in action. This little block of code will check to see if the executable has a currently running PID, and if it does it will end that processes. Otherwise, it will log an error on stopping the service:

if [ -n "`pidofproc $PATH`" ] ; then
    killproc $PATH
else
    failure "Stopping <service>"
fi

Another handy file to source into your script if you're doing something that requires network access is /etc/sysconfig/network. Once you've sourced that you can do the following:

[ "${NETWORKING}" = "no" ] && exit 1

This checks to see if the system has an active network connection, and if it doesn't ends the script with an error exit code.

If you only want to do certain actions on certian runlevels, but the script is being used on multiple ones, you can get the current run level with this one liner:

runlevel=$(set -- $(runlevel); eval "echo \$$#" )

That's All Folks

That just about covers writing your own script. You for further pointers, I'd reccommend reading the already provided scripts in /etc/init.d - they're quite helpful to model your script off of.

Comments

don said on Feb 9, 2014:

case "$1" in

hi corey why the line above ? just curious - when you run it at startup what is the purpose of "$1" ? hanks

Have Something to Say?

Questions? Comments? Concerns? Let me know what you’re thinking.

  • You can use Markdown formatting here.