1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-20 18:04:03 +03:00

Merge pull request #31026 from poettering/nspawn-tint

nspawn: allow tinting the background of interactive tty sessions
This commit is contained in:
Lennart Poettering 2024-01-23 22:32:00 +01:00 committed by GitHub
commit e944d3ab92
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 104 additions and 49 deletions

View File

@ -1711,6 +1711,21 @@ After=sys-subsystem-net-devices-ens1.device</programlisting>
<xi:include href="version-info.xml" xpointer="v242"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--background=<replaceable>COLOR</replaceable></option></term>
<listitem><para>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 <literal>40</literal>, <literal>41</literal>, …, <literal>47</literal>, <literal>48;2;…</literal>,
<literal>48;5;…</literal>. See <ulink
url="https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters">ANSI
Escape Code (Wikipedia)</ulink> for details. Assign an empty string to disable any coloring.</para>
<xi:include href="version-info.xml" xpointer="v256"/>
</listitem>
</varlistentry>
</variablelist>
</refsect2>

View File

@ -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

View File

@ -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:

View File

@ -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;

View File

@ -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,

View File

@ -5,6 +5,7 @@
#include <stdio.h>
#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;
}

View File

@ -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);