Files
systemd/docs/OSC_CONTEXT.md
Luca Boccassi 12ef7e0a2c docs: use '_' as separator for OSC page
Make it consistent with other pages

Fixes https://github.com/systemd/systemd/issues/39019
2025-09-19 20:11:46 +09:00

340 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: OSC 3008: Hierarchical Context Signalling
category: Interfaces
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# OSC 3008: Hierarchical Context Signalling
A terminal connects a user with programs. Control of the program side of
terminals is typically passed around to various different components while the
user is active: a shell might pass control to a process it invokes. If that
process is `run0` then primary control is passed to the privileged session of
the target user. If `systemd-nspawn` is invoked to start a container, primary
control is passed to that container, and so on.
A terminal emulator might be interested to know which component is currently in
primary control of the program side of a terminal. OSC 3008 is a mechanism to
inform it about such contexts. Each component taking over control can inform
the terminal emulators that a new context begins now, and then use the terminal
or pass control down to further apps, which can introduce contexts. Each
context may carry various descriptive metadata fields.
## Status
This OSC sequence has been invented by the systemd project and is generated by
systemd. Currently, no terminal application is known that consumes these
sequences.
## Use Cases
Terminal emulators can use hierarchical context information:
1. To introduce markers/bookmarks in the output that the user can jump between.
2. To visually identify output from different contexts. For example the
background of the associated output can be tinted in a reddish tone when
privileges are acquired, and similar.
3. Meta information on specific output can be shown in a tooltip or similar
4. Programs (and all subcontexts) can be killed via a right-click menu on the
output they generate.
5. Similar, a right-click menu might offer an item to offer opening a new
interactive shell in the same working directory that was current on the
selected context.
6. Failed commands or aborted sessions can be marked requesting user attention.
## Context Types
There are various types of contexts defined by this specification:
1. `boot` → a booted system initiates this context early at boot. (systemd's
PID 1 generates this on `/dev/console`.)
2. `container` → a container manager initialized an interactive connection to a
container. (`systemd-nspawn` generates this when interactively invoking a
container. `machinectl login`, `machinectl shell` do this too.)
3. `vm` → a VM manager initialized a terminal connection to a
VM. (`systemd-vmspawn` generates this when interactively invoking a VM, as
one example.)
4. `elevate` → when the user interactively acquired higher privileges. (`run0`
initiates a context of this type whenever the user invokes it to acquire
root privileges.)
5. `chpriv` → similar, but when the user acquired *different* privileges, not
necessarily higher ones. (`run0` initiates a context of this type whenever
the user invokes it to acquire non-root privileges of another user.)
5. `subcontext` → similar, but the source and target privileges where
identical. (`run0` initiates a context of this type whenever the user
invokes it to acquire privileges of the user itself.)
6. `remote` → a user invoked a tool such as `ssh` to connect to a remote
system.
7. `shell` → an interactive terminal shell initiates this context
8. `command` → a shell interactively invokes a new program.
9. `app` → an interactive program may initiate this context.
10. `service` → the service manager invokes an interactive service on the terminal
11. `session` → a login session of the user is initialized.
## Semantics
Contexts in the sense of OSC 3008 are hierarchical, and describe a tree
structure: whenever a new context is opened it becomes the new active context,
and the previously active context becomes its parent (if there is one). Only
one context is currently active, but previously opened contexts remain valid in
the background. Any other data written or read should be considered associated
with the currently active context.
Each context carries an identifier, chosen by the component opening the
context. The identifier can chosen freely, but must not be longer than 64
characters. The characters may be in the 32…126 byte range. Identifiers should
be universally unique, for example randomly generated. A freshly generated UUID
would work well for this, but this could also be something like the Linux boot
ID combined with the 64bit inode number of Linux pidfds, or something hashed
from it.
Fundamentally, there are two OSC 3008 commands defined:
1. OSC "`3008;start=`" … (the *start sequence*) → this initiates, updates or
indicates a return to a context. It carries a context identifier, and
typically some metadata. This may be sent to first initiate a context. If
sent again for the same context ID that was initiated already this indicates
an update of the existing context. In this case, *any* previously set
metadata fields for the context are flushed out, reset to their defaults,
and then reinitialized from the newly supplied data. Also, in this case any
subcontexts of the contexts are implicitly terminated.
2. OSC "`3008;end=`" … (the *end sequence*) → this terminates a context. It
carries a context identifier to close, initiated before with OSC
"`3008;start=`". It may also carry additional metadata.
## General Syntax
This builds on ECMA-48, and reuses the OSC and ST concepts introduced there.
For sequences following this specification it is recommended to encode OSC as
0x1B 0x5D, and ST as 0x1B 0x5C.
ECMA-48 only allows characters from the range 0x20…0x7e (i.e. 32…126) inside
OSC sequences. However, most terminal emulators nowadays allow the ASCII byte
range > 0x7f in the OSC sequences they process, and so does this
specification. Control characters (< 0x20 and 0x7f) are not allowed. The
semicolon character ("`;`") which is used as field separator by this
specification shall be replaced by "`\x3b`" and the backslash character
("`\`") shall be replaced by "`\x5c`". All textual fields must be encoded in
UTF-8, and then escaped with these two replacements.
The start sequence begins with OSC, followed by the string `3008;start=`,
followed by the context ID. This is then followed by any number of metadata
fields, including none. Metadata fields begin with a semicolon (`;`) followed
by in a string identifying the type of field, followed by an equal sign (`=`),
and the field value. The sequence ends in ST.
The end sequence begins with OSC, followed by the string `3008;end=`, followed
by the context ID, and a series of metadata fields in the same syntax as for
the start sequence. The sequence ends in ST.
## Metadata Fields
The following fields are currently defined for the start sequence:
| Field | Context Types | Description |
|---------------|---------------|-------------------------------------------------------------------------------------------------------------|
| `type=` | *all* | Declares the context type, one of the types described above |
| `user=` | *all* | UNIX user name the process issuing the sequence runs as |
| `hostname=` | *all* | UNIX host name of the system the process issuing the sequence runs on |
| `machineid=` | *all* | The machine ID (i.e. `/etc/machine-id`) of the system the process issuing the sequence runs on |
| `bootid=` | *all* | The boot ID (i.e. `/proc/sys/kernel/random/boot_id`) of the system the process issuing the sequence runs on |
| `pid=` | *all* | The numeric PID of the process issuing the sequence, in decimal notation |
| `pidfdid=` | *all* | The 64bit inode number of the pidfd of the process issuing the sequence, in decimal notation |
| `comm=` | *all* | The process name (i.e. `/proc/$PID/comm`, `PR_GET_NAME`) of the process issuing the sequence |
| `cwd=` | `shell`, `command` | The current working directory |
| `cmdline=` | `command` | The full command line of the invoked command |
| `vm=` | `vm` | The name of the VM being invoked |
| `container=` | `container` | The name of the container being invoked |
| `targetuser=` | `elevate`, `chpriv`, `vm`, `container`, `remote`, `session` | Target UNIX user name |
| `targethost=` | `remote` | Target UNIX, DNS host name, or IP address |
| `sessionid=` | `session` | New allocated session ID |
The following fields are currently defined for the end sequence:
| Field | Context Types | Description |
|---------------|---------------|-------------------------------------------------------------------------------------------------------------|
| `exit=` | `command` | One of `success`, `failure`, `crash`, `interrupt`, indicating how the program terminated |
| `status=` | `command` | The command's numeric exit status, i.e. the 0…255 value a program returns |
| `signal=` | `command` | The termination signal of the command, if it died abnormally. A symbolic signal name. (`SIGKILL`, …) |
All fields are optional, including the context type. However, it is generally
recommended to always include the first 7 fields listed above, to make it easy
to pinpoint the origin of a context in a race-free fashion, without any
ambiguities.
The order of the metadata fields is undefined, they may appear in any order
(including that `type=` is specified at the very end or in the middle!). Note
that `start=` and `end=` are not considered metadata fields but part of the
start sequence, and hence must always appear right after OSC.
## Processing, Limits, Security
All context information provided like this should be considered auxiliary and
to some degree redundant information. Hence, it would be wise for a terminal
to enforce limits on various resources, dropping additional data once these
limits are hit. Most importantly, a maximum stacking depth should probably
enforced: any attempts to initiate further contexts should be ignored once the
stack limit is hit (i.e. the earlier contexts should be kept, the later
contexts be discarded, not the opposite). Overly long fields should be
discarded (or potentially truncated, depending on the field type). This
specification does not recommend any specific stack or string limits for now.
The usual terminal reset sequences should *not* affect the stack of contexts
(this is a safety feature: a program down the stack should not be able to
affect the stack further up, possibly hiding relevant information). A temporary
TTY hangup (`vhangup()`) should result in a full reset of the stack.
All provided data should be processed in a lenient, graceful fashion: if a
sequence contains invalid fields, those fields should be ignored, but the rest
of the fields should still be used. In particular, unknown fields should be
ignored.
The fields provided in these sequences should not contain sensitive
information. Context IDs should not be considered confidential, but it is
strongly recommended to generate them in a fashion that guarantees their
sufficient uniqueness and avoids accidental or intended clashes with other
contents.
## Examples
1. A new container `foobar` has been invoked by user `lennart` on host `zeta`:
`OSC "3008;start=bed86fab93af4328bbed0a1224af6d40;type=container;user=lennart;hostname=zeta;machineid=3deb5353d3ba43d08201c136a47ead7b;bootid=d4a3d0fdf2e24fdea6d971ce73f4fbf2;pid=1062862;pidfdid=1063162;comm=systemd-nspawn;container=foobar" ST`
2. This context ends: `OSC "3008;end=bed86fab93af4328bbed0a1224af6d40" ST`
## Syntax in ABNF
```abnf
OSC = %x1B %x5D
ST = %x1B %x5C
DECIMAL = "0"-"9"
HEX = "0"-"9" / "A"-"F" / "a-f"
ID128 = 32*36(HEX / "-")
UINT64 = 1*20DECIMAL
ESCSEMICOLON = "\x3b"
ESCBACKSLASH = "\x5c"
SAFE = %x20-3a / %x3c-5b / %x5d-7e / ESCSEMICOLON / ESCBACKSLASH
CTXID = 1*64SAFE
TYPEENUM = "service" / "session" / "shell" / "command" / "vm" / "container" / "elevate" / "chpriv" / "subcontext" / "remote" / "boot" / "app"
TYPE = "type=" TYPEENUM
USER = "user=" 1*255SAFE
HOSTNAME = "hostname=" 1*255SAFE
MACHINEID = "machineid=" 1D128
BOOTID = "bootid=" ID128
PID = "pid=" UINT64
PIDFDID = "pidfdid=" UINT64
COMM = "comm=" 1*255SAFE
CWD = "cwd=" 1*255SAFE
CMDLINE = "cmdline=" *255SAFE
VM = "vm=" 1*255SAFE
CONTAINER = "container=" 1*255SAFE
TARGETUSER = "targetuser=" 1*255SAFE
TARGETHOST = "targethost=" 1*255SAFE
SESSIONID = "sessionid=" 1*255SAFE
STARTFIELD = TYPE / USER / HOSTNAME / MACHINEID / BOOTID / PID / PIDFDID / COMM / CWD / CMDLINE / VM / CONTAINER / TARGETUSER / TARGETHOST / SESSIONID
STARTSEQ = OSC "3008;start=" CTXID *(";" STARTFIELD) ST
EXITENUM = "success" / "failure" / "crash" / "interrupt"
SIGNALENUM = "SIGBUS" / "SIGTRAP" / "SIGABRT" / "SIGSEGV" /
EXIT = "exit=" EXITENUM
STATUS = "status=" UINT64
SIGNAL = "signal=" SIGNALENUM
ENDFIELD = EXIT / STATUS / SIGNAL
ENDSEQ = OSC "3008;end=" CTXID *(";" ENDFIELD) ST
```
## Known OSC Prefixes
Here's a list of OSC prefixes used by the various sequences currently in public
use in various terminal emulators. It's not going to be complete, but I tried
to do some reasonably thorough research to avoid conflicts with the new OSC
sequence defined above.
| OSC Prefix | Purpose |
|----------------:|------------------------------------------------------------|
| `OSC "0;…"` | Icon name + window title |
| `OSC "1;…"` | Icon name |
| `OSC "2;…"` | Window title |
| `OSC "3;…"` | X11 property |
| `OSC "4;…"` | Palette |
| `OSC "5;…"` | Special palette |
| `OSC "6;…"` | Disable special color |
| `OSC "7;…"` | Report cwd |
| `OSC "8;…"` | Hyperlink |
| `OSC "9;…"` | Progress bar (conemu) [conflict: also growl notifications] |
| `OSC "10;…"` | Change colors |
| `OSC "11;…"` | " |
| `OSC "12;…"` | " |
| `OSC "13;…"` | " |
| `OSC "14;…"` | " |
| `OSC "15;…"` | " |
| `OSC "16;…"` | " |
| `OSC "17;…"` | " |
| `OSC "18;…"` | " |
| `OSC "19;…"` | " |
| `OSC "21;…"` | Query colors (kitty) |
| `OSC "22;…"` | Cursor shape |
| `OSC "46;…"` | Log file |
| `OSC "50;…"` | Set font |
| `OSC "51;…"` | Emacs shell |
| `OSC "52;…"` | Manipulate selection data (aka clipboard) |
| `OSC "60;…"` | Query allowed |
| `OSC "61;…"` | Query disallowed |
| `OSC "99;…"` | Notifications (kitty) |
| `OSC "104;…"` | Reset color |
| `OSC "105;…"` | Enable/disable special color |
| `OSC "110;…"` | Reset colors |
| `OSC "111;…"` | " |
| `OSC "112;…"` | " |
| `OSC "113;…"` | " |
| `OSC "114;…"` | " |
| `OSC "115;…"` | " |
| `OSC "116;…"` | " |
| `OSC "117;…"` | " |
| `OSC "118;…"` | " |
| `OSC "119;…"` | " |
| `OSC "133;…"` | Prompt/command begin/command end (finalterm/iterm2) |
| `OSC "440;…"` | Audio (mintty) |
| `OSC "633;…"` | vscode action (Windows Terminal) |
| `OSC "666;…"` | "termprop" (vte) |
| `OSC "701;…"` | Locale (mintty) |
| `OSC "777;…"` | Notification (rxvt) |
| `OSC "3008;…"` | This specification |
| `OSC "7704;…"` | ANSI colors (mintty) |
| `OSC "7750;…"` | Emoji style (mintty) |
| `OSC "7770;…"` | Font size (mintty) |
| `OSC "7771;…"` | Glyph coverage (mintty) |
| `OSC "7721:…"` | Copy window title (mintty) |
| `OSC "7777;…"` | Window size (mintty) |
| `OSC "9001;…"` | Action (Windows Terminal) |
| `OSC "1337;…"` | iterm2 multiplex seeuqnece |
| `OSC "5522;…"` | Clipboard (kitty) |
| `OSC "30001;…"` | Push color onto stack (kitty) |
| `OSC "30101;…"` | Pop color from stack (kitty) |
| `OSC "77119;…"` | Wide chars (mintty) |