chiark / gitweb /
firstboot: get rid of firstboot generator again, introduce ConditionFirstBoot= instead
authorLennart Poettering <lennart@poettering.net>
Mon, 7 Jul 2014 17:25:31 +0000 (19:25 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 7 Jul 2014 19:05:09 +0000 (21:05 +0200)
As Zbigniew pointed out a new ConditionFirstBoot= appears like the nicer
way to hook in systemd-firstboot.service on first boots (those with /etc
unpopulated), so let's do this, and get rid of the generator again.

17 files changed:
.gitignore
Makefile-man.am
Makefile.am
man/systemd.unit.xml
src/core/condition.c
src/core/load-fragment-gperf.gperf.m4
src/core/main.c
src/core/manager.c
src/core/manager.h
src/core/shutdown.c
src/firstboot/firstboot-generator.c [deleted file]
src/shared/condition-util.c
src/shared/condition-util.h
src/shared/util.c
src/shared/util.h
src/sleep/sleep.c
units/systemd-firstboot.service.in

index 1ba3d06..e3ddbf8 100644 (file)
@@ -65,7 +65,6 @@
 /systemd-detect-virt
 /systemd-efi-boot-generator
 /systemd-firstboot
-/systemd-firstboot-generator
 /systemd-fsck
 /systemd-fstab-generator
 /systemd-getty-generator
index e6043f1..66c40b4 100644 (file)
@@ -63,7 +63,7 @@ MANPAGES += \
        man/systemd-delta.1 \
        man/systemd-detect-virt.1 \
        man/systemd-efi-boot-generator.8 \
-       man/systemd-firstboot.8 \
+       man/systemd-firstboot.1 \
        man/systemd-fsck@.service.8 \
        man/systemd-fstab-generator.8 \
        man/systemd-getty-generator.8 \
@@ -194,7 +194,7 @@ MANPAGES_ALIAS += \
        man/systemd-ask-password-console.path.8 \
        man/systemd-ask-password-wall.path.8 \
        man/systemd-ask-password-wall.service.8 \
-       man/systemd-firstboot.service.8 \
+       man/systemd-firstboot.service.1 \
        man/systemd-fsck-root.service.8 \
        man/systemd-fsck.8 \
        man/systemd-hibernate.service.8 \
@@ -300,7 +300,7 @@ man/sd_notifyf.3: man/sd_notify.3
 man/systemd-ask-password-console.path.8: man/systemd-ask-password-console.service.8
 man/systemd-ask-password-wall.path.8: man/systemd-ask-password-console.service.8
 man/systemd-ask-password-wall.service.8: man/systemd-ask-password-console.service.8
-man/systemd-firstboot.service.8: man/systemd-firstboot.8
+man/systemd-firstboot.service.1: man/systemd-firstboot.1
 man/systemd-fsck-root.service.8: man/systemd-fsck@.service.8
 man/systemd-fsck.8: man/systemd-fsck@.service.8
 man/systemd-hibernate.service.8: man/systemd-suspend.service.8
index 321379c..3ddbdf7 100644 (file)
@@ -1894,15 +1894,8 @@ nodist_systemunit_DATA += \
 EXTRA_DIST += \
        units/systemd-firstboot.service.in
 
-systemgenerator_PROGRAMS += \
-       systemd-firstboot-generator
-
-systemd_firstboot_generator_SOURCES = \
-       src/firstboot/firstboot-generator.c
-
-systemd_firstboot_generator_LDADD = \
-       libsystemd-label.la \
-       libsystemd-shared.la
+SYSINIT_TARGET_WANTS += \
+       systemd-firstboot.service
 
 endif
 
index cd3279c..b1f8108 100644 (file)
                                 <term><varname>ConditionCapability=</varname></term>
                                 <term><varname>ConditionACPower=</varname></term>
                                 <term><varname>ConditionNeedsUpdate=</varname></term>
+                                <term><varname>ConditionFirstBoot=</varname></term>
                                 <term><varname>ConditionPathExists=</varname></term>
                                 <term><varname>ConditionPathExistsGlob=</varname></term>
                                 <term><varname>ConditionPathIsDirectory=</varname></term>
                                 files's modification time gets reset
                                 indicating a completed update.</para>
 
+                                <para><varname>ConditionFirstBoot=</varname>
+                                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. This may be used to
+                                populate <filename>/etc</filename> on
+                                the first boot after factory reset, or
+                                when a new system instances boots up
+                                for the first time.</para>
+
                                 <para>With
                                 <varname>ConditionPathExists=</varname>
                                 a file existence condition is
index 410fb36..353e0c9 100644 (file)
@@ -120,6 +120,20 @@ static bool condition_test_needs_update(Condition *c) {
                 (usr.st_mtim.tv_sec == other.st_mtim.tv_sec && usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec)) == !c->negate;
 }
 
