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.
This commit is contained in:
Lennart Poettering
2023-12-20 12:09:27 +01:00
parent 447bcbfc90
commit 2f0b4d578b
3 changed files with 89 additions and 1 deletions

View File

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

View File

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

View File

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