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 toLocalService.HookIdentity— empty is the same as absent, and falls back to the service'sIdentity.DisplayNameandDescription— 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.