Compare commits
24 Commits
3fd910ba2d
...
b7142c64a1
Author | SHA1 | Date |
---|---|---|
Lennart Poettering | b7142c64a1 | |
gerblesh | bbec1c87d3 | |
Yu Watanabe | f29a07f3fc | |
Luca Boccassi | 0566bd9643 | |
Lennart Poettering | 7b4b3a8f7b | |
Winterhuman | 5bed97dd57 | |
Luca Boccassi | c4d7a13c06 | |
Abderrahim Kitouni | 0ae6f4843e | |
Yu Watanabe | 1ea1a79aa1 | |
Luca Boccassi | 7a9d0abe4d | |
Yu Watanabe | 6046cc3660 | |
Ivan Kruglov | 3aa3f130c1 | |
Ivan Kruglov | df18408ac6 | |
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) |
|
|
@ -684,6 +684,15 @@ fi</programlisting>
|
|||
<citerefentry><refentrytitle>file-hierarchy</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Notes</title>
|
||||
|
||||
<para>
|
||||
All example codes in this page are licensed under <literal>MIT No Attribution</literal>
|
||||
(SPDX-License-Identifier: MIT-0).
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para><simplelist type="inline">
|
||||
|
|
|
@ -128,7 +128,8 @@
|
|||
|
||||
<para>If <option>-keep-download=yes</option> is specified the image will be downloaded and stored in
|
||||
a read-only subvolume/directory in the image directory that is named after the specified URL and its
|
||||
HTTP etag. A writable snapshot is then taken from this subvolume, and named after the specified local
|
||||
HTTP etag (see <ulink url="https://en.wikipedia.org/wiki/HTTP_ETag">HTTP ETag</ulink> for more
|
||||
information). A writable snapshot is then taken from this subvolume, and named after the specified local
|
||||
name. This behavior ensures that creating multiple instances of the same URL is efficient, as
|
||||
multiple downloads are not necessary. In order to create only the read-only image, and avoid creating
|
||||
its writable snapshot, specify <literal>-</literal> as local name.</para>
|
||||
|
|
|
@ -28,7 +28,9 @@
|
|||
<title>Description</title>
|
||||
|
||||
<para><command>pam_systemd_loadkey</command> reads a NUL-separated password list from the kernel keyring,
|
||||
and sets the last password in the list as the PAM authtok.</para>
|
||||
and sets the last password in the list as the PAM authtok, which can be used by e.g.
|
||||
<citerefentry project='man-pages'><refentrytitle>pam_get_authtok</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
|
||||
</para>
|
||||
|
||||
<para>The password list is supposed to be stored in the "user" keyring of the root user,
|
||||
by an earlier call to
|
||||
|
|
|
@ -61,7 +61,10 @@
|
|||
<literal>systemd-run0</literal> PAM stack.</para>
|
||||
|
||||
<para>Note that <command>run0</command> is implemented as an alternative multi-call invocation of
|
||||
<citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
|
||||
<citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>. That is,
|
||||
<command>run0</command> is a symbolic link to <command>systemd-run</command> executable file, and it
|
||||
behaves as <command>run0</command> if it is invoked through the symbolic link, otherwise behaves as
|
||||
<command>systemd-run</command>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
|
|
@ -41,8 +41,10 @@
|
|||
<refsect1>
|
||||
<title>Kernel Command Line</title>
|
||||
|
||||
<para><filename>systemd-rfkill</filename> understands the
|
||||
following kernel command line parameter:</para>
|
||||
<para>
|
||||
<command>systemd-rfkill</command> understands the following kernel command line parameter. See also
|
||||
<citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
|
||||
</para>
|
||||
|
||||
<variablelist class='kernel-commandline-options'>
|
||||
<varlistentry>
|
||||
|
|
|
@ -302,7 +302,7 @@
|
|||
and running in an initrd equivalent to true, otherwise false. This implements a restricted subset of
|
||||
the per-unit setting of the same name, see
|
||||
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
details: currently, the <literal>full</literal> or <literal>struct</literal> values are not
|
||||
details: currently, the <literal>full</literal> or <literal>strict</literal> values are not
|
||||
supported.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
|
|
|
@ -394,9 +394,9 @@
|
|||
<listitem><para>SBAT metadata associated with the UKI or addon. SBAT policies are useful to revoke
|
||||
whole groups of UKIs or addons with a single, static policy update that does not take space in
|
||||
DBX/MOKX. If not specified manually, a default metadata entry consisting of
|
||||
<literal>uki,1,UKI,uki,1,https://uapi-group.org/specifications/specs/unified_kernel_image/</literal>
|
||||
<programlisting>uki,1,UKI,uki,1,https://uapi-group.org/specifications/specs/unified_kernel_image/</programlisting>
|
||||
for UKIs and
|
||||
<literal>uki-addon,1,UKI Addon,addon,1,https://www.freedesktop.org/software/systemd/man/latest/systemd-stub.html</literal>
|
||||
<programlisting>uki-addon,1,UKI Addon,addon,1,https://www.freedesktop.org/software/systemd/man/latest/systemd-stub.html</programlisting>
|
||||
for addons will be used, to ensure it is always possible to revoke them. For more information on
|
||||
SBAT see <ulink url="https://github.com/rhboot/shim/blob/main/SBAT.md">Shim documentation</ulink>.
|
||||
</para>
|
||||
|
|
|
@ -365,6 +365,8 @@ char* xescape_full(const char *s, const char *bad, size_t console_width, XEscape
|
|||
char *ans, *t, *prev, *prev2;
|
||||
const char *f;
|
||||
|
||||
assert(s);
|
||||
|
||||
/* 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
|
||||
* 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 < ' ' ||
|
||||
(!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)
|
||||
break;
|
||||
|
||||
|
|
|
@ -289,7 +289,8 @@ int write_string_file_full(
|
|||
const char *fn,
|
||||
const char *line,
|
||||
WriteStringFileFlags flags,
|
||||
const struct timespec *ts) {
|
||||
const struct timespec *ts,
|
||||
const char *label_fn) {
|
||||
|
||||
bool call_label_ops_post = false, made_file = false;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
@ -321,7 +322,8 @@ int write_string_file_full(
|
|||
mode_t mode = write_string_file_flags_to_mode(flags);
|
||||
|
||||
if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL|WRITE_STRING_FILE_CREATE)) {
|
||||
r = label_ops_pre(dir_fd, fn, mode);
|
||||
const char *lookup = label_fn ? label_fn : fn;
|
||||
r = label_ops_pre(dir_fd, lookup, mode);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
|
|
@ -51,12 +51,13 @@ int write_string_stream_full(FILE *f, const char *line, WriteStringFileFlags fla
|
|||
static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) {
|
||||
return write_string_stream_full(f, line, flags, /* ts= */ NULL);
|
||||
}
|
||||
int write_string_file_full(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts);
|
||||
|
||||
int write_string_file_full(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts, const char *label_fn);
|
||||
static inline int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
|
||||
return write_string_file_full(AT_FDCWD, fn, line, flags, /* ts= */ NULL);
|
||||
return write_string_file_full(AT_FDCWD, fn, line, flags, /* ts= */ NULL, /*label_fn=*/ NULL);
|
||||
}
|
||||
static inline int write_string_file_at(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags) {
|
||||
return write_string_file_full(dir_fd, fn, line, flags, /* ts= */ NULL);
|
||||
return write_string_file_full(dir_fd, fn, line, flags, /* ts= */ NULL, /*label_fn=*/ NULL);
|
||||
}
|
||||
int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4);
|
||||
|
||||
|
|
|
@ -866,6 +866,9 @@ void hexdump(FILE *f, const void *p, size_t s) {
|
|||
|
||||
assert(b || s == 0);
|
||||
|
||||
if (s == SIZE_MAX)
|
||||
s = strlen(p);
|
||||
|
||||
if (!f)
|
||||
f = stdout;
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/oom.h>
|
||||
#include <pthread.h>
|
||||
#include <spawn.h>
|
||||
|
@ -11,6 +12,9 @@
|
|||
#include <stdlib.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/personality.h>
|
||||
#if HAVE_PIDFD_OPEN
|
||||
#include <sys/pidfd.h>
|
||||
#endif
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
@ -40,6 +44,7 @@
|
|||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
#include "missing_magic.h"
|
||||
#include "missing_sched.h"
|
||||
#include "missing_syscall.h"
|
||||
#include "missing_threads.h"
|
||||
|
@ -2289,3 +2294,42 @@ _noreturn_ void report_errno_and_exit(int errno_fd, int error) {
|
|||
|
||||
_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);
|
||||
|
||||
_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;
|
||||
usec_t stamp_mono, stamp_real;
|
||||
pid_t pid, tid;
|
||||
uint64_t pidfdid;
|
||||
uint8_t auxval[16];
|
||||
} state = {
|
||||
/* 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));
|
||||
#endif
|
||||
|
||||
(void) getpidfdid_cached(&state.pidfdid);
|
||||
|
||||
while (n > 0) {
|
||||
struct sha256_ctx ctx;
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "efivars.h"
|
||||
#include "emergency-action.h"
|
||||
#include "env-util.h"
|
||||
#include "escape.h"
|
||||
#include "exit-status.h"
|
||||
#include "fd-util.h"
|
||||
#include "fdset.h"
|
||||
|
@ -57,6 +58,7 @@
|
|||
#include "ima-setup.h"
|
||||
#include "import-creds.h"
|
||||
#include "initrd-util.h"
|
||||
#include "io-util.h"
|
||||
#include "ipe-setup.h"
|
||||
#include "killall.h"
|
||||
#include "kmod-setup.h"
|
||||
|
@ -73,6 +75,7 @@
|
|||
#include "mount-setup.h"
|
||||
#include "mount-util.h"
|
||||
#include "os-util.h"
|
||||
#include "osc-context.h"
|
||||
#include "pager.h"
|
||||
#include "parse-argument.h"
|
||||
#include "parse-util.h"
|
||||
|
@ -2380,6 +2383,38 @@ static void log_execution_mode(bool *ret_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(
|
||||
bool skip_setup,
|
||||
bool first_boot,
|
||||
|
@ -2438,6 +2473,8 @@ static int initialize_runtime(
|
|||
|
||||
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
|
||||
* under RootDirectory=/RootImage= when we do a soft reboot. */
|
||||
r = setup_os_release(RUNTIME_SCOPE_SYSTEM);
|
||||
|
@ -3427,6 +3464,8 @@ finish:
|
|||
}
|
||||
#endif
|
||||
|
||||
(void) write_boot_or_shutdown_osc(/* boot= */ false);
|
||||
|
||||
if (r < 0)
|
||||
(void) sd_notifyf(/* unset_environment= */ false,
|
||||
"ERRNO=%i", -r);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "iovec-util.h"
|
||||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
#include "parse-util.h"
|
||||
|
@ -31,8 +32,7 @@ int decrypt_pkcs11_key(
|
|||
const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
const void *key_data, /* … or key_data and key_data_size (for literal keys) */
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data, /* … or literal keys via key_data */
|
||||
usec_t until,
|
||||
AskPasswordFlags askpw_flags,
|
||||
void **ret_decrypted_key,
|
||||
|
@ -47,15 +47,15 @@ int decrypt_pkcs11_key(
|
|||
|
||||
assert(friendly_name);
|
||||
assert(pkcs11_uri);
|
||||
assert(key_file || key_data);
|
||||
assert(key_file || iovec_is_set(key_data));
|
||||
assert(ret_decrypted_key);
|
||||
assert(ret_decrypted_key_size);
|
||||
|
||||
/* The functions called here log about all errors, except for EAGAIN which means "token not found right now" */
|
||||
|
||||
if (key_data) {
|
||||
data.encrypted_key = (void*) key_data;
|
||||
data.encrypted_key_size = key_data_size;
|
||||
if (iovec_is_set(key_data)) {
|
||||
data.encrypted_key = (void*) key_data->iov_base;
|
||||
data.encrypted_key_size = key_data->iov_len;
|
||||
|
||||
data.free_encrypted_key = false;
|
||||
} else {
|
||||
|
|
|
@ -16,8 +16,7 @@ int decrypt_pkcs11_key(
|
|||
const char *key_file,
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
const void *key_data,
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data,
|
||||
usec_t until,
|
||||
AskPasswordFlags askpw_flags,
|
||||
void **ret_decrypted_key,
|
||||
|
@ -39,8 +38,7 @@ static inline int decrypt_pkcs11_key(
|
|||
const char *key_file,
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
const void *key_data,
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data,
|
||||
usec_t until,
|
||||
AskPasswordFlags askpw_flags,
|
||||
void **ret_decrypted_key,
|
||||
|
|
|
@ -1471,8 +1471,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
|
|||
struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *key_file,
|
||||
const void *key_data,
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data,
|
||||
usec_t until,
|
||||
uint32_t flags,
|
||||
bool pass_volume_key) {
|
||||
|
@ -1489,7 +1488,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
|
|||
assert(name);
|
||||
assert(arg_fido2_device || arg_fido2_device_auto);
|
||||
|
||||
if (arg_fido2_cid && !key_file && !key_data)
|
||||
if (arg_fido2_cid && !key_file && !iovec_is_set(key_data))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"FIDO2 mode with manual parameters selected, but no keyfile specified, refusing.");
|
||||
|
||||
|
@ -1513,7 +1512,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
|
|||
arg_fido2_rp_id,
|
||||
arg_fido2_cid, arg_fido2_cid_size,
|
||||
key_file, arg_keyfile_size, arg_keyfile_offset,
|
||||
key_data, key_data_size,
|
||||
key_data,
|
||||
until,
|
||||
arg_fido2_manual_flags,
|
||||
"cryptsetup.fido2-pin",
|
||||
|
@ -1623,8 +1622,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||
struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *key_file,
|
||||
const void *key_data,
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data,
|
||||
usec_t until,
|
||||
uint32_t flags,
|
||||
bool pass_volume_key) {
|
||||
|
@ -1635,6 +1633,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||
_cleanup_(erase_and_freep) void *decrypted_key = NULL;
|
||||
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||
_cleanup_free_ void *discovered_key = NULL;
|
||||
struct iovec discovered_key_data = {};
|
||||
int keyslot = arg_key_slot, r;
|
||||
const char *uri = NULL;
|
||||
bool use_libcryptsetup_plugin = use_token_plugins();
|
||||
|
@ -1653,13 +1652,13 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||
return r;
|
||||
|
||||
uri = discovered_uri;
|
||||
key_data = discovered_key;
|
||||
key_data_size = discovered_key_size;
|
||||
discovered_key_data = IOVEC_MAKE(discovered_key, discovered_key_size);
|
||||
key_data = &discovered_key_data;
|
||||
}
|
||||
} else {
|
||||
uri = arg_pkcs11_uri;
|
||||
|
||||
if (!key_file && !key_data)
|
||||
if (!key_file && !iovec_is_set(key_data))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PKCS#11 mode selected but no key file specified, refusing.");
|
||||
}
|
||||
|
||||
|
@ -1682,7 +1681,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||
friendly,
|
||||
uri,
|
||||
key_file, arg_keyfile_size, arg_keyfile_offset,
|
||||
key_data, key_data_size,
|
||||
key_data,
|
||||
until,
|
||||
arg_ask_password_flags,
|
||||
&decrypted_key, &decrypted_key_size);
|
||||
|
@ -2231,9 +2230,9 @@ static int attach_luks_or_plain_or_bitlk(
|
|||
if (token_type == TOKEN_TPM2)
|
||||
return attach_luks_or_plain_or_bitlk_by_tpm2(cd, name, key_file, key_data, until, flags, pass_volume_key);
|
||||
if (token_type == TOKEN_FIDO2)
|
||||
return attach_luks_or_plain_or_bitlk_by_fido2(cd, name, key_file, key_data->iov_base, key_data->iov_len, until, flags, pass_volume_key);
|
||||
return attach_luks_or_plain_or_bitlk_by_fido2(cd, name, key_file, key_data, until, flags, pass_volume_key);
|
||||
if (token_type == TOKEN_PKCS11)
|
||||
return attach_luks_or_plain_or_bitlk_by_pkcs11(cd, name, key_file, key_data->iov_base, key_data->iov_len, until, flags, pass_volume_key);
|
||||
return attach_luks_or_plain_or_bitlk_by_pkcs11(cd, name, key_file, key_data, until, flags, pass_volume_key);
|
||||
if (key_data)
|
||||
return attach_luks_or_plain_or_bitlk_by_key_data(cd, name, key_data, flags, pass_volume_key);
|
||||
if (key_file)
|
||||
|
|
|
@ -1698,7 +1698,8 @@ _public_ int sd_varlink_get_events(sd_varlink *v) {
|
|||
ret |= EPOLLIN;
|
||||
|
||||
if (!v->write_disconnected &&
|
||||
v->output_buffer_size > 0)
|
||||
(v->output_queue ||
|
||||
v->output_buffer_size > 0))
|
||||
ret |= EPOLLOUT;
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "main-func.h"
|
||||
#include "mkdir.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "osc-context.h"
|
||||
#include "pager.h"
|
||||
#include "parse-argument.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);
|
||||
}
|
||||
|
||||
_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);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enable SIGINT/SITERM handling: %m");
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
#include "nsresource.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "os-util.h"
|
||||
#include "osc-context.h"
|
||||
#include "pager.h"
|
||||
#include "parse-argument.h"
|
||||
#include "parse-util.h"
|
||||
|
@ -5684,6 +5685,13 @@ static int run_container(
|
|||
(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) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
PTYForwardFlags flags = 0;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "fs-util.h"
|
||||
#include "hostname-util.h"
|
||||
#include "main-func.h"
|
||||
#include "osc-context.h"
|
||||
#include "parse-argument.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
|
@ -2041,6 +2042,7 @@ static int start_transient_service(sd_bus *bus) {
|
|||
return r;
|
||||
}
|
||||
|
||||
_cleanup_(osc_context_closep) sd_id128_t osc_context_id = SD_ID128_NULL;
|
||||
if (arg_wait || arg_stdio != ARG_STDIO_NONE) {
|
||||
_cleanup_(run_context_done) RunContext c = {
|
||||
.cpu_usage_nsec = NSEC_INFINITY,
|
||||
|
@ -2067,6 +2069,12 @@ static int start_transient_service(sd_bus *bus) {
|
|||
return log_oom();
|
||||
|
||||
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);
|
||||
|
||||
if (!arg_quiet)
|
||||
|
|
|
@ -24,8 +24,7 @@ int acquire_fido2_key(
|
|||
const char *key_file,
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
const void *key_data,
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data,
|
||||
usec_t until,
|
||||
Fido2EnrollFlags required,
|
||||
const char *askpw_credential,
|
||||
|
@ -45,10 +44,10 @@ int acquire_fido2_key(
|
|||
"Local verification is required to unlock this volume, but the 'headless' parameter was set.");
|
||||
|
||||
assert(cid);
|
||||
assert(key_file || key_data);
|
||||
assert(key_file || iovec_is_set(key_data));
|
||||
|
||||
if (key_data)
|
||||
salt = IOVEC_MAKE(key_data, key_data_size);
|
||||
if (iovec_is_set(key_data))
|
||||
salt = *key_data;
|
||||
else {
|
||||
if (key_file_size > 0)
|
||||
log_debug("Ignoring 'keyfile-size=' option for a FIDO2 salt file.");
|
||||
|
@ -252,7 +251,7 @@ int acquire_fido2_key_auto(
|
|||
/* key_file= */ NULL, /* salt is read from LUKS header instead of key_file */
|
||||
/* key_file_size= */ 0,
|
||||
/* key_file_offset= */ 0,
|
||||
salt, salt_size,
|
||||
&IOVEC_MAKE(salt, salt_size),
|
||||
until,
|
||||
required,
|
||||
"cryptsetup.fido2-pin",
|
||||
|
|
|
@ -20,8 +20,7 @@ int acquire_fido2_key(
|
|||
const char *key_file,
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
const void *key_data,
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data,
|
||||
usec_t until,
|
||||
Fido2EnrollFlags required,
|
||||
const char *askpw_credential,
|
||||
|
@ -52,8 +51,7 @@ static inline int acquire_fido2_key(
|
|||
const char *key_file,
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
const void *key_data,
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data,
|
||||
usec_t until,
|
||||
Fido2EnrollFlags required,
|
||||
const char *askpw_credential,
|
||||
|
|
|
@ -132,6 +132,7 @@ shared_sources = files(
|
|||
'open-file.c',
|
||||
'openssl-util.c',
|
||||
'output-mode.c',
|
||||
'osc-context.c',
|
||||
'pager.c',
|
||||
'parse-argument.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);
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <linux/loop.h>
|
||||
|
@ -45,6 +46,7 @@
|
|||
#include "process-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "sort-util.h"
|
||||
#include "selinux-util.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "terminal-util.h"
|
||||
|
@ -899,6 +901,7 @@ static int resolve_mutable_directory(
|
|||
_cleanup_free_ char *path = NULL, *resolved_path = NULL, *dir_name = NULL;
|
||||
const char *root = arg_root, *base = MUTABLE_EXTENSIONS_BASE_DIR;
|
||||
int r;
|
||||
_cleanup_close_ int atfd = -EBADF;
|
||||
|
||||
assert(hierarchy);
|
||||
assert(ret_resolved_mutable_directory);
|
||||
|
@ -943,6 +946,14 @@ static int resolve_mutable_directory(
|
|||
r = mkdir_p(path_in_root, 0700);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create a directory '%s': %m", path_in_root);
|
||||
|
||||
atfd = open(path_in_root, O_DIRECTORY|O_CLOEXEC);
|
||||
if (atfd < 0)
|
||||
return log_error_errno(errno, "Failed to open directory '%s': %m", path_in_root);
|
||||
|
||||
r = mac_selinux_fix_full(atfd, NULL, hierarchy, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", path_in_root);
|
||||
}
|
||||
|
||||
r = chase(path, root, CHASE_PREFIX_ROOT, &resolved_path, NULL);
|
||||
|
@ -1289,6 +1300,7 @@ static int mount_overlayfs_with_op(
|
|||
|
||||
int r;
|
||||
const char *top_layer = NULL;
|
||||
_cleanup_close_ int atfd = -EBADF;
|
||||
|
||||
assert(op);
|
||||
assert(overlay_path);
|
||||
|
@ -1301,10 +1313,28 @@ static int mount_overlayfs_with_op(
|
|||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to make directory '%s': %m", meta_path);
|
||||
|
||||
atfd = open(meta_path, O_DIRECTORY|O_CLOEXEC);
|
||||
if (atfd < 0)
|
||||
return log_error_errno(errno, "Failed to open directory '%s': %m", meta_path);
|
||||
|
||||
r = mac_selinux_fix_full(atfd, NULL, op->hierarchy, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", meta_path);
|
||||
|
||||
if (op->upper_dir && op->work_dir) {
|
||||
r = mkdir_p(op->work_dir, 0700);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to make directory '%s': %m", op->work_dir);
|
||||
_cleanup_close_ int dfd = -EBADF;
|
||||
|
||||
dfd = open(op->work_dir, O_DIRECTORY|O_CLOEXEC);
|
||||
if (dfd < 0)
|
||||
return log_error_errno(errno, "Failed to open directory '%s': %m", op->work_dir);
|
||||
|
||||
r = mac_selinux_fix_full(dfd, NULL, op->hierarchy, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", op->work_dir);
|
||||
|
||||
top_layer = op->upper_dir;
|
||||
} else {
|
||||
assert(!strv_isempty(op->lower_dirs));
|
||||
|
@ -1325,7 +1355,7 @@ static int mount_overlayfs_with_op(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int write_extensions_file(ImageClass image_class, char **extensions, const char *meta_path) {
|
||||
static int write_extensions_file(ImageClass image_class, char **extensions, const char *meta_path, const char *hierarchy) {
|
||||
_cleanup_free_ char *f = NULL, *buf = NULL;
|
||||
int r;
|
||||
|
||||
|
@ -1343,14 +1373,15 @@ static int write_extensions_file(ImageClass image_class, char **extensions, cons
|
|||
if (!buf)
|
||||
return log_oom();
|
||||
|
||||
r = write_string_file(f, buf, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755);
|
||||
const char *hierarchy_path = path_join(hierarchy, image_class_info[image_class].dot_directory_name, image_class_info[image_class].short_identifier_plural);
|
||||
r = write_string_file_full(AT_FDCWD,f, buf, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755|WRITE_STRING_FILE_LABEL, NULL, hierarchy_path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write extension meta file '%s': %m", f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_dev_file(ImageClass image_class, const char *meta_path, const char *overlay_path) {
|
||||
static int write_dev_file(ImageClass image_class, const char *meta_path, const char *overlay_path, const char *hierarchy) {
|
||||
_cleanup_free_ char *f = NULL;
|
||||
struct stat st;
|
||||
int r;
|
||||
|
@ -1372,14 +1403,15 @@ static int write_dev_file(ImageClass image_class, const char *meta_path, const c
|
|||
/* Modifying the underlying layers while the overlayfs is mounted is technically undefined, but at
|
||||
* least it won't crash or deadlock, as per the kernel docs about overlayfs:
|
||||
* https://www.kernel.org/doc/html/latest/filesystems/overlayfs.html#changes-to-underlying-filesystems */
|
||||
r = write_string_file(f, FORMAT_DEVNUM(st.st_dev), WRITE_STRING_FILE_CREATE);
|
||||
const char *hierarchy_path = path_join(hierarchy, image_class_info[image_class].dot_directory_name, image_class_info[image_class].short_identifier_plural);
|
||||
r = write_string_file_full(AT_FDCWD, f, FORMAT_DEVNUM(st.st_dev), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_LABEL, NULL, hierarchy_path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write '%s': %m", f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_work_dir_file(ImageClass image_class, const char *meta_path, const char *work_dir) {
|
||||
static int write_work_dir_file(ImageClass image_class, const char *meta_path, const char *work_dir, const char* hierarchy) {
|
||||
_cleanup_free_ char *escaped_work_dir_in_root = NULL, *f = NULL;
|
||||
char *work_dir_in_root = NULL;
|
||||
int r;
|
||||
|
@ -1406,7 +1438,8 @@ static int write_work_dir_file(ImageClass image_class, const char *meta_path, co
|
|||
escaped_work_dir_in_root = cescape(work_dir_in_root);
|
||||
if (!escaped_work_dir_in_root)
|
||||
return log_oom();
|
||||
r = write_string_file(f, escaped_work_dir_in_root, WRITE_STRING_FILE_CREATE);
|
||||
const char *hierarchy_path = path_join(hierarchy, image_class_info[image_class].dot_directory_name, "work_dir");
|
||||
r = write_string_file_full(AT_FDCWD, f, escaped_work_dir_in_root, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_LABEL, NULL, hierarchy_path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write '%s': %m", f);
|
||||
|
||||
|
@ -1418,8 +1451,10 @@ static int store_info_in_meta(
|
|||
char **extensions,
|
||||
const char *meta_path,
|
||||
const char *overlay_path,
|
||||
const char *work_dir) {
|
||||
|
||||
const char *work_dir,
|
||||
const char *hierarchy) {
|
||||
_cleanup_free_ char *f = NULL;
|
||||
_cleanup_close_ int atfd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(extensions);
|
||||
|
@ -1427,15 +1462,32 @@ static int store_info_in_meta(
|
|||
assert(overlay_path);
|
||||
/* work_dir may be NULL */
|
||||
|
||||
r = write_extensions_file(image_class, extensions, meta_path);
|
||||
f = path_join(meta_path, image_class_info[image_class].dot_directory_name);
|
||||
if (!f)
|
||||
return log_oom();
|
||||
|
||||
r = mkdir_p(f, 0755);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = write_dev_file(image_class, meta_path, overlay_path);
|
||||
atfd = open(f, O_DIRECTORY|O_CLOEXEC);
|
||||
if (atfd < 0)
|
||||
return log_error_errno(errno, "Failed to open directory '%s': %m", f);
|
||||
|
||||
r = mac_selinux_fix_full(atfd, NULL, hierarchy, 0);
|
||||
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", hierarchy);
|
||||
|
||||
r = write_extensions_file(image_class, extensions, meta_path, hierarchy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = write_work_dir_file(image_class, meta_path, work_dir);
|
||||
r = write_dev_file(image_class, meta_path, overlay_path, hierarchy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = write_work_dir_file(image_class, meta_path, work_dir, hierarchy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -1501,6 +1553,8 @@ static int merge_hierarchy(
|
|||
assert(overlay_path);
|
||||
assert(workspace_path);
|
||||
|
||||
mac_selinux_init();
|
||||
|
||||
r = determine_used_extensions(hierarchy, paths, &used_paths, &extensions_used);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -1528,7 +1582,7 @@ static int merge_hierarchy(
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = store_info_in_meta(image_class, extensions, meta_path, overlay_path, op->work_dir);
|
||||
r = store_info_in_meta(image_class, extensions, meta_path, overlay_path, op->work_dir, op->hierarchy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -1414,7 +1414,7 @@ static int verb_enable(int argc, char **argv, void *userdata) {
|
|||
"SetFeatureEnabled",
|
||||
&error,
|
||||
/* reply= */ NULL,
|
||||
"sbt",
|
||||
"sit",
|
||||
*feature,
|
||||
(int) enable,
|
||||
UINT64_C(0));
|
||||
|
|
|
@ -137,6 +137,7 @@ simple_tests += files(
|
|||
'test-open-file.c',
|
||||
'test-ordered-set.c',
|
||||
'test-os-util.c',
|
||||
'test-osc-context.c',
|
||||
'test-parse-argument.c',
|
||||
'test-parse-helpers.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);
|
||||
}
|
||||
|
||||
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) {
|
||||
log_show_color(true);
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -29,7 +29,7 @@ static int apply_timestamp(const char *path, struct timespec *ts) {
|
|||
timespec_load_nsec(ts)) < 0)
|
||||
return log_oom();
|
||||
|
||||
r = write_string_file_full(AT_FDCWD, path, message, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL, ts);
|
||||
r = write_string_file_full(AT_FDCWD, path, message, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL, ts, NULL);
|
||||
if (r == -EROFS)
|
||||
log_debug_errno(r, "Cannot create \"%s\", file system is read-only.", path);
|
||||
else if (r < 0)
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "main-func.h"
|
||||
#include "mkdir.h"
|
||||
#include "netif-util.h"
|
||||
#include "osc-context.h"
|
||||
#include "pager.h"
|
||||
#include "parse-argument.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 */
|
||||
(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;
|
||||
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);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create PTY forwarder: %m");
|
||||
|
|
|
@ -22,6 +22,11 @@ trap at_exit EXIT
|
|||
|
||||
systemctl service-log-level systemd-machined debug
|
||||
systemctl service-log-level systemd-importd debug
|
||||
# per request in https://github.com/systemd/systemd/pull/35117
|
||||
systemctl edit --runtime --stdin 'systemd-nspawn@.service' --drop-in=debug.conf <<EOF
|
||||
[Service]
|
||||
Environment=SYSTEMD_LOG_LEVEL=debug
|
||||
EOF
|
||||
|
||||
# Mount temporary directory over /var/lib/machines to not pollute the image
|
||||
mkdir -p /var/lib/machines
|
||||
|
@ -278,13 +283,13 @@ varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List
|
|||
# sending TRAP signal
|
||||
rm -f /var/lib/machines/long-running/trap
|
||||
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Kill '{"name":"long-running", "whom": "leader", "signal": 5}'
|
||||
timeout 30 bash -c "until test -e /var/lib/machines/long-running/trap; do sleep .5; done"
|
||||
timeout 120 bash -c "until test -e /var/lib/machines/long-running/trap; do sleep .5; done"
|
||||
|
||||
# test io.systemd.Machine.Terminate
|
||||
long_running_machine_start
|
||||
rm -f /var/lib/machines/long-running/terminate
|
||||
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Terminate '{"name":"long-running"}'
|
||||
timeout 10 bash -c "until test -e /var/lib/machines/long-running/terminate; do sleep .5; done"
|
||||
timeout 30 bash -c "until test -e /var/lib/machines/long-running/terminate; do sleep .5; done"
|
||||
timeout 30 bash -c "while varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{\"name\":\"long-running\"}'; do sleep 0.5; done"
|
||||
|
||||
# test io.systemd.Machine.Register
|
||||
|
@ -356,7 +361,7 @@ journalctl --sync
|
|||
machinectl terminate container-without-os-release
|
||||
machinectl terminate long-running
|
||||
# wait for the container being stopped, otherwise acquiring image metadata by io.systemd.MachineImage.List may fail in the below.
|
||||
timeout 10 bash -c "while machinectl status long-running &>/dev/null; do sleep .5; done"
|
||||
timeout 30 bash -c "while machinectl status long-running &>/dev/null; do sleep .5; done"
|
||||
systemctl kill --signal=KILL systemd-nspawn@long-running.service || :
|
||||
|
||||
(ip addr show lo | grep -q 192.168.1.100) || ip address add 192.168.1.100/24 dev lo
|
||||
|
|
Loading…
Reference in New Issue