[systemd-commits] 12 commits - src/core src/shared

Michal Schmidt michich at kemper.freedesktop.org
Wed Feb 27 17:27:16 PST 2013


 src/core/execute.c     |   41 ++++++++++
 src/core/execute.h     |    2 
 src/core/job.c         |   29 ++++---
 src/core/manager.c     |  191 ++++++++++++++++++++++++++++++++++++++++++++++++-
 src/core/manager.h     |   13 ++-
 src/core/transaction.c |    4 -
 src/core/unit.c        |   59 ++++++++-------
 src/core/unit.h        |    2 
 src/shared/util.c      |   57 ++++++++++----
 src/shared/util.h      |    7 +
 10 files changed, 335 insertions(+), 70 deletions(-)

New commits:
commit 03b717a3c4f9348807fc56e7a7d711d72d4ec0cb
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Thu Feb 28 00:03:22 2013 +0100

    core/manager: print status messages about running jobs
    
    Sometimes the boot gets stuck until a timeout hits. The usual timeouts
    are on the order of minutes, so users may lose patience.
    
    Print animated status messages telling the names of units with running
    jobs to make it easy to see what systemd is waiting for.
    
    The animation looks cooler with a shorter interval, but 1 s is OK and
    should not be too hard on slow serial console users.

diff --git a/src/core/manager.c b/src/core/manager.c
index c6f13f7..ec12a75 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -79,6 +79,11 @@
 /* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */
 #define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
 
+/* Initial delay and the interval for printing status messages about running jobs */
+#define JOBS_IN_PROGRESS_WAIT_SEC 5
+#define JOBS_IN_PROGRESS_PERIOD_SEC 1
+#define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3
+
 /* Where clients shall send notification messages to */
 #define NOTIFY_SOCKET "@/org/freedesktop/systemd1/notify"
 
@@ -140,6 +145,146 @@ static int manager_setup_notify(Manager *m) {
         return 0;
 }
 
