From 3de092fad7708a2ff587a55c52c62ece1a13f40b Mon Sep 17 00:00:00 2001 From: Chris Lindee Date: Mon, 16 Feb 2026 00:08:31 -0600 Subject: [PATCH 1/5] profile/systemd-osc-context: Bring exit up to spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The exit status should be compared against 128 — not 127 — as the Bash manual, under the EXIT STATUS section, states [0]: When a command terminates on a fatal signal N, bash uses the value of 128+N as the exit status. If a command is not found, the child process created to execute it returns a status of 127. If a command is found but is not executable, the return status is 126. Furthermore, UAPI.15 specifies the `signal` value must be the symbolic signal name, not a numerical value [1]. Luckily, POSIX.1-2008 ensures the shell must supply `kill -l`, which must be able to convert `$?` to the signal that could cause such an exit in that shell [2]. It should be noted that only a select handful of signals have a standard numeric value; all others are implementation-defined [3]. This is why UAPI.15 requires the symbolic name, as the value may differ across systems. Notably, not every value above 128 needs to correspond to a signal; on my Linux system, only exit codes 129–192 indicate a signal. Again, we can use `kill -l`, which will exit non-zero when an exit code does not come from a signal (plus 128) [4]. Signal 0 (which would correspond to exit code 128) is reserved for the null signal, per POSIX.1-2008 [5], and therefore will never be an exit signal. This change brings the implementation into compliance. References: [0] https://www.man7.org/linux/man-pages//man1/bash.1.html#EXIT_STATUS [1] https://uapi-group.org/specifications/specs/osc_context/ [2] https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/utilities/kill.html#:~:text=The%20letter%20ell [3] https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/utilities/kill.html#:~:text=The%20effects%20of%20specifying%20any%20signal_number [4] https://www.man7.org/linux/man-pages//man1/bash.1.html#:~:text=false%20if%20an%20error%20occurs%20or%20an%20invalid%20option%20is%20encountered [5] https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/basedefs/signal.h.html#:~:text=The%20value%200%20is%20reserved%20for%20use%20as%20the%20null%20signal --- profile.d/80-systemd-osc-context.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/profile.d/80-systemd-osc-context.sh b/profile.d/80-systemd-osc-context.sh index cfc8795d32..c7a556f66a 100644 --- a/profile.d/80-systemd-osc-context.sh +++ b/profile.d/80-systemd-osc-context.sh @@ -39,12 +39,12 @@ __systemd_osc_context_common() { } __systemd_osc_context_precmdline() { - local systemd_exitstatus="$?" + local systemd_exitstatus="$?" systemd_signal # Close previous command if [ -n "${systemd_osc_context_cmd_id:-}" ]; then - if [ "$systemd_exitstatus" -ge 127 ]; then - printf "\033]3008;end=%s;exit=interrupt;signal=%s\033\\" "$systemd_osc_context_cmd_id" $((systemd_exitstatus-127)) + if [ "$systemd_exitstatus" -gt 128 ] && systemd_signal=$(kill -l "$systemd_exitstatus" 2>&-); then + printf "\033]3008;end=%s;exit=interrupt;signal=SIG%s\033\\" "$systemd_osc_context_cmd_id" "$systemd_signal" elif [ "$systemd_exitstatus" -ne 0 ]; then printf "\033]3008;end=%s;exit=failure;status=%s\033\\" "$systemd_osc_context_cmd_id" $((systemd_exitstatus)) else From b88ab1c2dd8896a4bb710316b6a949817ef8d859 Mon Sep 17 00:00:00 2001 From: Chris Lindee Date: Mon, 16 Feb 2026 00:47:15 -0600 Subject: [PATCH 2/5] profile/systemd-osc-context: Acknowledge uncertainty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bash does not provide an easy way to discern if an exit status came from a signal, or was a legitimate non-zero exit (i.e. a failure). It can be done, by using job control or by invoking another program; however, such approaches require modifying the command entered by a user and are, thus, invasive and risky. Since an exit status of 129 on a command could either indicate it exited cleanly with `exit(129)` or was interrupted by `SIGHUP`, the osc context should report both possibilities, to acknowledge our uncertainty. Given we have no idea what happened, besides an unsuccessful exit, the exit is described as `exit=failure`. Moreover, discerning between an `interrupt` and a `crash` with a command likely involves categorizing every signal. It is fairly obvious `SIGINT` is an interrupt and also obvious, IMO, that `SIGSEGV` is a crash. Avoid the complication (and potential disagreements) by using the encompassing, generic value — one that remains true if no signal occurred. References: [0] https://stackoverflow.com/a/66431355 --- profile.d/80-systemd-osc-context.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/profile.d/80-systemd-osc-context.sh b/profile.d/80-systemd-osc-context.sh index c7a556f66a..df7f93afa3 100644 --- a/profile.d/80-systemd-osc-context.sh +++ b/profile.d/80-systemd-osc-context.sh @@ -44,7 +44,7 @@ __systemd_osc_context_precmdline() { # Close previous command if [ -n "${systemd_osc_context_cmd_id:-}" ]; then if [ "$systemd_exitstatus" -gt 128 ] && systemd_signal=$(kill -l "$systemd_exitstatus" 2>&-); then - printf "\033]3008;end=%s;exit=interrupt;signal=SIG%s\033\\" "$systemd_osc_context_cmd_id" "$systemd_signal" + printf "\033]3008;end=%s;exit=failure;status=%s;signal=SIG%s\033\\" "$systemd_osc_context_cmd_id" "$systemd_exitstatus" "$systemd_signal" elif [ "$systemd_exitstatus" -ne 0 ]; then printf "\033]3008;end=%s;exit=failure;status=%s\033\\" "$systemd_osc_context_cmd_id" $((systemd_exitstatus)) else From 6a46846871a5af20580d62d7f3181b3f5ac91eb2 Mon Sep 17 00:00:00 2001 From: Chris Lindee Date: Mon, 16 Feb 2026 00:08:31 -0600 Subject: [PATCH 3/5] profile/systemd-osc-context: Bring escape up to spec UAPI.15 requires: * `\` to be replaced with `\x5c` * `;` to be replaced with `\x3b` References: [0] https://uapi-group.org/specifications/specs/osc_context/#general-syntax --- profile.d/80-systemd-osc-context.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/profile.d/80-systemd-osc-context.sh b/profile.d/80-systemd-osc-context.sh index df7f93afa3..dfed466404 100644 --- a/profile.d/80-systemd-osc-context.sh +++ b/profile.d/80-systemd-osc-context.sh @@ -28,7 +28,7 @@ __systemd_osc_context_escape() { # 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. - echo "$1" | sed -e 's/\\/\\x5x/g' -e 's/;/\\x3b/g' + echo "$1" | sed -e 's/\\/\\x5c/g' -e 's/;/\\x3b/g' } __systemd_osc_context_common() { From 72e71897f9534ea503283e049f822ea8a0d42e28 Mon Sep 17 00:00:00 2001 From: Chris Lindee Date: Mon, 16 Feb 2026 00:08:31 -0600 Subject: [PATCH 4/5] profile/systemd-osc-context: Remove invalid octets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UAPI.15 requires: * No C0 Control Characters (`\x00-\x1f`) * No DEL character (`\x7f`) The following would be nice, but requires a `sed` implementation that is aware of UTF-8: `-e $'y/\x00-\x1f\x7f/␀-␟␡/'`. References: [0] https://uapi-group.org/specifications/specs/osc_context/#general-syntax --- profile.d/80-systemd-osc-context.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/profile.d/80-systemd-osc-context.sh b/profile.d/80-systemd-osc-context.sh index dfed466404..537facdf1a 100644 --- a/profile.d/80-systemd-osc-context.sh +++ b/profile.d/80-systemd-osc-context.sh @@ -28,7 +28,7 @@ __systemd_osc_context_escape() { # 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. - echo "$1" | sed -e 's/\\/\\x5c/g' -e 's/;/\\x3b/g' + echo "$1" | sed -e 's/\\/\\x5c/g' -e 's/;/\\x3b/g' -e 's/[[:cntrl:]]/⍰/g' } __systemd_osc_context_common() { From 2d738a0aeee0df0e9d6c001db1aeac52f65c2190 Mon Sep 17 00:00:00 2001 From: Chris Lindee Date: Mon, 16 Feb 2026 00:08:31 -0600 Subject: [PATCH 5/5] profile/systemd-osc-context: Enforce length limits UAPI.15 limits the length of fields; adhere to them. References: [0] https://uapi-group.org/specifications/specs/osc_context/#syntax-in-abnf --- profile.d/80-systemd-osc-context.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/profile.d/80-systemd-osc-context.sh b/profile.d/80-systemd-osc-context.sh index 537facdf1a..7d4b9a77f1 100644 --- a/profile.d/80-systemd-osc-context.sh +++ b/profile.d/80-systemd-osc-context.sh @@ -33,9 +33,9 @@ __systemd_osc_context_escape() { __systemd_osc_context_common() { if [ -f /etc/machine-id ]; then - printf ";machineid=%s" "$(&-); then - printf "\033]3008;end=%s;exit=failure;status=%s;signal=SIG%s\033\\" "$systemd_osc_context_cmd_id" "$systemd_exitstatus" "$systemd_signal" + printf "\033]3008;end=%.64s;exit=failure;status=%d;signal=SIG%s\033\\" "$systemd_osc_context_cmd_id" "$systemd_exitstatus" "$systemd_signal" elif [ "$systemd_exitstatus" -ne 0 ]; then - printf "\033]3008;end=%s;exit=failure;status=%s\033\\" "$systemd_osc_context_cmd_id" $((systemd_exitstatus)) + printf "\033]3008;end=%.64s;exit=failure;status=%d\033\\" "$systemd_osc_context_cmd_id" $((systemd_exitstatus)) else - printf "\033]3008;end=%s;exit=success\033\\" "$systemd_osc_context_cmd_id" + printf "\033]3008;end=%.64s;exit=success\033\\" "$systemd_osc_context_cmd_id" fi fi @@ -58,7 +58,7 @@ __systemd_osc_context_precmdline() { fi # Create or update the shell session - printf "\033]3008;start=%s%s;type=shell;cwd=%s\033\\" "$systemd_osc_context_shell_id" "$(__systemd_osc_context_common)" "$(__systemd_osc_context_escape "$PWD")" + printf "\033]3008;start=%.64s%s;type=shell;cwd=%.255s\033\\" "$systemd_osc_context_shell_id" "$(__systemd_osc_context_common)" "$(__systemd_osc_context_escape "$PWD")" # Prepare cmd id for next command read -r systemd_osc_context_cmd_id