<para>For operating system images which are created once and used on multiple
machines, for example for containers or in the cloud,
- <filename>/etc/machine-id</filename> should be an empty file in the generic file
- system image. An ID will be generated during boot and saved to this file if
- possible. Having an empty file in place is useful because it allows a temporary file
- to be bind-mounted over the real file, in case the image is used read-only.</para>
+ <filename>/etc/machine-id</filename> should be either missing or an empty file in the generic file
+ system image (the difference between the two options is described under "First Boot Semantics" below). An
+ ID will be generated during boot and saved to this file if possible. Having an empty file in place is
+ useful because it allows a temporary file to be bind-mounted over the real file, in case the image is
+ used read-only.</para>
<para><citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
may be used to initialize <filename>/etc/machine-id</filename> on mounted (but not
early boot but become writable later on.</para>
</refsect1>
+ <refsect1>
+ <title>First Boot Semantics</title>
+
+ <para><filename>/etc/machine-id</filename> is used to decide whether a boot is the first one. The rules
+ are as follows:</para>
+
+ <orderedlist>
+ <listitem><para>If <filename>/etc/machine-id</filename> does not exist, this is a first boot. During
+ early boot, <command>systemd</command> will write <literal>unitialized\n</literal> to this file and overmount
+ a temporary file which contains the actual machine ID. Later (after <filename>first-boot-complete.target</filename>
+ has been reached), the real machine ID will be written to disk.</para></listitem>
+
+ <listitem><para>If <filename>/etc/machine-id</filename> contains the string <literal>uninitialized</literal>,
+ a boot is also considered the first boot. The same mechanism as above applies.</para></listitem>
+
+ <listitem><para>If <filename>/etc/machine-id</filename> exists and is empty, a boot is
+ <emphasis>not</emphasis> considered the first boot. <command>systemd</command> will still bind-mount a file
+ containing the actual machine-id over it and later try to commit it to disk (if <filename>/etc/</filename> is
+ writable).</para></listitem>
+
+ <listitem><para>If <filename>/etc/machine-id</filename> already contains a valid machine-id, this is
+ not a first boot.</para></listitem>
+ </orderedlist>
+
+ <para>If by any of the above rules, a first boot is detected, units with <varname>ConditionFirstBoot=yes</varname>
+ will be run.</para>
+ </refsect1>
+
<refsect1>
<title>Relation to OSF UUIDs</title>
<term><varname>ConditionFirstBoot=</varname></term>
<listitem><para>Takes a boolean argument. This condition may be used to conditionalize units on
- whether the system is booting up with an unpopulated <filename>/etc/</filename> directory
- (specifically: an <filename>/etc/</filename> with no <filename>/etc/machine-id</filename>). This may
- be used to populate <filename>/etc/</filename> on the first boot after factory reset, or when a new
- system instance boots up for the first time.</para>
+ whether the system is booting up for the first time. This roughly means that <filename>/etc/</filename>
+ is unpopulated (for details, see "First Boot Semantics" in
+ <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
+ This may be used to populate <filename>/etc/</filename> on the first boot after factory reset, or
+ when a new system instance boots up for the first time.</para>
+
+ <para>For robustness, units with <varname>ConditionFirstBoot=yes</varname> should order themselves
+ before <filename>first-boot-complete.target</filename> and pull in this passive target with
+ <varname>Wants=</varname>. This ensures that in a case of an aborted first boot, these units will
+ be re-run during the next system startup.</para>
<para>If the <varname>systemd.condition-first-boot=</varname> option is specified on the kernel
command line (taking a boolean), it will override the result of this condition check, taking