A common scenario for running an application such as fwd is to run it as a true server application. Here are some of the requirements for fwd when it runs in that mode:
/etc
directory./var/log
directory./etc
directory./run/fwd.pid
. The application will also need to tell the init system where to find this pid file.On a Unix system an init application is an application that manages the startup process. On many modern Linux distributions the init system in common use is the systemd
application. You may encounter other init systems such as upstart
or the even older init
application.
systemd
expects developers of server applications to write a special configuration file, called a unit file, to tell systemd
how to manage the startup process for their application. Here are the contents of the unit file you would use for fwd.
[Unit] Description=Folder watcher application [Service] Type=forking PIDFile=/run/fwd.pid ExecStart=/opt/fwd/fwd [Install] WantedBy=multi-user.target
The unit file is named fwd.service
. You will place this unit file in the /lib/systemd/system/
directory, which is one of the standard directories that systemd
looks in to find unit files.
A unit file consists of several sections. Here is a description of some of the options I have set in these sections.
The [Unit]
section covers basic details of the service. The Description
option gives a brief description of the service. If you ask systemd to show you details about running services on a machine it will print that description as part of the information it shows you.
The [Service]
section is the most important section for configuring a service. The options in this section tell systemd
how to actually start the service and what to expect when the service starts. The most imporant option in this section is the ExecStart
option, which specifies a path to the application we want to start. The Type
option tells systemd
what to expect when it starts the application. In this case, since the application will fork to make a child process that runs in the background while the application itself exits, we need to tell systemd
to not worry about the fact that the application appears to exit as soon as it launches. Forking applications are expected to generate a pid file that stores the process id of the background application. The PIDFile
option tells systemd
where it can find that file. systemd
will use that process id to shut down the server application when the system shuts down or when the user asks systemd
to restart the service.
The [Install]
section is required for services that want to start as part of the boot process. To actually register a service for startup during the boot process, the unit has to be enabled, and must also have an [Install]
section in its unit file. The WantedBy
option links this service to one of the targets that systemd
attempts to bring up during the boot process. The multi-user
target is one of the later targets that systemd
brings up at boot time.
To activate a service we construct a unit file and arrange for it to be placed in one of the standard directories where systemd
looks for unit files. Once we have created a unit file and placed it in the proper location, we can ask systemd
to start it by issuing the command
sudo systemctl start fwd
systemctl
is the terminal application that provides a command interface to systemd
.
If we want our application to start automatically when the computer boots, we have to tell systemd
to enable its unit. We do this via the command
sudo systemctl enable fwd
More information about the systemctl
application and the things you can do with it are available online in this article. You can read more about the options available in unit files in this article.
Most server applications run on a system as daemons, which are processes designed for a long time in the background. The book The Linux Programming Interface by Michael Kerrisk gives an overview of the process that most daemons use to set themselves up properly. I summarize these steps below.
To become a daemon, a program typically performs the following steps at startup:
fork()
, after which the parent exits and the child continues. (As a consequence, the daemon becomes a child of the init
process.) This step is done for two reasons:setsid()
to start a new session and free itself of any association with a controlling terminal. If the daemon never opens any terminal devices thereafter, then we don’t need to worry about the daemon reacquiring a controlling terminal. If the daemon might later open a terminal device, then we must take steps to ensure that the device does not become the controlling terminal. To do this, the applications performs a second fork()
after the setsid()
call, and again has the parent exit and the (grand)child continue. This ensures that the child is not the session leader, and thus, according to the System V conventions for the acquisition of a controlling terminal (which Linux follows), the process can never reacquire a controlling terminal.umask()
to ensure that when the daemon creates files and directories they have the requested permissions.chdir()
, typically to the root directory (/). This is necessary because a daemon usually runs until system shutdown; if the daemon’s current working directory is on a file system other than the one containing /, then that file system can’t be unmounted. Alternatively, the daemon can change its working directory to a location where it does its job or a location defined in its configuration file, as long as we know that the file system containing this directory never needs to be unmounted. For example, cron
places itself in /var/spool/cron
./dev/null
and uses dup2()
(or similar) to make all those descriptors refer to this device. This is done for two reasons: