Process Management with Procd

Procd – Process Manager Internals

What is procd?

Procd (Process Daemon) is the core process management system in OpenWrt. It replaces traditional Unix init systems like SysVinit with a more lightweight and OpenWrt-optimized approach.

Procd is responsible for:

  1. Managing the lifecycle of system services.
  2. Providing a standard API for defining and controlling services.
  3. Handling service dependencies and startup order.
  4. Monitoring services and restarting them when necessary.
  5. Processing system events and hotplug notifications.

As the primary service management system, procd works closely with other OpenWrt subsystems through ubus (OpenWrt’s micro bus architecture) to coordinate system functions.


Procd Architecture

  flowchart LR
  %% System Components
  subgraph SC [System Components]
	IS["Init Scripts<br>/etc/init.d/*"]
	UB["ubus CLI"]
	CF["Config Files<br>/etc/config/*"]
  end

  %% Procd System
  subgraph PS [Procd System]
	INIT["init process"]
	PROCD["procd daemon"]
	UBUSD["ubusd"]
	HPH["Hotplug Handler"]
	SS["System Services"]
  end

  %% Flows from system components
  IS --> |"Uses procd API<br>(procd_open_service, etc.)"| PROCD
  UB --> |"Service Control<br>(start/stop)"| PROCD
  CF --> |"Trigger changes"| PROCD

  %% Internal procd system flows
  INIT -->|Starts| PROCD
  PROCD -->|Monitors| SS
  SS --> PROCD
  PROCD -->|Status updates| SS
  PROCD -->|Listens on| UBUSD
  PROCD -->|Processes| HPH

Procd consists of several components:

  • Main procd daemon: The core process that manages services
  • procd-ujail: Process isolation using Linux namespaces
  • procd-seccomp: System call filtering for security
  • uxc: Container management for OpenWrt

Procd is started early in the boot process and is responsible for initializing the system and starting other services. It communicates with other system components via ubus, which provides a lightweight IPC mechanism.


Service Management with Procd

How services work with Procd

  sequenceDiagram
  participant Init as Init Script
  participant API as procd API
  participant U as ubusd
  participant S as Service Process

  Init->>API: procd_open_service("name")
  Init->>API: procd_open_instance()
  Init->>API: procd_set_param command "/bin/service"
  Init->>API: procd_set_param respawn "3600 5 5"
  Init->>API: procd_close_instance()
  Init->>API: procd_close_service()
  API->>U: service set { ... }
  U->>S: Start service process
  S-->>U: Report status

  Note over S,U: If service crashes

  S--x U: Process dies
  U-->>API: Death notification
  API->>U: Restart service (respawn)
  U->>S: Start service process

Procd manages services through a standardized API that init scripts can use. The service definition process follows these steps:

  1. Open a service definition with procd_open_service
  2. Define one or more service instances with procd_open_instance and procd_close_instance
  3. Set parameters for each instance with procd_set_param
  4. Close the service definition with procd_close_service

Each service can have multiple instances, and each instance can have its own set of parameters.


Service Parameters

Procd supports a wide range of parameters for configuring services:

ParameterDescriptionExample
commandCommand line to executeprocd_set_param command /sbin/netifd
respawnRespawn settings (threshold, timeout, retry)procd_set_param respawn 3600 5 5
envEnvironment variablesprocd_set_param env PATH=/bin
dataCustom data for config change detectionprocd_set_param data config="value"
fileConfiguration files to monitorprocd_set_param file /etc/config/network
netdevNetwork device to monitorprocd_set_param netdev eth0
limitsResource limitsprocd_set_param limits core="unlimited"
userUser to run service asprocd_set_param user nobody
groupGroup to run service asprocd_set_param group nogroup
pidfileFile to write PID toprocd_set_param pidfile /var/run/service.pid
stdoutRedirect stdout to syslogprocd_set_param stdout 1
stderrRedirect stderr to syslogprocd_set_param stderr 1

These parameters allow fine-grained control over how services are started and managed.


Service Triggers

Procd can automatically restart services when certain events occur:

  flowchart TD

  %% Subgraph: Events
  subgraph Events
	E1["Config File<br>Change"]
	E2["Network Interface<br>State Change"]
	E3["Custom<br>Event"]
  end

  %% Subgraph: Trigger Types
  subgraph "Trigger Types"
	T1["Configuration Change<br>Trigger"]
	T2["Interface Change<br>Trigger"]
	T3["Raw Event<br>Trigger"]
  end

  %% Subgraph: Actions
  subgraph Actions
	A1["Reload<br>Service"]
	A2["Restart<br>Service"]
  end

  %% Connections
  E1 --> T1 --> A1
  E2 --> T2 --> A1
  E3 --> T3 --> A2