+static int manager_jobs_in_progress_mod_timer(Manager *m) {
+        struct itimerspec its;
+
+        zero(its);
+
+        its.it_value.tv_sec = JOBS_IN_PROGRESS_WAIT_SEC;
+        its.it_interval.tv_sec = JOBS_IN_PROGRESS_PERIOD_SEC;
+
+        if (timerfd_settime(m->jobs_in_progress_watch.fd, 0, &its, NULL) < 0)
+                return -errno;
+
+        return 0;
+}
+
+static int manager_watch_jobs_in_progress(Manager *m) {
+        struct epoll_event ev;
+        int r;
+
+        assert(m);
+
+        if (m->jobs_in_progress_watch.type != WATCH_INVALID)
+                return 0;
+
+        m->jobs_in_progress_watch.type = WATCH_JOBS_IN_PROGRESS;
+        m->jobs_in_progress_watch.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
+        if (m->jobs_in_progress_watch.fd < 0) {
+                log_error("Failed to create timerfd: %m");
+                r = -errno;
+                goto err;
+        }
+
+        r = manager_jobs_in_progress_mod_timer(m);
+        if (r < 0) {
+                log_error("Failed to set up timer for jobs progress watch: %s", strerror(-r));
+                goto err;
+        }
+
+        zero(ev);
+        ev.events = EPOLLIN;
+        ev.data.ptr = &m->jobs_in_progress_watch;
+
+        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->jobs_in_progress_watch.fd, &ev) < 0) {
+                log_error("Failed to add jobs progress timer fd to epoll: %m");
+                r = -errno;
+                goto err;
+        }
+
+        log_debug("Set up jobs progress timerfd.");
+
+        return 0;
+
+err:
+        if (m->jobs_in_progress_watch.fd >= 0)
+                close_nointr_nofail(m->jobs_in_progress_watch.fd);
+        watch_init(&m->jobs_in_progress_watch);
+        return r;
+}
+
+static void manager_unwatch_jobs_in_progress(Manager *m) {
+        if (m->jobs_in_progress_watch.type != WATCH_JOBS_IN_PROGRESS)
+                return;
+
+        assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, m->jobs_in_progress_watch.fd, NULL) >= 0);
+        close_nointr_nofail(m->jobs_in_progress_watch.fd);
+        watch_init(&m->jobs_in_progress_watch);
+        m->jobs_in_progress_iteration = 0;
+
+        log_debug("Closed jobs progress timerfd.");
+}
+
+#define CYLON_BUFFER_EXTRA (2*strlen(ANSI_RED_ON) + strlen(ANSI_HIGHLIGHT_RED_ON) + 2*strlen(ANSI_HIGHLIGHT_OFF))
+static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) {
+        char *p = buffer;
+
+        assert(buflen >= CYLON_BUFFER_EXTRA + width + 1);
+        assert(pos <= width+1); /* 0 or width+1 mean that the center light is behind the corner */
+
+        if (pos > 1) {
+                if (pos > 2) {
+                        memset(p, ' ', pos-2);
+                        p += pos-2;
+                }
+                memcpy(p, ANSI_RED_ON, strlen(ANSI_RED_ON));
+                p += strlen(ANSI_RED_ON);
+                *p++ = '*';
+        }
+
+        if (pos > 0 && pos <= width) {
+                memcpy(p, ANSI_HIGHLIGHT_RED_ON, strlen(ANSI_HIGHLIGHT_RED_ON));
+                p += strlen(ANSI_HIGHLIGHT_RED_ON);
+                *p++ = '*';
+        }
+
+        memcpy(p, ANSI_HIGHLIGHT_OFF, strlen(ANSI_HIGHLIGHT_OFF));
+        p += strlen(ANSI_HIGHLIGHT_OFF);
+
+        if (pos < width) {
+                memcpy(p, ANSI_RED_ON, strlen(ANSI_RED_ON));
+                p += strlen(ANSI_RED_ON);
+                *p++ = '*';
+                if (pos < width-1) {
+                        memset(p, ' ', width-1-pos);
+                        p += width-1-pos;
+                }
+                memcpy(p, ANSI_HIGHLIGHT_OFF, strlen(ANSI_HIGHLIGHT_OFF));
+                p += strlen(ANSI_HIGHLIGHT_OFF);
+        }
+        *p = 0;
+}
+
+static void manager_print_jobs_in_progress(Manager *m) {
+        Iterator i;
+        Job *j;
+        char *job_of_n = NULL;
+        unsigned counter = 0, print_nr;
+        char cylon[6 + CYLON_BUFFER_EXTRA + 1];
+        unsigned cylon_pos;
+
+        print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs;
+
+        HASHMAP_FOREACH(j, m->jobs, i)
+                if (j->state == JOB_RUNNING && counter++ == print_nr)
+                        break;
+
+        cylon_pos = m->jobs_in_progress_iteration % 14;
+        if (cylon_pos >= 8)
+                cylon_pos = 14 - cylon_pos;
+        draw_cylon(cylon, sizeof(cylon), 6, cylon_pos);
+
+        if (m->n_running_jobs > 1)
+                if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0)
+                        job_of_n = NULL;
+
+        manager_status_printf(m, true, cylon, "%sA %s job is running for %s",
+                              strempty(job_of_n), job_type_to_string(j->type), unit_description(j->unit));
+        free(job_of_n);
+
+        m->jobs_in_progress_iteration++;
+}
+
 static int manager_setup_time_change(Manager *m) {
         struct epoll_event ev;
         struct itimerspec its;
@@ -324,6 +469,7 @@ int manager_new(SystemdRunningAs running_as, Manager **_m) {
         watch_init(&m->swap_watch);
         watch_init(&m->udev_watch);
         watch_init(&m->time_change_watch);
+        watch_init(&m->jobs_in_progress_watch);
 
         m->epoll_fd = m->dev_autofs_fd = -1;
         m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
@@ -564,6 +710,8 @@ void manager_free(Manager *m) {
                 close_nointr_nofail(m->notify_watch.fd);
         if (m->time_change_watch.fd >= 0)
                 close_nointr_nofail(m->time_change_watch.fd);
+        if (m->jobs_in_progress_watch.fd >= 0)
+                close_nointr_nofail(m->jobs_in_progress_watch.fd);
 
         free(m->notify_socket);
 
@@ -988,6 +1136,10 @@ unsigned manager_dispatch_run_queue(Manager *m) {
         }
 
         m->dispatching_run_queue = false;
+
+        if (hashmap_size(m->jobs) > 0)
+                manager_watch_jobs_in_progress(m);
+
         return n;
 }
 
@@ -1527,6 +1679,16 @@ static int process_event(Manager *m, struct epoll_event *ev) {
                 break;
         }
 
+        case WATCH_JOBS_IN_PROGRESS: {
+                uint64_t v;
+
+                /* not interested in the data */
+                read(w->fd, &v, sizeof(v));
+
+                manager_print_jobs_in_progress(m);
+                break;
+        }
+
         default:
                 log_error("event type=%i", w->type);
                 assert_not_reached("Unknown epoll event type.");
@@ -2199,8 +2361,10 @@ void manager_check_finished(Manager *m) {
 
         assert(m);
 
-        if (hashmap_size(m->jobs) > 0)
+        if (hashmap_size(m->jobs) > 0) {
+                manager_jobs_in_progress_mod_timer(m);
                 return;
+        }
 
         /* Notify Type=idle units that we are done now */
         close_pipe(m->idle_pipe);
@@ -2208,6 +2372,8 @@ void manager_check_finished(Manager *m) {
         /* Turn off confirm spawn now */
         m->confirm_spawn = false;
 
+        manager_unwatch_jobs_in_progress(m);
+
         if (dual_timestamp_is_set(&m->finish_timestamp))
                 return;
 
@@ -2500,6 +2666,11 @@ void manager_status_printf(Manager *m, bool ephemeral, const char *status, const
         if (!manager_get_show_status(m))
                 return;
 
+        /* XXX We should totally drop the check for ephemeral here
+         * and thus effectively make 'Type=idle' pointless. */
+        if (ephemeral && m->n_on_console > 0)
+                return;
+
         if (!manager_is_booting_or_shutting_down(m))
                 return;
 
diff --git a/src/core/manager.h b/src/core/manager.h
index 78e4bc6..c486a16 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -61,7 +61,8 @@ enum WatchType {
         WATCH_UDEV,
         WATCH_DBUS_WATCH,
         WATCH_DBUS_TIMEOUT,
-        WATCH_TIME_CHANGE
+        WATCH_TIME_CHANGE,
+        WATCH_JOBS_IN_PROGRESS
 };
 
 struct Watch {
@@ -127,6 +128,7 @@ struct Manager {
         Watch notify_watch;
         Watch signal_watch;
         Watch time_change_watch;
+        Watch jobs_in_progress_watch;
 
         int epoll_fd;
 
@@ -225,8 +227,10 @@ struct Manager {
         unsigned n_installed_jobs;
         unsigned n_failed_jobs;
 
+        /* Jobs in progress watching */
         unsigned n_running_jobs;
         unsigned n_on_console;
+        unsigned jobs_in_progress_iteration;
 
         /* Type=idle pipes */
         int idle_pipe[2];
diff --git a/src/shared/util.h b/src/shared/util.h
index 555e1d8..b5ad1ff 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -55,6 +55,7 @@ union dirent_storage {
 #define FORMAT_BYTES_MAX 8
 
 #define ANSI_HIGHLIGHT_ON "\x1B[1;39m"
+#define ANSI_RED_ON "\x1B[31m"
 #define ANSI_HIGHLIGHT_RED_ON "\x1B[1;31m"
 #define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m"
 #define ANSI_HIGHLIGHT_YELLOW_ON "\x1B[1;33m"

commit 7ed9f6cd785634dd093e1b1550c3c6183177abf6
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Thu Feb 28 00:01:10 2013 +0100

    core: count active units that may mind our printing to /dev/console

diff --git a/src/core/manager.h b/src/core/manager.h
index 0d02552..78e4bc6 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -226,6 +226,7 @@ struct Manager {
         unsigned n_failed_jobs;
 
         unsigned n_running_jobs;
+        unsigned n_on_console;
 
         /* Type=idle pipes */
         int idle_pipe[2];
diff --git a/src/core/unit.c b/src/core/unit.c
index f8a913e..e2c06ae 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1357,6 +1357,21 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
         if (UNIT_IS_INACTIVE_OR_FAILED(ns))
                 cgroup_bonding_trim_list(u->cgroup_bondings, true);
 
+        if (UNIT_IS_INACTIVE_OR_FAILED(os) != UNIT_IS_INACTIVE_OR_FAILED(ns)) {
+                ExecContext *ec = unit_get_exec_context(u);
+                if (ec && exec_context_may_touch_console(ec)) {
+                        /* XXX The counter may get out of sync if the admin edits
+                         * TTY-related unit file properties and issues a daemon-reload
+                         * while the unit is active. No big deal though, because
+                         * it influences only the printing of boot/shutdown
+                         * status messages. */
+                        if (UNIT_IS_INACTIVE_OR_FAILED(ns))
+                                m->n_on_console--;
+                        else
+                                m->n_on_console++;
+                }
+        }
+
         if (u->job) {
                 unexpected = false;
 

commit 6ac8fdc9554a40024827ad9f64d02b4d8d2ab8ba
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Thu Feb 28 01:36:55 2013 +0100

    core/execute: determine if ExecContext may fiddle with /dev/console
    
    There is some guesswork, but it should work satisfactorily for the
    purpose of knowing when to suppress printing of status messages.

diff --git a/src/core/execute.c b/src/core/execute.c
index 1f62635..92cf174 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -1718,6 +1718,37 @@ int exec_context_load_environment(const ExecContext *c, char ***l) {
         return 0;
 }
 
+static bool tty_may_match_dev_console(const char *tty) {
+        char *active = NULL, *console;
+        bool b;
+
+        if (startswith(tty, "/dev/"))
+                tty += 5;
+
+        /* trivial identity? */
+        if (streq(tty, "console"))
+                return true;
+
+        console = resolve_dev_console(&active);
+        /* if we could not resolve, assume it may */
+        if (!console)
+                return true;
+
+        /* "tty0" means the active VC, so it may be the same sometimes */
+        b = streq(console, tty) || (streq(console, "tty0") && tty_is_vc(tty));
+        free(active);
+
+        return b;
+}
+
+bool exec_context_may_touch_console(ExecContext *ec) {
+        return (ec->tty_reset || ec->tty_vhangup || ec->tty_vt_disallocate ||
+                is_terminal_input(ec->std_input) ||
+                is_terminal_output(ec->std_output) ||
+                is_terminal_output(ec->std_error)) &&
+               tty_may_match_dev_console(tty_path(ec));
+}
+
 static void strv_fprintf(FILE *f, char **l) {
         char **g;
 
diff --git a/src/core/execute.h b/src/core/execute.h
index 2bcd2e1..001eb0e 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -198,6 +198,8 @@ void exec_context_tty_reset(const ExecContext *context);
 
 int exec_context_load_environment(const ExecContext *c, char ***l);
 
+bool exec_context_may_touch_console(ExecContext *c);
+
 void exec_status_start(ExecStatus *s, pid_t pid);
 void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status);
 void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix);

commit 3a1286b66883ef2cf577b29364e4b5fd43a295c8
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Thu Feb 28 01:35:47 2013 +0100

    core/execute: add internal is_terminal_output()
    
    Similar to already existing is_terminal_input().
    
    Note that the only current user (connect_logger_as) is never called
    for EXEC_OUTPUT_TTY, so it won't mind whether we accept it.

diff --git a/src/core/execute.c b/src/core/execute.c
index b28962a..1f62635 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -165,6 +165,14 @@ void exec_context_tty_reset(const ExecContext *context) {
                 vt_disallocate(context->tty_path);
 }
 
+static bool is_terminal_output(ExecOutput o) {
+        return
+                o == EXEC_OUTPUT_TTY ||
+                o == EXEC_OUTPUT_SYSLOG_AND_CONSOLE ||
+                o == EXEC_OUTPUT_KMSG_AND_CONSOLE ||
+                o == EXEC_OUTPUT_JOURNAL_AND_CONSOLE;
+}
+
 static int open_null_as(int flags, int nfd) {
         int fd, r;
 
@@ -224,7 +232,7 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons
                 !!context->syslog_level_prefix,
                 output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
                 output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE,
-                output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || output == EXEC_OUTPUT_KMSG_AND_CONSOLE || output == EXEC_OUTPUT_JOURNAL_AND_CONSOLE);
+                is_terminal_output(output));
 
         if (fd != nfd) {
                 r = dup2(fd, nfd) < 0 ? -errno : nfd;

commit 21baf21ae526d0180177cf4a26ce82d45b6103e2
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Thu Feb 28 01:30:38 2013 +0100

    util: split resolving of /dev/console into a new function

diff --git a/src/shared/util.c b/src/shared/util.c
index cc41589..e643cd3 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -3509,6 +3509,29 @@ int vtnr_from_tty(const char *tty) {
         return i;
 }
 
+char *resolve_dev_console(char **active) {
+        char *tty;
+
+        /* Resolve where /dev/console is pointing to, if /sys is actually ours
+         * (i.e. not read-only-mounted which is a sign for container setups) */
+
+        if (path_is_read_only_fs("/sys") > 0)
+                return NULL;
+
+        if (read_one_line_file("/sys/class/tty/console/active", active) < 0)
+                return NULL;
+
+        /* If multiple log outputs are configured the last one is what
+         * /dev/console points to */
+        tty = strrchr(*active, ' ');
+        if (tty)
+                tty++;
+        else
+                tty = *active;
+
+        return tty;
+}
+
 bool tty_is_vc_resolve(const char *tty) {
         char *active = NULL;
         bool b;
@@ -3518,19 +3541,11 @@ bool tty_is_vc_resolve(const char *tty) {
         if (startswith(tty, "/dev/"))
                 tty += 5;
 
-        /* Resolve where /dev/console is pointing to, if /sys is
-         * actually ours (i.e. not read-only-mounted which is a sign
-         * for container setups) */
-        if (streq(tty, "console") && path_is_read_only_fs("/sys") <= 0)
-                if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) {
-                        /* If multiple log outputs are configured the
-                         * last one is what /dev/console points to */
-                        tty = strrchr(active, ' ');
-                        if (tty)
-                                tty++;
-                        else
-                                tty = active;
-                }
+        if (streq(tty, "console")) {
+                tty = resolve_dev_console(&active);
+                if (!tty)
+                        return false;
+        }
 
         b = tty_is_vc(tty);
         free(active);
diff --git a/src/shared/util.h b/src/shared/util.h
index f8957bc..555e1d8 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -389,6 +389,7 @@ DIR *xopendirat(int dirfd, const char *name, int flags);
 
 char *fstab_node_to_udev_node(const char *p);
 
+char *resolve_dev_console(char **active);
 bool tty_is_vc(const char *tty);
 bool tty_is_vc_resolve(const char *tty);
 bool tty_is_console(const char *tty);

commit 546ac4f0078228ef0bdd764dc7566cacf684c562
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Wed Feb 27 23:58:10 2013 +0100

    core/unit: use a temp variable for manager pointer in unit_notify()

diff --git a/src/core/unit.c b/src/core/unit.c
index 6fee050..f8a913e 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1320,6 +1320,7 @@ void unit_trigger_on_failure(Unit *u) {
 }
 
 void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) {
+        Manager *m;
         bool unexpected;
 
         assert(u);
@@ -1332,7 +1333,9 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
          * behavior here. For example: if a mount point is remounted
          * this function will be called too! */
 
-        if (u->manager->n_reloading <= 0) {
+        m = u->manager;
+
+        if (m->n_reloading <= 0) {
                 dual_timestamp ts;
 
                 dual_timestamp_get(&ts);
@@ -1420,7 +1423,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
         } else
                 unexpected = true;
 
-        if (u->manager->n_reloading <= 0) {
+        if (m->n_reloading <= 0) {
 
                 /* If this state change happened without being
                  * requested by a job, then let's retroactively start
@@ -1456,18 +1459,18 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
                         /* The bus just might have become available,
                          * hence try to connect to it, if we aren't
                          * yet connected. */
-                        bus_init(u->manager, true);
+                        bus_init(m, true);
 
                 if (u->type == UNIT_SERVICE &&
                     !UNIT_IS_ACTIVE_OR_RELOADING(os) &&
-                    u->manager->n_reloading <= 0) {
+                    m->n_reloading <= 0) {
                         /* Write audit record if we have just finished starting up */
-                        manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_START, true);
+                        manager_send_unit_audit(m, u, AUDIT_SERVICE_START, true);
                         u->in_audit = true;
                 }
 
                 if (!UNIT_IS_ACTIVE_OR_RELOADING(os))
-                        manager_send_unit_plymouth(u->manager, u);
+                        manager_send_unit_plymouth(m, u);
 
         } else {
 
@@ -1477,25 +1480,25 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
                 if (u->type == UNIT_SERVICE &&
                     UNIT_IS_INACTIVE_OR_FAILED(ns) &&
                     !UNIT_IS_INACTIVE_OR_FAILED(os) &&
-                    u->manager->n_reloading <= 0) {
+                    m->n_reloading <= 0) {
 
                         /* Hmm, if there was no start record written
                          * write it now, so that we always have a nice
                          * pair */
                         if (!u->in_audit) {
-                                manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_START, ns == UNIT_INACTIVE);
+                                manager_send_unit_audit(m, u, AUDIT_SERVICE_START, ns == UNIT_INACTIVE);
 
                                 if (ns == UNIT_INACTIVE)
-                                        manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_STOP, true);
+                                        manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, true);
                         } else
                                 /* Write audit record if we have just finished shutting down */
-                                manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE);
+                                manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE);
 
                         u->in_audit = false;
                 }
         }
 
-        manager_recheck_journal(u->manager);
+        manager_recheck_journal(m);
 
         /* Maybe we finished startup and are now ready for being
          * stopped because unneeded? */

commit 984a2be450abac81474889b8bea4b3fbeddb26c5
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Wed Feb 27 22:52:43 2013 +0100

    util, core: add support for ephemeral status lines
    
    Ephemeral status lines do not end with a newline and they expect to be
    overwritten by the next printed status line.

diff --git a/src/core/job.c b/src/core/job.c
index 9f792b8..90de550 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -649,7 +649,7 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
 
                 case JOB_FAILED:
                         unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format);
-                        manager_status_printf(u->manager, NULL, "See 'systemctl status %s' for details.", u->id);
+                        manager_status_printf(u->manager, false, NULL, "See 'systemctl status %s' for details.", u->id);
                         break;
 
                 case JOB_DEPENDENCY:
diff --git a/src/core/manager.c b/src/core/manager.c
index 1dac69b..c6f13f7 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -2494,7 +2494,7 @@ static bool manager_get_show_status(Manager *m) {
         return plymouth_running();
 }
 
-void manager_status_printf(Manager *m, const char *status, const char *format, ...) {
+void manager_status_printf(Manager *m, bool ephemeral, const char *status, const char *format, ...) {
         va_list ap;
 
         if (!manager_get_show_status(m))
@@ -2504,7 +2504,7 @@ void manager_status_printf(Manager *m, const char *status, const char *format, .
                 return;
 
         va_start(ap, format);
-        status_vprintf(status, true, format, ap);
+        status_vprintf(status, true, ephemeral, format, ap);
         va_end(ap);
 }
 
diff --git a/src/core/manager.h b/src/core/manager.h
index d21f27d..0d02552 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -293,6 +293,6 @@ void manager_undo_generators(Manager *m);
 void manager_recheck_journal(Manager *m);
 
 void manager_set_show_status(Manager *m, bool b);
-void manager_status_printf(Manager *m, const char *status, const char *format, ...);
+void manager_status_printf(Manager *m, bool ephemeral, const char *status, const char *format, ...);
 
 void watch_init(Watch *w);
diff --git a/src/shared/util.c b/src/shared/util.c
index f5adedc..cc41589 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -2859,12 +2859,13 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
         }
 }
 
-int status_vprintf(const char *status, bool ellipse, const char *format, va_list ap) {
+int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
         static const char status_indent[] = "         "; /* "[" STATUS "] " */
         _cleanup_free_ char *s = NULL;
         _cleanup_close_ int fd = -1;
-        struct iovec iovec[5];
+        struct iovec iovec[6];
         int n = 0;
+        static bool prev_ephemeral;
 
         assert(format);
 
@@ -2902,6 +2903,10 @@ int status_vprintf(const char *status, bool ellipse, const char *format, va_list
 
         zero(iovec);
 
+        if (prev_ephemeral)
+                IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
+        prev_ephemeral = ephemeral;
+
         if (status) {
                 if (!isempty(status)) {
                         IOVEC_SET_STRING(iovec[n++], "[");
@@ -2912,7 +2917,8 @@ int status_vprintf(const char *status, bool ellipse, const char *format, va_list
         }
 
         IOVEC_SET_STRING(iovec[n++], s);
-        IOVEC_SET_STRING(iovec[n++], "\n");
+        if (!ephemeral)
+                IOVEC_SET_STRING(iovec[n++], "\n");
 
         if (writev(fd, iovec, n) < 0)
                 return -errno;
@@ -2920,14 +2926,14 @@ int status_vprintf(const char *status, bool ellipse, const char *format, va_list
         return 0;
 }
 
-int status_printf(const char *status, bool ellipse, const char *format, ...) {
+int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
         va_list ap;
         int r;
 
         assert(format);
 
         va_start(ap, format);
-        r = status_vprintf(status, ellipse, format, ap);
+        r = status_vprintf(status, ellipse, ephemeral, format, ap);
         va_end(ap);
 
         return r;
diff --git a/src/shared/util.h b/src/shared/util.h
index 19cc36a..f8957bc 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -59,6 +59,7 @@ union dirent_storage {
 #define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m"
 #define ANSI_HIGHLIGHT_YELLOW_ON "\x1B[1;33m"
 #define ANSI_HIGHLIGHT_OFF "\x1B[0m"
+#define ANSI_ERASE_TO_END_OF_LINE "\x1B[K"
 
 size_t page_size(void);
 #define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
@@ -354,8 +355,8 @@ int pipe_eof(int fd);
 
 cpu_set_t* cpu_set_malloc(unsigned *ncpus);
 
-int status_vprintf(const char *status, bool ellipse, const char *format, va_list ap);
-int status_printf(const char *status, bool ellipse, const char *format, ...);
+int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap);
+int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...);
 int status_welcome(void);
 
 int fd_columns(int fd);

commit 297d0749dd82ea2442203d53c23ee401bdf46fca
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Wed Feb 27 23:31:35 2013 +0100

    core/transaction: replace a bare status_printf()
    
    Like other status messages, this one too should not be printed
    unconditionally, but it should take the manager state into account.
    unit_status_printf() does that.

diff --git a/src/core/transaction.c b/src/core/transaction.c
index 0329366..4a8d90e 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -396,8 +396,8 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
                                        "Job %s/%s deleted to break ordering cycle starting with %s/%s",
                                        delete->unit->id, job_type_to_string(delete->type),
                                        j->unit->id, job_type_to_string(j->type));
-                        status_printf(ANSI_HIGHLIGHT_RED_ON " SKIP " ANSI_HIGHLIGHT_OFF, true,
-                                      "Ordering cycle found, skipping %s", unit_description(delete->unit));
+                        unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED_ON " SKIP " ANSI_HIGHLIGHT_OFF,
+                                           "Ordering cycle found, skipping %s");
                         transaction_delete_unit(tr, delete->unit);
                         return -EAGAIN;
                 }

commit 49b1d377263f33991a03235779e50f61273ba649
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Wed Feb 27 22:54:14 2013 +0100

    core: redefine unit_status_printf()
    
    Take advantage of the fact that almost all callers want to pass unit
    description as the last parameter. Those who don't can use the more
    flexible manager_status_printf().

diff --git a/src/core/job.c b/src/core/job.c
index 677a01d..9f792b8 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -644,20 +644,20 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
 
                 case JOB_DONE:
                         if (u->condition_result)
-                                unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
+                                unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, format);
                         break;
 
                 case JOB_FAILED:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format, unit_description(u));
-                        unit_status_printf(u, NULL, "See 'systemctl status %s' for details.", u->id);
+                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format);
+                        manager_status_printf(u->manager, NULL, "See 'systemctl status %s' for details.", u->id);
                         break;
 
                 case JOB_DEPENDENCY:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, format, unit_description(u));
+                        unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, format);
                         break;
 
                 case JOB_TIMEOUT:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
+                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
                         break;
 
                 default:
@@ -673,12 +673,12 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
                 switch (result) {
 
                 case JOB_TIMEOUT:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
+                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
                         break;
 
                 case JOB_DONE:
                 case JOB_FAILED:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
+                        unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, format);
                         break;
 
                 default:
@@ -691,7 +691,7 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
                  * Most likely a DEPEND warning from a requisiting unit will
                  * occur next and it's nice to see what was requisited. */
                 if (result == JOB_SKIPPED)
-                        unit_status_printf(u, ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, "%s is not active.", unit_description(u));
+                        unit_status_printf(u, ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, "%s is not active.");
         }
 }
 
