run0: optionally show superhero emoji on each shell prompt
authorLennart Poettering <lennart@poettering.net>
Thu, 24 Oct 2024 09:36:48 +0000 (11:36 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 25 Oct 2024 15:31:06 +0000 (17:31 +0200)
This makes use of the infra introduced in 229d4a980607e9478cf1935793652ddd9a14618b to indicate visually on each prompt that we are in superuser mode temporarily.
pick ad5de3222f userdbctl: add some basic client-side filtering

man/run0.xml
src/basic/glyph-util.c
src/basic/glyph-util.h
src/run/run.c
src/test/test-locale-util.c

index 422ca6bebbfa74968b84df39dfddcd8419070498..907222c0495661f8d4530fad528adfe82d917e06 100644 (file)
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--shell-prompt-prefix=<replaceable>STRING</replaceable></option></term>
+
+        <listitem><para>Set a shell prompt prefix string. This ultimately controls the
+        <varname>$SHELL_PROMPT_PREFIX</varname> environment variable for the invoked program, which is
+        typically imported into the shell prompt. By default – if emojis are supported – a superhero emoji is
+        shown (🦸). This default may also be changed (or turned off) by passing the
+        <varname>$SYSTEMD_RUN_SHELL_PROMPT_PREFIX</varname> environment variable to <varname>run0</varname>,
+        see below. Set to an empty string to disable shell prompt prefixing.</para>
+
+        <xi:include href="version-info.xml" xpointer="v257"/>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--machine=</option></term>
 
 
         <xi:include href="version-info.xml" xpointer="v256"/></listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><varname>$SHELL_PROMPT_PREFIX</varname></term>
+        <listitem><para>By default set to the superhero emoji (if supported), but may be overriden with the
+        <varname>$SYSTEMD_RUN_SHELL_PROMPT_PREFIX</varname> environment variable (see below), or the
+        <option>--shell-prompt-prefix=</option> switch (see above).</para>
+
+        <xi:include href="version-info.xml" xpointer="v257"/></listitem>
+      </varlistentry>
     </variablelist>
+
+    <para>The following variables may be passed to <command>run0</command>:</para>
+
+    <variablelist>
+      <varlistentry>
+        <term><varname>$SYSTEMD_RUN_SHELL_PROMPT_PREFIX</varname></term>
+        <listitem><para>If set, overrides the default shell prompt prefix that <command>run0</command> sets
+        for the invoked shell (the superhero emoji). Set to an empty string to disable shell prompt
+        prefixing.</para>
+
+        <xi:include href="version-info.xml" xpointer="v257"/></listitem>
+      </varlistentry>
+    </variablelist>
+
   </refsect1>
 
   <refsect1>
index 68fd3971adffb8eac5096c50b8adc7c2acb21bf6..1108afdf03e110bdd5250c10677cab2d34711877 100644 (file)
@@ -80,6 +80,7 @@ const char* special_glyph_full(SpecialGlyph code, bool force_utf) {
                         [SPECIAL_GLYPH_YELLOW_CIRCLE]           = "o",
                         [SPECIAL_GLYPH_BLUE_CIRCLE]             = "o",
                         [SPECIAL_GLYPH_GREEN_CIRCLE]            = "o",
+                        [SPECIAL_GLYPH_SUPERHERO]               = "S",
                 },
 
                 /* UTF-8 */
@@ -149,6 +150,7 @@ const char* special_glyph_full(SpecialGlyph code, bool force_utf) {
                         [SPECIAL_GLYPH_YELLOW_CIRCLE]           = u8"🟡",
                         [SPECIAL_GLYPH_BLUE_CIRCLE]             = u8"🔵",
                         [SPECIAL_GLYPH_GREEN_CIRCLE]            = u8"🟢",
+                        [SPECIAL_GLYPH_SUPERHERO]               = u8"🦸",
                 },
         };
 
index 9b5c3a8d2264237b44eb7a983f726feb004f2bf6..c31c3c18bba4b3aac8e0cc15573a2461b55e7cae 100644 (file)
@@ -55,6 +55,7 @@ typedef enum SpecialGlyph {
         SPECIAL_GLYPH_YELLOW_CIRCLE,
         SPECIAL_GLYPH_BLUE_CIRCLE,
         SPECIAL_GLYPH_GREEN_CIRCLE,
+        SPECIAL_GLYPH_SUPERHERO,
         _SPECIAL_GLYPH_MAX,
         _SPECIAL_GLYPH_INVALID = -EINVAL,
 } SpecialGlyph;
index 529e9d1bcce1f77e5b390f13b0ea54a49b17e53b..88fe8a0c8f78f9364bd2c7ecf89cfc8fada99c12 100644 (file)
@@ -85,6 +85,7 @@ static char *arg_exec_path = NULL;
 static bool arg_ignore_failure = false;
 static char *arg_background = NULL;
 static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
+static char *arg_shell_prompt_prefix = NULL;
 
 STATIC_DESTRUCTOR_REGISTER(arg_description, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_environment, strv_freep);