Service triggers include:

  1. Configuration triggers: Restart services when configuration files change
    procd_add_reload_trigger "network"
  2. Interface triggers: Restart services when network interfaces change
    procd_add_reload_interface_trigger "wan"
  3. Raw triggers: Custom triggers for specific events
    procd_add_raw_trigger "custom-event" 1000 /etc/init.d/service reload

These triggers ensure that services automatically adapt to system changes without manual intervention.


Integration with Init scripts

OpenWRT init scripts can use procd by setting USE_PROCD=1 at the beginning of the script. This enables procd-specific functions in the script.

Here’s how a typical procd-enabled init script is structured:

#!/bin/sh /etc/rc.common
START=10
USE_PROCD=1

start_service() {
	procd_open_instance
	procd_set_param command /usr/sbin/my-daemon
	procd_set_param respawn
	procd_close_instance
}

When USE_PROCD=1 is set, the rc.common framework transforms traditional init function calls:

Traditional FunctionProcd Equivalent
start()Calls start_service() and wraps it with procd API calls
stop()Calls stop_service() and uses procd to kill the service
reload()Calls reload_service() if it exists, otherwise restarts the service
status()Uses procd to check if the service is running

This makes it easy to convert existing init scripts to use procd.


Process Isolation Features

Procd provides several mechanisms for isolating and securing processes:

  flowchart TD

  %% Subgraph 1: Process Isolation
  subgraph ProcessIsolation [Process Isolation]
	A1["procd-ujail<br>Namespace Isolation"]
	A2["uxc<br>Container Management"]
	A3["procd-seccomp<br>System Call Filtering"]
  end

  %% Subgraph 2: Isolation Features
  subgraph IsolationFeatures [Isolation Features]
	B1["Linux Namespaces<br>(pid, net, mount)"]
	B2["Process Containerization"]
	B3["System Call Filtering"]
  end

  %% Subgraph 3: Security Benefits
  subgraph SecurityBenefits [Security Benefits]
	C1["Limited Process Visibility"]
	C2["Limited System Access"]
	C3["Limited Process Capabilities"]
  end

  %% Flow connections
  A1 --> B1 --> C1
  A2 --> B2 --> C2
  A3 --> B3 --> C3

procd-ujail

The ujail component provides namespace-based isolation for processes. It can be configured through the procd API:

procd_add_jail name [options]

Options include:

  • log: Enable logging
  • ubus: Allow access to ubus
  • procfs: Mount procfs in the jail
  • sysfs: Mount sysfs in the jail
  • ronly: Make root filesystem read-only
  • netns: Use a separate network namespace

procd-seccomp

The seccomp component provides system call filtering for processes, restricting what system calls they can make:

procd_set_param seccomp /etc/seccomp/profile.json

uxc - OpenWrt Container Management

Uxc provides container management capabilities built on top of procd-ujail. It allows running containerized applications on OpenWrt.


Event Handling and Hotplug

Procd handles system events through its hotplug mechanism, defined in hotplug.json. This configuration directs how procd responds to various system events like device addition/removal.

  flowchart TD
  A["System Event<br>(add/remove device)"]
  B["procd Hotplug<br>Handler"]
  C["hotplug.json<br>Rules"]
  D["Action<br>(create device node,<br>load firmware, etc.)"]

  A --> B
  B -->|Consult| C
  C -->|Define| D
  B -->|Execute| D

The hotplug handler processes events for:

  • Device addition and removal
  • Device node creation
  • Firmware loading
  • Button presses
  • USB serial devices

Procd also monitors configuration changes through the reload_config script, which compares current configuration with previous state and triggers events when differences are detected.


Procd API Reference

Shell API

The procd shell API provides functions for defining and managing services:

FunctionDescription
procd_open_serviceBegin a service definition
procd_close_serviceEnd a service definition
procd_open_instanceBegin a service instance definition
procd_close_instanceEnd a service instance definition
procd_set_paramSet a parameter for the current instance
procd_append_paramAppend to a parameter for the current instance
procd_add_validationAdd validation for service parameters
procd_add_reload_triggerAdd a configuration reload trigger
procd_add_reload_interface_triggerAdd a network interface reload trigger
procd_runningCheck if a service is running
procd_killKill a service

Example Service Definition

Here’s an example of defining a service using the procd API:

start_service() {
	# Create a new service instance
	procd_open_instance

	# Set the command to run
	procd_set_param command /usr/sbin/my-daemon --option value

	# Configure automatic respawning
	procd_set_param respawn 3600 5 5  # threshold timeout retry

	# Add dependency on a config file
	procd_set_param file /etc/config/myservice

	# Set resource limits
	procd_set_param limits core="unlimited"

	# Redirect output to syslog
	procd_set_param stdout 1
	procd_set_param stderr 1

	# Run as a specific user
	procd_set_param user nobody

	# Finalize the instance
	procd_close_instance
}

# Add configuration triggers
service_triggers() {
	procd_add_reload_trigger "myservice"
	procd_add_reload_interface_trigger "wan"
}