diff --git a/src/core/unit.c b/src/core/unit.c
index 74b0e47..6fee050 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -994,7 +994,7 @@ static void unit_status_print_starting_stopping(Unit *u, JobType t) {
         if (!format)
                 return;
 
-        unit_status_printf(u, "", format, unit_description(u));
+        unit_status_printf(u, "", format);
 }
 
 #pragma GCC diagnostic push
@@ -2535,6 +2535,10 @@ int unit_coldplug(Unit *u) {
         return 0;
 }
 
+void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) {
+        manager_status_printf(u->manager, false, status, unit_status_msg_format, unit_description(u));
+}
+
 bool unit_need_daemon_reload(Unit *u) {
         struct stat st;
 
diff --git a/src/core/unit.h b/src/core/unit.h
index 84aabd5..9029d62 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -520,8 +520,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants);
 
 int unit_coldplug(Unit *u);
 
-#define unit_status_printf(u, st, fo, ...) \
-        manager_status_printf((u)->manager, st, fo, __VA_ARGS__)
+void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format);
 
 bool unit_need_daemon_reload(Unit *u);
 

commit 6084e22e57afd588ad205697c0af119d93db1e39
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Thu Feb 28 00:14:47 2013 +0100

    core/manager: make a couple of functions static
    
    They're not used outside manager.c anymore.

