Home / Alt manpages / init-d-script(5)

  • init-d-script(5)
  • File format
  • linux

Build a Small Debian init.d Script with init-d-script

You will finish with a compact Debian-style /etc/init.d/ wrapper for a daemon, with start, stop, status and optional reload actions supplied by init-d-script. The examples match sysvinit-utils 3.08-6ubuntu3 installed on this machine. Allow about fifteen minutes for the file and a read-only review. Starting or stopping a real service needs root and can interrupt users, so this guide does not run those actions for you.

1. Check the helper and its boundary

The helper is a shell interpreter at /lib/init/init-d-script. Check that the package and file are present as your ordinary user:

$ dpkg-query -W -f='${Package} ${Version}\n' sysvinit-utils
sysvinit-utils 3.08-6ubuntu3
$ test -r /lib/init/init-d-script && echo 'helper is readable'
helper is readable

The script does not replace the daemon. It supplies the repetitive start-stop-daemon calls and standard actions, then reads the variables and functions in your script. It also reads /etc/default/${NAME} when that file is readable. That file is executable shell input, not a passive key-value document, so review its ownership and contents before using it.

Checkpoint: keep the helper path, package version and the name of the daemon you intend to manage visible while you work. A common distraction is writing a complete hand-rolled case statement when the helper already owns that control flow.

2. Create the script skeleton

Choose a service name that will also make a clear NAME and PID-file default. The following is a template. Replace /usr/local/sbin/example-daemon with an executable daemon that already exists on the target host:

#!/bin/sh /lib/init/init-d-script
### BEGIN INIT INFO
# Provides:          example-daemon
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Example daemon
# Description:       Starts and stops the example daemon.
### END INIT INFO

DAEMON=/usr/local/sbin/example-daemon
DESC="Example daemon"
DAEMON_ARGS="--config /etc/example-daemon.conf"

The BEGIN INIT INFO block describes boot ordering and runlevels to Debian tooling. It does not make the daemon safe to start, create the binary, or validate the configuration. The helper derives NAME from the basename of DAEMON when you do not set it, so this example uses example-daemon. DESC is the human-readable label printed during actions.

Do not install this template over an existing service. If you are replacing a script, copy the old file to a root-readable backup first so that recovery is a simple restore and service stop, not a reconstruction.

3. Understand the defaults before first start

With the variables above, the helper passes DAEMON_ARGS to the daemon on start and uses a PID file at /var/run/example-daemon.pid unless you set PIDFILE. The PID file is removed by the helper after a normal stop attempt. Set an explicit path when the daemon has a documented PID-file location:

PIDFILE=/run/example-daemon.pid
COMMAND_NAME=example-daemon

COMMAND_NAME is used for the process-name match. Set it to none to disable that match, and set PIDFILE=none when no PID file should be used. Do this only when the daemon's process and lifecycle make those matching rules reliable. A loose match can stop the wrong process; a missing match can leave an old daemon running.

Optional START_ARGS, STOP_ARGS and RELOAD_ARGS alter the options sent to start-stop-daemon. They are not daemon arguments. Keep daemon arguments in DAEMON_ARGS; mixing the two is a frequent source of a script that appears to start but ignores its configuration.

4. Add reload only when the daemon supports it

Reload is not enabled merely because the action exists in the script interface. By default, reload prints usage and exits with status 3. If the daemon reloads its configuration on HUP, declare the signal explicitly:

RELOAD_SIGNAL=HUP

The helper then uses start-stop-daemon to send that signal to the matching process. The manpage also permits the number 1. Use the daemon's own documentation to choose the signal. Sending HUP to a process that does not define that behaviour can terminate it or do something unexpected.

If reload needs more than a signal, define do_reload_cmd and let the helper wrap it, or define do_reload yourself. Function overrides use an _override suffix, such as do_status_override; do_reload is the exception and keeps its original name.

5. Handle a non-daemon service explicitly

Some init scripts configure a kernel or filesystem setting rather than supervise a daemon. Set DAEMON=none and provide the three operation overrides instead of letting the helper try to match an empty executable:

DAEMON=none

do_start_override() {
    /usr/sbin/example-configurator
}

do_stop_override() {
    return 0
}

do_status_override() {
    return 0
}

Those functions are real shell code and can change system state. Review every path, argument and privilege assumption before installing the script. There is no generic undo for a configurator, so use the configurator's documented rollback or restore procedure.

6. Validate without disrupting the host

Before installing, check shell syntax and inspect the file as an ordinary user:

$ sh -n ./example-daemon
$ sed -n '1,120p' ./example-daemon

Ask the script for usage. This executes the helper's read-only usage path and should not start the daemon:

$ sh ./example-daemon
Usage: ./example-daemon {start|stop|status|restart|try-restart|force-reload}

After adding RELOAD_SIGNAL, the usage line also includes reload. An unsupported action or no action exits with status 3. Check it immediately with printf '%s\n' "$?"; another command would replace the status you meant to inspect.

For a real installation, use root only for the copy, ownership, mode and service action:

# install -o root -g root -m 0755 ./example-daemon /etc/init.d/example-daemon
# /etc/init.d/example-daemon status

Do not run start, restart or force-reload until the daemon path, configuration, PID matching and stop behaviour have been tested. force-reload falls back to restart when no reload implementation exists, which can be service-disrupting.

To undo the installation, stop the service if it is running, restore the backed-up script, or remove this new script, then review any boot-registration change separately. Removing a script does not stop an already running daemon.

Done means

  • The script starts with /bin/sh /lib/init/init-d-script and contains valid LSB metadata.
  • DAEMON, arguments, process matching and PID-file behaviour have been checked against the daemon's documentation.
  • Reload is enabled only when the daemon's signal or custom reload command is known to be safe.
  • sh -n and the no-argument usage check pass without starting a service.
  • Any root-level installation or service action has an explicit rollback plan.