# Writing a Proper Linux Daemon in Swift with Signal Handling and Cleanup

Creating a production-grade Linux daemon requires more than simply running a program in the background.  
A correct daemon must detach from the controlling terminal, manage lifecycle files, respond predictably to operating system signals, and clean up all resources before termination.

This article explains the architecture and implementation of **`signal_15.swift`**, a Swift-based Linux daemon that correctly implements **POSIX daemonization and signal-based cleanup**.  
It follows the classic UNIX daemon model and demonstrates that Swift can be used for serious Linux systems programming—not just application-level code.

---

## Key Concepts

A correct Linux daemon must address the following responsibilities:

- Process detachment and session management  
- Lifecycle visibility using a **PID file**  
- Liveness indication using a **heartbeat file**  
- POSIX-compliant **signal handling**  
- Predictable and safe shutdown semantics  

This implementation focuses on all of the above.

---

## Daemonization

A proper Linux daemon follows the classic **double-fork with session detachment** pattern.  
This ensures the process:

- Has no controlling terminal  
- Cannot accidentally reacquire a terminal  
- Is fully detached from the user session  

### Why Double-Fork?

- Prevents terminal reattachment  
- Matches traditional UNIX daemon behavior  
- Required for long-running background services  

### Required Steps

1. Fork once and let the parent exit  
2. Call `setsid()` to create a new session  
3. Fork again so the daemon is not a session leader  
4. Redirect standard file descriptors to `/dev/null`  

### Swift Implementation

```swift
if fork() > 0 { exit(0) }
setsid()
if fork() > 0 { exit(0) }

let fd = open("/dev/null", O_RDWR)
dup2(fd, STDIN_FILENO)
dup2(fd, STDOUT_FILENO)
dup2(fd, STDERR_FILENO)```

## PID Files and Heartbeat Files

Lifecycle files are critical for **daemon management and observability**.  
They allow external tools, administrators, and supervisors to reason about the daemon’s state without attaching debuggers or parsing logs.

---

### PID File

A **PID file** records the process ID of the running daemon.

#### Purpose

- Allows `systemd`, scripts, or administrators to locate the daemon process
- Enables clean termination using `kill`
- Prevents multiple instances of the daemon from running simultaneously

#### Behavioral Rules

- Write the PID file **only after successful daemonization**
- Remove the PID file during **graceful shutdown**
- Never leave **stale PID files** behind

Failure to manage the PID file correctly can lead to:
- Orphaned processes
- Broken service restarts
- Incorrect health reporting by supervisors

---

### Heartbeat File

A **heartbeat file** proves that the daemon is alive **without parsing logs**.

#### Purpose

- Lightweight health check mechanism
- Human-readable liveness signal
- Works even when logs are rotated, unavailable, or redirected

Heartbeat files are especially useful for:
- Simple monitoring scripts
- Debugging hung or stalled daemons
- Environments without centralized logging

---

## Logging Strategy

Daemons must **never write to a terminal**.  
Once daemonized, `stdin`, `stdout`, and `stderr` are redirected and should not be relied upon.

### Recommended Logging Options

- **Dedicated log file** (manual rotation or `logrotate`)
- **syslog** integration
- **journalctl** (when managed via `systemd`)

A correct logging strategy ensures:
- Logs survive restarts
- Diagnostics are available post-crash
- No accidental dependency on terminal I/O


## Signal Handler Design in Swift

A production-grade daemon must **handle OS termination signals explicitly**.  
Failing to do so results in stale PID files, leaked file descriptors, and undefined shutdown behavior.

In UNIX systems, signal handlers have strict constraints:

- They cannot accept custom arguments
- They must execute quickly
- They must operate on globally accessible state

Because of this, any resources that require cleanup—such as PID files or open file handles—must be stored in **global variables** so that both `main()` and the signal handler can access them.

---

### Global State for Cleanup

```swift
let pidFilePath = "/var/run/my-daemon.pid"
var aliveFileHandle: FileHandle? = nil```

`signal_15.swift` demonstrates that Swift is not just for iOS or server frameworks; it is a capable systems programming language for long-running background processes on Linux.