diff --git a/src/core/manager.c b/src/core/manager.c
index d6c6e2d..1dac69b 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -2152,7 +2152,7 @@ finish:
         return r;
 }
 
-bool manager_is_booting_or_shutting_down(Manager *m) {
+static bool manager_is_booting_or_shutting_down(Manager *m) {
         Unit *u;
 
         assert(m);
@@ -2479,7 +2479,7 @@ void manager_set_show_status(Manager *m, bool b) {
                 unlink("/run/systemd/show-status");
 }
 
-bool manager_get_show_status(Manager *m) {
+static bool manager_get_show_status(Manager *m) {
         assert(m);
 
         if (m->running_as != SYSTEMD_SYSTEM)
diff --git a/src/core/manager.h b/src/core/manager.h
index 3ec8d70..d21f27d 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -278,8 +278,6 @@ int manager_distribute_fds(Manager *m, FDSet *fds);
 
 int manager_reload(Manager *m);
 
-bool manager_is_booting_or_shutting_down(Manager *m);
-
 void manager_reset_failed(Manager *m);
 
 void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success);
@@ -296,6 +294,5 @@ void manager_recheck_journal(Manager *m);
 
 void manager_set_show_status(Manager *m, bool b);
 void manager_status_printf(Manager *m, const char *status, const char *format, ...);
-bool manager_get_show_status(Manager *m);
 
 void watch_init(Watch *w);

commit 25cee55076a7c00c0a584731c2705686cc843210
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Thu Feb 28 00:14:40 2013 +0100

    core: add manager_status_printf()
    
    unit_status_printf() checks the state of the manager, not of the unit
    as such. Move it to manager.c and rename it to manager_status_printf().
    
    Temporarily keep unit_status_printf as a wrapper macro.

diff --git a/src/core/manager.c b/src/core/manager.c
index a578813..d6c6e2d 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -2494,6 +2494,20 @@ bool manager_get_show_status(Manager *m) {
         return plymouth_running();
 }
 
+void manager_status_printf(Manager *m, const char *status, const char *format, ...) {
+        va_list ap;
+
+        if (!manager_get_show_status(m))
+                return;
+
+        if (!manager_is_booting_or_shutting_down(m))
+                return;
+
+        va_start(ap, format);
+        status_vprintf(status, true, format, ap);
+        va_end(ap);
+}
+
 void watch_init(Watch *w) {
         assert(w);
 
diff --git a/src/core/manager.h b/src/core/manager.h
index 0bd7a6d..3ec8d70 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -295,6 +295,7 @@ void manager_undo_generators(Manager *m);
 void manager_recheck_journal(Manager *m);
 
 void manager_set_show_status(Manager *m, bool b);
+void manager_status_printf(Manager *m, const char *status, const char *format, ...);
 bool manager_get_show_status(Manager *m);
 
 void watch_init(Watch *w);
diff --git a/src/core/unit.c b/src/core/unit.c
index 370ad67..74b0e47 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -2535,23 +2535,6 @@ int unit_coldplug(Unit *u) {
         return 0;
 }
 
-void unit_status_printf(Unit *u, const char *status, const char *format, ...) {
-        va_list ap;
-
-        assert(u);
-        assert(format);
-
-        if (!manager_get_show_status(u->manager))
-                return;
-
-        if (!manager_is_booting_or_shutting_down(u->manager))
-                return;
-
-        va_start(ap, format);
-        status_vprintf(status, true, format, ap);
-        va_end(ap);
-}
-
 bool unit_need_daemon_reload(Unit *u) {
         struct stat st;
 
diff --git a/src/core/unit.h b/src/core/unit.h
index 17a5a5f..84aabd5 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -520,7 +520,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 *status, const char *format, ...);
+#define unit_status_printf(u, st, fo, ...) \
+        manager_status_printf((u)->manager, st, fo, __VA_ARGS__)
 
 bool unit_need_daemon_reload(Unit *u);
 

commit 637f8b8eb5decb6dd626276ea9e3a545c895e086
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Tue Feb 26 12:09:41 2013 +0100

    core: keep track of the number of JOB_RUNNING jobs

diff --git a/src/core/job.c b/src/core/job.c
index 990607f..677a01d 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -206,6 +206,7 @@ Job* job_install(Job *j) {
                                                "Merged into running job, re-running: %s/%s as %u",
                                                uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
                                 uj->state = JOB_WAITING;
+                                uj->manager->n_running_jobs--;
                                 return uj;
                         }
                 }
@@ -483,7 +484,7 @@ static void job_change_type(Job *j, JobType newtype) {
 int job_run_and_invalidate(Job *j) {
         int r;
         uint32_t id;
-        Manager *m;
+        Manager *m = j->manager;
 
         assert(j);
         assert(j->installed);
@@ -500,6 +501,7 @@ int job_run_and_invalidate(Job *j) {
                 return -EAGAIN;
 
         j->state = JOB_RUNNING;
+        m->n_running_jobs++;
         job_add_to_dbus_queue(j);
 
         /* While we execute this operation the job might go away (for
@@ -508,7 +510,6 @@ int job_run_and_invalidate(Job *j) {
          * store the id here, so that we can verify the job is still
          * valid. */
         id = j->id;
-        m = j->manager;
 
         switch (j->type) {
 
@@ -558,9 +559,10 @@ int job_run_and_invalidate(Job *j) {
                         r = job_finish_and_invalidate(j, JOB_DONE, true);
                 else if (r == -ENOEXEC)
                         r = job_finish_and_invalidate(j, JOB_SKIPPED, true);
-                else if (r == -EAGAIN)
+                else if (r == -EAGAIN) {
                         j->state = JOB_WAITING;
-                else if (r < 0)
+                        m->n_running_jobs--;
+                } else if (r < 0)
                         r = job_finish_and_invalidate(j, JOB_FAILED, true);
         }
 
@@ -760,6 +762,9 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
 
         j->result = result;
 
+        if (j->state == JOB_RUNNING)
+                j->manager->n_running_jobs--;
+
         log_debug_unit(u->id, "Job %s/%s finished, result=%s",
                        u->id, job_type_to_string(t), job_result_to_string(result));
 
diff --git a/src/core/manager.h b/src/core/manager.h
index cc4edf8..0bd7a6d 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -225,6 +225,8 @@ struct Manager {
         unsigned n_installed_jobs;
         unsigned n_failed_jobs;
 
+        unsigned n_running_jobs;
+
         /* Type=idle pipes */
         int idle_pipe[2];
 



More information about the systemd-commits mailing list