What Is OSC 3008: systemd Terminal Context Signaling and Garbage Output Troubleshooting

An explanation of UAPI.15 OSC 3008 Hierarchical Context Signalling: what it does, what data it sends, where systemd uses it, and how to troubleshoot or disable garbage output in incompatible terminals.

OSC 3008, formally Hierarchical Context Signalling, is UAPI.15 in the UAPI Group specifications. It defines a set of terminal control sequences that let programs tell a terminal emulator about the current context hierarchy inside a terminal session.

In plain terms, it tries to answer a question that has become common in modern Linux terminals: which layer are you actually in?

For example, you may SSH from your local machine to a server, enter a container, and then use run0 or a similar tool to run a command with elevated privileges. To you, it still looks like one continuous terminal window. To the terminal emulator, without an extra signal, it is hard to know whether the current output comes from the local machine, the remote host, a container, or an elevated command.

OSC 3008 is designed for that kind of situation. The UAPI specification says it allows terminal emulators to track the hierarchical context of the current content on screen. systemd also provides an implementation, usually through a script named 80-systemd-osc-context.sh.

Official references:

Why OSC 3008 Exists

Traditional terminals mainly display program output. At most, they use window titles, colors, and prompts to help distinguish environments. The problem is that modern terminal sessions are often nested:

1
local shell -> SSH remote server -> Docker/Podman/systemd-nspawn container -> run0 elevated command

If everything depends only on PS1, several problems appear:

  1. The prompt can only describe the current shell and struggles to express the full nesting hierarchy.
  2. Different shells, distributions, and user configurations can override one another.
  3. The terminal emulator cannot reliably know which output belongs to which context.
  4. Some control sequences become visible garbage in incompatible terminals.

OSC 3008 provides a more structured approach: the program that enters a context sends a start sequence, and the program that leaves the context sends an end sequence. After parsing those sequences, the terminal emulator can know which context node the current output belongs to.

What Information It Sends

OSC 3008 is a set of OSC escape sequences. The specification defines two core commands:

1
2
OSC "3008;start=..." ST
OSC "3008;end=..." ST

start means a context starts, is updated, or becomes current again. end means a context ends.

Each context can carry metadata fields. Common fields include:

  1. type=: context type, such as shell, command, remote, container, vm, or elevate.
  2. user=: the UNIX user that emits the sequence.
  3. hostname=: the hostname.
  4. machineid=: the machine ID from /etc/machine-id.
  5. bootid=: the boot ID from /proc/sys/kernel/random/boot_id.
  6. pid=: the PID of the process that emits the sequence.
  7. comm=: the process name.
  8. cwd=: the current working directory, mainly for shell or command.
  9. cmdline=: the command line invoked interactively.
  10. container= and vm=: container or virtual machine names.
  11. targetuser= and targethost=: target user or remote target host.

These fields are not meant to be read directly by users. They are meant for terminal emulators to parse. A compatible terminal consumes these control sequences and uses them to improve the interface.

What It Can Improve

If a terminal emulator supports OSC 3008, it can do smarter things.

First, it can mark output from different contexts. For example, container output, elevated-command output, and remote SSH output may use different backgrounds, borders, or hints.

Second, it can display a hierarchy breadcrumb. The terminal may know that the current session is roughly:

1
local machine -> remote host -> container -> root command

This is more stable than relying only on a window title or PS1.

Third, it can help window titles, tabs, and context menus. The terminal can update tab titles according to the current context, or provide actions such as opening a shell in the same directory for a selected output segment.

Fourth, it can reduce mistakes. If you are inside a production container and running commands as root, the terminal can show a more obvious warning and reduce the chance of running dangerous commands in the wrong environment.

How systemd Hooks Into It

systemd’s implementation mainly lives in 80-systemd-osc-context.sh. This script is loaded through the profile mechanism and sets related functions and prompt hooks in interactive Bash environments.

Common paths may include:

1
2
/etc/profile.d/80-systemd-osc-context.sh
/usr/lib/systemd/profile.d/80-systemd-osc-context.sh

The exact location depends on the distribution. Comments in the systemd source explain that this file can be activated through systemd-tmpfiles, which links it into /etc/profile.d/.

In Bash, it uses function names such as:

1
2
3
__systemd_osc_context_escape
__systemd_osc_context_common
__systemd_osc_context_precmdline

It also affects PROMPT_COMMAND and PS0. PS0 is expanded after Bash reads a command and before it executes the command. That is why incompatible terminals may show a long 3008;start=... text before each command runs.

Why Some Terminals Show Garbage

