Skip to main content

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;