+static bool condition_test_first_boot(Condition *c) {
+        int r;
+
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_FIRST_BOOT);
+
+        r = parse_boolean(c->parameter);
+        if (r < 0)
+                return c->negate;
+
+        return ((access("/run/systemd/first-boot", F_OK) >= 0) == !!r) == !c->negate;
+}
+
 static bool condition_test(Condition *c) {
         assert(c);
 
@@ -202,6 +216,9 @@ static bool condition_test(Condition *c) {
         case CONDITION_NEEDS_UPDATE:
                 return condition_test_needs_update(c);
 
+        case CONDITION_FIRST_BOOT:
+                return condition_test_first_boot(c);
+
         case CONDITION_NULL:
                 return !c->negate;
 
index a7c4469..4c092d7 100644 (file)
@@ -162,6 +162,7 @@ Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path,   CONDITION_D
 Unit.ConditionFileNotEmpty,      config_parse_unit_condition_path,   CONDITION_FILE_NOT_EMPTY,      0
 Unit.ConditionFileIsExecutable,  config_parse_unit_condition_path,   CONDITION_FILE_IS_EXECUTABLE,  0
 Unit.ConditionNeedsUpdate,       config_parse_unit_condition_path,   CONDITION_NEEDS_UPDATE,        0
+Unit.ConditionFirstBoot,         config_parse_unit_condition_path,   CONDITION_FIRST_BOOT,          0
 Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, 0
 Unit.ConditionArchitecture,      config_parse_unit_condition_string, CONDITION_ARCHITECTURE,        0
 Unit.ConditionVirtualization,    config_parse_unit_condition_string, CONDITION_VIRTUALIZATION,      0
index e1fc3f3..a21a959 100644 (file)
@@ -1648,11 +1648,11 @@ int main(int argc, char *argv[]) {
         m->initrd_timestamp = initrd_timestamp;
         m->security_start_timestamp = security_start_timestamp;
         m->security_finish_timestamp = security_finish_timestamp;
-        m->is_first_boot = empty_etc;
 
         manager_set_default_rlimits(m, arg_default_rlimit);
         manager_environment_add(m, NULL, arg_default_environment);
         manager_set_show_status(m, arg_show_status);
+        manager_set_first_boot(m, empty_etc);
 
         /* Remember whether we should queue the default job */
         queue_default_job = !arg_serialization || arg_switched_root;
index 9d078c0..3dffbe2 100644 (file)
@@ -2477,7 +2477,7 @@ void manager_check_finished(Manager *m) {
         m->confirm_spawn = false;
 
         /* This is no longer the first boot */
-        m->is_first_boot = false;
+        manager_set_first_boot(m, false);
 
         if (dual_timestamp_is_set(&m->finish_timestamp))
                 return;
@@ -2631,7 +2631,6 @@ void manager_run_generators(Manager *m) {
         _cleanup_closedir_ DIR *d = NULL;
         const char *generator_path;
         const char *argv[5];
-        const char *env[2];
         int r;
 
         assert(m);
@@ -2665,14 +2664,8 @@ void manager_run_generators(Manager *m) {
         argv[3] = m->generator_unit_path_late;
         argv[4] = NULL;
 
-        if (m->is_first_boot) {
-                env[0] = (char*) "SYSTEMD_FIRST_BOOT=1";
-                env[1] = NULL;
-        } else
-                env[0] = NULL;
-
         RUN_WITH_UMASK(0022)
-                execute_directory(generator_path, d, DEFAULT_TIMEOUT_USEC, (char**) argv, (char**) env);
+                execute_directory(generator_path, d, DEFAULT_TIMEOUT_USEC, (char**) argv);
 
 finish:
         trim_generator_dir(m, &m->generator_unit_path);
@@ -2816,6 +2809,20 @@ static bool manager_get_show_status(Manager *m) {
         return plymouth_running();
 }
 
+void manager_set_first_boot(Manager *m, bool b) {
+        assert(m);
+
+        if (m->running_as != SYSTEMD_SYSTEM)
+                return;
+
+        m->first_boot = b;
+
+        if (m->first_boot)
+                touch("/run/systemd/first-boot");
+        else
+                unlink("/run/systemd/first-boot");
+}
+
 void manager_status_printf(Manager *m, bool ephemeral, const char *status, const char *format, ...) {
         va_list ap;
 
index eff639d..718c29f 100644 (file)
@@ -228,6 +228,7 @@ struct Manager {
         bool dispatching_dbus_queue:1;
 
         bool taint_usr:1;
+        bool first_boot:1;
 
         ShowStatus show_status;
         bool confirm_spawn;
@@ -243,7 +244,6 @@ struct Manager {
         bool default_cpu_accounting;
         bool default_memory_accounting;
         bool default_blockio_accounting;
-        bool is_first_boot;
 
         usec_t default_timer_accuracy_usec;
 
@@ -334,6 +334,8 @@ void manager_undo_generators(Manager *m);
 void manager_recheck_journal(Manager *m);
 
 void manager_set_show_status(Manager *m, ShowStatus mode);
+void manager_set_first_boot(Manager *m, bool b);
+
 void manager_status_printf(Manager *m, bool ephemeral, const char *status, const char *format, ...) _printf_(4,5);
 void manager_flip_auto_status(Manager *m, bool enable);
 
index e7771c9..fde3ce9 100644 (file)
@@ -375,7 +375,7 @@ int main(int argc, char *argv[]) {
         arguments[0] = NULL;
         arguments[1] = arg_verb;
         arguments[2] = NULL;
-        execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments, NULL);
+        execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
 
         if (!in_container && !in_initrd() &&
             access("/run/initramfs/shutdown", X_OK) == 0) {
diff --git a/src/firstboot/firstboot-generator.c b/src/firstboot/firstboot-generator.c
deleted file mode 100644 (file)
index 6d23f40..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2014 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "util.h"
-#include "mkdir.h"
-
-static const char *arg_dest = "/tmp";
-
-static bool is_first_boot(void) {
-        const char *e;
-
-        e = getenv("SYSTEMD_FIRST_BOOT");
-        if (!e)
-                return false;
-
-        return parse_boolean(e) > 0;
-}
-
-int main(int argc, char *argv[]) {
-        int r;
-
-        if (argc > 1 && argc != 4) {
-                log_error("This program takes three or no arguments.");
-                return EXIT_FAILURE;
-        }
-
-        if (argc > 1)
-                arg_dest = argv[2];
-
-        log_set_target(LOG_TARGET_SAFE);
-        log_parse_environment();
-        log_open();
-
-        umask(0022);
-
-        if (is_first_boot()) {
-                const char *t;
-
-                t = strappenda(arg_dest, "/default.target.wants/systemd-firstboot.service");
-
-                mkdir_parents(t, 0755);
-                if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-firstboot.service", t) < 0 && errno != EEXIST) {
-                        log_error("Failed to create firstboot service symlinks %s: %m", t);
-                        r = -errno;
-                        goto finish;
-                }
-        }
-
-        r = 0;
-
-finish:
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}
index 7b89b0f..928edee 100644 (file)
@@ -257,6 +257,7 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
         [CONDITION_AC_POWER] = "ConditionACPower",
         [CONDITION_ARCHITECTURE] = "ConditionArchitecture",
         [CONDITION_NEEDS_UPDATE] = "ConditionNeedsUpdate",
+        [CONDITION_FIRST_BOOT] = "ConditionFirstBoot",
         [CONDITION_NULL] = "ConditionNull"
 };
 
index 0b09f83..047fdbf 100644 (file)
@@ -45,6 +45,7 @@ typedef enum ConditionType {
         CONDITION_AC_POWER,
         CONDITION_ARCHITECTURE,
         CONDITION_NEEDS_UPDATE,
+        CONDITION_FIRST_BOOT,
         CONDITION_NULL,
         _CONDITION_TYPE_MAX,
         _CONDITION_TYPE_INVALID = -1
index 88511b6..3342798 100644 (file)
@@ -3795,7 +3795,7 @@ bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) {
         return endswith(de->d_name, suffix);
 }
 
-void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv[], char *env[]) {
+void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv[]) {
         pid_t executor_pid;
         int r;
 
@@ -3826,14 +3826,6 @@ void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv
 
                 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
 
-                if (!strv_isempty(env)) {
-                        char **i;
-
-                        STRV_FOREACH(i, env)
-                                putenv(*i);
-                }
-
-
                 if (!d) {
                         d = _d = opendir(directory);
                         if (!d) {
index fb852d6..c5eadc9 100644 (file)
@@ -505,7 +505,7 @@ bool tty_is_console(const char *tty) _pure_;
 int vtnr_from_tty(const char *tty);
 const char *default_term_for_tty(const char *tty);
 
-void execute_directory(const char *directory, DIR *_d, usec_t timeout, char *argv[], char *env[]);
+void execute_directory(const char *directory, DIR *_d, usec_t timeout, char *argv[]);
 
 int kill_and_sigcont(pid_t pid, int sig);
 
index 3b0e927..5adbea5 100644 (file)
@@ -110,7 +110,7 @@ static int execute(char **modes, char **states) {
         arguments[1] = (char*) "pre";
         arguments[2] = arg_verb;
         arguments[3] = NULL;
-        execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments, NULL);
+        execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
 
         log_struct(LOG_INFO,
                    MESSAGE_ID(SD_MESSAGE_SLEEP_START),
@@ -129,7 +129,7 @@ static int execute(char **modes, char **states) {
                    NULL);
 
         arguments[1] = (char*) "post";
-        execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments, NULL);
+        execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
 
         return r;
 }
index e7ae745..a8719a8 100644 (file)
@@ -13,6 +13,7 @@ Conflicts=shutdown.target
 After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service systemd-sysusers.service
 Before=sysinit.target shutdown.target
 ConditionPathIsReadWrite=/etc
+ConditionFirstBoot=yes
 
 [Service]
 Type=oneshot