Linux Daemonize

Linux daemonize

From http://www.steve.org.uk/Reference/Unix/faq_2.html#SEC16

Here are the steps to become a daemon:

  1. fork() so the parent can exit, this returns control to the command line or shell invoking your program. This step is required so that the new process is guaranteed not to be a process group leader. The next step, setsid(), fails if you're a process group leader.
  2. setsid() to become a process group and session group leader. Since a controlling terminal is associated with a session, and this new session has not yet acquired a controlling terminal our process now has no controlling terminal, which is a Good Thing for daemons.
  3. fork() again so the parent, (the session group leader), can exit. This means that we, as a non-session group leader, can never regain a controlling terminal.
  4. chdir("/") to ensure that our process doesn't keep any directory in use. Failure to do this could make it so that an administrator couldn't unmount a filesystem, because it was our current directory. [Equivalently, we could change to any directory containing files important to the daemon's operation.]
  5. umask(0) so that we have complete control over the permissions of anything we write. We don't know what umask we may have inherited. [This step is optional]
  6. close() fds 0, 1, and 2. This releases the standard in, out, and error we inherited from our parent process. We have no way of knowing where these fds might have been redirected to. Note that many daemons use sysconf() to determine the limit _SC_OPEN_MAX. _SC_OPEN_MAX tells you the maximun open files/process. Then in a loop, the daemon can close all possible file descriptors. You have to decide if you need to do this or not. If you think that there might be file-descriptors open you should close them, since there's a limit on number of concurrent file descriptors.
  7. Establish new open descriptors for stdin, stdout and stderr. Even if you don't plan to use them, it is still a good idea to have them open. The precise handling of these is a matter of taste; if you have a logfile, for example, you might wish to open it as stdout or stderr, and open '/dev/null' as stdin; alternatively, you could open '/dev/console' as stderr and/or stdout, and '/dev/null' as stdin, or any other combination that makes sense for your particular daemon.

Better yet, just call the daemon() function if it's available.

how to daemonize a script

AFAIK, most daemon or deamonize programs change the current dir to root as part of the daemonization process. That means that you must give the full path of the command:

daemon --name="foo" -b ~/daemon.out -l ~/daemon.err -v -- /path/to/foo.sh

If it still did not work, you could try to specify a shell:

daemon --name="foo" -b ~/daemon.out -l ~/daemon.err -v -- /bin/bash -c /path/to/foo.sh

Creating a daemon in Linux

In Linux i want to add a daemon that cannot be stopped and which monitors filesystem changes. If any changes would be detected it should write the path to the console where it was started + a newline.

Daemons work in the background and (usually...) don't belong to a TTY that's why you can't use stdout/stderr in the way you probably want.
Usually a syslog daemon (syslogd) is used for logging messages to files (debug, error,...).

Besides that, there are a few required steps to daemonize a process.


If I remember correctly these steps are:

  • fork off the parent process & let it terminate if forking was successful. -> Because the parent process has terminated, the child process now runs in the background.
  • setsid - Create a new session. The calling process becomes the leader of the new session and the process group leader of the new process group. The process is now detached from its controlling terminal (CTTY).
  • Catch signals - Ignore and/or handle signals.
  • fork again & let the parent process terminate to ensure that you get rid of the session leading process. (Only session leaders may get a TTY again.)
  • chdir - Change the working directory of the daemon.
  • umask - Change the file mode mask according to the needs of the daemon.
  • close - Close all open file descriptors that may be inherited from the parent process.

To give you a starting point: Look at this skeleton code that shows the basic steps. This code can now also be forked on GitHub: Basic skeleton of a linux daemon

/*
* daemonize.c
* This example daemonizes a process, writes a few log messages,
* sleeps 20 seconds and terminates afterwards.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>

static void skeleton_daemon()
{
pid_t pid;

/* Fork off the parent process */
pid = fork();

/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);

/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);

/* On success: The child process becomes session leader */
if (setsid() < 0)
exit(EXIT_FAILURE);

/* Catch, ignore and handle signals */
//TODO: Implement a working signal handler */
signal(SIGCHLD, SIG_IGN);
signal(SIGHUP, SIG_IGN);

/* Fork off for the second time*/
pid = fork();

/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);

/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);

/* Set new file permissions */
umask(0);

/* Change the working directory to the root directory */
/* or another appropriated directory */
chdir("/");

