]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
doc: add OSC 3008 spec
authorLennart Poettering <lennart@poettering.net>
Mon, 18 Nov 2024 23:05:42 +0000 (00:05 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 27 Feb 2025 14:03:17 +0000 (15:03 +0100)
docs/OSC-CONTEXT.md [new file with mode: 0644]

diff --git a/docs/OSC-CONTEXT.md b/docs/OSC-CONTEXT.md
new file mode 100644 (file)
index 0000000..52ccb03
--- /dev/null
@@ -0,0 +1,339 @@
+---
+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* effect 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)                                        |