2.6 Boot Modes

peinit boots in one of three modes, forming an escalation path from normal operation to last-resort maintenance.

Full boot ---+-- success ----------------> counter reset, operational
             |
             +-- cycle w/ Critical ------> Safe mode (no reboot)
             |
             +-- conflict w/ Critical ---> Safe mode (no reboot)
             |
             +-- Critical failure -------> sync + reboot --+
                                                           |
Safe boot ---+-- success ----------------> counter reset,  |
             |   operational (reduced)                     |
             +-- Critical failure -------> sync + reboot --+
                                                           |
                             counter increments <----------+
                                        |
                             counter >= N ---------> Recovery mode
                             Phase 1 failure ------> Recovery mode

2.6.1 Full mode #

The default. Every boot-triggered service starts in dependency order, as §2.5 describes.

2.6.2 Safe mode #

Safe mode starts a reduced set. Eligibility is a filter within the boot-triggered set, not a replacement for it: a service with no boot trigger does not auto-start in Safe mode whatever its SafeMode or ErrorControl says, and remains demand-only. Within the boot-triggered set, two categories are eligible:

  • Critical services (ErrorControl=Critical) start. If one fails, the ordinary Critical failure path applies — restart budget, reboot, counter increment, eventually recovery.
  • SafeMode=1 services are attempted best-effort. If one fails, Safe mode continues without it.

ErrorControl=Critical implies SafeMode, so a Critical service does not have to declare both.

2.6.2.1 What caused the downgrade #

The rebuild discards the Full-mode graph, so a service that forced Safe mode and is then excluded from the rebuilt graph is never entered into the blocked set and never marked Failed. That is deliberate: Safe mode was never going to start it, and a Failed state would say something about its own health that is not true. status should keep meaning "this service is broken".

A service that survives into the rebuilt graph gets no such protection. Two Critical services that require each other are both eligible in Safe mode, so the rebuild contains the same cycle and blocks them both, exactly as it would anywhere else — and there is no order that could have started either.

The reason is therefore recorded at boot level rather than per service. Every finding that forced the downgrade — each critical cycle, each critical boot conflict — is written to the console and emitted as a peinit.boot.downgraded KMES event naming the services involved, an essential type the emission policy cannot switch off.

All of them are reported, not just the first. A machine can be downgraded by a cycle and a conflict at once, and an operator who fixed only the one they were shown would reboot straight back into Safe mode.

They stay available for the rest of the boot: the control socket's boot command reports the mode, why, and every finding (§10.8).

peinit rebuilds the dependency graph from scratch using only the eligible services. Dependencies on excluded services are dropped: if A depends on non-Critical B and B is excluded, A's dependency on B does not exist in the Safe mode graph. This is what makes Safe mode useful — it is a graph in which the broken parts of the configuration are simply not present, rather than a graph in which they are present and failing.

A successful Safe boot resets the boot attempt counter.

2.6.2.2 Entry #

  • A cycle involving a Critical service at boot. Graph validation detects it and peinit downgrades in place, without rebooting — the cycle is a configuration error, and rebooting would find it again.
  • An unresolvable conflict involving a Critical service at boot. Same reasoning.
  • peios.safemode=1 on the kernel command line.

Safe mode is not entered because a Critical service crashed at runtime. That follows the ordinary path: restart budget, reboot, counter increment, recovery.

2.6.3 Console output #

peios.quiet=N bounds what peinit writes to the console:

ValueBehaviour
0Write unconditionally.
1Do not write to a terminal held as the controlling terminal of a running service, except to announce loss of the system. This is the default.
2Additionally drop ordinary progress everywhere, while still emitting errors.

The two rules are independent, and an error is never less visible at 2 than at 1. A terminal is matched by device rather than by path, since /dev/console and /dev/ttyS<n> can name the same device ; where the device cannot be determined, peinit treats the terminal as free and writes to it. Guessing wrong in that direction costs a scrambled line, which is recoverable; guessing wrong the other way costs the operator their console output at the moment the machine is least able to explain itself. Suppressed messages are discarded rather than buffered.

The autorun step (§2.3) bypasses the policy: a script that ran that early and went wrong is worth interrupting a login prompt for.

2.6.4 Kernel command line #

ParameterEffect
peios.safemode=1Force Safe mode.
peios.recovery=1Force recovery mode regardless of the counter.
peios.bootattempts=NSet the recovery threshold; 0 disables the check.
peios.quiet=NConsole verbosity, as above.
peios.notifysocket=PATHOverride the notification socket path.

A malformed value is ignored in favour of the default rather than failing the boot. Nothing exists this early to report a diagnostic to.

Edit this page