]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
profile/systemd-osc-context: also escape $USER and $HOSTNAME 43091/head
authorRasmus Villemoes <rv@rasmusvillemoes.dk>
Tue, 21 Jul 2026 08:43:22 +0000 (10:43 +0200)
committerRasmus Villemoes <rv@rasmusvillemoes.dk>
Tue, 21 Jul 2026 09:21:00 +0000 (11:21 +0200)
Claude pointed out that while rather unlikely, it is possible for the USER and
HOSTNAME environment variables to contain problematic characters that require
escaping. Now that that escaping no longer involves the fork+exec overhead of
calling sed, let's ensure those fields do get put through the escape routine.

Refactor __systemd_osc_context_escape so that it not only takes the value and
prints that, but also the format specifier used for emitting the field. That
way, we avoid an extra subshell (i.e. fork+pipe and all that overhead), and
combined with the previous commit, we now only spawn one subshell instead of
two per start= sequence.

That could be reduced to zero, if the "callers" were rewritten to something
like

    printf "\033]3008;start=%.64s;type=shell" "$systemd_osc_context_shell_id"
    __systemd_osc_context_common
    printf "\033\\"

but that will mean that the sequence is not emitted with a single write()
system call [which isn't really guaranteed currently either, just very likely],
so some background process could end up writing to the middle of the sequence,
thus losing that output and mangling the OSC3008 info. This in turn could be
overcome by building the whole sequence in a shell variable using 'printf -v'
and only printing at the end, but that would be a somewhat invasive change.

profile.d/80-systemd-osc-context.sh

index 6b4aa348cfffc994e46e5f73156d75e65f7a6f57..80c4740d47da0221183e645020b0faf799d39e0e 100644 (file)
 shopt -q promptvars || return 0
 
 __systemd_osc_context_escape() {
-    # Escape according to the OSC 3008 spec. We'll only do it where it's
-    # strictly necessary, and skip it when processing strings we are pretty
-    # sure we won't need it for, such as uuids, id128, hostnames, usernames,
-    # since they all come with syntax requirements that exclude \ and ;
-    # anyway. This hence primarily is about escaping the current working
-    # directory.
-    local systemd_value="$1"
+    # Escape according to the OSC 3008 spec. We'll skip it when processing
+    # strings we are pretty sure we won't need it for, such as uuids
+    # (originating from /proc/sys/kernel/ or /etc/machine-id) and special shell
+    # variables such as $$ and $? that always expand to decimal numbers.
+    local systemd_format="$1"
+    local systemd_value="$2"
     systemd_value="${systemd_value//\\/\\x5c}"
     systemd_value="${systemd_value//;/\\x3b}"
     systemd_value="${systemd_value//[[:cntrl:]]/⍰}"
-    printf "%s" "$systemd_value"
+    # shellcheck disable=SC2059 # always called with fixed format strings with a single string specifier
+    printf "$systemd_format" "$systemd_value"
 }
 
 __systemd_osc_context_common() {
     if [ -f /etc/machine-id ]; then
         printf ";machineid=%.36s" "$(</etc/machine-id)"
     fi
-    printf ";user=%.255s;hostname=%.255s;bootid=%.36s;pid=%.20s" "$USER" "$HOSTNAME" "$(</proc/sys/kernel/random/boot_id)" "$$"
-    printf ";cwd=%.255s" "$(__systemd_osc_context_escape "$PWD")"
+    __systemd_osc_context_escape ";user=%.255s" "$USER"
+    __systemd_osc_context_escape ";hostname=%.255s" "$HOSTNAME"
+    printf ";bootid=%.36s;pid=%.20s" "$(</proc/sys/kernel/random/boot_id)" "$$"
+    __systemd_osc_context_escape ";cwd=%.255s" "$PWD"
 }
 
 __systemd_osc_context_precmdline() {