Understanding Daemonization in Unix-like Systems
Daemonization is the process of turning a regular process into a daemon, a background process that runs independently of any controlling terminal. Daemons are essential for various system services. This article explains the steps involved in daemonization and clarifies why certain techniques, including using subshells, source
, or .
, are insufficient.
What is a Daemon?
A daemon is a background process that:
- Runs independently of any user interaction or terminal.
- Typically starts at boot time and continues running until the system shuts down.
- Performs system-level tasks or provides services to other processes.
The Daemonization Process
Daemonization involves a specific sequence of steps to detach a process from its controlling terminal and ensure its proper background execution. These steps are typically implemented in C or other languages that provide access to system calls:
-
Fork the First Time: The process calls
fork()
. This creates a child process, which is an exact copy of the parent. -
Parent Process Exits: The original (parent) process exits immediately. This disassociates the process from the controlling terminal.
-
Create a New Session (
setsid()
): The child process callssetsid()
. This creates a new session, makes the child process the session leader, and detaches it from the old session (and thus the controlling terminal). This is the key step. -
Fork the Second Time (Highly Recommended): The child process forks again. The first child then exits. This grandchild is adopted by
init
orsystemd
, further isolating the daemon. -
Change Working Directory (
chdir("/")
): The process changes its working directory to the root directory (/
). -
Close Standard File Descriptors (
close()
): The process closes stdin (0), stdout (1), and stderr (2). -
Set File Mode Creation Mask (
umask(0)
): Sets the file mode creation mask to 0 for predictable file permissions.
Why Subshells, source
, and .
Don't Work for Daemonization (with Demonstration)
A common misunderstanding is that you can daemonize a process by simply running it in a subshell, using the source
command (or its shorthand .
), or a combination of these with backgrounding. This is incorrect.
- Subshells: While a subshell creates a separate shell environment, it's still a child process of the parent shell.
source
and.
: These commands do not create a subshell. They execute the contents of a file in the current shell environment.
Demonstration:
Let's illustrate with Bash scripts:
1. Subshell Example (test_daemon_subshell.sh
):
#!/bin/bash
echo "Parent shell PID: $$"
(
echo "Subshell PID: $$"
sleep 60
echo "Subshell exiting"
) &
echo "Parent shell exiting"
2. Source Example (test_daemon_source.sh
):
#!/bin/bash
echo "Parent shell PID: $$"
. ./sleep_script.sh # or source ./sleep_script.sh
echo "Parent shell exiting"
sleep_script.sh
(used by the source example):
#!/bin/bash
echo "Sourced script PID: $$"
sleep 60
echo "Sourced script exiting"
Steps:
-
Make scripts executable:
chmod +x test_daemon_subshell.sh test_daemon_source.sh sleep_script.sh
-
Run the subshell script:
./test_daemon_subshell.sh
-
Run the source script:
./test_daemon_source.sh
-
Observe the output and PIDs: Note the PIDs of the parent shell, subshell (if applicable), and the
sleep
process in each case. -
Check running processes: Use
ps aux | grep sleep
in another terminal. -
Close the original terminals: Observe that the
sleep
processes are terminated in both cases when the parent shell exits.
Explanation:
- Subshells: As before, the subshell and its backgrounded process are children of the parent shell and receive SIGHUP.
source
and.
: The crucial difference here is that the sourced script executes within the current shell. Therefore, thesleep
command runs directly in the parent shell, and it's even more directly connected than in the subshell example.
Key takeaway: Neither subshells nor source
/.
provide the necessary detachment for daemonization. They do not create new sessions with setsid()
.