chiark / gitweb /
manager: optionally print status updates to console on boot
authorLennart Poettering <lennart@poettering.net>
Tue, 6 Jul 2010 22:00:59 +0000 (00:00 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 6 Jul 2010 22:00:59 +0000 (00:00 +0200)
13 files changed:
src/dbus-manager.c
src/job.c
src/main.c
src/manager.c
src/manager.h
src/mount.c
src/service.c
src/swap.c
src/test-engine.c
src/unit.c
src/unit.h
src/util.c
src/util.h

index 99c2dcd..cd6a975 100644 (file)
         "  <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n"     \
         "  <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
         "  <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
         "  <property name=\"SysVInitPath\" type=\"as\" access=\"read\"/>\n" \
         "  <property name=\"SysVRcndPath\" type=\"as\" access=\"read\"/>\n" \
@@ -222,6 +223,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
                 { "org.freedesktop.systemd1.Manager", "NJobs",         bus_manager_append_n_jobs,     "u",  NULL               },
                 { "org.freedesktop.systemd1.Manager", "Environment",   bus_property_append_strv,      "as", m->environment     },
                 { "org.freedesktop.systemd1.Manager", "ConfirmSpawn",  bus_property_append_bool,      "b",  &m->confirm_spawn  },
+                { "org.freedesktop.systemd1.Manager", "ShowStatus",    bus_property_append_bool,      "b",  &m->show_status    },
                 { "org.freedesktop.systemd1.Manager", "UnitPath",      bus_property_append_strv,      "as", m->lookup_paths.unit_path },
                 { "org.freedesktop.systemd1.Manager", "SysVInitPath",  bus_property_append_strv,      "as", m->lookup_paths.sysvinit_path },
                 { "org.freedesktop.systemd1.Manager", "SysVRcndPath",  bus_property_append_strv,      "as", m->lookup_paths.sysvrcnd_path },
index a090ec9..2199d75 100644 (file)
--- a/src/job.c
+++ b/src/job.c
@@ -483,6 +483,9 @@ int job_finish_and_invalidate(Job *j, bool success) {
         t = j->type;
         job_free(j);
 
+        if (!success)
+                unit_status_printf(u, "Starting %s... " ANSI_HIGHLIGHT_ON "failed" ANSI_HIGHLIGHT_OFF ".\n", unit_description(u));
+
         /* Fail depending jobs on failure */
         if (!success) {
 
index e51f6b7..99bea75 100644 (file)
@@ -59,6 +59,7 @@ static bool arg_crash_shell = false;
 static int arg_crash_chvt = -1;
 static bool arg_confirm_spawn = false;
 static bool arg_nomodules = false;
+static bool arg_show_status = true;
 
 static FILE* serialization = NULL;
 
@@ -236,6 +237,7 @@ static int parse_proc_cmdline_word(const char *word) {
                 "4",      SPECIAL_RUNLEVEL4_TARGET,
                 "5",      SPECIAL_RUNLEVEL5_TARGET
         };
+        bool ignore_quiet = false;
 
         if (startswith(word, "systemd.unit="))
                 return set_default_unit(word + 13);
@@ -292,6 +294,16 @@ static int parse_proc_cmdline_word(const char *word) {
                 else
                         arg_crash_chvt = k;
 
+        } else if (startswith(word, "systemd.show_status=")) {
+                int r;
+
+                if ((r = parse_boolean(word + 20)) < 0)
+                        log_warning("Failed to parse show status switch %s, Ignoring.", word + 20);
+                else {
+                        arg_show_status = r;
+                        ignore_quiet = true;
+                }
+
         } else if (startswith(word, "systemd.")) {
 
                 log_warning("Unknown kernel switch %s. Ignoring.", word);
@@ -304,13 +316,17 @@ static int parse_proc_cmdline_word(const char *word) {
                          "systemd.log_color=0|1                    Highlight important log messages\n"
                          "systemd.log_location=0|1                 Include code location in log messages\n"
                          "systemd.dump_core=0|1                    Dump core on crash\n"
-                         "systemd.crash_shell=0|1                  On crash run shell\n"
+                         "systemd.crash_shell=0|1                  Run shell on crash\n"
                          "systemd.crash_chvt=N                     Change to VT #N on crash\n"
-                         "systemd.confirm_spawn=0|1                Confirm every process spawn");
+                         "systemd.confirm_spawn=0|1                Confirm every process spawn\n"
+                         "systemd.show_status=0|1                  Show status updates on the console during bootup\n");
 
         } else if (streq(word, "nomodules"))
                 arg_nomodules = true;
-        else {
+        else if (streq(word, "quiet")) {
+                if (!ignore_quiet)
+                        arg_show_status = false;
+        } else {
                 unsigned i;
 
                 /* SysV compatibility */
@@ -367,7 +383,10 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_RUNNING_AS,
                 ARG_TEST,
                 ARG_DUMP_CONFIGURATION_ITEMS,
+                ARG_DUMP_CORE,
+                ARG_CRASH_SHELL,
                 ARG_CONFIRM_SPAWN,
+                ARG_SHOW_STATUS,
                 ARG_DESERIALIZE,
                 ARG_INTROSPECT
         };
@@ -382,7 +401,10 @@ static int parse_argv(int argc, char *argv[]) {
                 { "test",                     no_argument,       NULL, ARG_TEST                     },
                 { "help",                     no_argument,       NULL, 'h'                          },
                 { "dump-configuration-items", no_argument,       NULL, ARG_DUMP_CONFIGURATION_ITEMS },
+                { "dump-core",                no_argument,       NULL, ARG_DUMP_CORE                },
+                { "crash-shell",              no_argument,       NULL, ARG_CRASH_SHELL              },
                 { "confirm-spawn",            no_argument,       NULL, ARG_CONFIRM_SPAWN            },
+                { "show-status",              no_argument,       NULL, ARG_SHOW_STATUS              },
                 { "deserialize",              required_argument, NULL, ARG_DESERIALIZE              },
                 { "introspect",               optional_argument, NULL, ARG_INTROSPECT               },
                 { NULL,                       0,                 NULL, 0                            }
@@ -467,10 +489,22 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_action = ACTION_DUMP_CONFIGURATION_ITEMS;
                         break;
 
+                case ARG_DUMP_CORE:
+                        arg_dump_core = true;
+                        break;
+
+                case ARG_CRASH_SHELL:
+                        arg_crash_shell = true;
+                        break;
+
                 case ARG_CONFIRM_SPAWN:
                         arg_confirm_spawn = true;
                         break;
 
+                case ARG_SHOW_STATUS:
+                        arg_show_status = true;
+                        break;
+
                 case ARG_DESERIALIZE: {
                         int fd;
                         FILE *f;
@@ -543,14 +577,17 @@ static int help(void) {
         printf("%s [OPTIONS...]\n\n"
                "Starts up and maintains the system or a session.\n\n"
                "  -h --help                      Show this help\n"
-               "     --unit=UNIT                 Set default unit\n"
-               "     --running-as=AS             Set running as (system, session)\n"
                "     --test                      Determine startup sequence, dump it and exit\n"
                "     --dump-configuration-items  Dump understood unit configuration items\n"
-               "     --confirm-spawn             Ask for confirmation when spawning processes\n"
                "     --introspect[=INTERFACE]    Extract D-Bus interface data\n"
-               "     --log-level=LEVEL           Set log level\n"
+               "     --unit=UNIT                 Set default unit\n"
+               "     --running-as=AS             Set running as (system, session)\n"
+               "     --dump-core                 Dump core on crash\n"
+               "     --crash-shell               Run shell on crash\n"
+               "     --confirm-spawn             Ask for confirmation when spawning processes\n"
+               "     --show-status               Show status updates on the console during bootup\n"
                "     --log-target=TARGET         Set log target (console, syslog, kmsg, syslog-or-kmsg, null)\n"
+               "     --log-level=LEVEL           Set log level (debug, info, notice, warning, err, crit, alert, emerg)\n"
                "     --log-color[=0|1]           Highlight important log messages\n"
                "     --log-location[=0|1]        Include code location in log messages\n",
                program_invocation_short_name);
@@ -734,11 +771,14 @@ int main(int argc, char *argv[]) {
                 loopback_setup();
         }
 
-        if ((r = manager_new(arg_running_as, arg_confirm_spawn, &m)) < 0) {
+        if ((r = manager_new(arg_running_as, &m)) < 0) {
                 log_error("Failed to allocate manager object: %s", strerror(-r));
                 goto finish;
         }
 
+        m->confirm_spawn = arg_confirm_spawn;
+        m->show_status = arg_show_status;
+
         if ((r = manager_startup(m, serialization, fds)) < 0)
                 log_error("Failed to fully start up daemon: %s", strerror(-r));
 
index 6e571ea..e19bacf 100644 (file)
@@ -182,7 +182,7 @@ static int manager_setup_signals(Manager *m) {
         return 0;
 }
 
-int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **_m) {
+int manager_new(ManagerRunningAs running_as, Manager **_m) {
         Manager *m;
         int r = -ENOMEM;
         char *p;
@@ -197,7 +197,6 @@ int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **_m) {
         dual_timestamp_get(&m->startup_timestamp);
 
         m->running_as = running_as;
-        m->confirm_spawn = confirm_spawn;
         m->name_data_slot = m->subscribed_data_slot = -1;
         m->exit_code = _MANAGER_EXIT_CODE_INVALID;
         m->pin_cgroupfs_fd = -1;
@@ -2336,6 +2335,22 @@ finish:
         return r;
 }
 
+bool manager_is_booting_or_shutting_down(Manager *m) {
+        Unit *u;
+
+        assert(m);
+
+        /* Is the initial job still around? */
+        if (manager_get_job(m, 1))
+                return true;
+
+        /* Is there a job for the shutdown target? */
+        if (((u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET))))
+                return !!u->meta.job;
+
+        return false;
+}
+
 static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = {
         [MANAGER_SYSTEM] = "system",
         [MANAGER_SESSION] = "session"
index aff4cb8..b997181 100644 (file)
@@ -192,10 +192,11 @@ struct Manager {
 
         bool utmp_reboot_written:1;
 
+        bool show_status;
         bool confirm_spawn;
 };
 
-int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **m);
+int manager_new(ManagerRunningAs running_as, Manager **m);
 void manager_free(Manager *m);
 
 int manager_enumerate(Manager *m);
@@ -240,6 +241,8 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds);
 
 int manager_reload(Manager *m);
 
+bool manager_is_booting_or_shutting_down(Manager *m);
+
 const char *manager_running_as_to_string(ManagerRunningAs i);
 ManagerRunningAs manager_running_as_from_string(const char *s);
 
index 6da880e..49081d1 100644 (file)
@@ -1548,6 +1548,7 @@ const UnitVTable mount_vtable = {
         .no_alias = true,
         .no_instances = true,
         .no_isolate = true,
+        .show_status = true,
 
         .init = mount_init,
         .load = mount_load,
index ae8a763..d689734 100644 (file)
@@ -2671,6 +2671,7 @@ DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess);
 
 const UnitVTable service_vtable = {
         .suffix = ".service",
+        .show_status = true,
 
         .init = service_init,
         .done = service_done,
index d093c2e..f72ede6 100644 (file)
@@ -547,6 +547,7 @@ const UnitVTable swap_vtable = {
 
         .no_instances = true,
         .no_isolate = true,
+        .show_status = true,
 
         .init = swap_init,
         .load = swap_load,
index 60c6aa2..89631c4 100644 (file)
@@ -33,7 +33,7 @@ int main(int argc, char *argv[]) {
 
         assert_se(set_unit_path("test2") >= 0);
 
-        assert_se(manager_new(MANAGER_SYSTEM, false, &m) >= 0);
+        assert_se(manager_new(MANAGER_SYSTEM, &m) >= 0);
 
         printf("Load1:\n");
         assert_se(manager_load_unit(m, "a.service", NULL, &a) >= 0);
index 8b57148..701dbc0 100644 (file)
@@ -776,6 +776,9 @@ int unit_start(Unit *u) {
          * before it will start again. */
 
         unit_add_to_dbus_queue(u);
+
+        unit_status_printf(u, "Starting %s...\n", unit_description(u));
+
         return UNIT_VTABLE(u)->start(u);
 }
 
@@ -803,6 +806,9 @@ int unit_stop(Unit *u) {
                 return -EBADR;
 
         unit_add_to_dbus_queue(u);
+
+        unit_status_printf(u, "Stopping %s...\n", unit_description(u));
+
         return UNIT_VTABLE(u)->stop(u);
 }
 
@@ -939,7 +945,6 @@ static void retroactively_stop_dependencies(Unit *u) {
 }
 
 void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
-        bool unexpected = false;
         dual_timestamp ts;
 
         assert(u);
@@ -969,6 +974,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
         path_unit_notify(u, ns);
 
         if (u->meta.job) {
+                bool unexpected = false;
 
                 if (u->meta.job->state == JOB_WAITING)
 
@@ -1028,16 +1034,17 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
                 default:
                         assert_not_reached("Job type unknown");
                 }
-        }
 
-        /* If this state change happened without being requested by a
-         * job, then let's retroactively start or stop dependencies */
+                /* If this state change happened without being
+                 * requested by a job, then let's retroactively start
+                 * or stop dependencies */
 
-        if (unexpected) {
-                if (UNIT_IS_INACTIVE_OR_DEACTIVATING(os) && UNIT_IS_ACTIVE_OR_ACTIVATING(ns))
-                        retroactively_start_dependencies(u);
-                else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
-                        retroactively_stop_dependencies(u);
+                if (unexpected) {
+                        if (UNIT_IS_INACTIVE_OR_DEACTIVATING(os) && UNIT_IS_ACTIVE_OR_ACTIVATING(ns))
+                                retroactively_start_dependencies(u);
+                        else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
+                                retroactively_stop_dependencies(u);
+                }
         }
 
         /* Some names are special */
@@ -1997,6 +2004,29 @@ int unit_coldplug(Unit *u) {
         return 0;
 }
 
+void unit_status_printf(Unit *u, const char *format, ...) {
+        va_list ap;
+
+        assert(u);
+        assert(format);
+
+        if (!UNIT_VTABLE(u)->show_status)
+                return;
+
+        if (u->meta.manager->running_as != MANAGER_SYSTEM)
+                return;
+
+        if (!u->meta.manager->show_status)
+                return;
+
+        if (!manager_is_booting_or_shutting_down(u->meta.manager))
+                return;
+
+        va_start(ap, format);
+        status_vprintf(format, ap);
+        va_end(ap);
+}
+
 static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
         [UNIT_SERVICE] = "service",
         [UNIT_TIMER] = "timer",
index b6351d5..abd97f9 100644 (file)
@@ -335,6 +335,9 @@ struct UnitVTable {
 
         /* Exclude from isolation requests */
         bool no_isolate:1;
+
+        /* Show status updates on the console */
+        bool show_status:1;
 };
 
 extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
@@ -459,6 +462,8 @@ int unit_add_node_link(Unit *u, const char *what, bool wants);
 
 int unit_coldplug(Unit *u);
 
+void unit_status_printf(Unit *u, const char *format, ...);
+
 const char *unit_type_to_string(UnitType i);
 UnitType unit_type_from_string(const char *s);
 
index d1120c6..4795dbc 100644 (file)
@@ -2627,6 +2627,30 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
         }
 }
 
+void status_vprintf(const char *format, va_list ap) {
+        char *s = NULL;
+        int fd = -1;
+
+        assert(format);
+
+        /* This independent of logging, as status messages are
+         * optional and go exclusively to the console. */
+
+        if (vasprintf(&s, format, ap) < 0)
+                goto finish;
+
+        if ((fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0)
+                goto finish;
+
+        write(fd, s, strlen(s));
+
+finish:
+        free(s);
+
+        if (fd >= 0)
+                close_nointr_nofail(fd);
+}
+
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
         [IOPRIO_CLASS_RT] = "realtime",
index cb47c7a..0465915 100644 (file)
@@ -291,6 +291,8 @@ int rm_rf(const char *path, bool only_dirs, bool delete_root);
 
 cpu_set_t* cpu_set_malloc(unsigned *ncpus);
 
+void status_vprintf(const char *format, va_list ap);
+
 const char *ioprio_class_to_string(int i);
 int ioprio_class_from_string(const char *s);