Normally, a terminal emulator should parse OSC 3008 as a control sequence and not display it directly.

But if the terminal does not recognize OSC 3008, or an intermediate layer filters, escapes, or breaks the control characters, the raw content may be displayed. Common cases include:

  1. Older terminal emulators.
  2. SSH clients that have not adapted to OSC 3008.
  3. Web bastion hosts or browser terminals, including some Apache Guacamole environments.
  4. Environments with limited OSC support, such as Emacs term.el, serial terminals, or minicom.
  5. Multi-hop forwarding where an intermediate layer damages the control sequence.

In that case, you may see something like:

1
]3008;start=...;type=command;cwd=...

Or you may see long strings containing machineid=, bootid=, pid=, comm=, and cwd=. These are not normal program output. They are context signals that were supposed to be handled by the terminal.

How to Tell Whether It Is OSC 3008

Check three clues first.

First, does the garbage include 3008;start= or 3008;end=?

Second, does it appear before or after command execution, especially every time you press Enter to run a command?

Third, has the current system loaded systemd’s OSC functions?

1
declare -f __systemd_osc_context_precmdline

If you can see a function definition, the current shell has loaded the related logic.

You can also check the profile file:

1
ls -l /etc/profile.d/80-systemd-osc-context.sh

If this path exists and your terminal does not support OSC 3008, the garbage output likely comes from there.

Temporary Workaround

If only the current session is affected, you can override the related functions and clear PS0:

1
2
3
4
__systemd_osc_context_precmdline() { :; }
__systemd_osc_context_common() { :; }
__systemd_osc_context_escape() { :; }
PS0=""

If you want this to happen automatically only in SSH sessions, put it in ~/.bashrc:

1
2
3
4
5
6
7
8
if [[ -n "$SSH_CLIENT" || -n "$SSH_TTY" || -n "$SSH_CONNECTION" ]]; then
    if declare -f __systemd_osc_context_precmdline >/dev/null; then
        __systemd_osc_context_precmdline() { :; }
        __systemd_osc_context_common() { :; }
        __systemd_osc_context_escape() { :; }
        PS0=""
    fi
fi

This has a small scope. It does not change system-level profile files and is easy to remove later.

System-Level Disable Method

If you are sure this machine’s terminal environment is generally incompatible with OSC 3008, you can consider disabling it system-wide. Be careful: this affects all users and login sessions.

The idea described in the systemd script comments is to remove the /etc/profile.d/80-systemd-osc-context.sh symlink and mask the corresponding tmpfiles fragment so it will not be recreated later.

You can use a command like this:

1
2
3
test -h /etc/profile.d/80-systemd-osc-context.sh && \
rm -v /etc/profile.d/80-systemd-osc-context.sh && \
ln -s /dev/null /etc/tmpfiles.d/20-systemd-osc-context.conf

This is heavier than changing ~/.bashrc. Try the temporary workaround first to confirm the problem really comes from OSC 3008, then decide whether system-level disablement is justified.

If only your personal SSH client is incompatible, do not change system-level configuration first. Prefer your own ~/.bashrc, or configure a post-login cleanup command in the SSH client.

Upgrade the Terminal or Disable OSC 3008?

If you use a modern terminal that already supports OSC 3008, it is better to keep this capability. It may make remote shells, containers, virtual machines, and elevated commands easier to understand in the future.

If your actual environment is a bastion host, serial console, old terminal, or Web SSH client that cannot be upgraded soon, suppressing it is more practical. For most operations work, clean and readable terminal output is more important than enhanced context display.

Use this order:

  1. If you can upgrade the terminal emulator, upgrade it first.
  2. If you cannot upgrade and only your own session is affected, suppress it in ~/.bashrc or the client’s post-login command.
  3. If the whole machine is affected, then consider removing /etc/profile.d/80-systemd-osc-context.sh and masking the tmpfiles fragment.

Short Conclusion

OSC 3008 is not malware and not random program output. It is UAPI.15 terminal context signaling, designed to help terminals understand the hierarchy between shells, SSH sessions, containers, virtual machines, and elevated commands.

The real issue is usually compatibility. A compatible terminal parses it automatically. An incompatible one may show the control sequence as garbage.

If you see content such as 3008;start=, machineid=, bootid=, or cwd=, first check whether systemd’s 80-systemd-osc-context.sh injected it. After confirmation, choose a temporary workaround, a personal .bashrc workaround, or system-level disablement depending on the scope of the impact.

记录并分享
Built with Hugo
Theme Stack designed by Jimmy