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 are detected, it should write the path to the console where it was started plus a newline. I already have the filesystem changing code almost ready but I cannot figure out how to create a daemon. My code is from here: http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html What to do after the fork?
int main (int argc, char **argv) < pid_t pID = fork(); if (pID == 0) < // child // Code only executed by child process sIdentifier = "Child Process: "; >else if (pID < 0) < cerr else // parent < // Code only executed by parent process sIdentifier = "Parent Process:"; >return 0; >
possible duplicate of: stackoverflow.com/questions/5384168/… for the daemonize part, stackoverflow.com/questions/931093/… for the filesystem watch
If you don’t need POSIX compliance you may be interested in inotify API. See: inotify_init , inotify_add_watch , inotify_rm_watch .
9 Answers 9
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 #include #include #include #include #include #include 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:
Create a systemd daemon
Like it or hate it, you’ll find systemd on any modern linux system these days. This management subsystem is the newer replacement for the older init scripts-based systems.
In today’s article, I’m going to show you how to create a daemon that will sit under the management of systemd.
.service file
A service file instructs systemd how to interact with the deployed application. It’s referred to as the service unit configuration. The following is an example:
[Unit] Description=My Service After=network.target [Service] ExecStart=/usr/bin/my-service Restart=on-failure [Install] WantedBy=multi-user.target
Installation
This file, once you’ve created it gets deployed to systemd with a cp . You also need to notify systemd.
sudo cp my-service.service /lib/systemd/system sudo systemctl daemon-reload sudo systemctl enable my-service
Interacting with the service
Once the service is in place, you can start to interact with the daemon using systemctl .
sudo systemctl start my-service sudo systemctl status my-service
You can also get a hold of any log pushed out to the standard system file descriptors:
journalctl --unit my-service --follow
Removal
Once you no longer need your service, you can remove it simply my rm ‘ing the .service file. Of course, you’ll need to disable your service first.
That’s it for creating a systemd service.