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:
- Managing the lifecycle of system services.
- Providing a standard API for defining and controlling services.
- Handling service dependencies and startup order.
- Monitoring services and restarting them when necessary.
- 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:
- Open a service definition with
procd_open_service
- Define one or more service instances with
procd_open_instance
andprocd_close_instance
- Set parameters for each instance with
procd_set_param
- 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:
Parameter | Description | Example |
---|---|---|
command | Command line to execute | procd_set_param command /sbin/netifd |
respawn | Respawn settings (threshold, timeout, retry) | procd_set_param respawn 3600 5 5 |
env | Environment variables | procd_set_param env PATH=/bin |
data | Custom data for config change detection | procd_set_param data config="value" |
file | Configuration files to monitor | procd_set_param file /etc/config/network |
netdev | Network device to monitor | procd_set_param netdev eth0 |
limits | Resource limits | procd_set_param limits core="unlimited" |
user | User to run service as | procd_set_param user nobody |
group | Group to run service as | procd_set_param group nogroup |
pidfile | File to write PID to | procd_set_param pidfile /var/run/service.pid |
stdout | Redirect stdout to syslog | procd_set_param stdout 1 |
stderr | Redirect stderr to syslog | procd_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:
- Configuration triggers: Restart services when configuration files change
procd_add_reload_trigger "network"
- Interface triggers: Restart services when network interfaces change
procd_add_reload_interface_trigger "wan"
- 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 Function | Procd 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 loggingubus
: Allow access to ubusprocfs
: Mount procfs in the jailsysfs
: Mount sysfs in the jailronly
: Make root filesystem read-onlynetns
: 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:
Function | Description |
---|---|
procd_open_service | Begin a service definition |
procd_close_service | End a service definition |
procd_open_instance | Begin a service instance definition |
procd_close_instance | End a service instance definition |
procd_set_param | Set a parameter for the current instance |
procd_append_param | Append to a parameter for the current instance |
procd_add_validation | Add validation for service parameters |
procd_add_reload_trigger | Add a configuration reload trigger |
procd_add_reload_interface_trigger | Add a network interface reload trigger |
procd_running | Check if a service is running |
procd_kill | Kill 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"
}