Compare commits

..

7 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek df46dbca92
Merge pull request #14976 from keszybz/show-status-message
core: fix message about show status state
2020-03-01 23:37:41 +01:00
Zbigniew Jędrzejewski-Szmek 0d066dd1a4 pid1: add new mode systemd.show-status=error and use it when 'quiet' is passed
systemd.show-status=error is useful for the case where people care about errors
only.

If people want to have a quiet boot, they most likely don't want to see all
status output even if there is a delay in boot, so make "quiet" imply
systemd.show-status=error instead of systemd.show-status=auto.

Fixes #14976.
2020-03-01 11:48:23 +01:00
Zbigniew Jędrzejewski-Szmek 5bcf34ebf3 pid1: when showing error status, do not switch to status=temporary
We would flip to status=temporary mode on the first error, and then switch back
to status=auto after the initial transaction was done. This isn't very useful,
because usually all the messages about successfully started units and not
related to the original failure. In fact, all those messages most likely cause
the information about the prime error to scroll off screen. And if the user
requested quiet boot, there's no reason to think that they care about those
success messages.

Also, when logging about dependency cycles, treat this similarly to a unit
error and show the message even if the status is "soft disabled" (before we
wouldn't show it in that case).
2020-03-01 11:42:42 +01:00
Zbigniew Jędrzejewski-Szmek 1b4154a891 pid1: make cylon timeout significantly bigger when not showing any messages
When we are booting with show-status=on, normally new status updates happen a
few times per second. Thus, it is reasonable to start showing the cylon eye
after 5 s, because that means a significant delay has happened. When we are
running with show-status=off or show-status=auto (and no error had occured),
the user is expecting maybe 15 to 90 seconds with no output (because that's
usually how long the whole boot takes). So we shouldn't bother the user with
information about a few seconds of delay. Let's make the timeout 25s if we are
not showing any messages.

Conversly, when we are outputting status messages, we can show the cylon eye
with a shorter delay, now that we removed the connection to enablement status.
Let's make this 2s, so users get feedback about delays more quickly.
2020-03-01 11:42:35 +01:00
Zbigniew Jędrzejewski-Szmek ef15d3e1ab pid1: touch the /run/systemd/show-status just once
We know if we created the file before, no need to repeat the operation. The
state in /run should always match our internal state. Since we call
manager_set_show_status() quite often internally, this saves quite a few
pointless syscalls.
2020-03-01 11:42:26 +01:00
Zbigniew Jędrzejewski-Szmek 7365a29670 pid1: when printing status message status, give reason 2020-03-01 11:42:19 +01:00
Zbigniew Jędrzejewski-Szmek 5ca02bfc39 core: fix message about show status state
We would say "Enabling" also for SHOW_STATUS_AUTO, which is actually
"soft off". So just print the exact state to make things easier to understand.
Also add a helper function to avoid repeating the enum value list.

For #14814.
2020-03-01 11:42:12 +01:00
11 changed files with 68 additions and 49 deletions

3
TODO
View File

@ -677,9 +677,6 @@ Features:
* merge ~/.local/share and ~/.local/lib into one similar /usr/lib and /usr/share....
* systemd.show_status= should probably have a mode where only failed
units are shown.
* add systemd.abort_on_kill or some other such flag to send SIGABRT instead of SIGKILL
(throughout the codebase, not only PID1)

View File

@ -798,15 +798,14 @@
<varlistentry>
<term><varname>systemd.show_status</varname></term>
<listitem><para>Takes a boolean argument or the constant
<constant>auto</constant>. Can be also specified without an argument, with
the same effect as a positive boolean. If enabled, the systemd manager (PID
1) shows terse service status updates on the console during bootup.
<constant>auto</constant> behaves like <option>false</option> until a unit
fails or there is a significant delay in boot. Defaults to enabled, unless
<option>quiet</option> is passed as kernel command line option, in which case
it defaults to <constant>auto</constant>. If specified overrides the system
manager configuration file option <option>ShowStatus=</option>, see
<listitem><para>Takes a boolean argument or the constants <constant>error</constant> and
<constant>auto</constant>. Can be also specified without an argument, with the same effect as a
positive boolean. If enabled, the systemd manager (PID 1) shows terse service status updates on the
console during bootup. With <constant>error</constant>, only messages about failures are shown, but
boot is otherwise quiet. <constant>auto</constant> behaves like <option>false</option> until there is
a significant delay in boot. Defaults to enabled, unless <option>quiet</option> is passed as kernel
command line option, in which case it defaults to <constant>error</constant>. If specified overrides
the system manager configuration file option <option>ShowStatus=</option>, see
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para></listitem>
</varlistentry>

View File

@ -572,7 +572,7 @@ static void job_print_begin_status_message(Unit *u, JobType t) {
format = job_get_begin_status_message_format(u, t);
DISABLE_WARNING_FORMAT_NONLITERAL;
unit_status_printf(u, "", format);
unit_status_printf(u, STATUS_TYPE_NORMAL, "", format);
REENABLE_WARNING;
}
@ -861,11 +861,10 @@ static void job_print_done_status_message(Unit *u, JobType t, JobResult result)
else
status = job_print_done_status_messages[result].word;
if (result != JOB_DONE)
manager_flip_auto_status(u->manager, true);
DISABLE_WARNING_FORMAT_NONLITERAL;
unit_status_printf(u, status, format);
unit_status_printf(u,
result == JOB_DONE ? STATUS_TYPE_NORMAL : STATUS_TYPE_NOTICE,
status, format);
REENABLE_WARNING;
if (t == JOB_START && result == JOB_FAILED) {

View File

@ -494,7 +494,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
} else if (streq(key, "quiet") && !value) {
if (arg_show_status == _SHOW_STATUS_INVALID)
arg_show_status = SHOW_STATUS_AUTO;
arg_show_status = SHOW_STATUS_ERROR;
} else if (streq(key, "debug") && !value) {
@ -711,7 +711,7 @@ static void set_manager_settings(Manager *m) {
m->kexec_watchdog = arg_kexec_watchdog;
m->cad_burst_action = arg_cad_burst_action;
manager_set_show_status(m, arg_show_status);
manager_set_show_status(m, arg_show_status, "commandline");
m->status_unit_format = arg_status_unit_format;
}
@ -1254,7 +1254,7 @@ static int status_welcome(void) {
_cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL;
int r;
if (IN_SET(arg_show_status, SHOW_STATUS_NO, SHOW_STATUS_AUTO))
if (!show_status_on(arg_show_status))
return 0;
r = parse_os_release(NULL,

View File

@ -85,7 +85,8 @@
#define CGROUPS_AGENT_RCVBUF_SIZE (8*1024*1024)
/* Initial delay and the interval for printing status messages about running jobs */
#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
#define JOBS_IN_PROGRESS_WAIT_USEC (2*USEC_PER_SEC)
#define JOBS_IN_PROGRESS_QUIET_WAIT_USEC (25*USEC_PER_SEC)
#define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3)
#define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3
@ -109,6 +110,12 @@ static int manager_dispatch_timezone_change(sd_event_source *source, const struc
static int manager_run_environment_generators(Manager *m);
static int manager_run_generators(Manager *m);
static usec_t manager_watch_jobs_next_time(Manager *m) {
return usec_add(now(CLOCK_MONOTONIC),
show_status_on(m->show_status) ? JOBS_IN_PROGRESS_WAIT_USEC :
JOBS_IN_PROGRESS_QUIET_WAIT_USEC);
}
static void manager_watch_jobs_in_progress(Manager *m) {
usec_t next;
int r;
@ -124,7 +131,7 @@ static void manager_watch_jobs_in_progress(Manager *m) {
if (m->jobs_in_progress_event_source)
return;
next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
next = manager_watch_jobs_next_time(m);
r = sd_event_add_time(
m->event,
&m->jobs_in_progress_event_source,
@ -173,15 +180,15 @@ static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned po
}
}
void manager_flip_auto_status(Manager *m, bool enable) {
void manager_flip_auto_status(Manager *m, bool enable, const char *reason) {
assert(m);
if (enable) {
if (m->show_status == SHOW_STATUS_AUTO)
manager_set_show_status(m, SHOW_STATUS_TEMPORARY);
manager_set_show_status(m, SHOW_STATUS_TEMPORARY, reason);
} else {
if (m->show_status == SHOW_STATUS_TEMPORARY)
manager_set_show_status(m, SHOW_STATUS_AUTO);
manager_set_show_status(m, SHOW_STATUS_AUTO, reason);
}
}
@ -198,7 +205,7 @@ static void manager_print_jobs_in_progress(Manager *m) {
assert(m);
assert(m->n_running_jobs > 0);
manager_flip_auto_status(m, true);
manager_flip_auto_status(m, true, "delay");
print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs;
@ -2736,11 +2743,11 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
switch (sfsi.ssi_signo - SIGRTMIN) {
case 20:
manager_set_show_status(m, SHOW_STATUS_YES);
manager_set_show_status(m, SHOW_STATUS_YES, "signal");
break;
case 21:
manager_set_show_status(m, SHOW_STATUS_NO);
manager_set_show_status(m, SHOW_STATUS_NO, "signal");
break;
case 22:
@ -3402,7 +3409,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
if (s < 0)
log_notice("Failed to parse show-status flag '%s', ignoring.", val);
else
manager_set_show_status(m, s);
manager_set_show_status(m, s, "deserialization");
} else if ((val = startswith(l, "log-level-override="))) {
int level;
@ -3773,12 +3780,12 @@ void manager_check_finished(Manager *m) {
if (hashmap_size(m->jobs) > 0) {
if (m->jobs_in_progress_event_source)
/* Ignore any failure, this is only for feedback */
(void) sd_event_source_set_time(m->jobs_in_progress_event_source, now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
(void) sd_event_source_set_time(m->jobs_in_progress_event_source,
manager_watch_jobs_next_time(m));
return;
}
manager_flip_auto_status(m, false);
manager_flip_auto_status(m, false, "boot finished");
/* Notify Type=idle units that we are done now */
manager_close_idle_pipe(m);
@ -4076,19 +4083,24 @@ void manager_recheck_journal(Manager *m) {
log_open();
}
void manager_set_show_status(Manager *m, ShowStatus mode) {
void manager_set_show_status(Manager *m, ShowStatus mode, const char *reason) {
assert(m);
assert(IN_SET(mode, SHOW_STATUS_AUTO, SHOW_STATUS_NO, SHOW_STATUS_YES, SHOW_STATUS_TEMPORARY));
assert(mode >= 0 && mode < _SHOW_STATUS_MAX);
if (!MANAGER_IS_SYSTEM(m))
return;
if (m->show_status != mode)
log_debug("%s showing of status.",
mode == SHOW_STATUS_NO ? "Disabling" : "Enabling");
if (mode == m->show_status)
return;
bool enabled = IN_SET(mode, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES);
log_debug("%s (%s) showing of status (%s).",
enabled ? "Enabling" : "Disabling",
strna(show_status_to_string(mode)),
reason);
m->show_status = mode;
if (IN_SET(mode, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES))
if (enabled)
(void) touch("/run/systemd/show-status");
else
(void) unlink("/run/systemd/show-status");
@ -4110,7 +4122,10 @@ static bool manager_get_show_status(Manager *m, StatusType type) {
if (type != STATUS_TYPE_EMERGENCY && manager_check_ask_password(m) > 0)
return false;
return IN_SET(m->show_status, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES);
if (type == STATUS_TYPE_NOTICE && m->show_status != SHOW_STATUS_NO)
return true;
return show_status_on(m->show_status);
}
const char *manager_get_confirm_spawn(Manager *m) {

View File

@ -56,6 +56,7 @@ typedef enum ManagerObjective {
typedef enum StatusType {
STATUS_TYPE_EPHEMERAL,
STATUS_TYPE_NORMAL,
STATUS_TYPE_NOTICE,
STATUS_TYPE_EMERGENCY,
} StatusType;
@ -505,11 +506,11 @@ void disable_printk_ratelimit(void);
void manager_recheck_dbus(Manager *m);
void manager_recheck_journal(Manager *m);
void manager_set_show_status(Manager *m, ShowStatus mode);
void manager_set_show_status(Manager *m, ShowStatus mode, const char *reason);
void manager_set_first_boot(Manager *m, bool b);
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) _printf_(4,5);
void manager_flip_auto_status(Manager *m, bool enable);
void manager_flip_auto_status(Manager *m, bool enable, const char *reason);
Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path);

View File

@ -16,6 +16,7 @@
static const char* const show_status_table[_SHOW_STATUS_MAX] = {
[SHOW_STATUS_NO] = "no",
[SHOW_STATUS_ERROR] = "error",
[SHOW_STATUS_AUTO] = "auto",
[SHOW_STATUS_TEMPORARY] = "temporary",
[SHOW_STATUS_YES] = "yes",

View File

@ -8,10 +8,11 @@
/* Manager status */
typedef enum ShowStatus {
SHOW_STATUS_NO,
SHOW_STATUS_AUTO,
SHOW_STATUS_TEMPORARY,
SHOW_STATUS_YES,
SHOW_STATUS_NO, /* printing of status is disabled */
SHOW_STATUS_ERROR, /* only print errors */
SHOW_STATUS_AUTO, /* disabled but may flip to _TEMPORARY */
SHOW_STATUS_TEMPORARY, /* enabled temporarily, may flip back to _AUTO */
SHOW_STATUS_YES, /* printing of status is enabled */
_SHOW_STATUS_MAX,
_SHOW_STATUS_INVALID = -1,
} ShowStatus;
@ -28,6 +29,9 @@ typedef enum StatusUnitFormat {
_STATUS_UNIT_FORMAT_INVALID = -1,
} StatusUnitFormat;
static inline bool show_status_on(ShowStatus s) {
return IN_SET(s, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES);
}
ShowStatus show_status_from_string(const char *v) _const_;
const char* show_status_to_string(ShowStatus s) _pure_;
int parse_show_status(const char *v, ShowStatus *ret);

View File

@ -425,7 +425,9 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
else
status = " SKIP ";
unit_status_printf(delete->unit, status,
unit_status_printf(delete->unit,
STATUS_TYPE_NOTICE,
status,
"Ordering cycle found, skipping %s");
transaction_delete_unit(tr, delete->unit);
return -EAGAIN;

View File

@ -1659,7 +1659,7 @@ static bool unit_test_assert(Unit *u) {
return u->assert_result;
}
void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) {
void unit_status_printf(Unit *u, StatusType status_type, const char *status, const char *unit_status_msg_format) {
const char *d;
d = unit_status_string(u);
@ -1667,7 +1667,7 @@ void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg
d = strjoina(ANSI_HIGHLIGHT, d, ANSI_NORMAL);
DISABLE_WARNING_FORMAT_NONLITERAL;
manager_status_printf(u->manager, STATUS_TYPE_NORMAL, status, unit_status_msg_format, d);
manager_status_printf(u->manager, status_type, status, unit_status_msg_format, d);
REENABLE_WARNING;
}

View File

@ -9,6 +9,7 @@
#include "condition.h"
#include "emergency-action.h"
#include "list.h"
#include "show-status.h"
#include "set.h"
#include "unit-file.h"
#include "cgroup.h"
@ -748,7 +749,7 @@ int unit_add_blockdev_dependency(Unit *u, const char *what, UnitDependencyMask m
int unit_coldplug(Unit *u);
void unit_catchup(Unit *u);
void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) _printf_(3, 0);
void unit_status_printf(Unit *u, StatusType status_type, const char *status, const char *unit_status_msg_format) _printf_(4, 0);
bool unit_need_daemon_reload(Unit *u);