<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
+ <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>uninitialized\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>The kernel command argument <varname>systemd.condition-first-boot=</varname> may be
+ used to override the autodetection logic, see
+ <citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
+ </para></listitem>
+
+ <listitem><para>Otherwise, if <filename>/etc/machine-id</filename> does not exist, this is a first
+ boot. During early boot, <command>systemd</command> will write <literal>uninitialized\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>
+ 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
+ <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>
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>
+ <para>If according to the above rules a first boot is detected, units with
+ <varname>ConditionFirstBoot=yes</varname> will be run.</para>
</refsect1>
<refsect1>
<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 for the first time. This roughly means that <filename>/etc/</filename>
- is unpopulated (for details, see "First Boot Semantics" in
+ whether the system is booting up for the first time. This roughly means that <filename>/etc/</filename>
+ was unpopulated when the system started booting (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>
+ First boot is considered finished (this condition will evaluate as false) after the manager
+ has finished the startup phase.</para>
+
+ <para>This condition 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
+ <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
}
static void log_execution_mode(bool *ret_first_boot) {
+ bool first_boot = false;
+
assert(ret_first_boot);
if (arg_system) {
log_info("Detected architecture %s.", architecture_to_string(uname_architecture()));
- if (in_initrd()) {
- *ret_first_boot = false;
+ if (in_initrd())
log_info("Running in initrd.");
- } else {
+ else {
int r;
_cleanup_free_ char *id_text = NULL;
- /* Let's check whether we are in first boot. We use /etc/machine-id as flag file
- * for this: If it is missing or contains the value "uninitialized", this is the
- * first boot. In any other case, it is not. This allows container managers and
- * installers to provision a couple of files already. If the container manager
- * wants to provision the machine ID itself it should pass $container_uuid to PID 1. */
-
- r = read_one_line_file("/etc/machine-id", &id_text);
- if (r < 0 || streq(id_text, "uninitialized")) {
- if (r < 0 && r != -ENOENT)
- log_warning_errno(r, "Unexpected error while reading /etc/machine-id, ignoring: %m");
-
- *ret_first_boot = true;
- log_info("Detected first boot.");
- } else {
- *ret_first_boot = false;
- log_debug("Detected initialized system, this is not the first boot.");
+ /* Let's check whether we are in first boot. First, check if an override was
+ * specified on the kernel commandline. If yes, we honour that. */
+
+ r = proc_cmdline_get_bool("systemd.condition-first-boot", &first_boot);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse systemd.condition-first-boot= kernel commandline argument, ignoring: %m");
+
+ if (r > 0)
+ log_full(first_boot ? LOG_INFO : LOG_DEBUG,
+ "Kernel commandline argument says we are %s first boot.",
+ first_boot ? "in" : "not in");
+ else {
+ /* Second, perform autodetection. We use /etc/machine-id as flag file for
+ * this: If it is missing or contains the value "uninitialized", this is the
+ * first boot. In other cases, it is not. This allows container managers and
+ * installers to provision a couple of files in /etc but still permit the
+ * first-boot initialization to occur. If the container manager wants to
+ * provision the machine ID it should pass $container_uuid to PID 1. */
+
+ r = read_one_line_file("/etc/machine-id", &id_text);
+ if (r < 0 || streq(id_text, "uninitialized")) {
+ if (r < 0 && r != -ENOENT)
+ log_warning_errno(r, "Unexpected error while reading /etc/machine-id, ignoring: %m");
+
+ first_boot = true;
+ log_info("Detected first boot.");
+ } else
+ log_debug("Detected initialized system, this is not the first boot.");
}
}
arg_action == ACTION_TEST ? " test" : "",
getuid(), strna(t), systemd_features);
}
-
- *ret_first_boot = false;
}
+
+ *ret_first_boot = first_boot;
}
static int initialize_runtime(
(void) os_release_status();
(void) hostname_setup(true);
/* Force transient machine-id on first boot. */
- machine_id_setup(NULL, first_boot, arg_machine_id, NULL);
+ machine_id_setup(NULL, /* force_transient= */ first_boot, arg_machine_id, NULL);
(void) loopback_setup();
bump_unix_max_dgram_qlen();
bump_file_max_and_nr_open();
static int condition_test_first_boot(Condition *c, char **env) {
int r, q;
- bool b;
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_FIRST_BOOT);
- r = proc_cmdline_get_bool("systemd.condition-first-boot", &b);
- if (r < 0)
- log_debug_errno(r, "Failed to parse systemd.condition-first-boot= kernel command line argument, ignoring: %m");
- if (r > 0)
- return b == !!r;
-
r = parse_boolean(c->parameter);
if (r < 0)
return r;
q = access("/run/systemd/first-boot", F_OK);
if (q < 0 && errno != ENOENT)
- log_debug_errno(errno, "Failed to check if /run/systemd/first-boot exists, ignoring: %m");
+ log_debug_errno(errno, "Failed to check if /run/systemd/first-boot exists, assuming no: %m");
- return (q >= 0) == !!r;
+ return (q >= 0) == r;
}
static int condition_test_environment(Condition *c, char **env) {