A Daemon is a specialized UNIX/Linux background process designed to execute unattended, without direct human interaction or an active terminal window. Core Linux operating system features—such as SSH remote logins (sshd), scheduled cron tasks (crond), web hosting (httpd/nginx), and database engines (mysqld)—operate exclusively as daemons.
In this advanced tutorial, you will master the canonical 7-step daemonization workflow in C, implement live configuration reloading via Linux Signals, integrate system logging with syslog(), and configure a production-ready systemd unit file.
Figure 1: Complete 7-Step UNIX Daemon Creation Workflow and Systemd Integration
1. The Canonical 7-Step Daemonization Recipe in C
To transform a standard C program into a well-behaved background daemon, you must execute the following sequence:
fork() & Parent Exit: Spawns a child process. The parent terminates immediately, giving control back to the shell prompt and leaving the child as an orphan adopted by init or systemd (PPID 1).setsid(): The child becomes session leader, creates a new process group, and permanently severs ties with the controlling terminal (tty).fork(): The session leader forks a grandchild and exits. This ensures the daemon is NOT a session leader, preventing it from ever re-acquiring a controlling terminal.umask(0): Eliminates inherited permission restrictions so the daemon can create log or data files with exact intended permissions (e.g., 0644).chdir("/"): Changes current directory to root so the daemon does not lock mounted filesystems and prevent system administrators from unmounting disks./dev/null via dup2() so background writes don't corrupt active user terminals.printf() with openlog() and syslog() to record events in /var/log/syslog.2. Complete Compilable C Daemon Implementation
Here is a production-grade C daemon demonstrating signal handling for SIGHUP (reload config) and SIGTERM (graceful shutdown):
/* mydaemon.c - Robust Linux Daemon Implementation in C */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>
#include <fcntl.h>
static volatile sig_atomic_t g_running = 1;
void handle_signal(int sig) {
if (sig == SIGHUP) {
syslog(LOG_INFO, "mydaemon: Received SIGHUP! Reloading configuration...");
} else if (sig == SIGTERM || sig == SIGINT) {
syslog(LOG_INFO, "mydaemon: Received termination signal! Shutting down gracefully...");
g_running = 0;
}
}
void daemonize(void) {
pid_t pid;
/* Step 1: Fork and terminate parent */
pid = fork();
if (pid < 0) exit(EXIT_FAILURE);
if (pid > 0) exit(EXIT_SUCCESS); /* Parent exits */
/* Step 2: Create new session & detach from TTY */
if (setsid() < 0) exit(EXIT_FAILURE);
/* Step 3: Second fork */
pid = fork();
if (pid < 0) exit(EXIT_FAILURE);
if (pid > 0) exit(EXIT_SUCCESS);
/* Step 4: Clear file creation mask */
umask(0);
/* Step 5: Change working directory to root */
if (chdir("/") < 0) exit(EXIT_FAILURE);
/* Step 6: Close standard descriptors & point to /dev/null */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
int null_fd = open("/dev/null", O_RDWR);
if (null_fd != -1) {
dup2(null_fd, STDIN_FILENO);
dup2(null_fd, STDOUT_FILENO);
dup2(null_fd, STDERR_FILENO);
if (null_fd > 2) close(null_fd);
}
}
int main(void) {
/* Step 7: Open syslog connection */
openlog("mydaemon", LOG_PID, LOG_DAEMON);
/* Setup signal handlers */
struct sigaction sa;
sa.sa_handler = handle_signal;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
/* Enter background daemon mode */
daemonize();
syslog(LOG_INFO, "mydaemon started successfully with PID %d", getpid());
/* Main Daemon Service Loop */
while (g_running) {
syslog(LOG_INFO, "mydaemon heartbeat: system service operational.");
sleep(10);
}
syslog(LOG_INFO, "mydaemon stopped cleanly.");
closelog();
return 0;
}
Compile and test the daemon in your terminal:
$ gcc -Wall mydaemon.c -o mydaemon
$ ./mydaemon
$ ps -ef | grep mydaemon
root 42150 1 0 14:10 ? 00:00:00 ./mydaemon
# Notice PPID is 1 (adopted by systemd) and TTY is '?' (detached)!
$ tail -n 5 /var/log/syslog
mydaemon[42150]: mydaemon started successfully with PID 42150
mydaemon[42150]: mydaemon heartbeat: system service operational.
# Send SIGHUP to test dynamic configuration reload
$ kill -HUP 42150
# Terminate daemon cleanly
$ kill -TERM 42150
3. Creating a Modern Systemd Service Unit File
In modern Linux distributions (Ubuntu, Debian, RHEL, CentOS, Arch), services are controlled via systemd. Create a unit file at /etc/systemd/system/mydaemon.service:
[Unit]
Description=Custom Veewom Background Daemon Service
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/bin/mydaemon
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
Manage the service using standard systemctl commands:
$ sudo cp mydaemon /usr/local/bin/
$ sudo systemctl daemon-reload
$ sudo systemctl start mydaemon
$ sudo systemctl status mydaemon
$ sudo systemctl enable mydaemon # Start automatically at boot
$ sudo journalctl -u mydaemon -f # Stream live log output
Learn how to scale daemons and servers to handle tens of thousands of concurrent network connections in Class 33: Linux I/O Multiplexing & epoll().
Continue to Class 33: I/O Multiplexing & epoll → Previous Class: ← Memory Management
4. University Viva & Job Interview Q&A
Answer: Use a PID lockfile (e.g. /var/run/mydaemon.pid). When starting, the daemon opens the lockfile and applies an advisory write lock using fcntl(fd, F_SETLK, ...) or flock(). If locking fails, another instance is already active and the new process exits.
Answer: The C library provides int daemon(int nochdir, int noclose);, which automates forking, calling setsid(), changing to root, and redirecting standard streams to /dev/null in a single call. Writing it manually, however, offers full control over double-forking and logging.
5. Frequently Asked Questions (FAQ)
Yes. In modern Linux with systemd, any script or program (Python, Go, Bash) can behave as a daemon simply by creating a systemd service unit with Type=simple and running in the foreground without manual fork/setsid gymnastics.