Compare commits
24 Commits
8e6eb99398
...
cbd88b88f7
Author | SHA1 | Date |
---|---|---|
Lennart Poettering | cbd88b88f7 | |
Ani Sinha | 4b356c90dc | |
Léane GRASSER | f28e16d14e | |
Yu Watanabe | 9e05e33871 | |
Lennart Poettering | 95116bdfd5 | |
Lennart Poettering | 2bd290ca02 | |
Yu Watanabe | 1e9fb1d456 | |
Yu Watanabe | 56c761f8c6 | |
Yu Watanabe | b76730f3fe | |
Yu Watanabe | 3dda236c5c | |
Zbigniew Jędrzejewski-Szmek | 5598454a3f | |
Yu Watanabe | 2994ca354b | |
Yu Watanabe | eb14b993bb | |
Lennart Poettering | 4c9769353e | |
Lennart Poettering | b16c6b0c08 | |
Lennart Poettering | a48ae38ea3 | |
Lennart Poettering | 3722a71a87 | |
Lennart Poettering | 805495ade2 | |
Lennart Poettering | 03d8af8da4 | |
Lennart Poettering | 9ed47d39d9 | |
Lennart Poettering | 462baeb410 | |
Lennart Poettering | 420b74654d | |
Lennart Poettering | b56421e0dc | |
Lennart Poettering | 221d6e54c6 |
|
@ -0,0 +1,283 @@
|
||||||
|
---
|
||||||
|
title: OSC 300819: Hierarchial Context Signalling
|
||||||
|
category: Interfaces
|
||||||
|
layout: default
|
||||||
|
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
---
|
||||||
|
|
||||||
|
# OSC 300819: Hierarchial 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
|
||||||
|
controls is passed to that container, and so on.
|
||||||
|
|
||||||
|
A terminal emulator might be interested to know which component is currently is
|
||||||
|
in primary control of the program side of a terminal. OSC 3000910 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 discriptive metadata fields.
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
This OS is invented by systemd. Currently, no terminal application is known
|
||||||
|
that consumes these sequences.
|
||||||
|
|
||||||
|
## Usecases
|
||||||
|
|
||||||
|
Terminal emulators can use hierarchial 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 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 by right-clicking on the output
|
||||||
|
they generate.
|
||||||
|
|
||||||
|
5. Failed commands or aborted sessions can be marked requesting use 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 managed 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 VMM initialized a terminal connection to 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 300819 are hierarchial, 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 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 300819 commands defined:
|
||||||
|
|
||||||
|
1. OSC "`300819;S`" (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 send to first initiate a context. If sent again for the a 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 subcontects of the contexts are
|
||||||
|
implicitly terminated.
|
||||||
|
|
||||||
|
2. OSC "`300819;X`" (the *end sequence*)→ this terminates a context. It carries a context
|
||||||
|
identifier to close, initiated before with OSC `300819;S`. 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. Hence, any fields that shall contain characters outside of this
|
||||||
|
range require escaping. All textual fields must be encoded in UTF-8, which
|
||||||
|
then must be escaped.
|
||||||
|
|
||||||
|
Escaping shall be applied by taking the byte values of the characters to
|
||||||
|
escape, and formatting them as lower-case hexadecimal prefixed with
|
||||||
|
`\x`. Example: `Schöpfgefäß` becomes `Sch\xc3\xb6pfgef\xc3\xa4\xc3\x9f`.
|
||||||
|
|
||||||
|
The start sequence begins with OSC, followed by the character `S`, followed by
|
||||||
|
the context ID. This is then followed by any number of metadata fields,
|
||||||
|
including none. Metadata fields begin with a semicolon (`;`) and end in a
|
||||||
|
character identifiying the type of field. The sequence ends in ST.
|
||||||
|
|
||||||
|
The end sequence begins with OSC, followed by the character `X`, followed by
|
||||||
|
the context ID, and a series of metadata fields in the the syntax as for the
|
||||||
|
start sequence.
|
||||||
|
|
||||||
|
## Metadata Fields
|
||||||
|
|
||||||
|
The following fields are currently defined:
|
||||||
|
|
||||||
|
| Suffix | Context Types | Description |
|
||||||
|
|--------|---------------|-------------------------------------------------------------------------------------------------------------|
|
||||||
|
| `u` | *all* | UNIX user name the process issuing the sequence runs as |
|
||||||
|
| `h` | *all* | UNIX host name of the system the process issuing the sequence runs on |
|
||||||
|
| `m` | *all* | The machine ID (i.e. `/etc/machine-id`) of the system the process issuing the sequence runs on |
|
||||||
|
| `b` | *all* | The boot ID (i.e. `/proc/sys/kernel/random/boot_id`) of the system the process issuing the sequence runs on |
|
||||||
|
| `p` | *all* | The numeric PID of the process issuing the sequence, in decimal notation |
|
||||||
|
| `P` | *all* | The 64bit inode number of the pidfd of the process issuing the sequence, in decimal notation |
|
||||||
|
| `c` | *all* | The process name (i.e. `/proc/$PID/comm`, `PR_GET_NAME`) of the process issuing the sequence |
|
||||||
|
| `v` | `vm` | The name of the VM being invoked |
|
||||||
|
| `C` | `container` | The name of the container being invoked |
|
||||||
|
| `U` | `elevate`, `chpriv`, `vm`, `container`, `remote` | Target UNIX user name |
|
||||||
|
| `H` | `remote` | Target UNIX, DNS host name, or IP address |
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
1. A new container `foobar` has been invoked by user `lennart` on host `zeta`:
|
||||||
|
`OSC "300819;Sbed86fab93af4328bbed0a1224af6d40;lennartu;zetah;3deb5353d3ba43d08201c136a47ead7bm;d4a3d0fdf2e24fdea6d971ce73f4fbf2b;1062862p;1063162P;foobarc;containert" ST`
|
||||||
|
|
||||||
|
2. A context ends: `OSC "300819;Xbed86fab93af4328bbed0a1224af6d40" 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
|
||||||
|
ESCAPED = "\x" HEX HEX
|
||||||
|
SAFE = %x20-3a / %x3c-5b / %x5d-7e / ESCAPED
|
||||||
|
|
||||||
|
CTXID = 1*64SAFE
|
||||||
|
|
||||||
|
USER = 1*255SAFE "u"
|
||||||
|
HOSTNAME = 1*255SAFE "h"
|
||||||
|
MACHINEID = 1D128 "m"
|
||||||
|
BOOTID = ID128 "b"
|
||||||
|
PID = UINT64 "p"
|
||||||
|
PIDFDID = UINT64 "P"
|
||||||
|
COMM = 1*255SAFE "c"
|
||||||
|
|
||||||
|
TYPE = ("service" / "session" / "shell" / "command" / "vm" / "container" / "elevate" / "chpriv" / "subcontext" / "remote" / "boot" / "app") "t"
|
||||||
|
|
||||||
|
SESSIONID = 1*255SAFE "s"
|
||||||
|
CWD = 1*255SAFE "d"
|
||||||
|
CMDLINE = *255SAFE "L"
|
||||||
|
VMNAME = 1*255SAFE "v"
|
||||||
|
CONTAINERNAME= 1*255SAFE "C"
|
||||||
|
TARGETUSER = 1*255SAFE "U"
|
||||||
|
TARGETHOST = 1*255SAFE "H"
|
||||||
|
APPID = 1*255SAFE "A"
|
||||||
|
|
||||||
|
STARTFIELD = (USER / HOSTNAME / MACHINEID / BOOTID / PID / PIDFDID / COMM / TYPE / SESSIONID / CWD / CMDLINE / VMNAME / CONTAINERNAME / TARGETUSER / TARGETHOST / APPID)
|
||||||
|
STARTSEQ = OSC "300819;" CTXID "S" *(";" STARTFIELD) ST
|
||||||
|
|
||||||
|
EXIT = "success" / "failure" / "crash" / "interrupt"
|
||||||
|
STATUS = UINT64
|
||||||
|
SIGNAL = "SIGBUS" / "SIGTRAP" / "SIGABRT" / "SIGSEGV" / …
|
||||||
|
|
||||||
|
ENDFIELD = (EXIT / STATUS / SIGNAL)
|
||||||
|
ENDSEQ = OSC "300819;" CTXID "X" *(";" 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 "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) |
|
4
po/fr.po
4
po/fr.po
|
@ -12,7 +12,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-11-06 14:42+0000\n"
|
"POT-Creation-Date: 2024-11-06 14:42+0000\n"
|
||||||
"PO-Revision-Date: 2024-11-20 19:13+0000\n"
|
"PO-Revision-Date: 2024-11-23 10:38+0000\n"
|
||||||
"Last-Translator: Léane GRASSER <leane.grasser@proton.me>\n"
|
"Last-Translator: Léane GRASSER <leane.grasser@proton.me>\n"
|
||||||
"Language-Team: French <https://translate.fedoraproject.org/projects/systemd/"
|
"Language-Team: French <https://translate.fedoraproject.org/projects/systemd/"
|
||||||
"main/fr/>\n"
|
"main/fr/>\n"
|
||||||
|
@ -1258,7 +1258,7 @@ msgstr ""
|
||||||
|
|
||||||
#: src/sysupdate/org.freedesktop.sysupdate1.policy:75
|
#: src/sysupdate/org.freedesktop.sysupdate1.policy:75
|
||||||
msgid "Manage optional features"
|
msgid "Manage optional features"
|
||||||
msgstr "Gérer les fonctionnalités en option"
|
msgstr "Gérer les fonctionnalités facultatives"
|
||||||
|
|
||||||
#: src/sysupdate/org.freedesktop.sysupdate1.policy:76
|
#: src/sysupdate/org.freedesktop.sysupdate1.policy:76
|
||||||
msgid "Authentication is required to manage optional features"
|
msgid "Authentication is required to manage optional features"
|
||||||
|
|
|
@ -365,6 +365,8 @@ char* xescape_full(const char *s, const char *bad, size_t console_width, XEscape
|
||||||
char *ans, *t, *prev, *prev2;
|
char *ans, *t, *prev, *prev2;
|
||||||
const char *f;
|
const char *f;
|
||||||
|
|
||||||
|
assert(s);
|
||||||
|
|
||||||
/* Escapes all chars in bad, in addition to \ and all special chars, in \xFF style escaping. May be
|
/* Escapes all chars in bad, in addition to \ and all special chars, in \xFF style escaping. May be
|
||||||
* reversed with cunescape(). If XESCAPE_8_BIT is specified, characters >= 127 are let through
|
* reversed with cunescape(). If XESCAPE_8_BIT is specified, characters >= 127 are let through
|
||||||
* unchanged. This corresponds to non-ASCII printable characters in pre-unicode encodings.
|
* unchanged. This corresponds to non-ASCII printable characters in pre-unicode encodings.
|
||||||
|
@ -397,7 +399,7 @@ char* xescape_full(const char *s, const char *bad, size_t console_width, XEscape
|
||||||
|
|
||||||
if ((unsigned char) *f < ' ' ||
|
if ((unsigned char) *f < ' ' ||
|
||||||
(!FLAGS_SET(flags, XESCAPE_8_BIT) && (unsigned char) *f >= 127) ||
|
(!FLAGS_SET(flags, XESCAPE_8_BIT) && (unsigned char) *f >= 127) ||
|
||||||
*f == '\\' || strchr(bad, *f)) {
|
*f == '\\' || (bad && strchr(bad, *f))) {
|
||||||
if ((size_t) (t - ans) + 4 + 3 * force_ellipsis > console_width)
|
if ((size_t) (t - ans) + 4 + 3 * force_ellipsis > console_width)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -866,6 +866,9 @@ void hexdump(FILE *f, const void *p, size_t s) {
|
||||||
|
|
||||||
assert(b || s == 0);
|
assert(b || s == 0);
|
||||||
|
|
||||||
|
if (s == SIZE_MAX)
|
||||||
|
s = strlen(p);
|
||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
f = stdout;
|
f = stdout;
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define AUTOFS_MIN_PROTO_VERSION 3
|
#define AUTOFS_MIN_PROTO_VERSION 3
|
||||||
#define AUTOFS_MAX_PROTO_VERSION 5
|
#define AUTOFS_MAX_PROTO_VERSION 5
|
||||||
|
|
||||||
#define AUTOFS_PROTO_SUBVERSION 5
|
#define AUTOFS_PROTO_SUBVERSION 6
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The wait_queue_token (autofs_wqt_t) is part of a structure which is passed
|
* The wait_queue_token (autofs_wqt_t) is part of a structure which is passed
|
||||||
|
|
|
@ -1121,6 +1121,9 @@ enum bpf_attach_type {
|
||||||
|
|
||||||
#define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE
|
#define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE
|
||||||
|
|
||||||
|
/* Add BPF_LINK_TYPE(type, name) in bpf_types.h to keep bpf_link_type_strs[]
|
||||||
|
* in sync with the definitions below.
|
||||||
|
*/
|
||||||
enum bpf_link_type {
|
enum bpf_link_type {
|
||||||
BPF_LINK_TYPE_UNSPEC = 0,
|
BPF_LINK_TYPE_UNSPEC = 0,
|
||||||
BPF_LINK_TYPE_RAW_TRACEPOINT = 1,
|
BPF_LINK_TYPE_RAW_TRACEPOINT = 1,
|
||||||
|
@ -2851,7 +2854,7 @@ union bpf_attr {
|
||||||
* **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**,
|
* **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**,
|
||||||
* **TCP_NODELAY**, **TCP_MAXSEG**, **TCP_WINDOW_CLAMP**,
|
* **TCP_NODELAY**, **TCP_MAXSEG**, **TCP_WINDOW_CLAMP**,
|
||||||
* **TCP_THIN_LINEAR_TIMEOUTS**, **TCP_BPF_DELACK_MAX**,
|
* **TCP_THIN_LINEAR_TIMEOUTS**, **TCP_BPF_DELACK_MAX**,
|
||||||
* **TCP_BPF_RTO_MIN**.
|
* **TCP_BPF_RTO_MIN**, **TCP_BPF_SOCK_OPS_CB_FLAGS**.
|
||||||
* * **IPPROTO_IP**, which supports *optname* **IP_TOS**.
|
* * **IPPROTO_IP**, which supports *optname* **IP_TOS**.
|
||||||
* * **IPPROTO_IPV6**, which supports the following *optname*\ s:
|
* * **IPPROTO_IPV6**, which supports the following *optname*\ s:
|
||||||
* **IPV6_TCLASS**, **IPV6_AUTOFLOWLABEL**.
|
* **IPV6_TCLASS**, **IPV6_AUTOFLOWLABEL**.
|
||||||
|
@ -5519,11 +5522,12 @@ union bpf_attr {
|
||||||
* **-EOPNOTSUPP** if the hash calculation failed or **-EINVAL** if
|
* **-EOPNOTSUPP** if the hash calculation failed or **-EINVAL** if
|
||||||
* invalid arguments are passed.
|
* invalid arguments are passed.
|
||||||
*
|
*
|
||||||
* void *bpf_kptr_xchg(void *map_value, void *ptr)
|
* void *bpf_kptr_xchg(void *dst, void *ptr)
|
||||||
* Description
|
* Description
|
||||||
* Exchange kptr at pointer *map_value* with *ptr*, and return the
|
* Exchange kptr at pointer *dst* with *ptr*, and return the old value.
|
||||||
* old value. *ptr* can be NULL, otherwise it must be a referenced
|
* *dst* can be map value or local kptr. *ptr* can be NULL, otherwise
|
||||||
* pointer which will be released when this helper is called.
|
* it must be a referenced pointer which will be released when this helper
|
||||||
|
* is called.
|
||||||
* Return
|
* Return
|
||||||
* The old value of kptr (which can be NULL). The returned pointer
|
* The old value of kptr (which can be NULL). The returned pointer
|
||||||
* if not NULL, is a reference which must be released using its
|
* if not NULL, is a reference which must be released using its
|
||||||
|
@ -6046,11 +6050,6 @@ enum {
|
||||||
BPF_F_MARK_ENFORCE = (1ULL << 6),
|
BPF_F_MARK_ENFORCE = (1ULL << 6),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
|
|
||||||
enum {
|
|
||||||
BPF_F_INGRESS = (1ULL << 0),
|
|
||||||
};
|
|
||||||
|
|
||||||
/* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */
|
/* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */
|
||||||
enum {
|
enum {
|
||||||
BPF_F_TUNINFO_IPV6 = (1ULL << 0),
|
BPF_F_TUNINFO_IPV6 = (1ULL << 0),
|
||||||
|
@ -6197,10 +6196,12 @@ enum {
|
||||||
BPF_F_BPRM_SECUREEXEC = (1ULL << 0),
|
BPF_F_BPRM_SECUREEXEC = (1ULL << 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Flags for bpf_redirect_map helper */
|
/* Flags for bpf_redirect and bpf_redirect_map helpers */
|
||||||
enum {
|
enum {
|
||||||
BPF_F_BROADCAST = (1ULL << 3),
|
BPF_F_INGRESS = (1ULL << 0), /* used for skb path */
|
||||||
BPF_F_EXCLUDE_INGRESS = (1ULL << 4),
|
BPF_F_BROADCAST = (1ULL << 3), /* used for XDP path */
|
||||||
|
BPF_F_EXCLUDE_INGRESS = (1ULL << 4), /* used for XDP path */
|
||||||
|
#define BPF_F_REDIRECT_FLAGS (BPF_F_INGRESS | BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define __bpf_md_ptr(type, name) \
|
#define __bpf_md_ptr(type, name) \
|
||||||
|
@ -7080,6 +7081,7 @@ enum {
|
||||||
TCP_BPF_SYN = 1005, /* Copy the TCP header */
|
TCP_BPF_SYN = 1005, /* Copy the TCP header */
|
||||||
TCP_BPF_SYN_IP = 1006, /* Copy the IP[46] and TCP header */
|
TCP_BPF_SYN_IP = 1006, /* Copy the IP[46] and TCP header */
|
||||||
TCP_BPF_SYN_MAC = 1007, /* Copy the MAC, IP[46], and TCP header */
|
TCP_BPF_SYN_MAC = 1007, /* Copy the MAC, IP[46], and TCP header */
|
||||||
|
TCP_BPF_SOCK_OPS_CB_FLAGS = 1008, /* Get or Set TCP sock ops flags */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -7512,4 +7514,13 @@ struct bpf_iter_num {
|
||||||
__u64 __opaque[1];
|
__u64 __opaque[1];
|
||||||
} __attribute__((aligned(8)));
|
} __attribute__((aligned(8)));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flags to control BPF kfunc behaviour.
|
||||||
|
* - BPF_F_PAD_ZEROS: Pad destination buffer with zeros. (See the respective
|
||||||
|
* helper documentation for details.)
|
||||||
|
*/
|
||||||
|
enum bpf_kfunc_flags {
|
||||||
|
BPF_F_PAD_ZEROS = (1ULL << 0),
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* __LINUX_BPF_H__ */
|
#endif /* __LINUX_BPF_H__ */
|
||||||
|
|
|
@ -28,6 +28,23 @@
|
||||||
#define _BITUL(x) (_UL(1) << (x))
|
#define _BITUL(x) (_UL(1) << (x))
|
||||||
#define _BITULL(x) (_ULL(1) << (x))
|
#define _BITULL(x) (_ULL(1) << (x))
|
||||||
|
|
||||||
|
#if !defined(__ASSEMBLY__)
|
||||||
|
/*
|
||||||
|
* Missing __asm__ support
|
||||||
|
*
|
||||||
|
* __BIT128() would not work in the __asm__ code, as it shifts an
|
||||||
|
* 'unsigned __init128' data type as direct representation of
|
||||||
|
* 128 bit constants is not supported in the gcc compiler, as
|
||||||
|
* they get silently truncated.
|
||||||
|
*
|
||||||
|
* TODO: Please revisit this implementation when gcc compiler
|
||||||
|
* starts representing 128 bit constants directly like long
|
||||||
|
* and unsigned long etc. Subsequently drop the comment for
|
||||||
|
* GENMASK_U128() which would then start supporting __asm__ code.
|
||||||
|
*/
|
||||||
|
#define _BIT128(x) ((unsigned __int128)(1) << (x))
|
||||||
|
#endif
|
||||||
|
|
||||||
#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1)
|
#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1)
|
||||||
#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
||||||
|
|
||||||
|
|
|
@ -2531,4 +2531,20 @@ struct ethtool_link_settings {
|
||||||
* __u32 map_lp_advertising[link_mode_masks_nwords];
|
* __u32 map_lp_advertising[link_mode_masks_nwords];
|
||||||
*/
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum phy_upstream - Represents the upstream component a given PHY device
|
||||||
|
* is connected to, as in what is on the other end of the MII bus. Most PHYs
|
||||||
|
* will be attached to an Ethernet MAC controller, but in some cases, there's
|
||||||
|
* an intermediate PHY used as a media-converter, which will driver another
|
||||||
|
* MII interface as its output.
|
||||||
|
* @PHY_UPSTREAM_MAC: Upstream component is a MAC (a switch port,
|
||||||
|
* or ethernet controller)
|
||||||
|
* @PHY_UPSTREAM_PHY: Upstream component is a PHY (likely a media converter)
|
||||||
|
*/
|
||||||
|
enum phy_upstream {
|
||||||
|
PHY_UPSTREAM_MAC,
|
||||||
|
PHY_UPSTREAM_PHY,
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _LINUX_ETHTOOL_H */
|
#endif /* _LINUX_ETHTOOL_H */
|
||||||
|
|
|
@ -67,6 +67,7 @@ enum {
|
||||||
FRA_IP_PROTO, /* ip proto */
|
FRA_IP_PROTO, /* ip proto */
|
||||||
FRA_SPORT_RANGE, /* sport */
|
FRA_SPORT_RANGE, /* sport */
|
||||||
FRA_DPORT_RANGE, /* dport */
|
FRA_DPORT_RANGE, /* dport */
|
||||||
|
FRA_DSCP, /* dscp */
|
||||||
__FRA_MAX
|
__FRA_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -230,8 +230,8 @@ struct tpacket_hdr_v1 {
|
||||||
* ts_first_pkt:
|
* ts_first_pkt:
|
||||||
* Is always the time-stamp when the block was opened.
|
* Is always the time-stamp when the block was opened.
|
||||||
* Case a) ZERO packets
|
* Case a) ZERO packets
|
||||||
* No packets to deal with but atleast you know the
|
* No packets to deal with but at least you know
|
||||||
* time-interval of this block.
|
* the time-interval of this block.
|
||||||
* Case b) Non-zero packets
|
* Case b) Non-zero packets
|
||||||
* Use the ts of the first packet in the block.
|
* Use the ts of the first packet in the block.
|
||||||
*
|
*
|
||||||
|
@ -265,7 +265,8 @@ enum tpacket_versions {
|
||||||
- struct tpacket_hdr
|
- struct tpacket_hdr
|
||||||
- pad to TPACKET_ALIGNMENT=16
|
- pad to TPACKET_ALIGNMENT=16
|
||||||
- struct sockaddr_ll
|
- struct sockaddr_ll
|
||||||
- Gap, chosen so that packet data (Start+tp_net) alignes to TPACKET_ALIGNMENT=16
|
- Gap, chosen so that packet data (Start+tp_net) aligns to
|
||||||
|
TPACKET_ALIGNMENT=16
|
||||||
- Start+tp_mac: [ Optional MAC header ]
|
- Start+tp_mac: [ Optional MAC header ]
|
||||||
- Start+tp_net: Packet data, aligned to TPACKET_ALIGNMENT=16.
|
- Start+tp_net: Packet data, aligned to TPACKET_ALIGNMENT=16.
|
||||||
- Pad to align to TPACKET_ALIGNMENT=16
|
- Pad to align to TPACKET_ALIGNMENT=16
|
||||||
|
|
|
@ -141,7 +141,7 @@ struct in_addr {
|
||||||
*/
|
*/
|
||||||
#define IP_PMTUDISC_INTERFACE 4
|
#define IP_PMTUDISC_INTERFACE 4
|
||||||
/* weaker version of IP_PMTUDISC_INTERFACE, which allows packets to get
|
/* weaker version of IP_PMTUDISC_INTERFACE, which allows packets to get
|
||||||
* fragmented if they exeed the interface mtu
|
* fragmented if they exceed the interface mtu
|
||||||
*/
|
*/
|
||||||
#define IP_PMTUDISC_OMIT 5
|
#define IP_PMTUDISC_OMIT 5
|
||||||
|
|
||||||
|
|
|
@ -140,25 +140,6 @@
|
||||||
|
|
||||||
#endif /* _NETINET_IN_H */
|
#endif /* _NETINET_IN_H */
|
||||||
|
|
||||||
/* Coordinate with glibc netipx/ipx.h header. */
|
|
||||||
#if defined(__NETIPX_IPX_H)
|
|
||||||
|
|
||||||
#define __UAPI_DEF_SOCKADDR_IPX 0
|
|
||||||
#define __UAPI_DEF_IPX_ROUTE_DEFINITION 0
|
|
||||||
#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 0
|
|
||||||
#define __UAPI_DEF_IPX_CONFIG_DATA 0
|
|
||||||
#define __UAPI_DEF_IPX_ROUTE_DEF 0
|
|
||||||
|
|
||||||
#else /* defined(__NETIPX_IPX_H) */
|
|
||||||
|
|
||||||
#define __UAPI_DEF_SOCKADDR_IPX 1
|
|
||||||
#define __UAPI_DEF_IPX_ROUTE_DEFINITION 1
|
|
||||||
#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 1
|
|
||||||
#define __UAPI_DEF_IPX_CONFIG_DATA 1
|
|
||||||
#define __UAPI_DEF_IPX_ROUTE_DEF 1
|
|
||||||
|
|
||||||
#endif /* defined(__NETIPX_IPX_H) */
|
|
||||||
|
|
||||||
/* Definitions for xattr.h */
|
/* Definitions for xattr.h */
|
||||||
#if defined(_SYS_XATTR_H)
|
#if defined(_SYS_XATTR_H)
|
||||||
#define __UAPI_DEF_XATTR 0
|
#define __UAPI_DEF_XATTR 0
|
||||||
|
@ -240,23 +221,6 @@
|
||||||
#define __UAPI_DEF_IP6_MTUINFO 1
|
#define __UAPI_DEF_IP6_MTUINFO 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Definitions for ipx.h */
|
|
||||||
#ifndef __UAPI_DEF_SOCKADDR_IPX
|
|
||||||
#define __UAPI_DEF_SOCKADDR_IPX 1
|
|
||||||
#endif
|
|
||||||
#ifndef __UAPI_DEF_IPX_ROUTE_DEFINITION
|
|
||||||
#define __UAPI_DEF_IPX_ROUTE_DEFINITION 1
|
|
||||||
#endif
|
|
||||||
#ifndef __UAPI_DEF_IPX_INTERFACE_DEFINITION
|
|
||||||
#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 1
|
|
||||||
#endif
|
|
||||||
#ifndef __UAPI_DEF_IPX_CONFIG_DATA
|
|
||||||
#define __UAPI_DEF_IPX_CONFIG_DATA 1
|
|
||||||
#endif
|
|
||||||
#ifndef __UAPI_DEF_IPX_ROUTE_DEF
|
|
||||||
#define __UAPI_DEF_IPX_ROUTE_DEF 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Definitions for xattr.h */
|
/* Definitions for xattr.h */
|
||||||
#ifndef __UAPI_DEF_XATTR
|
#ifndef __UAPI_DEF_XATTR
|
||||||
#define __UAPI_DEF_XATTR 1
|
#define __UAPI_DEF_XATTR 1
|
||||||
|
|
|
@ -436,7 +436,7 @@ enum nft_set_elem_flags {
|
||||||
* @NFTA_SET_ELEM_KEY: key value (NLA_NESTED: nft_data)
|
* @NFTA_SET_ELEM_KEY: key value (NLA_NESTED: nft_data)
|
||||||
* @NFTA_SET_ELEM_DATA: data value of mapping (NLA_NESTED: nft_data_attributes)
|
* @NFTA_SET_ELEM_DATA: data value of mapping (NLA_NESTED: nft_data_attributes)
|
||||||
* @NFTA_SET_ELEM_FLAGS: bitmask of nft_set_elem_flags (NLA_U32)
|
* @NFTA_SET_ELEM_FLAGS: bitmask of nft_set_elem_flags (NLA_U32)
|
||||||
* @NFTA_SET_ELEM_TIMEOUT: timeout value (NLA_U64)
|
* @NFTA_SET_ELEM_TIMEOUT: timeout value, zero means never times out (NLA_U64)
|
||||||
* @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64)
|
* @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64)
|
||||||
* @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
|
* @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
|
||||||
* @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
|
* @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
|
||||||
|
@ -1694,7 +1694,7 @@ enum nft_flowtable_flags {
|
||||||
*
|
*
|
||||||
* @NFTA_FLOWTABLE_TABLE: name of the table containing the expression (NLA_STRING)
|
* @NFTA_FLOWTABLE_TABLE: name of the table containing the expression (NLA_STRING)
|
||||||
* @NFTA_FLOWTABLE_NAME: name of this flow table (NLA_STRING)
|
* @NFTA_FLOWTABLE_NAME: name of this flow table (NLA_STRING)
|
||||||
* @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
|
* @NFTA_FLOWTABLE_HOOK: netfilter hook configuration (NLA_NESTED)
|
||||||
* @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
|
* @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
|
||||||
* @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
|
* @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
|
||||||
* @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32)
|
* @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32)
|
||||||
|
|
|
@ -16,10 +16,15 @@ struct nhmsg {
|
||||||
struct nexthop_grp {
|
struct nexthop_grp {
|
||||||
__u32 id; /* nexthop id - must exist */
|
__u32 id; /* nexthop id - must exist */
|
||||||
__u8 weight; /* weight of this nexthop */
|
__u8 weight; /* weight of this nexthop */
|
||||||
__u8 resvd1;
|
__u8 weight_high; /* high order bits of weight */
|
||||||
__u16 resvd2;
|
__u16 resvd2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static __inline__ __u16 nexthop_grp_weight(const struct nexthop_grp *entry)
|
||||||
|
{
|
||||||
|
return ((entry->weight_high << 8) | entry->weight) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
NEXTHOP_GRP_TYPE_MPATH, /* hash-threshold nexthop group
|
NEXTHOP_GRP_TYPE_MPATH, /* hash-threshold nexthop group
|
||||||
* default type if not specified
|
* default type if not specified
|
||||||
|
@ -33,6 +38,9 @@ enum {
|
||||||
#define NHA_OP_FLAG_DUMP_STATS BIT(0)
|
#define NHA_OP_FLAG_DUMP_STATS BIT(0)
|
||||||
#define NHA_OP_FLAG_DUMP_HW_STATS BIT(1)
|
#define NHA_OP_FLAG_DUMP_HW_STATS BIT(1)
|
||||||
|
|
||||||
|
/* Response OP_FLAGS. */
|
||||||
|
#define NHA_OP_FLAG_RESP_GRP_RESVD_0 BIT(31) /* Dump clears resvd fields. */
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
NHA_UNSPEC,
|
NHA_UNSPEC,
|
||||||
NHA_ID, /* u32; id for nexthop. id == 0 means auto-assign */
|
NHA_ID, /* u32; id for nexthop. id == 0 means auto-assign */
|
||||||
|
|
|
@ -531,20 +531,24 @@ int is_idmapping_supported(const char *path) {
|
||||||
userns_fd = userns_acquire(uid_map, gid_map);
|
userns_fd = userns_acquire(uid_map, gid_map);
|
||||||
if (ERRNO_IS_NEG_NOT_SUPPORTED(userns_fd) || ERRNO_IS_NEG_PRIVILEGE(userns_fd))
|
if (ERRNO_IS_NEG_NOT_SUPPORTED(userns_fd) || ERRNO_IS_NEG_PRIVILEGE(userns_fd))
|
||||||
return false;
|
return false;
|
||||||
|
if (userns_fd == -ENOSPC) {
|
||||||
|
log_debug_errno(userns_fd, "Failed to acquire new user namespace, user.max_user_namespaces seems to be exhausted or maybe even zero, assuming ID-mapping is not supported: %m");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (userns_fd < 0)
|
if (userns_fd < 0)
|
||||||
return log_debug_errno(userns_fd, "ID-mapping supported namespace acquire failed for '%s' : %m", path);
|
return log_debug_errno(userns_fd, "Failed to acquire new user namespace for checking if '%s' supports ID-mapping: %m", path);
|
||||||
|
|
||||||
dir_fd = RET_NERRNO(open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
|
dir_fd = RET_NERRNO(open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
|
||||||
if (ERRNO_IS_NEG_NOT_SUPPORTED(dir_fd))
|
if (ERRNO_IS_NEG_NOT_SUPPORTED(dir_fd))
|
||||||
return false;
|
return false;
|
||||||
if (dir_fd < 0)
|
if (dir_fd < 0)
|
||||||
return log_debug_errno(dir_fd, "ID-mapping supported open failed for '%s' : %m", path);
|
return log_debug_errno(dir_fd, "Failed to open '%s', cannot determine if ID-mapping is supported: %m", path);
|
||||||
|
|
||||||
mount_fd = RET_NERRNO(open_tree(dir_fd, "", AT_EMPTY_PATH | OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC));
|
mount_fd = RET_NERRNO(open_tree(dir_fd, "", AT_EMPTY_PATH | OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC));
|
||||||
if (ERRNO_IS_NEG_NOT_SUPPORTED(mount_fd) || ERRNO_IS_NEG_PRIVILEGE(mount_fd) || mount_fd == -EINVAL)
|
if (ERRNO_IS_NEG_NOT_SUPPORTED(mount_fd) || ERRNO_IS_NEG_PRIVILEGE(mount_fd) || mount_fd == -EINVAL)
|
||||||
return false;
|
return false;
|
||||||
if (mount_fd < 0)
|
if (mount_fd < 0)
|
||||||
return log_debug_errno(mount_fd, "ID-mapping supported open_tree failed for '%s' : %m", path);
|
return log_debug_errno(mount_fd, "Failed to open mount tree '%s', cannot determine if ID-mapping is supported: %m", path);
|
||||||
|
|
||||||
r = RET_NERRNO(mount_setattr(mount_fd, "", AT_EMPTY_PATH,
|
r = RET_NERRNO(mount_setattr(mount_fd, "", AT_EMPTY_PATH,
|
||||||
&(struct mount_attr) {
|
&(struct mount_attr) {
|
||||||
|
@ -554,7 +558,7 @@ int is_idmapping_supported(const char *path) {
|
||||||
if (ERRNO_IS_NEG_NOT_SUPPORTED(r) || ERRNO_IS_NEG_PRIVILEGE(r) || r == -EINVAL)
|
if (ERRNO_IS_NEG_NOT_SUPPORTED(r) || ERRNO_IS_NEG_PRIVILEGE(r) || r == -EINVAL)
|
||||||
return false;
|
return false;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "ID-mapping supported setattr failed for '%s' : %m", path);
|
return log_debug_errno(r, "Failed to set mount attribute to '%s', cannot determine if ID-mapping is supported: %m", path);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <linux/magic.h>
|
||||||
#include <linux/oom.h>
|
#include <linux/oom.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <spawn.h>
|
#include <spawn.h>
|
||||||
|
@ -11,6 +12,9 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/personality.h>
|
#include <sys/personality.h>
|
||||||
|
#if HAVE_PIDFD_OPEN
|
||||||
|
#include <sys/pidfd.h>
|
||||||
|
#endif
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
@ -40,6 +44,7 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "memory-util.h"
|
#include "memory-util.h"
|
||||||
|
#include "missing_magic.h"
|
||||||
#include "missing_sched.h"
|
#include "missing_sched.h"
|
||||||
#include "missing_syscall.h"
|
#include "missing_syscall.h"
|
||||||
#include "missing_threads.h"
|
#include "missing_threads.h"
|
||||||
|
@ -2289,3 +2294,42 @@ _noreturn_ void report_errno_and_exit(int errno_fd, int error) {
|
||||||
|
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getpidfdid_cached(uint64_t *ret) {
|
||||||
|
static uint64_t cached = 0;
|
||||||
|
static int initialized = 0;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
if (initialized > 0) {
|
||||||
|
*ret = cached;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (initialized < 0)
|
||||||
|
return initialized;
|
||||||
|
|
||||||
|
_cleanup_close_ int fd = pidfd_open(getpid_cached(), 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
if (ERRNO_IS_NOT_SUPPORTED(errno))
|
||||||
|
return (initialized = -EOPNOTSUPP);
|
||||||
|
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = fd_is_fs_type(fd, PID_FS_MAGIC);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
return (initialized = -EOPNOTSUPP);
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (fstat(fd, &st) < 0)
|
||||||
|
return -errno;
|
||||||
|
if (st.st_ino == 0)
|
||||||
|
return (initialized = -EOPNOTSUPP);
|
||||||
|
|
||||||
|
*ret = cached = st.st_ino;
|
||||||
|
initialized = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -275,3 +275,5 @@ int proc_dir_read(DIR *d, pid_t *ret);
|
||||||
int proc_dir_read_pidref(DIR *d, PidRef *ret);
|
int proc_dir_read_pidref(DIR *d, PidRef *ret);
|
||||||
|
|
||||||
_noreturn_ void report_errno_and_exit(int errno_fd, int error);
|
_noreturn_ void report_errno_and_exit(int errno_fd, int error);
|
||||||
|
|
||||||
|
int getpidfdid_cached(uint64_t *ret);
|
||||||
|
|
|
@ -42,6 +42,7 @@ static void fallback_random_bytes(void *p, size_t n) {
|
||||||
uint64_t call_id, block_id;
|
uint64_t call_id, block_id;
|
||||||
usec_t stamp_mono, stamp_real;
|
usec_t stamp_mono, stamp_real;
|
||||||
pid_t pid, tid;
|
pid_t pid, tid;
|
||||||
|
uint64_t pidfdid;
|
||||||
uint8_t auxval[16];
|
uint8_t auxval[16];
|
||||||
} state = {
|
} state = {
|
||||||
/* Arbitrary domain separation to prevent other usage of AT_RANDOM from clashing. */
|
/* Arbitrary domain separation to prevent other usage of AT_RANDOM from clashing. */
|
||||||
|
@ -57,6 +58,8 @@ static void fallback_random_bytes(void *p, size_t n) {
|
||||||
memcpy(state.auxval, ULONG_TO_PTR(getauxval(AT_RANDOM)), sizeof(state.auxval));
|
memcpy(state.auxval, ULONG_TO_PTR(getauxval(AT_RANDOM)), sizeof(state.auxval));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
(void) getpidfdid_cached(&state.pidfdid);
|
||||||
|
|
||||||
while (n > 0) {
|
while (n > 0) {
|
||||||
struct sha256_ctx ctx;
|
struct sha256_ctx ctx;
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#include "efivars.h"
|
#include "efivars.h"
|
||||||
#include "emergency-action.h"
|
#include "emergency-action.h"
|
||||||
#include "env-util.h"
|
#include "env-util.h"
|
||||||
|
#include "escape.h"
|
||||||
#include "exit-status.h"
|
#include "exit-status.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fdset.h"
|
#include "fdset.h"
|
||||||
|
@ -57,6 +58,7 @@
|
||||||
#include "ima-setup.h"
|
#include "ima-setup.h"
|
||||||
#include "import-creds.h"
|
#include "import-creds.h"
|
||||||
#include "initrd-util.h"
|
#include "initrd-util.h"
|
||||||
|
#include "io-util.h"
|
||||||
#include "ipe-setup.h"
|
#include "ipe-setup.h"
|
||||||
#include "killall.h"
|
#include "killall.h"
|
||||||
#include "kmod-setup.h"
|
#include "kmod-setup.h"
|
||||||
|
@ -73,6 +75,7 @@
|
||||||
#include "mount-setup.h"
|
#include "mount-setup.h"
|
||||||
#include "mount-util.h"
|
#include "mount-util.h"
|
||||||
#include "os-util.h"
|
#include "os-util.h"
|
||||||
|
#include "osc-context.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
#include "parse-argument.h"
|
#include "parse-argument.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
|
@ -2380,6 +2383,38 @@ static void log_execution_mode(bool *ret_first_boot) {
|
||||||
*ret_first_boot = first_boot;
|
*ret_first_boot = first_boot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int write_boot_or_shutdown_osc(bool boot) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (getenv_terminal_is_dumb())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const char *type = boot ? "boot" : "shutdown";
|
||||||
|
|
||||||
|
_cleanup_close_ int fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
|
||||||
|
if (fd < 0)
|
||||||
|
return log_debug_errno(fd, "Failed to open /dev/console to print %s OSC, ignoring: %m", type);
|
||||||
|
|
||||||
|
_cleanup_free_ char *seq = NULL;
|
||||||
|
if (boot)
|
||||||
|
r = osc_context_open_boot(&seq);
|
||||||
|
else
|
||||||
|
r = osc_context_close(SD_ID128_ALLF, &seq);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to acquire %s OSC sequence, ignoring: %m", type);
|
||||||
|
|
||||||
|
r = loop_write(fd, seq, strlen(seq));
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to write %s OSC sequence, ignoring: %m", type);
|
||||||
|
|
||||||
|
if (DEBUG_LOGGING) {
|
||||||
|
_cleanup_free_ char *h = cescape(seq);
|
||||||
|
log_debug("OSC sequence for %s successfully written: %s", type, strna(h));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int initialize_runtime(
|
static int initialize_runtime(
|
||||||
bool skip_setup,
|
bool skip_setup,
|
||||||
bool first_boot,
|
bool first_boot,
|
||||||
|
@ -2438,6 +2473,8 @@ static int initialize_runtime(
|
||||||
|
|
||||||
write_container_id();
|
write_container_id();
|
||||||
|
|
||||||
|
(void) write_boot_or_shutdown_osc(/* boot= */ true);
|
||||||
|
|
||||||
/* Copy os-release to the propagate directory, so that we update it for services running
|
/* Copy os-release to the propagate directory, so that we update it for services running
|
||||||
* under RootDirectory=/RootImage= when we do a soft reboot. */
|
* under RootDirectory=/RootImage= when we do a soft reboot. */
|
||||||
r = setup_os_release(RUNTIME_SCOPE_SYSTEM);
|
r = setup_os_release(RUNTIME_SCOPE_SYSTEM);
|
||||||
|
@ -3427,6 +3464,8 @@ finish:
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
(void) write_boot_or_shutdown_osc(/* boot= */ false);
|
||||||
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
(void) sd_notifyf(/* unset_environment= */ false,
|
(void) sd_notifyf(/* unset_environment= */ false,
|
||||||
"ERRNO=%i", -r);
|
"ERRNO=%i", -r);
|
||||||
|
|
|
@ -98,16 +98,11 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_SYSV_COMPAT
|
else if (streq(key, "fastboot") && !value)
|
||||||
else if (streq(key, "fastboot") && !value) {
|
|
||||||
log_warning("Please pass 'fsck.mode=skip' rather than 'fastboot' on the kernel command line.");
|
|
||||||
arg_skip = true;
|
arg_skip = true;
|
||||||
|
|
||||||
} else if (streq(key, "forcefsck") && !value) {
|
else if (streq(key, "forcefsck") && !value)
|
||||||
log_warning("Please pass 'fsck.mode=force' rather than 'forcefsck' on the kernel command line.");
|
|
||||||
arg_force = true;
|
arg_force = true;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
#include "mkdir.h"
|
#include "mkdir.h"
|
||||||
#include "nulstr-util.h"
|
#include "nulstr-util.h"
|
||||||
|
#include "osc-context.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
#include "parse-argument.h"
|
#include "parse-argument.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
|
@ -1227,6 +1228,13 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, PT
|
||||||
log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", name);
|
log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_cleanup_(osc_context_closep) sd_id128_t osc_context_id = SD_ID128_NULL;
|
||||||
|
if (!terminal_is_dumb()) {
|
||||||
|
r = osc_context_open_container(name, /* ret_seq= */ NULL, &osc_context_id);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r = sd_event_set_signal_exit(event, true);
|
r = sd_event_set_signal_exit(event, true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to enable SIGINT/SITERM handling: %m");
|
return log_error_errno(r, "Failed to enable SIGINT/SITERM handling: %m");
|
||||||
|
|
|
@ -108,6 +108,7 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||||
" --ucode=PATH Path to microcode image file %7$s .ucode\n"
|
" --ucode=PATH Path to microcode image file %7$s .ucode\n"
|
||||||
" --splash=PATH Path to splash bitmap file %7$s .splash\n"
|
" --splash=PATH Path to splash bitmap file %7$s .splash\n"
|
||||||
" --dtb=PATH Path to DeviceTree file %7$s .dtb\n"
|
" --dtb=PATH Path to DeviceTree file %7$s .dtb\n"
|
||||||
|
" --dtbauto=PATH Path to DeviceTree file for auto selection %7$s .dtbauto\n"
|
||||||
" --uname=PATH Path to 'uname -r' file %7$s .uname\n"
|
" --uname=PATH Path to 'uname -r' file %7$s .uname\n"
|
||||||
" --sbat=PATH Path to SBAT file %7$s .sbat\n"
|
" --sbat=PATH Path to SBAT file %7$s .sbat\n"
|
||||||
" --pcrpkey=PATH Path to public key for PCR signatures %7$s .pcrpkey\n"
|
" --pcrpkey=PATH Path to public key for PCR signatures %7$s .pcrpkey\n"
|
||||||
|
|
|
@ -84,6 +84,7 @@
|
||||||
#include "nsresource.h"
|
#include "nsresource.h"
|
||||||
#include "nulstr-util.h"
|
#include "nulstr-util.h"
|
||||||
#include "os-util.h"
|
#include "os-util.h"
|
||||||
|
#include "osc-context.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
#include "parse-argument.h"
|
#include "parse-argument.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
|
@ -2280,10 +2281,9 @@ static int copy_devnode_one(const char *dest, const char *node, bool ignore_mkno
|
||||||
r = path_extract_directory(from, &parent);
|
r = path_extract_directory(from, &parent);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to extract directory from %s: %m", from);
|
return log_error_errno(r, "Failed to extract directory from %s: %m", from);
|
||||||
if (!path_equal(parent, "/dev/")) {
|
r = userns_mkdir(dest, parent, 0755, 0, 0);
|
||||||
if (userns_mkdir(dest, parent, 0755, 0, 0) < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to create directory %s: %m", parent);
|
return log_error_errno(r, "Failed to create directory %s: %m", parent);
|
||||||
}
|
|
||||||
|
|
||||||
if (mknod(to, st.st_mode, st.st_rdev) < 0) {
|
if (mknod(to, st.st_mode, st.st_rdev) < 0) {
|
||||||
r = -errno; /* Save the original error code. */
|
r = -errno; /* Save the original error code. */
|
||||||
|
@ -4654,7 +4654,7 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
|
||||||
|
|
||||||
ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
|
ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
|
||||||
if (!ucred || ucred->pid != inner_child_pid) {
|
if (!ucred || ucred->pid != inner_child_pid) {
|
||||||
log_debug("Received notify message without valid credentials. Ignoring.");
|
log_debug("Received notify message from process that is not the payload's PID 1. Ignoring.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5685,6 +5685,13 @@ static int run_container(
|
||||||
(void) expose_port_execute(rtnl, &expose_args->fw_ctx, arg_expose_ports, AF_INET6, &expose_args->address6);
|
(void) expose_port_execute(rtnl, &expose_args->fw_ctx, arg_expose_ports, AF_INET6, &expose_args->address6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_cleanup_(osc_context_closep) sd_id128_t osc_context_id = SD_ID128_NULL;
|
||||||
|
if (IN_SET(arg_console_mode, CONSOLE_INTERACTIVE, CONSOLE_READ_ONLY) && !terminal_is_dumb()) {
|
||||||
|
r = osc_context_open_container(arg_machine, /* ret_seq= */ NULL, &osc_context_id);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (arg_console_mode != CONSOLE_PIPE) {
|
if (arg_console_mode != CONSOLE_PIPE) {
|
||||||
_cleanup_close_ int fd = -EBADF;
|
_cleanup_close_ int fd = -EBADF;
|
||||||
PTYForwardFlags flags = 0;
|
PTYForwardFlags flags = 0;
|
||||||
|
|
|
@ -36,14 +36,9 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||||
arg_skip = true;
|
arg_skip = true;
|
||||||
else
|
else
|
||||||
log_warning("Invalid quotacheck.mode= value, ignoring: %s", value);
|
log_warning("Invalid quotacheck.mode= value, ignoring: %s", value);
|
||||||
}
|
|
||||||
|
|
||||||
#if HAVE_SYSV_COMPAT
|
} else if (streq(key, "forcequotacheck") && !value)
|
||||||
else if (streq(key, "forcequotacheck") && !value) {
|
|
||||||
log_warning("Please use 'quotacheck.mode=force' rather than 'forcequotacheck' on the kernel command line. Proceeding anyway.");
|
|
||||||
arg_force = true;
|
arg_force = true;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "hostname-util.h"
|
#include "hostname-util.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
|
#include "osc-context.h"
|
||||||
#include "parse-argument.h"
|
#include "parse-argument.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
|
@ -2041,6 +2042,7 @@ static int start_transient_service(sd_bus *bus) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_cleanup_(osc_context_closep) sd_id128_t osc_context_id = SD_ID128_NULL;
|
||||||
if (arg_wait || arg_stdio != ARG_STDIO_NONE) {
|
if (arg_wait || arg_stdio != ARG_STDIO_NONE) {
|
||||||
_cleanup_(run_context_done) RunContext c = {
|
_cleanup_(run_context_done) RunContext c = {
|
||||||
.cpu_usage_nsec = NSEC_INFINITY,
|
.cpu_usage_nsec = NSEC_INFINITY,
|
||||||
|
@ -2067,6 +2069,12 @@ static int start_transient_service(sd_bus *bus) {
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
if (pty_fd >= 0) {
|
if (pty_fd >= 0) {
|
||||||
|
if (!terminal_is_dumb() && arg_exec_user) {
|
||||||
|
r = osc_context_open_chpriv(arg_exec_user, /* ret_seq= */ NULL, &osc_context_id);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
(void) sd_event_set_signal_exit(c.event, true);
|
(void) sd_event_set_signal_exit(c.event, true);
|
||||||
|
|
||||||
if (!arg_quiet)
|
if (!arg_quiet)
|
||||||
|
|
|
@ -132,6 +132,7 @@ shared_sources = files(
|
||||||
'open-file.c',
|
'open-file.c',
|
||||||
'openssl-util.c',
|
'openssl-util.c',
|
||||||
'output-mode.c',
|
'output-mode.c',
|
||||||
|
'osc-context.c',
|
||||||
'pager.c',
|
'pager.c',
|
||||||
'parse-argument.c',
|
'parse-argument.c',
|
||||||
'parse-helpers.c',
|
'parse-helpers.c',
|
||||||
|
|
|
@ -0,0 +1,275 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#if HAVE_SYS_AUXV_H
|
||||||
|
# include <sys/auxv.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "escape.h"
|
||||||
|
#include "hostname-util.h"
|
||||||
|
#include "osc-context.h"
|
||||||
|
#include "process-util.h"
|
||||||
|
#include "string-util.h"
|
||||||
|
#include "terminal-util.h"
|
||||||
|
#include "user-util.h"
|
||||||
|
|
||||||
|
/* This currently generates open sequences for OSC 300819 types "boot", "container", "vm", "elevate",
|
||||||
|
* "chpriv", "subcontext". */
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
*
|
||||||
|
* → "service" (from the service manager)
|
||||||
|
* → "session" (from pam_systemd?)
|
||||||
|
* → "shell", "command" (from a bash profile drop-in?)
|
||||||
|
*
|
||||||
|
* Not generated by systemd: "remote" (would have to be generated from the SSH client), "app".
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int strextend_escaped(char **s, const char *prefix, const char *value, const char *suffix) {
|
||||||
|
assert(s);
|
||||||
|
assert(value);
|
||||||
|
|
||||||
|
if (!strextend(s, prefix))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
_cleanup_free_ char *e = xescape(value, ";\\");
|
||||||
|
if (!e)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (!strextend(s, e))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (!strextend(s, suffix))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int osc_append_identity(char **s) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(s);
|
||||||
|
|
||||||
|
_cleanup_free_ char *u = getusername_malloc();
|
||||||
|
if (u) {
|
||||||
|
r = strextend_escaped(s, ";", u, "u");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanup_free_ char *h = gethostname_malloc();
|
||||||
|
if (h) {
|
||||||
|
r = strextend_escaped(s, ";", h, "h");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
sd_id128_t id;
|
||||||
|
if (sd_id128_get_machine(&id) >= 0) {
|
||||||
|
r = strextendf(s, ";" SD_ID128_FORMAT_STR "m", SD_ID128_FORMAT_VAL(id));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sd_id128_get_boot(&id) >= 0) {
|
||||||
|
r = strextendf(s, ";" SD_ID128_FORMAT_STR "b", SD_ID128_FORMAT_VAL(id));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = strextendf(s, ";" PID_FMT "p", getpid_cached());
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
uint64_t pidfdid;
|
||||||
|
r = getpidfdid_cached(&pidfdid);
|
||||||
|
if (r >= 0) {
|
||||||
|
r = strextendf(s, ";%" PRIu64 "P", pidfdid);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = strextend_escaped(s, ";", program_invocation_short_name, "c");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void osc_context_default_id(sd_id128_t *ret_id) {
|
||||||
|
|
||||||
|
/* Usually we only want one context ID per tool. Since we don't want to store the ID let's just hash
|
||||||
|
* one from process credentials */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint64_t pidfdid;
|
||||||
|
uint8_t auxval[16];
|
||||||
|
pid_t pid;
|
||||||
|
} data = {
|
||||||
|
.pid = getpid_cached(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(ret_id);
|
||||||
|
|
||||||
|
(void) getpidfdid_cached(&data.pidfdid);
|
||||||
|
|
||||||
|
memcpy(data.auxval, ULONG_TO_PTR(getauxval(AT_RANDOM)), sizeof(data.auxval));
|
||||||
|
|
||||||
|
ret_id->qwords[0] = siphash24(&data, sizeof(data), SD_ID128_MAKE(3f,8c,ee,e1,fd,35,41,ec,b8,b1,90,d4,59,e2,ae,5b).bytes);
|
||||||
|
ret_id->qwords[1] = siphash24(&data, sizeof(data), SD_ID128_MAKE(c6,41,ec,1b,d8,85,48,c0,8e,11,d7,e1,e1,fa,9e,03).bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int osc_context_intro(char **ret_seq, sd_id128_t *ret_context_id) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(ret_seq);
|
||||||
|
|
||||||
|
/* If the user passed us a buffer for the context ID generate a randomized one, since we have a place
|
||||||
|
* to store it. The user should pass the ID back to osc_context_close() later on. if the user did not
|
||||||
|
* pass us a buffer, we'll use a session ID hashed from process properties that remain stable as long
|
||||||
|
* our process exists. It hence also remains stable across reexec and similar. */
|
||||||
|
sd_id128_t id;
|
||||||
|
if (ret_context_id) {
|
||||||
|
r = sd_id128_randomize(&id);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
} else
|
||||||
|
osc_context_default_id(&id);
|
||||||
|
|
||||||
|
_cleanup_free_ char *seq = NULL;
|
||||||
|
if (asprintf(&seq, ANSI_OSC "300819;S" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id)) < 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
r = osc_append_identity(&seq);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (ret_context_id)
|
||||||
|
*ret_context_id = id;
|
||||||
|
|
||||||
|
*ret_seq = TAKE_PTR(seq);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int osc_context_outro(char *_seq, sd_id128_t id, char **ret_seq, sd_id128_t *ret_context_id) {
|
||||||
|
_cleanup_free_ char *seq = TAKE_PTR(_seq); /* We take possession of the string no matter what */
|
||||||
|
|
||||||
|
if (ret_seq)
|
||||||
|
*ret_seq = TAKE_PTR(seq);
|
||||||
|
else {
|
||||||
|
fputs(seq, stdout);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret_context_id)
|
||||||
|
*ret_context_id = id;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int osc_context_open_boot(char **ret_seq) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
_cleanup_free_ char *seq = NULL;
|
||||||
|
sd_id128_t id;
|
||||||
|
r = osc_context_intro(&seq, /* ret_context_id= */ NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (!strextend(&seq, ";" "boot" "t" ANSI_ST))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
return osc_context_outro(TAKE_PTR(seq), id, ret_seq, /* ret_context_id= */ NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int osc_context_open_container(const char *name, char **ret_seq, sd_id128_t *ret_context_id) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
_cleanup_free_ char *seq = NULL;
|
||||||
|
sd_id128_t id;
|
||||||
|
r = osc_context_intro(&seq, ret_context_id ?: &id);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
r = strextend_escaped(&seq, ";", name, "C");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strextend(&seq, ";" "container" "t" ANSI_ST))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
return osc_context_outro(TAKE_PTR(seq), id, ret_seq, ret_context_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int osc_context_open_vm(const char *name, char **ret_seq, sd_id128_t *ret_context_id) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(name);
|
||||||
|
|
||||||
|
_cleanup_free_ char *seq = NULL;
|
||||||
|
sd_id128_t id;
|
||||||
|
r = osc_context_intro(&seq, ret_context_id ?: &id);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = strextend_escaped(&seq, ";", name, "v");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (!strextend(&seq, ";" "vm" "t" ANSI_ST))
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return osc_context_outro(TAKE_PTR(seq), id, ret_seq, ret_context_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int osc_context_open_chpriv(const char *target_user, char **ret_seq, sd_id128_t *ret_context_id) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(target_user);
|
||||||
|
|
||||||
|
_cleanup_free_ char *seq = NULL;
|
||||||
|
sd_id128_t id;
|
||||||
|
r = osc_context_intro(&seq, ret_context_id ?: &id);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (STR_IN_SET(target_user, "root", "0")) {
|
||||||
|
if (!strextend(&seq, ";" "elevate" "t" ANSI_ST))
|
||||||
|
return -ENOMEM;
|
||||||
|
} else if (is_this_me(target_user) > 0) {
|
||||||
|
if (!strextend(&seq, ";" "subcontext" "t" ANSI_ST))
|
||||||
|
return -ENOMEM;
|
||||||
|
} else {
|
||||||
|
r = strextend_escaped(&seq, ";", target_user, "U");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (!strextend(&seq, ";" "chpriv" "t" ANSI_ST))
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return osc_context_outro(TAKE_PTR(seq), id, ret_seq, ret_context_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int osc_context_close(sd_id128_t id, char **ret_seq) {
|
||||||
|
|
||||||
|
if (sd_id128_is_null(id)) /* nil uuid: no session opened */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (sd_id128_is_allf(id)) /* max uuid: default session opened */
|
||||||
|
osc_context_default_id(&id);
|
||||||
|
|
||||||
|
_cleanup_free_ char *seq = NULL;
|
||||||
|
if (asprintf(&seq, ANSI_OSC "300819;X" SD_ID128_FORMAT_STR ANSI_ST, SD_ID128_FORMAT_VAL(id)) < 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (ret_seq)
|
||||||
|
*ret_seq = TAKE_PTR(seq);
|
||||||
|
else {
|
||||||
|
fputs(seq, stdout);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sd-id128.h"
|
||||||
|
|
||||||
|
int osc_context_open_boot(char **ret_seq);
|
||||||
|
int osc_context_open_container(const char *name, char **ret_seq, sd_id128_t *ret_context_id);
|
||||||
|
int osc_context_open_vm(const char *name, char **ret_seq, sd_id128_t *ret_context_id);
|
||||||
|
int osc_context_open_chpriv(const char *target_user, char **ret_seq, sd_id128_t *ret_context_id);
|
||||||
|
int osc_context_close(sd_id128_t id, char **ret_seq);
|
||||||
|
|
||||||
|
static inline void osc_context_closep(sd_id128_t *context_id) {
|
||||||
|
(void) osc_context_close(*context_id, NULL);
|
||||||
|
}
|
|
@ -98,15 +98,17 @@ static int delete_dm(DeviceMapper *m) {
|
||||||
assert(major(m->devnum) != 0);
|
assert(major(m->devnum) != 0);
|
||||||
assert(m->path);
|
assert(m->path);
|
||||||
|
|
||||||
|
fd = open(m->path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
|
||||||
|
if (fd < 0)
|
||||||
|
log_debug_errno(errno, "Failed to open DM block device %s for syncing, ignoring: %m", m->path);
|
||||||
|
else {
|
||||||
|
(void) sync_with_progress(fd);
|
||||||
|
fd = safe_close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
|
fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -errno;
|
return log_debug_errno(errno, "Failed to open /dev/mapper/control: %m");
|
||||||
|
|
||||||
_cleanup_close_ int block_fd = open(m->path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
|
|
||||||
if (block_fd < 0)
|
|
||||||
log_debug_errno(errno, "Failed to open DM block device %s for syncing, ignoring: %m", m->path);
|
|
||||||
else
|
|
||||||
(void) sync_with_progress(block_fd);
|
|
||||||
|
|
||||||
return RET_NERRNO(ioctl(fd, DM_DEV_REMOVE, &(struct dm_ioctl) {
|
return RET_NERRNO(ioctl(fd, DM_DEV_REMOVE, &(struct dm_ioctl) {
|
||||||
.version = {
|
.version = {
|
||||||
|
|
|
@ -211,10 +211,8 @@ static int sync_making_progress(unsigned long long *prev_dirty) {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if (sscanf(line, "%*s %llu %*s", &ull) != 1) {
|
if (sscanf(line, "%*s %llu %*s", &ull) != 1)
|
||||||
log_warning_errno(errno_or_else(EIO), "Failed to parse /proc/meminfo field, ignoring: %m");
|
return log_warning_errno(errno_or_else(EIO), "Failed to parse /proc/meminfo field: %m");
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
val += ull;
|
val += ull;
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,7 @@ simple_tests += files(
|
||||||
'test-open-file.c',
|
'test-open-file.c',
|
||||||
'test-ordered-set.c',
|
'test-ordered-set.c',
|
||||||
'test-os-util.c',
|
'test-os-util.c',
|
||||||
|
'test-osc-context.c',
|
||||||
'test-parse-argument.c',
|
'test-parse-argument.c',
|
||||||
'test-parse-helpers.c',
|
'test-parse-helpers.c',
|
||||||
'test-path-lookup.c',
|
'test-path-lookup.c',
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include "hexdecoct.h"
|
||||||
|
#include "osc-context.h"
|
||||||
|
#include "tests.h"
|
||||||
|
|
||||||
|
#include "escape.h"
|
||||||
|
|
||||||
|
TEST(osc) {
|
||||||
|
_cleanup_free_ char *seq = NULL;
|
||||||
|
|
||||||
|
log_info("boot");
|
||||||
|
assert_se(osc_context_open_boot(&seq) >= 0);
|
||||||
|
hexdump(/* f = */ NULL, seq, SIZE_MAX);
|
||||||
|
seq = mfree(seq);
|
||||||
|
|
||||||
|
assert_se(osc_context_close(SD_ID128_ALLF, &seq) >= 0);
|
||||||
|
hexdump(/* f = */ NULL, seq, SIZE_MAX);
|
||||||
|
seq = mfree(seq);
|
||||||
|
|
||||||
|
log_info("container");
|
||||||
|
sd_id128_t id;
|
||||||
|
assert_se(osc_context_open_container("foobar", &seq, &id) >= 0);
|
||||||
|
hexdump(/* f = */ NULL, seq, SIZE_MAX);
|
||||||
|
seq = mfree(seq);
|
||||||
|
|
||||||
|
assert_se(osc_context_close(id, &seq) >= 0);
|
||||||
|
hexdump(/* f = */ NULL, seq, SIZE_MAX);
|
||||||
|
seq = mfree(seq);
|
||||||
|
|
||||||
|
log_info("vm");
|
||||||
|
assert_se(osc_context_open_vm("foobar", &seq, &id) >= 0);
|
||||||
|
hexdump(/* f = */ NULL, seq, SIZE_MAX);
|
||||||
|
seq = mfree(seq);
|
||||||
|
|
||||||
|
assert_se(osc_context_close(id, &seq) >= 0);
|
||||||
|
hexdump(/* f = */ NULL, seq, SIZE_MAX);
|
||||||
|
seq = mfree(seq);
|
||||||
|
|
||||||
|
printf("%s\n", xescape("Schöpfgefäß", NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int intro(void) {
|
||||||
|
log_show_color(true);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);
|
|
@ -994,6 +994,21 @@ TEST(pid_get_start_time) {
|
||||||
ASSERT_GE(start_time2, start_time);
|
ASSERT_GE(start_time2, start_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(getpidfdid_cached) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
log_info("pid=" PID_FMT, getpid_cached());
|
||||||
|
|
||||||
|
uint64_t id;
|
||||||
|
r = getpidfdid_cached(&id);
|
||||||
|
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
|
||||||
|
log_info("pidfdid not supported");
|
||||||
|
else {
|
||||||
|
assert(r >= 0);
|
||||||
|
log_info("pidfdid=%" PRIu64, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int intro(void) {
|
static int intro(void) {
|
||||||
log_show_color(true);
|
log_show_color(true);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
#include "mkdir.h"
|
#include "mkdir.h"
|
||||||
#include "netif-util.h"
|
#include "netif-util.h"
|
||||||
|
#include "osc-context.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
#include "parse-argument.h"
|
#include "parse-argument.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
|
@ -2189,8 +2190,15 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
||||||
/* Exit when the child exits */
|
/* Exit when the child exits */
|
||||||
(void) event_add_child_pidref(event, NULL, &child_pidref, WEXITED, on_child_exit, NULL);
|
(void) event_add_child_pidref(event, NULL, &child_pidref, WEXITED, on_child_exit, NULL);
|
||||||
|
|
||||||
|
_cleanup_(osc_context_closep) sd_id128_t osc_context_id = SD_ID128_NULL;
|
||||||
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
|
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
|
||||||
if (master >= 0) {
|
if (master >= 0) {
|
||||||
|
if (!terminal_is_dumb()) {
|
||||||
|
r = osc_context_open_vm(arg_machine, /* ret_seq= */ NULL, &osc_context_id);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r = pty_forward_new(event, master, ptyfwd_flags, &forward);
|
r = pty_forward_new(event, master, ptyfwd_flags, &forward);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to create PTY forwarder: %m");
|
return log_error_errno(r, "Failed to create PTY forwarder: %m");
|
||||||
|
|
|
@ -960,10 +960,13 @@ exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ {{ s/^.*=/
|
||||||
|
|
||||||
# wait until devices got created
|
# wait until devices got created
|
||||||
for _ in range(50):
|
for _ in range(50):
|
||||||
out = subprocess.check_output(['ip', 'a', 'show', 'dev', self.if_router])
|
if subprocess.run(['ip', 'link', 'show', 'dev', self.if_router],
|
||||||
if b'state UP' in out and b'scope global' in out:
|
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0:
|
||||||
break
|
break
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
else:
|
||||||
|
subprocess.call(['ip', 'link', 'show', 'dev', self.if_router])
|
||||||
|
self.fail('Timed out waiting for {ifr} created.'.format(ifr=self.if_router))
|
||||||
|
|
||||||
def shutdown_iface(self):
|
def shutdown_iface(self):
|
||||||
'''Remove test interface and stop DHCP server'''
|
'''Remove test interface and stop DHCP server'''
|
||||||
|
|
Loading…
Reference in New Issue