epics-tools-rs 0.20.2

Operational tooling for EPICS deployments — process supervisors, log/audit dumpers, config validators. First tenant: procserv (Rust port of epics-modules/procServ).
Documentation

epics-tools-rs

Operational tooling for EPICS deployments — process supervisors, log/audit dumpers, config validators.

First tenant: procserv — a pure-Rust port of epics-modules/procServ. PTY-based process supervisor with a multi-client telnet console. Drop-in flag compatibility with C procServ, so existing wrapper scripts and systemd units do not need to be rewritten.

Unix-only (depends on forkpty(3) and POSIX signals). On non-Unix targets the crate compiles to an empty library so workspace builds keep succeeding; the procserv-rs binary is unavailable there.

Build

From the workspace root:

cargo build -p epics-tools-rs --release --bin procserv-rs
# binary: target/release/procserv-rs

The default features (procserv, procserv-bin) already pull in the binary; no extra --features flag is needed. To use the library only without the CLI dependencies (clap, tracing-subscriber):

[dependencies]
epics-tools-rs = { version = "*", default-features = false, features = ["procserv"] }

Run

procserv-rs mirrors the C procServ flag surface. Common shapes:

# Foreground, port 4051, supervising a softIoc
procserv-rs -f -p 4051 -- softIoc -d my.db

# Daemonized with log/pid/info files
procserv-rs -p 4051 \
    --logfile /var/log/ioc.log \
    --pidfile /var/run/ioc.pid \
    --info-file /var/run/ioc.info \
    --name myioc \
    -- softIoc -d my.db

# Bind to all interfaces (default is localhost only)
procserv-rs -f -p 4051 --allow -- softIoc -d my.db

# UNIX domain socket instead of TCP
procserv-rs -f --unixpath /tmp/ioc.sock -- softIoc -d my.db

Everything after -- is the child program and its argv.

Flags

Flag Description Default
-p, --port <PORT> TCP listen port
--allow Bind 0.0.0.0 instead of 127.0.0.1 off
--unixpath <PATH> UNIX-domain socket path
-f, --foreground Do not daemonize off
-L, --logfile <PATH> Log file
--pidfile <PATH> PID file
--info-file <PATH> PROCSERV_INFO info file
--holdoff <SEC> Hold-off between restarts 15
-w, --wait Do not start child until first console request off
--chdir <DIR> chdir before exec'ing child
--name <NAME> Display name in banners child basename
--max-restarts <N> Max restarts inside --restart-window 10
--restart-window <SEC> Sliding window for --max-restarts 600
--kill-char <BYTE> Force-kill key (Ctrl-X = 24, 0 disables) 24
--toggle-restart-char <BYTE> Toggle restart-mode key (Ctrl-T = 20) 20
--logout-char <BYTE> Per-client logout key (Ctrl-] = 29) 29

Connecting to the console

telnet localhost 4051
# or, for UNIX-socket listeners:
nc -U /tmp/ioc.sock

Multiple clients may connect simultaneously and share the child's stdout in a party-line fashion. Built-in keys:

  • Ctrl-X — force-kill the child (sends SIGKILL by default).
  • Ctrl-T — toggle restart mode (OnExit ↔ off).
  • Ctrl-R — manually restart the child when it is dead.
  • Ctrl-] — log this client out (child stays running).

Logging

procserv-rs uses the tracing ecosystem with an EnvFilter:

RUST_LOG=debug procserv-rs -f -p 4051 -- softIoc -d my.db
RUST_LOG=epics_tools_rs::procserv=trace procserv-rs ...

Use as a library

use epics_tools_rs::procserv::{ProcServ, ProcServConfig};

# async fn run(cfg: ProcServConfig) -> Result<(), Box<dyn std::error::Error>> {
let server = ProcServ::new(cfg)?;
server.run().await?;
# Ok(()) }

The end-to-end test at tests/procserv_e2e.rs shows a complete config literal with TCP listener, key bindings, restart policy and a /bin/cat child — useful as a copy-paste starting point.

Architecture

The C → Rust mapping is documented at the crate root in src/lib.rs. High-level points:

  • Hub-and-spoke fan-out via a single supervisor task forwarding per-connection mpsc messages, matching C SendToAll's exclude-the-sender semantics without tokio::sync::broadcast re-delivery.
  • Per-connection readonly flag instead of a master role.
  • Stateless command-key dispatch (no menu FSM); keys are still echoed to other connections.
  • Narrow telnet usage — only IAC WILL ECHO and IAC DO LINEMODE are negotiated, so the in-crate parser stays under ~80 LOC instead of vendoring libtelnet.c.

License

See LICENSE.