/* Close all open file descriptors */
int x;
for (x = sysconf(_SC_OPEN_MAX); x>=0; x--)
{
close (x);
}

/* Open the log file */
openlog ("firstdaemon", LOG_PID, LOG_DAEMON);
}
int main()
{
skeleton_daemon();

while (1)
{
//TODO: Insert daemon code here.
syslog (LOG_NOTICE, "First daemon started.");
sleep (20);
break;
}

syslog (LOG_NOTICE, "First daemon terminated.");
closelog();

return EXIT_SUCCESS;
}


  • Compile the code: gcc -o firstdaemon daemonize.c
  • Start the daemon: ./firstdaemon
  • Check if everything is working properly: ps -xj | grep firstdaemon

  • The output should be similar to this one:


+------+------+------+------+-----+-------+------+------+------+-----+
| PPID | PID | PGID | SID | TTY | TPGID | STAT | UID | TIME | CMD |
+------+------+------+------+-----+-------+------+------+------+-----+
| 1 | 3387 | 3386 | 3386 | ? | -1 | S | 1000 | 0:00 | ./ |
+------+------+------+------+-----+-------+------+------+------+-----+

What you should see here is:

  • The daemon has no controlling terminal (TTY = ?)
  • The parent process ID (PPID) is 1 (The init process)
  • The PID != SID which means that our process is NOT the session leader

    (because of the second fork())
  • Because PID != SID our process can't take control of a TTY again

Reading the syslog:

  • Locate your syslog file. Mine is here: /var/log/syslog
  • Do a: grep firstdaemon /var/log/syslog

  • The output should be similar to this one:


firstdaemon[3387]: First daemon started.
firstdaemon[3387]: First daemon terminated.



A note:
In reality you would also want to implement a signal handler and set up the logging properly (Files, log levels...).

Further reading:

  • Linux-UNIX-Programmierung - German
  • Unix Daemon Server Programming

How do I daemonize an arbitrary script in unix?

You can daemonize any executable in Unix by using nohup and the & operator:

nohup yourScript.sh script args&

The nohup command allows you to shut down your shell session without it killing your script, while the & places your script in the background so you get a shell prompt to continue your session. The only minor problem with this is standard out and standard error both get sent to ./nohup.out, so if you start several scripts in this manor their output will be intertwined. A better command would be:

nohup yourScript.sh script args >script.out 2>script.error&

This will send standard out to the file of your choice and standard error to a different file of your choice. If you want to use just one file for both standard out and standard error you can us this:

nohup yourScript.sh script args >script.out 2>&1 &

The 2>&1 tells the shell to redirect standard error (file descriptor 2) to the same file as standard out (file descriptor 1).

To run a command only once and restart it if it dies you can use this script:

#!/bin/bash

if [[ $# < 1 ]]; then
echo "Name of pid file not given."
exit
fi

# Get the pid file's name.
PIDFILE=$1
shift

if [[ $# < 1 ]]; then
echo "No command given."
exit
fi

echo "Checking pid in file $PIDFILE."

#Check to see if process running.
PID=$(cat $PIDFILE 2>/dev/null)
if [[ $? = 0 ]]; then
ps -p $PID >/dev/null 2>&1
if [[ $? = 0 ]]; then
echo "Command $1 already running."
exit
fi
fi

# Write our pid to file.
echo $$ >$PIDFILE

# Get command.
COMMAND=$1
shift

# Run command until we're killed.
while true; do
$COMMAND "$@"
sleep 10 # if command dies immediately, don't go into un-ctrl-c-able loop
done

The first argument is the name of the pid file to use. The second argument is the command. And all other arguments are the command's arguments.

If you name this script restart.sh this is how you would call it:

nohup restart.sh pidFileName yourScript.sh script args >script.out 2>&1 &

How to properly start a process that will daemonize using Go?

Daemonizing a process is just a fancy way of forking the process. That means that the process you start will exit as soon as the daemonized process is started. Therefore you want to use Run, which will wait for the started process to return (the successful fork).

Process A:
|
|`-- run(B)
| Process B:
| |
| |`-- daemonize(C)
| |
| `-- exit
|
`-- daemonizing done

If you want to wait for a state of the daemon, the most reliable way is to be signalled by the daemon. For example using a socket, a file or shared memory.



Related Topics



Leave a reply



Submit