@@ -96,6 +97,7 @@ 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_DESTRUCTOR_REGISTER(arg_shell_prompt_prefix, freep);
 
 static int help(void) {
         _cleanup_free_ char *link = NULL;
@@ -194,6 +196,7 @@ static int help_sudo_mode(void) {
                "     --background=COLOR           Set ANSI color for background\n"
                "     --pty                        Request allocation of a pseudo TTY for stdio\n"
                "     --pipe                       Request direct pipe for stdio\n"
+               "     --shell-prompt-prefix=PREFIX Set $SHELL_PROMPT_PREFIX\n"
                "\nSee the %s for details.\n",
                program_invocation_short_name,
                ansi_highlight(),
@@ -778,29 +781,31 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
                 ARG_BACKGROUND,
                 ARG_PTY,
                 ARG_PIPE,
+                ARG_SHELL_PROMPT_PREFIX,
         };
 
         /* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions
          * though (but limit the extension to long options). */
 
         static const struct option options[] = {
-                { "help",               no_argument,       NULL, 'h'                    },
-                { "version",            no_argument,       NULL, 'V'                    },
-                { "no-ask-password",    no_argument,       NULL, ARG_NO_ASK_PASSWORD    },
-                { "machine",            required_argument, NULL, ARG_MACHINE            },
-                { "unit",               required_argument, NULL, ARG_UNIT               },
-                { "property",           required_argument, NULL, ARG_PROPERTY           },
-                { "description",        required_argument, NULL, ARG_DESCRIPTION        },
-                { "slice",              required_argument, NULL, ARG_SLICE              },
-                { "slice-inherit",      no_argument,       NULL, ARG_SLICE_INHERIT      },
-                { "user",               required_argument, NULL, 'u'                    },
-                { "group",              required_argument, NULL, 'g'                    },
-                { "nice",               required_argument, NULL, ARG_NICE               },
-                { "chdir",              required_argument, NULL, 'D'                    },
-                { "setenv",             required_argument, NULL, ARG_SETENV             },
-                { "background",         required_argument, NULL, ARG_BACKGROUND         },
-                { "pty",                no_argument,       NULL, ARG_PTY                },
-                { "pipe",               no_argument,       NULL, ARG_PIPE               },
+                { "help",                no_argument,       NULL, 'h'                     },
+                { "version",             no_argument,       NULL, 'V'                     },
+                { "no-ask-password",     no_argument,       NULL, ARG_NO_ASK_PASSWORD     },
+                { "machine",             required_argument, NULL, ARG_MACHINE             },
+                { "unit",                required_argument, NULL, ARG_UNIT                },
+                { "property",            required_argument, NULL, ARG_PROPERTY            },
+                { "description",         required_argument, NULL, ARG_DESCRIPTION         },
+                { "slice",               required_argument, NULL, ARG_SLICE               },
+                { "slice-inherit",       no_argument,       NULL, ARG_SLICE_INHERIT       },
+                { "user",                required_argument, NULL, 'u'                     },
+                { "group",               required_argument, NULL, 'g'                     },
+                { "nice",                required_argument, NULL, ARG_NICE                },
+                { "chdir",               required_argument, NULL, 'D'                     },
+                { "setenv",              required_argument, NULL, ARG_SETENV              },
+                { "background",          required_argument, NULL, ARG_BACKGROUND          },
+                { "pty",                 no_argument,       NULL, ARG_PTY                 },
+                { "pipe",                no_argument,       NULL, ARG_PIPE                },
+                { "shell-prompt-prefix", required_argument, NULL, ARG_SHELL_PROMPT_PREFIX },
                 {},
         };
 
@@ -907,6 +912,12 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
                                 arg_stdio = ARG_STDIO_DIRECT;
                         break;
 
+                case ARG_SHELL_PROMPT_PREFIX:
+                        r = free_and_strdup_warn(&arg_shell_prompt_prefix, optarg);
+                        if (r < 0)
+                                return r;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -1019,6 +1030,25 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
                         log_debug_errno(r, "Unable to get terminal background color, not tinting background: %m");
         }
 
+        if (!arg_shell_prompt_prefix) {
+                const char *e = secure_getenv("SYSTEMD_RUN_SHELL_PROMPT_PREFIX");
+                if (e) {
+                        arg_shell_prompt_prefix = strdup(e);
+                        if (!arg_shell_prompt_prefix)
+                                return log_oom();
+                } else if (emoji_enabled()) {
+                        arg_shell_prompt_prefix = strjoin(special_glyph(SPECIAL_GLYPH_SUPERHERO), " ");
+                        if (!arg_shell_prompt_prefix)
+                                return log_oom();
+                }
+        }
+
+        if (!isempty(arg_shell_prompt_prefix)) {
+                r = strv_env_assign(&arg_environment, "SHELL_PROMPT_PREFIX", arg_shell_prompt_prefix);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to set $SHELL_PROMPT_PREFIX environment variable: %m");
+        }
+
         return 1;
 }
 
index ab2d1f5746cf22fa20c272f1a08f7dac6ef45fd6..7afa446bfb6087dd2d09b86935e84460cde9afe3 100644 (file)
@@ -82,7 +82,7 @@ TEST(keymaps) {
 
 #define dump_glyph(x) log_info(STRINGIFY(x) ": %s", special_glyph(x))
 TEST(dump_special_glyphs) {
-        assert_cc(SPECIAL_GLYPH_GREEN_CIRCLE + 1 == _SPECIAL_GLYPH_MAX);
+        assert_cc(SPECIAL_GLYPH_SUPERHERO + 1 == _SPECIAL_GLYPH_MAX);
 
         log_info("is_locale_utf8: %s", yes_no(is_locale_utf8()));
 
@@ -133,6 +133,7 @@ TEST(dump_special_glyphs) {
         dump_glyph(SPECIAL_GLYPH_YELLOW_CIRCLE);
         dump_glyph(SPECIAL_GLYPH_BLUE_CIRCLE);
         dump_glyph(SPECIAL_GLYPH_GREEN_CIRCLE);
+        dump_glyph(SPECIAL_GLYPH_SUPERHERO);
 }
 
 DEFINE_TEST_MAIN(LOG_INFO);