3.3 Field Formats

Rules that apply to how a field's value is written, as distinct from what it means.

3.3.1 Strings #

A string field that is present is non-empty, unless this section says otherwise for that field. Three fields treat the empty string as absence:

  • Identity — empty is the same as absent, and defaults to LocalService.
  • HookIdentity — empty is the same as absent, and falls back to the service's Identity.
  • DisplayName and Description — empty is the same as absent.

WorkingDirectory, when present, is a non-empty absolute path. Whether it exists, is a directory, and is reachable is checked when the service starts, not when the definition is read.

TTYPath is checked for emptiness before absoluteness: an empty value means no terminal, and a non-empty relative path is rejected.

3.3.2 Identity and HookIdentity #

Either a well-known principal name — SYSTEM, LocalService, NetworkService — matched case-insensitively and canonicalised, or a literal SID string such as S-1-5-18. Anything else is passed to authd verbatim to resolve (§4.3).

3.3.3 RequiredPrivileges #

Privilege names, matched case-sensitively against the published privilege table. A name that does not match exactly fails token materialisation and therefore the service start, so SeTCBPrivilege does not start a service that SeTcbPrivilege would.

3.3.4 RuntimeDirectories #

Each entry names one directory directly under /run. Entries are non-empty relative names; an entry equal to . or .. is rejected, as is any entry containing /, \, a NUL, or a control character. A dot inside a name is fine — app.sock.d is a valid entry.

For an entry foo, peinit creates /run/foo immediately before launching the service's main process, with a descriptor granting full access to SYSTEM, Administrators, and the service's own SID. Hook processes inherit the service's environment and identity rules but do not cause provisioning — the directories belong to the main start.

If creation or descriptor assignment fails, the start fails with ParentSetupFailure.

peinit does not remove runtime directories when a service stops. /run is a boot-scoped tmpfs and the next boot clears it.

3.3.5 Environment #

Each entry is KEY=VALUE, with a non-empty key containing no NUL. An entry that does not split into that shape is a decode error.

3.3.6 SuccessExitCodes #

Each entry is a decimal integer from 0 to 255 — a process exit code. Signal names and ranges are not accepted. Code 0 is always success and does not need listing. Duplicates are collapsed.

3.3.7 Dependency and handler names #

Entries in Requires, Wants, BindsTo and Conflicts, and the value of OnFailure, are validated as service names when the definition is read. A dependency naming something outside [A-Za-z0-9._-] is a decode error rather than an unresolved dependency discovered later — the difference being that a typo containing an illegal character is caught immediately, while a typo that is still a legal name is caught at graph validation as a missing target.

3.3.8 Timeouts and intervals #

Every timeout and interval in the schema is in whole seconds unless the field says otherwise. The two sd_notify fields that carry durations, WATCHDOG_USEC and EXTEND_TIMEOUT_USEC, are in microseconds because that is what the protocol specifies.

3.3.9 Identifiers peinit generates #

Job identifiers, operation identifiers, and every other GUID peinit mints are UUIDv7. UUIDv7 is time-ordered, so identifiers sort by creation time — which is what keeps eventd's time-range and recency queries over jobs and operations cheap.

Edit this page