# 3.1 Services

_Peios / Advanced Peios / peinit / The Service Model_

> The primary unit of management — names, the two service types, and how a forking daemon differs from a simple one.

A service is the primary unit of management: a definition in the
registry, a runtime state, a Security Descriptor, and at most one
running main process. Definitions live under
`Machine\System\Services\<name>`, where the key name *is* the service
name. peinit reads them at Phase 2 boot and on an explicit
reload-config.

## 3.1.1 Names

A service name is 1 to 128 bytes drawn from `[A-Za-z0-9._-]`. Any other
byte makes the name invalid.

Two exclusions are deliberate. `/` is out because names map directly
onto cgroup identifiers (§5.1) and onto registry key names, and a name
containing a separator would mean something different in each. `:` is
reserved for peinit's own synthetic naming.

## 3.1.2 The two types

### 3.1.2.1 Simple

A long-running daemon. peinit forks, installs a token, and execs the
binary; the process *is* the service. When it exits, the service has
stopped. This is the default and covers nearly everything — registryd,
authd, sshd, application services.

Readiness comes from the `Readiness` field. `Notify`, the default,
waits for `READY=1`. `Alive` treats the process as ready the moment it
exists.

The service goes Active on readiness and stays Active until the process
exits or something stops it.

### 3.1.2.2 Oneshot

A run-to-completion task: database initialisation, a schema migration, a
directory that has to exist. peinit forks, installs a token, execs, and
waits for the exit.

`Readiness` is ignored. A Oneshot's readiness is always "it exited
successfully", because `READY=1` is meaningless from a process whose job
is to finish. Success means exit code 0, or any code listed in
`SuccessExitCodes`.

The differences from Simple are:

- A successful exit goes to Completed. With `RemainAfterExit=1` it stays
  there; without, it passes through Completed to release dependents and
  then goes Inactive.
- A non-zero exit goes to Failed.
- `ExecStartPost` runs after the successful exit rather than after a
  readiness signal, and does not run at all if the Oneshot failed.
- `StartTimeout` covers the entire execution, from the first pre-hook to
  the process exiting.

`RemainAfterExit` matters when the Completed state itself is the useful
information — so a status query shows a migration as finished rather
than as inactive.

## 3.1.3 Forking daemons

peinit does not support them. A service that double-forks to daemonise
itself is working around a problem that does not exist when the service
manager tracks the process it spawned, and peinit tracks its child
through a pidfd obtained at fork. There is no `MAINPID=`, and no way to
point supervision at a different process.

A legacy binary that insists on double-forking is wrapped by whoever
packages it — a script with a `--no-daemon` flag, typically. That is a
packaging concern.
