diff options
author | Lennart Poettering <lennart@poettering.net> | 2023-12-20 12:09:27 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2023-12-21 19:15:01 +0100 |
commit | 2f0b4d578b7d3bb7fbaba0cdf3f9bc358a40800d (patch) | |
tree | bc42fdde0d5dbf9044ec41d718b4879c5312f236 | |
parent | color-util: add helper to convert RGB → HSV (diff) | |
download | systemd-2f0b4d578b7d3bb7fbaba0cdf3f9bc358a40800d.tar.xz systemd-2f0b4d578b7d3bb7fbaba0cdf3f9bc358a40800d.zip |
run/uid0: tint the terminal background color (and add new --background= switch)
This adds a new --background= switch that allows specifiying a
background color for the terminal while the tool runs.
It also teaches the tool when invoked as uid0 to tint the terminal in a
reddish hue when operating as root, and in a yellowish hue when
operating as any other user.
This should highlight nicely when the user is operating with elevated
privileges, or changed privileges.
-rw-r--r-- | man/systemd-run.xml | 14 | ||||
-rw-r--r-- | man/uid0.xml | 18 | ||||
-rw-r--r-- | src/run/run.c | 58 |
3 files changed, 89 insertions, 1 deletions
diff --git a/man/systemd-run.xml b/man/systemd-run.xml index a334ab94d5..7b508a462c 100644 --- a/man/systemd-run.xml +++ b/man/systemd-run.xml @@ -496,6 +496,20 @@ <xi:include href="version-info.xml" xpointer="v256"/></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 + session lasts. 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.</para> + + <xi:include href="version-info.xml" xpointer="v256"/> + </listitem> + </varlistentry> + <xi:include href="user-system-options.xml" xpointer="user" /> <xi:include href="user-system-options.xml" xpointer="system" /> <xi:include href="user-system-options.xml" xpointer="host" /> diff --git a/man/uid0.xml b/man/uid0.xml index 6ef868a8e5..0d36ca77a4 100644 --- a/man/uid0.xml +++ b/man/uid0.xml @@ -182,6 +182,24 @@ </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 + session lasts. If not specified, the background will be tinted in a reddish tone when operating as + root, and in a yellowish tone when operating under another UID, as reminder of the changed + privileges. 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. Set to an empty string to disable.</para> + + <para>Example: <literal>--background=44</literal> for a blue background.</para> + + <xi:include href="version-info.xml" xpointer="v256"/> + </listitem> + </varlistentry> + <xi:include href="user-system-options.xml" xpointer="machine" /> <xi:include href="standard-options.xml" xpointer="help" /> <xi:include href="standard-options.xml" xpointer="version" /> diff --git a/src/run/run.c b/src/run/run.c index d90dbbe411..920e38af0c 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -17,6 +17,7 @@ #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" @@ -75,6 +76,7 @@ static bool arg_shell = false; static char **arg_cmdline = NULL; static char *arg_exec_path = NULL; static bool arg_ignore_failure = false; +static char *arg_background = NULL; STATIC_DESTRUCTOR_REGISTER(arg_description, freep); STATIC_DESTRUCTOR_REGISTER(arg_environment, strv_freep); @@ -85,6 +87,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_timer_property, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_working_directory, freep); STATIC_DESTRUCTOR_REGISTER(arg_cmdline, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_exec_path, freep); +STATIC_DESTRUCTOR_REGISTER(arg_background, freep); static int help(void) { _cleanup_free_ char *link = NULL; @@ -127,6 +130,7 @@ static int help(void) { " -G --collect Unload unit after it ran, even when failed\n" " -S --shell Invoke a $SHELL interactively\n" " --ignore-failure Ignore the exit status of the invoked process\n" + " --background=COLOR Set ANSI color for background\n" "\n%3$sPath options:%4$s\n" " --path-property=NAME=VALUE Set path unit property\n" "\n%3$sSocket options:%4$s\n" @@ -174,6 +178,7 @@ static int help_sudo_mode(void) { " --nice=NICE Nice level\n" " -D --chdir=PATH Set working directory\n" " --setenv=NAME[=VALUE] Set environment variable\n" + " --background=COLOR Set ANSI color for background\n" "\nSee the %s for details.\n", program_invocation_short_name, ansi_highlight(), @@ -244,6 +249,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_WORKING_DIRECTORY, ARG_SHELL, ARG_IGNORE_FAILURE, + ARG_BACKGROUND, }; static const struct option options[] = { @@ -290,6 +296,7 @@ static int parse_argv(int argc, char *argv[]) { { "same-dir", no_argument, NULL, 'd' }, { "shell", no_argument, NULL, 'S' }, { "ignore-failure", no_argument, NULL, ARG_IGNORE_FAILURE }, + { "background", no_argument, NULL, ARG_BACKGROUND }, {}, }; @@ -333,7 +340,7 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_DESCRIPTION: - r = free_and_strdup(&arg_description, optarg); + r = free_and_strdup_warn(&arg_description, optarg); if (r < 0) return r; break; @@ -579,6 +586,12 @@ static int parse_argv(int argc, char *argv[]) { arg_ignore_failure = true; break; + case ARG_BACKGROUND: + r = free_and_strdup_warn(&arg_background, optarg); + if (r < 0) + return r; + break; + case '?': return -EINVAL; @@ -719,6 +732,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) { ARG_SLICE_INHERIT, ARG_NICE, ARG_SETENV, + ARG_BACKGROUND, }; /* If invoked as "uid0" binary, let's expose a more sudo-like interface. We add various extensions @@ -739,6 +753,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) { { "nice", required_argument, NULL, ARG_NICE }, { "chdir", required_argument, NULL, 'D' }, { "setenv", required_argument, NULL, ARG_SETENV }, + { "background", required_argument, NULL, ARG_BACKGROUND }, {}, }; @@ -823,6 +838,13 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) { break; + case ARG_BACKGROUND: + r = free_and_strdup_warn(&arg_background, optarg); + if (r < 0) + return r; + + break; + case '?': return -EINVAL; @@ -916,6 +938,37 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) { if (strv_extend(&arg_property, "PAMName=systemd-uid0") < 0) return log_oom(); + if (!arg_background && arg_stdio == ARG_STDIO_PTY) { + double red, green, blue; + + r = get_default_background_color(&red, &green, &blue); + 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; } @@ -1701,6 +1754,9 @@ static int start_transient_service(sd_bus *bus) { /* Make sure to process any TTY events before we process bus events */ (void) pty_forward_set_priority(c.forward, SD_EVENT_PRIORITY_IMPORTANT); + + if (!isempty(arg_background)) + (void) pty_forward_set_background_color(c.forward, arg_background); } path = unit_dbus_path_from_name(service); |