epics_tools_rs/lib.rs
1//! Operational tooling for EPICS deployments.
2//!
3//! ## First tenant: `procserv`
4//!
5//! Rust port of `epics-modules/procServ` — a PTY-based process
6//! supervisor with multi-client telnet console. The C implementation
7//! has these load-bearing pieces; their Rust equivalents in this
8//! crate are listed alongside:
9//!
10//! | C source | Rust module |
11//! |---------------------------------------|----------------------------|
12//! | `procServ.cc` (main, SendToAll) | [`procserv::supervisor`] |
13//! | `processFactory.cc` (PTY child) | [`procserv::child`] |
14//! | `acceptFactory.cc` (TCP/UNIX listen) | [`procserv::listener`] |
15//! | `clientFactory.cc` (per-client conn) | [`procserv::client`] |
16//! | libtelnet IAC parser/encoder | [`procserv::telnet`] |
17//! | `processInput` command-key dispatch | [`procserv::menu`] |
18//! | `processFactoryNeedsRestart` policy | [`procserv::restart`] |
19//! | `forkAndGo` daemonize + signals | [`procserv::daemon`] |
20//! | log/info/pid file + PROCSERV_INFO env | [`procserv::sidecar`] |
21//!
22//! ## Architectural notes (from porting analysis)
23//!
24//! * **Hub-and-spoke fan-out**, not direct broadcast. The C version's
25//! `SendToAll(buf, count, sender)` excludes the sender from the
26//! party-line; we get the same semantics naturally with a single
27//! supervisor task that forwards each per-connection mpsc message
28//! to every other connection's mpsc. `tokio::sync::broadcast` would
29//! re-deliver to the sender — extra filtering required.
30//!
31//! * **No "master" role**. Permissions are per-connection
32//! (`readonly: bool`), set at construct time. Every non-readonly
33//! client can input. The PTY child is itself a connection, so
34//! client input flowing through the supervisor naturally reaches
35//! the child's stdin via the PTY-master fd. Matches C
36//! `connectionItem::_readonly` model.
37//!
38//! * **Stateless command-key dispatch**, not a menu FSM. Each input
39//! byte is matched against the configured `restartChar`/`killChar`/
40//! `toggleRestartChar`/`logoutChar`/`quitChar` and acted on
41//! immediately. The keys are still echoed to other connections.
42//!
43//! * **Narrow telnet usage**. Only `IAC WILL ECHO` + `IAC DO
44//! LINEMODE` negotiated; only DATA/SEND/ERROR events handled. The
45//! in-crate [`procserv::telnet`] parser is ~80 LOC, vendoring
46//! `libtelnet.c` is unnecessary.
47//!
48//! * **Unix-only initially**. C procServ requires `forkpty(3)` and
49//! POSIX signals. Cross-platform support (ConPTY on Windows) is
50//! future work; the whole `procserv` module is `#[cfg(unix)]`-gated
51//! so workspace builds on non-Unix succeed but the binary is
52//! unavailable.
53
54#![cfg_attr(docsrs, feature(doc_cfg))]
55
56#[cfg(all(feature = "procserv", unix))]
57pub mod procserv;