Locates and speaks to the forcola_shim binary.
The shim is a Rust port program (source under native/forcola_shim).
Release builds are published per target to GitHub Releases and fetched
at compile time with SHA256 verification, so consumers need no Rust
toolchain; a locally built binary in priv/ takes precedence during
development.
Wire protocol (BEAM <-> shim), v0, documented in full in
native/forcola_shim/src/main.rs:
Frames are {:packet, 4}-style: a 4-byte big-endian length prefix
(handled by the Erlang port itself), then a 1-byte tag, then the
payload. This module owns the tag constants and the JSON payload
shapes for SPAWN/EXIT/ERROR; Forcola.run/2 drives the protocol.
Summary
Functions
Closes the port and drains its remaining relayed messages.
Decodes the contained flag from an EXIT frame payload.
Decodes an ERROR frame payload into its reason string.
Decodes an EXIT frame payload into {status_or_signal, timed_out}.
Decodes the native EXIT report without discarding the observed child status
when cleanup was unconfirmed. decode_exit/1 retains its legacy status shape.
Encodes a CREDIT frame payload: an 8-byte big-endian byte count.
Encodes a SPAWN frame payload from Forcola.run/2 options.
Opens the shim binary as a port, framed with {:packet, 4}.
Absolute path to the shim binary for the current target.
Sends a tagged frame to the shim port.
Functions
@spec close(port()) :: :ok | {:error, :guard_close_timeout}
Closes the port and drains its remaining relayed messages.
Call once from the process that opened the port, after consuming its result.
The OS port is closed synchronously; draining normally finishes immediately.
If the guard itself fails to finish, draining is bounded by five seconds and
returns {:error, :guard_close_timeout}.
Decodes the contained flag from an EXIT frame payload.
true when Linux cgroup v2 containment was actually active for the run;
false on the default path, on fallback (macOS, no cgroup v2, or no
delegated subtree), and whenever the field is absent (older shim). Reports
which kill mechanism was used.
Decodes an ERROR frame payload into its reason string.
@spec decode_exit(binary()) :: {non_neg_integer() | {:signal, atom() | non_neg_integer()}, boolean()}
Decodes an EXIT frame payload into {status_or_signal, timed_out}.
A new shim reports confirmed: false when its bounded cleanup probes still
observed a live process group or cgroup. That maps to
{:signal, :unconfirmed} in every execution mode. The field defaults to true
when absent for compatibility with older shims.
Decodes the native EXIT report without discarding the observed child status
when cleanup was unconfirmed. decode_exit/1 retains its legacy status shape.
@spec encode_credit(non_neg_integer()) :: binary()
Encodes a CREDIT frame payload: an 8-byte big-endian byte count.
Grants the pump selected by the frame tag that many more bytes of read
budget. Forcola.Stream uses stdout credit; bounded Forcola.Duplex
grants separate stdout and stderr credit.
Encodes a SPAWN frame payload from Forcola.run/2 options.
Shared by all four modes. Besides :cd/:env/:merge_stderr/:timeout_ms/
:kill_grace_ms and the pty options, it threads :user and :group (each a
string name or an integer id) through to the shim so the child can be run as a
different user; see Forcola.run/2 for the semantics.
:cgroup opts into Linux cgroup v2 containment. Only added to the payload
when truthy, so the default SPAWN payload is unchanged; the shim defaults it
to false when the key is absent. See Forcola.run/2 for the Linux-only,
delegation-required, graceful-fallback semantics.
:window_bytes opts into demand-driven backpressure on the child's stdout
(see Forcola.Stream.lines/2). Only added to the payload when present, so
the default SPAWN payload is unchanged; the shim gates its stdout pump when
the field is present and reads eagerly otherwise. Duplex pull mode also
supplies :stderr_window_bytes and :strict_output so both pumps stay
gated until output is consumed or explicitly discarded.
Opens the shim binary as a port, framed with {:packet, 4}.
The caller controls the returned port: send it SPAWN/STDIN/EOF/KILL
frames via send_frame/2 and receive {port, {:data, <<tag, payload::binary>>}}
messages for STDOUT/STDERR/EXIT/ERROR frames.
A guard process owns the port and relays its messages in order. It monitors
the caller and closes the port if the caller dies. This retains EOF-driven
process cleanup without letting a broken shim's port errors (such as
:epipe) kill the caller or change the caller's exit-trapping behavior.
When finished, the opening process should call close/1 to close the port
and drain the guard's remaining messages.
Accepts the trusted :shim_path override documented in path/1.
Synchronous operating-system errors opening the port return
{:error, {:shim_start_failed, reason}}.
Absolute path to the shim binary for the current target.
Returns {:error, :not_found} if no binary has been built or
downloaded yet. An explicit :shim_path overrides discovery and must
name an absolute path to a regular file with executable permissions.
Invalid overrides return {:error, {:invalid_shim_path, reason}}.
The override is trusted executable code. The caller must supply the matching Forcola shim for this version and target, protect the file and its ancestor directories from replacement, and own its lifetime and cleanup. Symlinks are followed and must satisfy the same trust contract. Validation does not authenticate the binary or prevent path replacement.
@spec send_frame(port(), non_neg_integer(), iodata()) :: boolean()
Sends a tagged frame to the shim port.
Returns false if the port has already closed. The caller still receives
the terminal port event and handles it through its ordinary shim-death path.