Documentation
¶
Overview ¶
Package daemonlifecycle provides the small cross-platform primitives shared by CLI daemons: owner-only state paths, advisory file locking, detached process start, and process identity.
It deliberately does not own a daemon's state machine, readiness protocol, timeouts, or recovery policy. Those remain product decisions. This package only keeps the security- and OS-sensitive mechanics identical across CLI implementations.
Index ¶
- Variables
- func ConfigureDetached(command *exec.Cmd)
- func Lock(ctx context.Context, file *os.File, interval time.Duration) error
- func ProcessIdentity(pid int) (string, error)
- func ProtectOwnerOnly(path string) error
- func ProtectOwnerOnlyFile(file *os.File) error
- func StartDetached(template *exec.Cmd, log *os.File) (*os.Process, error)
- func TerminateIfSameProcess(pid int, identity string) error
- func TryLock(file *os.File) (bool, error)
- func Unlock(file *os.File) error
- func ValidateOwnerOnly(path string) error
- func ValidateOwnerOnlyFile(file *os.File) error
Constants ¶
This section is empty.
Variables ¶
var ErrProcessMismatch = errors.New("process identity does not match")
ErrProcessMismatch reports that the pid now belongs to a different process than the one whose identity was recorded, typically after pid reuse.
var ErrProcessNotFound = errors.New("process not found")
ErrProcessNotFound reports that no running process has the requested pid. Exited processes that have not been reaped yet (zombies) count as not found.
Functions ¶
func ConfigureDetached ¶ added in v0.13.0
ConfigureDetached puts command's child in its own session, so it survives the process that started it, has no controlling terminal, and a later process-group signal stays scoped to that child and its descendants.
On Windows it sets DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP | CREATE_BREAKAWAY_FROM_JOB and hides the window. Starting such a command fails with ERROR_ACCESS_DENIED inside a job that forbids breakaway; StartDetached handles that retry.
func Lock ¶
Lock waits for an exclusive advisory lock, polling at interval until ctx is cancelled. A non-positive interval uses 25 milliseconds.
func ProcessIdentity ¶ added in v0.13.0
ProcessIdentity returns an opaque token that names the running process pid for its whole life, so a pid recorded together with its identity can later be checked against the process that holds the pid now. Two calls for the same process return equal strings; a process that later reuses the pid gets a different one. Compare tokens only for equality and do not parse them.
The token is built from values the kernel records once and never recomputes, so wall-clock steps do not change it: on Linux the boot id plus the start time in clock ticks since boot, on macOS the kernel's start timeval, and on Windows the creation FILETIME.
It returns an error wrapping ErrProcessNotFound when no running process has that pid. It is implemented for Linux, macOS and Windows without cgo; other platforms return an error.
func ProtectOwnerOnly ¶
ProtectOwnerOnly makes the current user the owner and replaces path's access policy with one granting access only to that user. Directories keep inheritable permissions for children.
func ProtectOwnerOnlyFile ¶
ProtectOwnerOnlyFile makes the current user the owner and replaces an already-open file's access policy with one granting access only to that user. Consumers must subsequently call ValidateOwnerOnlyFile before trusting the handle. On Windows, applying the policy uses the file name because ordinary os.OpenFile handles do not carry WRITE_DAC; the handle-based validation detects any path replacement.
func StartDetached ¶ added in v0.13.0
StartDetached starts the program described by template as a process that outlives its caller and never holds the caller's standard streams.
Only template's Path, Args, Env and Dir are used; template itself is never started, so its Stdin, Stdout, Stderr, ExtraFiles, SysProcAttr, Cancel and WaitDelay must be unset: a detached child does not follow a context. The child reads from the null device and writes both output streams to log, which the caller owns and may close once StartDetached returns. No other handle is inherited: on Unix every other descriptor is close-on-exec, and on Windows only the three standard handles are listed for inheritance. A caller whose own stdout is a pipe therefore sees EOF as soon as it exits, even while the child keeps running.
The child is configured with ConfigureDetached. On Windows, when the caller's job object forbids CREATE_BREAKAWAY_FROM_JOB and process creation fails with ERROR_ACCESS_DENIED, StartDetached retries once without the breakaway flag; that child stays in the job and dies with it, which the caller detects as a readiness failure.
The returned process is the caller's to Wait on (to observe an early exit) or Release. Readiness, timeouts and stopping remain the caller's policy.
func TerminateIfSameProcess ¶ added in v0.13.0
TerminateIfSameProcess forcibly terminates pid only when its current identity equals identity, as returned earlier by ProcessIdentity. Otherwise it returns an error wrapping ErrProcessMismatch (or ErrProcessNotFound) and sends nothing.
On Windows the check and the termination use one process handle, so the pid cannot be reused in between. On Unix the check is immediately followed by SIGKILL; a pid reused within that instant is not distinguishable.
func ValidateOwnerOnly ¶
ValidateOwnerOnly verifies that path is a regular file or directory whose effective access policy grants access only to the current user.
func ValidateOwnerOnlyFile ¶
ValidateOwnerOnlyFile verifies the effective policy of an already-open regular file. Consumers that make security decisions after opening a lock or state file should prefer this handle-based form.
Types ¶
This section is empty.