# How witr Detects the Source of systemd, launchd, and rc.d Services

> Learn how witr detects systemd, launchd, and rc.d service sources by analyzing process ancestry and applying platform-specific detectors for detailed unit information.

- Repository: [Pranshu Parmar/witr](https://github.com/pranshuparmar/witr)
- Tags: deep-dive
- Published: 2026-08-09

---

**witr determines which init system started a process by walking the process ancestry tree and applying platform-specific detectors that return a structured `model.Source` containing the service type, unit name, and metadata.**

The `pranshuparmar/witr` repository implements a unified detection architecture that identifies whether a running process originated from systemd, launchd, or traditional BSD rc.d initialization systems. By combining process tree traversal with filesystem and API inspection, witr maps each process back to its defining service unit.

## The Detection Pipeline

witr orchestrates detection through [`internal/source/detect.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/detect.go). The system first constructs a process ancestry slice by walking from the target PID up to PID 1, collecting `model.Process` objects. It then executes platform-specific detectors in priority order—**systemd**, **launchd**, and **bsdrc**—returning the first non-nil `*model.Source` result. Each detector populates the universal `Source` struct defined in [`pkg/model/source.go`](https://github.com/pranshuparmar/witr/blob/main/pkg/model/source.go), which standardizes fields for `Type`, `Name`, `Description`, `UnitFile`, and a `Details` map.

## Systemd Detection on Linux

The Linux systemd detector resides in [`internal/source/systemd_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/systemd_linux.go) and implements the `detectSystemd` function.

### Verifying systemd as the Init System

Before querying service metadata, the detector confirms systemd is the active init system. The `IsSystemdRunning()` function checks for the existence of `/run/systemd/system` (the canonical test used by `sd_booted()`) and verifies that PID 1 exists within the collected ancestry (lines 24–42).

### Extracting the Unit Name

Once validated, witr derives the systemd unit by inspecting the control group (cgroup) of the target process. The `getUnitNameFromCgroup` helper (line 50) parses the cgroup path to extract the service identifier.

### Enriching via D-Bus

The `enrichFromSystemd()` function (lines 61–98) establishes a D-Bus connection using `sd.NewSystemConnectionContext` and queries:
- Unit properties for the description and fragment path
- Service properties for restart counts
- Timer properties for execution schedules

This enrichment is best-effort; any D-Bus failures result in empty fields rather than detection errors.

```go
// Conceptual implementation based on internal/source/systemd_linux.go
source := &model.Source{
    Type: model.SourceSystemd,
    Name: unitName,
}

if conn, err := sd.NewSystemConnectionContext(ctx); err == nil {
    source.Description = getUnitDescription(conn, unitName)
    source.UnitFile = getFragmentPath(conn, unitName)
    source.Details["NRestarts"] = getRestartCount(conn, unitName)
}

```

## Launchd Detection on macOS

For macOS systems, [`internal/source/launchd_darwin.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/launchd_darwin.go) provides the `detectLaunchd` function.

### Identifying launchd in the Ancestry

The detector scans the process ancestry for an entry where `PID == 1` and `Command == "launchd"` (lines 13–19). This confirms the process tree originates from the Darwin init system.

### Querying Service Metadata

Upon confirmation, witr invokes `launchd.GetLaunchdInfo(target.PID)` to retrieve the service label, comment, and plist configuration (lines 32–40). The detector populates:
- **Name**: The service label (e.g., `com.openssh.sshd`)
- **Description**: The comment field from the plist
- **UnitFile**: The path to the plist file
- **Details**: Domain description (Agent vs Daemon), schedule strings, trigger conditions, and KeepAlive status

```go
// Based on internal/source/launchd_darwin.go
if info, err := launchd.GetLaunchdInfo(target.PID); err == nil {
    source := &model.Source{
        Type:        model.SourceLaunchd,
        Name:        info.Label,
        Description: info.Comment,
        UnitFile:    info.PlistPath,
    }
    source.Details["type"] = info.DomainDescription
    source.Details["keepalive"] = info.KeepAlive
}

```

## rc.d Detection for BSD-Style Init

Traditional BSD rc.d services are handled by [`internal/source/bsdrc_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/bsdrc_linux.go) via the `detectBsdRc` function.

### Confirming BSD-Style Init

The detector verifies two conditions to avoid false positives on systemd systems. First, it checks if PID 1's command starts with `init` using `strings.HasPrefix(p.Command, "init")` (around line 15). Second, it confirms the existence of `/etc/rc.d` or `/etc/init.d` directories via `os.Stat` (around line 22).

### Resolving Service Scripts

witr walks the process ancestry to match parent processes against filenames in the rc.d directories. When a match is found, it reads the init script to extract the `# Description:` comment (around line 50), constructing a source with:

- **Type**: `SourceBsdRc`
- **Name**: The script basename (e.g., `sshd`)
- **UnitFile**: The full path (e.g., `/etc/rc.d/sshd`)

Unlike the systemd implementation, this detector does not use D-Bus; it relies entirely on static filesystem inspection and process command-line metadata.

## Source Model and Orchestration

The `Source` struct in [`pkg/model/source.go`](https://github.com/pranshuparmar/witr/blob/main/pkg/model/source.go) provides the universal interface for all detection results. It contains:
- `Type`: Enumeration (`SourceSystemd`, `SourceLaunchd`, `SourceBsdRc`)
- `Name`: The service identifier (unit name, label, or script name)
- `Description`: Human-readable summary
- `UnitFile`: Path to the service definition
- `Details`: Map for platform-specific metadata

The orchestration layer in [`internal/source/detect.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/detect.go) executes detectors sequentially, ensuring that on systems with multiple init systems present, the most specific and informative source is reported.

## Summary

- witr detects service sources by walking the process ancestry from the target PID to PID 1.
- The **systemd** detector validates against `/run/systemd/system` and enriches data via D-Bus queries for unit properties in [`internal/source/systemd_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/systemd_linux.go).
- The **launchd** detector identifies macOS init systems by checking for `launchd` as PID 1 and queries the launchd API for plist metadata in [`internal/source/launchd_darwin.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/launchd_darwin.go).
- The **rc.d** detector identifies BSD-style init by verifying PID 1 is `init` and `/etc/rc.d` exists, then maps processes to their corresponding init scripts in [`internal/source/bsdrc_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/bsdrc_linux.go).
- All detectors return a standardized `model.Source` struct defined in [`pkg/model/source.go`](https://github.com/pranshuparmar/witr/blob/main/pkg/model/source.go).

## Frequently Asked Questions

### How does witr distinguish between systemd and traditional SysV init on Linux?

witr first checks for the presence of `/run/systemd/system` using `IsSystemdRunning()`. If this directory exists and PID 1 appears in the process ancestry, it treats the system as systemd-managed. If not, it falls back to the rc.d detector, which looks for `init` as PID 1 and the existence of `/etc/init.d` or `/etc/rc.d` directories to identify SysV-style initialization.

### Can witr detect services started by launchd on older macOS versions?

Yes, as long as the system uses `launchd` as PID 1, the detector in [`internal/source/launchd_darwin.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/launchd_darwin.go) identifies the init system by verifying the process name. However, the richness of metadata depends on the `launchd.GetLaunchdInfo` function's ability to query the specific macOS version's APIs for service details.

### What happens if witr encounters a process started manually rather than by an init system?

If none of the detectors—systemd, launchd, or rc.d—can associate the process with a known service unit or script, the detection returns `nil`. The orchestration logic in [`internal/source/detect.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/detect.go) handles this by continuing through the detector chain until exhausted, resulting in no source being reported for manually executed binaries.

### Does witr require root privileges to detect service sources?

Root privileges are not strictly required for the ancestry walk, but they significantly improve detection accuracy. Accessing D-Bus interfaces for systemd, querying certain process attributes, and reading all init scripts in `/etc/rc.d` may require elevated permissions depending on system security policies. Without root, witr may return partial or empty source information.