proc

package
v0.2.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package proc is the process boundary: the one subprocess gateway in CSF. Starting another program crosses into another address space through fork and exec, so it happens only through a capability granted by the binary that owns the process, and this is the only package in candace/ that imports os/exec.

A binary constructs one HostLauncher and passes it, as an ILauncher, to whatever needs to run a program; a service receives the capability in its constructor and never builds an exec.Cmd itself. The gateway owns the whole life of a child:

  • launch: an argument vector, never a shell string, in an explicit directory and environment;
  • input and output: caller-supplied readers and writers, or captured output returned as a structured Result;
  • cancellation: the context passed to HostLauncher.Run or HostLauncher.Start bounds the child, and canceling it kills the child's whole process group, so a shell's own children die with it;
  • waiting and cleanup: HostLauncher.Run always reaps its child, and a started Process is reaped by Process.Wait, so no child is left a zombie.

The package starts no goroutines of its own. The copying goroutines os/exec runs for non-file writers, and the one that watches a context, are owned by the call: they start in Run or Start and are joined by the Wait that completes it.

Index

Constants

View Source
const (
	// DefaultWaitDelay bounds how long Wait keeps reading a canceled child's
	// output pipes after the kill: a grandchild that escaped the group must
	// not hold the caller forever.
	DefaultWaitDelay = 5 * time.Second
	// DefaultDiagnosticBytes bounds captured standard error.
	DefaultDiagnosticBytes = 64 << 10
)

Variables

View Source
var (
	// ErrTerminalRun is returned when a terminal is requested from Run: an
	// interactive terminal belongs to a started [Process].
	ErrTerminalRun = errors.New("ipc/proc: a terminal command must be started, not run")
	// ErrStreamConflict is returned for a command whose stream fields
	// contradict each other.
	ErrStreamConflict = errors.New("ipc/proc: conflicting standard stream configuration")
	// ErrExecutableRequired is returned for a command with no executable.
	ErrExecutableRequired = errors.New("ipc/proc: executable is required")
	// ErrInvalidOption is returned by NewHostLauncher for a nil or
	// out-of-range option.
	ErrInvalidOption = errors.New("ipc/proc: invalid launcher option")
	// ErrNoTerminal is returned by Resize on a process started without one.
	ErrNoTerminal = errors.New("ipc/proc: process has no terminal")
)

Functions

This section is empty.

Types

type Command

type Command struct {
	// Executable is a path, or a name resolved on PATH.
	Executable string
	// Arguments follow the executable in the argument vector.
	Arguments []string
	// Directory is the working directory; empty means the caller's.
	Directory string
	// Environment replaces the inherited environment when non-nil.
	Environment []string
	// ExtraEnvironment is appended to the environment the child receives,
	// inherited or replaced, so a caller adds a variable without reading the
	// process environment itself.
	ExtraEnvironment []string
	// Stdin is the child's standard input; nil means none.
	Stdin io.Reader
	// Stdout receives standard output. When nil it is captured into
	// [Result.Stdout] (unbounded, like exec.Cmd.Output), unless StdoutPipe
	// is set on a started process.
	Stdout io.Writer
	// Stderr receives standard error. When nil it is captured, bounded by the
	// launcher's diagnostic limit, into [Result.Stderr] and [ExitError],
	// whose message then carries it. A caller whose child's diagnostics may
	// hold secrets passes io.Discard to keep them out of every error.
	Stderr io.Writer
	// StdoutPipe exposes standard output as [Process.Stdout] on a started
	// process. Read it to the end before Wait.
	StdoutPipe bool
	// Terminal attaches the child to a new pseudo-terminal of this size, in
	// its own session. Stdin, Stdout and Stderr must be nil: the terminal is
	// all three, read and written through [Process.Terminal].
	Terminal *TerminalSize
}

Command is one program invocation.

type ExitError

type ExitError struct {
	Executable string
	Code       int
	Stderr     []byte
	// contains filtered or unexported fields
}

ExitError reports a child that ran and exited unsuccessfully.

func (*ExitError) Error

func (exitError *ExitError) Error() string

