diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 1a9fb09aae..59b2c1a2d0 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -1711,6 +1711,21 @@ After=sys-subsystem-net-devices-ens1.device + + + + + Change the terminal background color to the specified ANSI color as long as the + container runs. The color specified should be an ANSI X3.64 SGR background color, i.e. strings such + as 40, 41, …, 47, 48;2;…, + 48;5;…. See ANSI + Escape Code (Wikipedia) for details. Assign an empty string to disable any coloring. + + + + + diff --git a/shell-completion/bash/systemd-nspawn b/shell-completion/bash/systemd-nspawn index cc3d2f6598..b12711be80 100644 --- a/shell-completion/bash/systemd-nspawn +++ b/shell-completion/bash/systemd-nspawn @@ -73,7 +73,7 @@ _systemd_nspawn() { --pivot-root --property --private-users --private-users-ownership --network-namespace-path --network-ipvlan --network-veth-extra --network-zone -p --port --system-call-filter --overlay --overlay-ro --settings --rlimit --hostname --no-new-privileges --oom-score-adjust --cpu-affinity - --resolv-conf --timezone --root-hash-sig' + --resolv-conf --timezone --root-hash-sig --background' ) _init_completion || return diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 89ef0e4daa..50bb0565ca 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -236,6 +236,7 @@ static bool arg_suppress_sync = false; static char *arg_settings_filename = NULL; static Architecture arg_architecture = _ARCHITECTURE_INVALID; static ImagePolicy *arg_image_policy = NULL; +static char *arg_background = NULL; STATIC_DESTRUCTOR_REGISTER(arg_directory, freep); STATIC_DESTRUCTOR_REGISTER(arg_template, freep); @@ -272,6 +273,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_sysctl, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_bind_user, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_settings_filename, freep); STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); +STATIC_DESTRUCTOR_REGISTER(arg_background, freep); static int handle_arg_console(const char *arg) { if (streq(arg, "help")) { @@ -450,6 +452,7 @@ static int help(void) { " --console=MODE Select how stdin/stdout/stderr and /dev/console are\n" " set up for the container.\n" " -P --pipe Equivalent to --console=pipe\n\n" + " --background=COLOR Set ANSI color for background\n" "%3$sCredentials:%4$s\n" " --set-credential=ID:VALUE\n" " Pass a credential with literal value to container.\n" @@ -745,6 +748,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_BIND_USER, ARG_SUPPRESS_SYNC, ARG_IMAGE_POLICY, + ARG_BACKGROUND, }; static const struct option options[] = { @@ -819,6 +823,7 @@ static int parse_argv(int argc, char *argv[]) { { "bind-user", required_argument, NULL, ARG_BIND_USER }, { "suppress-sync", required_argument, NULL, ARG_SUPPRESS_SYNC }, { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, + { "background", required_argument, NULL, ARG_BACKGROUND }, {} }; @@ -1608,6 +1613,12 @@ static int parse_argv(int argc, char *argv[]) { return r; break; + case ARG_BACKGROUND: + r = free_and_strdup_warn(&arg_background, optarg); + if (r < 0) + return r; + break; + case '?': return -EINVAL; @@ -5339,9 +5350,22 @@ static int run_container( return log_error_errno(r, "Failed to create PTY forwarder: %m"); if (arg_console_width != UINT_MAX || arg_console_height != UINT_MAX) - (void) pty_forward_set_width_height(forward, - arg_console_width, - arg_console_height); + (void) pty_forward_set_width_height( + forward, + arg_console_width, + arg_console_height); + + if (!arg_background) { + _cleanup_free_ char *bg = NULL; + + r = terminal_tint_color(220 /* blue */, &bg); + if (r < 0) + log_debug_errno(r, "Failed to determine terminal background color, not tinting."); + else + (void) pty_forward_set_background_color(forward, bg); + } else if (!isempty(arg_background)) + (void) pty_forward_set_background_color(forward, arg_background); + break; default: diff --git a/src/run/run.c b/src/run/run.c index c3313c6c52..a695fea0f0 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -17,7 +17,6 @@ #include "bus-unit-util.h" #include "bus-wait-for-jobs.h" #include "calendarspec.h" -#include "color-util.h" #include "env-util.h" #include "escape.h" #include "exit-status.h" @@ -940,34 +939,16 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) { return log_oom(); if (!arg_background && arg_stdio == ARG_STDIO_PTY) { - double red, green, blue; + double hue; - r = get_default_background_color(&red, &green, &blue); + if (!arg_exec_user || STR_IN_SET(arg_exec_user, "root", "0")) + hue = 0; /* red */ + else + hue = 60 /* yellow */; + + r = terminal_tint_color(hue, &arg_background); if (r < 0) log_debug_errno(r, "Unable to get terminal background color, not tinting background: %m"); - else { - double h, s, v; - - rgb_to_hsv(red, green, blue, &h, &s, &v); - - if (!arg_exec_user || STR_IN_SET(arg_exec_user, "root", "0")) - h = 0; /* red */ - else - h = 60 /* yellow */; - - if (v > 50) /* If the background is bright, then pull down saturation */ - s = 25; - else /* otherwise pump it up */ - s = 75; - - v = MAX(30, v); /* Make sure we don't hide the color in black */ - - uint8_t r8, g8, b8; - hsv_to_rgb(h, s, v, &r8, &g8, &b8); - - if (asprintf(&arg_background, "48;2;%u;%u;%u", r8, g8, b8) < 0) - return log_oom(); - } } return 1; diff --git a/src/shared/color-util.c b/src/shared/color-util.c index 776445ecfc..9d714c0fff 100644 --- a/src/shared/color-util.c +++ b/src/shared/color-util.c @@ -11,35 +11,38 @@ void rgb_to_hsv(double r, double g, double b, assert(r >= 0 && r <= 1); assert(g >= 0 && g <= 1); assert(b >= 0 && b <= 1); - assert(ret_h); - assert(ret_s); - assert(ret_v); double max_color = fmax(r, fmax(g, b)); double min_color = fmin(r, fmin(g, b)); double delta = max_color - min_color; - *ret_v = max_color * 100.0; + if (ret_v) + *ret_v = max_color * 100.0; - if (max_color > 0) - *ret_s = delta / max_color * 100.0; - else { - *ret_s = 0; - *ret_h = NAN; + if (max_color <= 0) { + if (ret_s) + *ret_s = 0; + if (ret_h) + *ret_h = NAN; return; } - if (delta > 0) { - if (r >= max_color) - *ret_h = 60 * fmod((g - b) / delta, 6); - else if (g >= max_color) - *ret_h = 60 * (((b - r) / delta) + 2); - else if (b >= max_color) - *ret_h = 60 * (((r - g) / delta) + 4); + if (ret_s) + *ret_s = delta / max_color * 100.0; - *ret_h = fmod(*ret_h, 360); - } else - *ret_h = NAN; + if (ret_h) { + if (delta > 0) { + if (r >= max_color) + *ret_h = 60 * fmod((g - b) / delta, 6); + else if (g >= max_color) + *ret_h = 60 * (((b - r) / delta) + 2); + else if (b >= max_color) + *ret_h = 60 * (((r - g) / delta) + 4); + + *ret_h = fmod(*ret_h, 360); + } else + *ret_h = NAN; + } } void hsv_to_rgb(double h, double s, double v, diff --git a/src/shared/pretty-print.c b/src/shared/pretty-print.c index cb1ac2bb76..7dd31a099f 100644 --- a/src/shared/pretty-print.c +++ b/src/shared/pretty-print.c @@ -5,6 +5,7 @@ #include #include "alloc-util.h" +#include "color-util.h" #include "conf-files.h" #include "constants.h" #include "env-util.h" @@ -441,3 +442,32 @@ int conf_files_cat(const char *root, const char *name, CatFlags flags) { return cat_files(path, files, flags); } + +int terminal_tint_color(double hue, char **ret) { + double red, green, blue; + int r; + + assert(ret); + + r = get_default_background_color(&red, &green, &blue); + if (r < 0) + return log_debug_errno(r, "Unable to get terminal background color: %m"); + + double s, v; + rgb_to_hsv(red, green, blue, /* h= */ NULL, &s, &v); + + if (v > 50) /* If the background is bright, then pull down saturation */ + s = 25; + else /* otherwise pump it up */ + s = 75; + + v = MAX(30, v); /* Make sure we don't hide the color in black */ + + uint8_t r8, g8, b8; + hsv_to_rgb(hue, s, v, &r8, &g8, &b8); + + if (asprintf(ret, "48;2;%u;%u;%u", r8, g8, b8) < 0) + return -ENOMEM; + + return 0; +} diff --git a/src/shared/pretty-print.h b/src/shared/pretty-print.h index c17e976580..6069318be7 100644 --- a/src/shared/pretty-print.h +++ b/src/shared/pretty-print.h @@ -47,3 +47,5 @@ static inline const char *green_check_mark_internal(char buffer[static GREEN_CHE #define GREEN_CHECK_MARK() green_check_mark_internal((char[GREEN_CHECK_MARK_MAX]) {}) #define COLOR_MARK_BOOL(b) ((b) ? GREEN_CHECK_MARK() : RED_CROSS_MARK()) + +int terminal_tint_color(double hue, char **ret);