# Platform Specific Code in herdr src/platform: Linux, macOS and Fallback Implementations

> Discover platform specific code in herdr src/platform. Explore Linux, macOS, and fallback implementations isolating OS-dependent behavior behind a unified Rust API.

- Repository: [Can Celik/herdr](https://github.com/ogulcancelik/herdr)
- Tags: deep-dive
- Published: 2026-05-31

---

**The `src/platform` module in herdr isolates all OS-dependent behavior behind a unified Rust API, providing concrete implementations for Linux via the `/proc` filesystem, macOS via `proc_*` syscalls, and no-op stubs for unsupported systems.**

`herdr` is a Rust-based process management and automation tool that requires deep integration with operating system primitives for clipboard access, process inspection, and desktop notifications. To maintain cross-platform compatibility without scattering conditional compilation directives throughout the codebase, the project centralizes all platform specific code in the `src/platform` directory, exposing a consistent interface defined in [`src/platform/mod.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/platform/mod.rs).

## Architecture of the Platform Abstraction Layer

The platform module uses Rust's conditional compilation attributes to select the appropriate implementation at compile time based on the target operating system.

### The Public API in mod.rs

[`src/platform/mod.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/platform/mod.rs) defines the shared types and function signatures that every platform must implement:

- **Process structures** – `ForegroundProcess` and `ForegroundJob` for grouping related processes
- **Signal enumeration** – `Signal` variants including `Hangup`, `Terminate`, and `Kill`
- **Clipboard abstractions** – `ClipboardCommand` and `ClipboardImage` for handling system clipboard data
- **I/O helpers** – `read_limited_reader` and the `LimitedRead` enum for safe data consumption

This file also declares the platform-specific functions—such as `foreground_job()`, `write_clipboard()`, `open_url()`, and `show_desktop_notification()`—without providing implementations. The actual logic resides in OS-specific submodules.

### Conditional Compilation Strategy

The module uses `#[cfg]` attributes to re-export the correct implementation:

- `#[cfg(target_os = "linux")] mod linux; pub use linux::*;`
- `#[cfg(target_os = "macos")] mod macos; pub use macos::*;`
- `#[cfg(not(any(target_os = "linux", target_os = "macos")))] mod fallback; pub use fallback::*;`

This approach ensures that calling code simply imports from `herdr::platform` without needing to know the underlying operating system.

## Linux Implementation (src/platform/linux.rs)

[`src/platform/linux.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/platform/linux.rs) provides the Linux-specific implementation using procfs and external command-line utilities. According to the herdr source code, this file avoids GUI library dependencies by shelling out to standard Unix tools.

**Process Inspection via /proc**

The Linux implementation reads from the virtual `/proc` filesystem to gather process information:

- `foreground_job()` parses `/proc/<pid>/stat` and iterates `/proc` directories to construct a `ForegroundJob` containing all processes sharing the same terminal process group
- `process_pgrp_and_comm()` extracts process group ID and command name from procfs entries
- `process_argv()` and `process_cwd()` read command-line arguments and current working directory from `/proc/<pid>/cmdline` and `/proc/<pid>/cwd` symlinks
- `session_processes()` identifies all PIDs belonging to the same session ID

**Signal Handling**

The `signal_processes()` function uses `libc::kill` to deliver signals to process groups, implementing the `Signal` enum variants defined in the public API.

**Clipboard Integration**

Linux clipboard handling detects the display server environment at runtime:
- **Wayland**: Uses `wl-copy` and `wl-paste` when `WAYLAND_DISPLAY` is present
- **X11**: Falls back to `xclip` or `xsel` when `DISPLAY` is set
- **Reading images**: Executes `wl-paste` or `xclip` with size limits to prevent memory exhaustion

**System Integration**

- `open_url()` invokes `xdg-open` to launch the default browser or application handler
- `show_desktop_notification()` executes `notify-send` when an X server is available
- `raise_server_nofile_limit()` currently exists as a stub preparing for future file descriptor limit adjustments

## macOS Implementation (src/platform/macos.rs)

[`src/platform/macos.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/platform/macos.rs) replaces Linux's procfs approach with macOS-specific `proc_*` syscalls and system frameworks, providing equivalent functionality through the BSD process management interface.

**Process Inspection via proc_* Syscalls**

macOS uses the `libproc` API for process enumeration and inspection:

- `foreground_job()` calls `libc::proc_pidinfo` with `PROC_PIDTBSDINFO` to obtain the `e_tpgid` (terminal process group ID), then uses `proc_listpids` to enumerate all PIDs in that process group
- `process_argv()` implements `kern_procargs2` via `sysctl(KERN_PROCARGS2)` to read the complete argument vector, accurately capturing process titles even after modification
- `process_cwd()` retrieves the current working directory through `proc_pidinfo(PROC_PIDVNODEPATHINFO)` and the `pvi_cdir.vip_path` field
- `session_processes()` groups processes using `libc::getsid` to identify session leaders

**Signal Handling**

Like Linux, macOS uses `libc::kill` for delivering signals to processes, maintaining API consistency across platforms.

**Clipboard and System Integration**

- `write_clipboard()` invokes the native `pbcopy` command
- `open_url()` uses the macOS `open` command
- `show_desktop_notification()` first attempts to use `terminal-notifier` (allowing terminal activation), falling back to an AppleScript `osascript` notification if the former is unavailable
- `read_clipboard_image()` executes an AppleScript that extracts PNG data from the system clipboard into a temporary file

**Terminal Detection**

The macOS implementation includes helpers to detect the current terminal emulator via `TERM_PROGRAM`, `TERM`, and window-ID environment variables, enabling notifications to correctly activate the originating terminal window.

## Fallback Implementation (src/platform/fallback.rs)

For targets other than Linux and macOS, [`src/platform/fallback.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/platform/fallback.rs) provides safe no-op implementations that compile successfully but return empty results or errors. This guarantees that the herdr codebase remains portable and compiles on unsupported platforms without modification, though runtime functionality is limited.

Each function in the fallback module mirrors the public API signatures, ensuring type compatibility while gracefully degrading when OS-specific features are unavailable.

## Practical Usage Examples

The following examples demonstrate how consuming code interacts with the platform layer without conditional compilation:

### Open a URL in a Platform-Agnostic Way

```rust
use herdr::platform::open_url;

fn launch_manual() -> std::io::Result<()> {
    // Resolves to xdg-open on Linux, open on macOS
    open_url("https://herdr.dev")?;
    Ok(())
}

```

### Write Text to the System Clipboard

```rust
use herdr::platform::write_clipboard;

fn copy_my_text(text: &str) -> bool {
    // Linux: wl-copy/xclip, macOS: pbcopy, Other: returns false
    write_clipboard(text.as_bytes())
}

```

### Show a Desktop Notification

```rust
use herdr::platform::show_desktop_notification;

fn notify(title: &str, body: Option<&str>) {
    // Linux uses notify-send, macOS uses terminal-notifier or AppleScript
    let _ = show_desktop_notification(title, body);
}

```

### Retrieve Foreground Job Information

```rust
use herdr::platform::foreground_job;

fn list_foreground_processes(pid: u32) {
    if let Some(job) = foreground_job(pid) {
        for proc in job.processes {
            println!("{} (pid {})", proc.name, proc.pid);
        }
    } else {
        println!("No foreground job found for pid {}", pid);
    }
}

```

## Summary

- **Centralized abstraction**: [`src/platform/mod.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/platform/mod.rs) defines types like `ForegroundProcess` and functions like `foreground_job()`, hiding OS differences behind a unified API.
- **Linux implementation**: Located in [`src/platform/linux.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/platform/linux.rs), uses `/proc` filesystem parsing, `libc::kill`, and external commands including `xdg-open`, `wl-copy`, and `notify-send`.
- **macOS implementation**: Located in [`src/platform/macos.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/platform/macos.rs), leverages `proc_pidinfo`, `sysctl(KERN_PROCARGS2)`, `pbcopy`, and AppleScript for equivalent functionality.
- **Fallback safety**: [`src/platform/fallback.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/platform/fallback.rs) provides no-op stubs ensuring compilation on unsupported platforms.
- **Zero GUI dependencies**: Both platforms shell out to command-line tools rather than linking GUI frameworks, keeping the binary lightweight.

## Frequently Asked Questions

### What is the purpose of the src/platform directory in herdr?

The `src/platform` directory isolates operating system-specific code from the rest of the application. It defines a common API in [`mod.rs`](https://github.com/ogulcancelik/herdr/blob/main/mod.rs) and provides separate implementations for Linux ([`linux.rs`](https://github.com/ogulcancelik/herdr/blob/main/linux.rs)), macOS ([`macos.rs`](https://github.com/ogulcancelik/herdr/blob/main/macos.rs)), and unsupported systems ([`fallback.rs`](https://github.com/ogulcancelik/herdr/blob/main/fallback.rs)). This architecture allows the rest of herdr to call platform functions without knowing which operating system is running.

### How does herdr handle clipboard operations differently on Linux and macOS?

On Linux, [`src/platform/linux.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/platform/linux.rs) detects the display server by checking `WAYLAND_DISPLAY` or `DISPLAY` environment variables, then calls `wl-copy`/`wl-paste` for Wayland or `xclip`/`xsel` for X11. On macOS, [`src/platform/macos.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/platform/macos.rs) simply invokes the built-in `pbcopy` command. For reading clipboard images, Linux uses the same command-line tools with size limits, while macOS executes an AppleScript to extract PNG data to a temporary file.

### Why does the macOS implementation use proc_pidinfo instead of /proc?

macOS does not provide a `/proc` filesystem like Linux. Instead, [`src/platform/macos.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/platform/macos.rs) uses the `proc_*` family of system calls available in `libproc`, such as `proc_pidinfo` with `PROC_PIDTBSDINFO` and `PROC_PIDVNODEPATHINFO`, to retrieve process group information, arguments, and current working directories. This provides equivalent functionality to Linux's procfs using native BSD-derived APIs.

### What happens when herdr is compiled on Windows or other unsupported platforms?

When the target is neither Linux nor macOS, the build system selects [`src/platform/fallback.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/platform/fallback.rs), which provides stub implementations that return empty results or errors. This ensures the codebase compiles successfully on any Rust-supported platform, though OS-specific features like clipboard access and process enumeration will not function at runtime.