Error names the program, its status and, when captured, its diagnostics.

func (*ExitError) Unwrap

func (exitError *ExitError) Unwrap() error

Unwrap exposes the operating system's report.

type HostLauncher

type HostLauncher struct {
	// contains filtered or unexported fields
}

HostLauncher is this host's process table, granted as a capability.

func NewHostLauncher

func NewHostLauncher(options ...HostLauncherOption) (*HostLauncher, error)

NewHostLauncher returns the host's process capability.

func (*HostLauncher) LookPath

func (launcher *HostLauncher) LookPath(name string) (string, error)

LookPath resolves name on PATH.

func (*HostLauncher) Run

func (launcher *HostLauncher) Run(ctx context.Context, command Command) (Result, error)

Run starts command, waits for it, and returns its result. A child that exits unsuccessfully returns an *ExitError; a canceled context kills the child's process group and returns the context's cause. The result carries whatever output was captured in every case.

func (*HostLauncher) Start

func (launcher *HostLauncher) Start(ctx context.Context, command Command) (*Process, error)

Start launches command. The returned process must be waited for; the context bounds it exactly as it bounds Run, so a child meant to outlive a request is started with a context that does not end with the request.

type HostLauncherOption

type HostLauncherOption func(launcher *HostLauncher) error

HostLauncherOption configures a HostLauncher.

func WithDiagnosticBytes

func WithDiagnosticBytes(limit int64) HostLauncherOption

WithDiagnosticBytes bounds captured standard error.

func WithWaitDelay

func WithWaitDelay(delay time.Duration) HostLauncherOption

WithWaitDelay bounds how long a canceled child's pipes are drained.

type ILauncher

type ILauncher interface {
	// Run starts command, waits for it and returns its structured result.
	Run(ctx context.Context, command Command) (Result, error)
	// Start launches command and returns the running process, which the
	// caller must Wait for.
	Start(ctx context.Context, command Command) (*Process, error)
	// LookPath resolves an executable name the way Run would.
	LookPath(name string) (string, error)
}

ILauncher runs programs. It is the process-boundary capability.

type Process

type Process struct {
	// contains filtered or unexported fields
}

Process is one started child. Exactly one goroutine calls Process.Wait; Process.Kill, Process.Signal and Process.Resize may be called from any goroutine before or during that Wait.

func (*Process) Kill

func (process *Process) Kill() error

Kill ends the child and everything it started: its process group, and for a terminal every process in its session, including background jobs a shell moved into groups of their own. It does not wait; Wait reaps the child.

func (*Process) Pid

func (process *Process) Pid() int

Pid is the child's process identifier; for a terminal it is also the session and process-group identifier.

func (*Process) Resize

func (process *Process) Resize(size TerminalSize) error

Resize changes a terminal command's window size.

func (*Process) Signal

func (process *Process) Signal(signal os.Signal) error

Signal delivers signal to the child alone, the way an interrupt asks a program to run its own shutdown.

func (*Process) Stdout

func (process *Process) Stdout() io.Reader

Stdout is standard output when the command asked for StdoutPipe, else nil. Read it to the end before Wait.

func (*Process) Terminal

func (process *Process) Terminal() *os.File

Terminal is the controlling side of a terminal command's pseudo-terminal, else nil. The process owns it: Wait closes it.

func (*Process) Wait

func (process *Process) Wait() (Result, error)

Wait blocks until the child exits, reaps it and returns its result, with the same error semantics as HostLauncher.Run.

type Result

type Result struct {
	// ExitCode is the child's exit status, or -1 if it was killed by a
	// signal or never ran.
	ExitCode int
	// Stdout is captured standard output when Command.Stdout was nil.
	Stdout []byte
	// Stderr is captured standard error when Command.Stderr was nil.
	Stderr []byte
	// StderrTruncated reports that captured standard error exceeded the
	// diagnostic limit and only its prefix was kept.
	StderrTruncated bool
}

Result is what a finished child left behind.

type TerminalSize

type TerminalSize struct {
	Rows    uint16
	Columns uint16
}

TerminalSize is a pseudo-terminal window in character cells.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL