Merge pull request #31739 from poettering/pid1-sd-notify-tweaks

pid1: send various notifications via sd_notify() reporting boot progress
This commit is contained in:
Lennart Poettering 2024-03-14 18:43:57 +01:00 committed by GitHub
commit f63c1ada25
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 393 additions and 120 deletions

View file

@ -8,7 +8,7 @@ SPDX-License-Identifier: LGPL-2.1-or-later
# The Container Interface
Also consult [Writing Virtual Machine or Container
Managers](https://www.freedesktop.org/wiki/Software/systemd/writing-vm-managers).
Managers](https://systemd.io/WRITING_VM_AND_CONTAINER_MANAGERS).
systemd has a number of interfaces for interacting with container managers,
when systemd is used inside of an OS container. If you work on a container
@ -121,7 +121,7 @@ manager, please consider supporting the following interfaces.
variable's name you may only specify ptys, and not other types of ttys. Also
you need to specify the pty itself, a symlink will not suffice. This is
implemented in
[systemd-getty-generator(8)](https://www.freedesktop.org/software/systemd/man/systemd-getty-generator.html).
[systemd-getty-generator(8)](https://www.freedesktop.org/software/systemd/man/latest/systemd-getty-generator.html).
Note that this variable should not include the pty that `/dev/console` maps
to if it maps to one (see below). Example: if the container receives
`container_ttys=pts/7 pts/8 pts/14` it will spawn three additional login
@ -131,7 +131,7 @@ manager, please consider supporting the following interfaces.
running the container manager, if this is considered desirable, please parse
the host's `/etc/os-release` and set a `$container_host_<key>=<VALUE>`
environment variable for the ID fields described by the [os-release
interface](https://www.freedesktop.org/software/systemd/man/os-release.html), eg:
interface](https://www.freedesktop.org/software/systemd/man/latest/os-release.html), eg:
`$container_host_id=debian`
`$container_host_build_id=2020-06-15`
`$container_host_variant_id=server`
@ -165,10 +165,15 @@ manager, please consider supporting the following interfaces.
issuing `journalctl -m`. The container machine ID can be determined from
`/etc/machine-id` in the container.
3. If the container manager wants to cleanly shutdown the container, it might
3. If the container manager wants to cleanly shut down the container, it might
be a good idea to send `SIGRTMIN+3` to its init process. systemd will then
do a clean shutdown. Note however, that since only systemd understands
`SIGRTMIN+3` like this, this might confuse other init systems.
`SIGRTMIN+3` like this, this might confuse other init systems. A container
manager may implement the `$NOTIFY_SOCKET` protocol mentioned below in which
case it will receive a notification message `X_SYSTEMD_SIGNALS_LEVEL=2` that
indicates if and when these additional signal handlers are installed. If
these signals are sent to the container's PID 1 before this notification
message is sent they might not be handled correctly yet.
4. To support [Socket Activated
Containers](https://0pointer.de/blog/projects/socket-activated-containers.html)
@ -190,12 +195,14 @@ manager, please consider supporting the following interfaces.
unit they created for their container. That's private property of systemd,
and no other code should modify it.
6. systemd running inside the container can report when boot-up is complete
using the usual `sd_notify()` protocol that is also used when a service
wants to tell the service manager about readiness. A container manager can
set the `$NOTIFY_SOCKET` environment variable to a suitable socket path to
make use of this functionality. (Also see information about
`/run/host/notify` below.)
6. systemd running inside the container can report when boot-up is complete,
boot progress and functionality as well as various other bits of system
information using the `sd_notify()` protocol that is also used when a
service wants to tell the service manager about readiness. A container
manager can set the `$NOTIFY_SOCKET` environment variable to a suitable
socket path to make use of this functionality. (Also see information about
`/run/host/notify` below, as well as the Readiness Protocol section on
[systemd(1)](https://www.freedesktop.org/software/systemd/man/latest/systemd.html)
## Networking

54
docs/VM_INTERFACE.md Normal file
View file

@ -0,0 +1,54 @@
---
title: VM Interface
category: Interfaces
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# The VM Interface
Also consult [Writing Virtual Machine or Container
Managers](https://systemd.io/WRITING_VM_AND_CONTAINER_MANAGERS).
systemd has a number of interfaces for interacting with virtual machine
managers, when systemd is used inside of a VM. If you work on a VM manager,
please consider supporting the following interfaces.
1. systemd supports passing immutable binary data blobs with limited size and
restricted access to services via the `ImportCredential=`, `LoadCredential=`
and `SetCredential=` settings. These credentials may be passed into a system
via SMBIOS Type 11 vendor strings, see
[systemd(1)](https://www.freedesktop.org/software/systemd/man/latest/systemd.html)
for details. This concept may be used to flexibily configure various facets
ot the guest system. See
[systemd.system-credentials(7)](https://www.freedesktop.org/software/systemd/man/latest/systemd.system-credentials.html)
for a list of system credentials implemented by various systemd components.
2. Readiness, information about various system properties and functionality, as
well as progress of boot may be reported by systemd to a machine manager via
the `sd_notify()` protocol via `AF_VSOCK` sockets. The address of this
socket may be configured via the `vmm.notify_socket` system credential. See
[systemd(1)](https://www.freedesktop.org/software/systemd/man/latest/systemd.html).
3. The
[systemd-ssh-generator(8)](https://www.freedesktop.org/software/systemd/man/latest/systemd-ssh-generator.html)
functionality will automatically bind SSH login functionality to `AF_VSOCK`
port 22, if the system runs in a VM.
4. If not initialized yet the system's
[machine-id(5)](https://www.freedesktop.org/software/systemd/man/latest/machine-id.html)
is automatically set to the SMBIOS product UUID if available and invocation
in an VM environment is detected.
5. The
[`systemd-boot(7)`](https://www.freedesktop.org/software/systemd/man/latest/systemd-boot.html)
and
[`systemd-stub(7)`](https://www.freedesktop.org/software/systemd/man/latest/systemd-stub.html)
components support two SMBIOS Type 11 vendor strings that may be used to
extend the kernel command line of booted Linux environments:
`io.systemd.stub.kernel-cmdline-extra=` and
`io.systemd.boot.kernel-cmdline-extra=`.
Also see
[smbios-type-11(7)](https://www.freedesktop.org/software/systemd/man/latest/smbios-type-11.html)
for a list of supported SMBIOS Type 11 vendor strings.

View file

@ -5,25 +5,50 @@ layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# Writing VM and Container Managers
_Or: How to hook up your favorite VM or container manager with systemd_
Nomenclature: a _Virtual Machine_ shall refer to a system running on virtualized hardware consisting of a full OS with its own kernel. A _Container_ shall refer to a system running on the same shared kernel of the host, but running a mostly complete OS with its own init system. Both kinds of virtualized systems shall collectively be called "machines".
Nomenclature: a _Virtual Machine_ shall refer to a system running on
virtualized hardware consisting of a full OS with its own kernel. A _Container_
shall refer to a system running on the same shared kernel of the host, but
running a mostly complete OS with its own init system. Both kinds of
virtualized systems shall collectively be called "machines".
systemd provides a number of integration points with virtual machine and container managers, such as libvirt, LXC or systemd-nspawn. On one hand there are integration points of the VM/container manager towards the host OS it is running on, and on the other there integration points for container managers towards the guest OS it is managing.
systemd provides a number of integration points with virtual machine and
container managers, such as libvirt, LXC or systemd-nspawn. On one hand there
are integration points of the VM/container manager towards the host OS it is
running on, and on the other there integration points for container managers
towards the guest OS it is managing.
Note that this document does not cover lightweight containers for the purpose of application sandboxes, i.e. containers that do _not_ run a init system of their own.
Note that this document does not cover lightweight containers for the purpose
of application sandboxes, i.e. containers that do _not_ run a init system of
their own.
## Host OS Integration
All virtual machines and containers should be registered with the [machined](http://www.freedesktop.org/wiki/Software/systemd/machined) mini service that is part of systemd. This provides integration into the core OS at various points. For example, tools like ps, cgls, gnome-system-manager use this registration information to show machine information for running processes, as each of the VM's/container's processes can reliably attributed to a registered machine. The various systemd tools (like systemctl, journalctl, loginctl, systemd-run, ...) all support a -M switch that operates on machines registered with machined. "machinectl" may be used to execute operations on any such machine. When a machine is registered via machined its processes will automatically be placed in a systemd scope unit (that is located in the machines.slice slice) and thus appear in "systemctl" and similar commands. The scope unit name is based on the machine meta information passed to machined at registration.
All virtual machines and containers should be registered with the
[systemd-machined(8)](https://www.freedesktop.org/software/systemd/man/latest/systemd-machined.service.html)
mini service that is part of systemd. This provides integration into the core
OS at various points. For example, tools like ps, cgls, gnome-system-manager
use this registration information to show machine information for running
processes, as each of the VM's/container's processes can reliably attributed to
a registered machine. The various systemd tools (like systemctl, journalctl,
loginctl, systemd-run, ...) all support a -M switch that operates on machines
registered with machined. "machinectl" may be used to execute operations on any
such machine. When a machine is registered via machined its processes will
automatically be placed in a systemd scope unit (that is located in the
machines.slice slice) and thus appear in "systemctl" and similar commands. The
scope unit name is based on the machine meta information passed to machined at
registration.
For more details on the APIs provided by machine consult [the bus API interface documentation](http://www.freedesktop.org/wiki/Software/systemd/machined).
For more details on the APIs provided by machine consult [the bus API interface
documentation](https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.machine1.html).
## Guest OS Integration
As container virtualization is much less comprehensive, and the guest is less isolated from the host, there are a number of interfaces defined how the container manager can set up the environment for systemd running inside a container. These Interfaces are documented in [Container Interface of systemd](http://www.freedesktop.org/wiki/Software/systemd/ContainerInterface).
VM virtualization is more comprehensive and fewer integration APIs are available. In fact there's only one: a VM manager may initialize the SMBIOS DMI field "Product UUUID" to a UUID uniquely identifying this virtual machine instance. This is read in the guest via /sys/class/dmi/id/product_uuid, and used as configuration source for /etc/machine-id if in the guest, if that file is not initialized yet. Note that this is currently only supported for kvm hosts, but may be extended to other managers as well.
A number of interfaces are defined that permit a machine or container manager
to set provide integration points with the payload/guest system. These
interfaces are documented in [Container Interface of
systemd](https://systemd.io/CONTAINER_INTERFACE) and [VM Interface of
systemd](https://systemd.io/VM_INTERFACE).

View file

@ -446,9 +446,14 @@
</variablelist>
<para>The notification messages sent by services are interpreted by the service manager. Unknown
assignments may be logged, but are otherwise ignored. Thus, it is not useful to send assignments which
are not in this list. The service manager also sends some messages to <emphasis>its</emphasis>
notification socket, which are then consumed by the machine or container manager.</para>
assignments are ignored. Thus, it is is safe (but often without effect) to send assignments which are not
in this list. The protocol is extensible, but care should be taken to ensure private extensions are
recognizable as such. Specifically, it is recommend to prefix them with <literal>X_</literal> followed by
some namespace identifier. The service manager also sends some messages to <emphasis>its</emphasis>
notification socket, which may then consumed by a supervising machine or container manager further up the
stack. The service manager sends a number of extension fields, for example
<varname>X_SYSTEMD_UNIT_ACTIVE=</varname>, for details see
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>

View file

@ -83,6 +83,7 @@
<filename>sockets.target</filename>,
<filename>soft-reboot.target</filename>,
<filename>sound.target</filename>,
<filename>ssh-access.target</filename>,
<filename>storage-target-mode.target</filename>,
<filename>suspend.target</filename>,
<filename>swap.target</filename>,
@ -1172,6 +1173,19 @@
the <literal>$portmap</literal> facility.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><filename>ssh-access.target</filename></term>
<listitem>
<para>Service and socket units that provide remote SSH secure shell access to the local system
should pull in this unit and order themselves before this unit. It's supposed to act as a
milestone indicating if and when SSH access into the system is available. It should only become
active when an SSH port is bound for remote clients (i.e. if SSH is used as a local privilege
escalation mechanism, it should <emphasis>not</emphasis> involve this target unit), regardless of
the protocol choices, i.e. regardless if IPv4, IPv6 or <constant>AF_VSOCK</constant> is
used.</para>
<xi:include href="version-info.xml" xpointer="v256"/>
</listitem>
</varlistentry>
<varlistentry>
<term><filename>time-set.target</filename></term>
<listitem>

View file

@ -372,6 +372,14 @@
<refsect1>
<title>Signals</title>
<para>The service listens to various UNIX process signals that can be used to request various actions
asynchronously. The signal handling is enabled very early during boot, before any further processes are
invoked. However, a supervising container manager or similar that intends to request these operations via
this mechanism must take into consideration that this functionality is not available during the earliest
initialization phase. An <function>sd_notify()</function> notification message carrying the
<varname>X_SYSTEMD_SIGNALS_LEVEL=2</varname> field is emitted once the signal handlers are enabled, see
below. This may be used to schedule submission of these signals correctly.</para>
<variablelist>
<varlistentry>
<term><constant>SIGTERM</constant></term>
@ -769,10 +777,11 @@
<varlistentry>
<term><varname>$NOTIFY_SOCKET</varname></term>
<listitem><para>Set by systemd for supervised processes for
status and start-up completion notification. See
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for more information.</para></listitem>
<listitem><para>Set by service manager for its services for status and readiness notifications. Also
consumed by service manager for notifying supervising container managers or service managers up the
stack about its own progress. See
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> and the
relevant section below for more information.</para></listitem>
</varlistentry>
</variablelist>
@ -1109,7 +1118,7 @@
</refsect1>
<refsect1>
<title>System credentials</title>
<title>System Credentials</title>
<para>During initialization the service manager will import credentials from various sources into the
system's set of credentials, which can then be propagated into services and consumed by
@ -1151,14 +1160,16 @@
<term><varname>vmm.notify_socket</varname></term>
<listitem>
<para>Contains a <constant>AF_VSOCK</constant> or <constant>AF_UNIX</constant> address where to
send a <constant>READY=1</constant> notification datagram when the system has finished booting. See
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> for
more information. Note that in case the hypervisor does not support <constant>SOCK_DGRAM</constant>
over <constant>AF_VSOCK</constant>, <constant>SOCK_SEQPACKET</constant> will be tried instead. The
credential payload for <constant>AF_VSOCK</constant> should be in the form
send a <constant>READY=1</constant> notification message when the service manager has completed
booting. See
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> and
the next section for more information. Note that in case the hypervisor does not support
<constant>SOCK_DGRAM</constant> over <constant>AF_VSOCK</constant>,
<constant>SOCK_SEQPACKET</constant> will be tried instead. The credential payload for
<constant>AF_VSOCK</constant> should be a string in the form
<literal>vsock:CID:PORT</literal>.</para>
<para>This feature is useful for hypervisors/VMMs or other processes on the host to receive a
<para>This feature is useful for machine managers or other processes on the host to receive a
notification via VSOCK when a virtual machine has finished booting.</para>
<xi:include href="version-info.xml" xpointer="v254"/>
@ -1177,6 +1188,77 @@
</listitem>
</varlistentry>
</variablelist>
<para>For a list of system credentials various other components of systemd consume, see
<citerefentry><refentrytitle>systemd.system-credentials</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
<title>Readiness Protocol</title>
<para>The service manager implements a readiness notification protocol both between the manager and its
services (i.e. down the stack), and between the manager and a potential supervisor further up the stack
(the latter could be a machine or container manager, or in case of a per-user service manager the system
service manager instance). The basic protocol (and the suggested API for it) is described in
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
<para>The notification socket the service manager (including PID 1) uses for reporting readiness to its
own supervisor is set via the usual <varname>$NOTIFY_SOCKET</varname> environment variable (see
above). Since this is directly settable only for container managers and for the per-user instance of the
service manager, an additional mechanism to configure this is available, in particular intended for use
in VM environments: the <varname>vmm.notify_socket</varname> system credential (see above) may be set to
a suitable socket (typically an <constant>AF_VSOCK</constant> one) via SMBIOS Type 11 vendor strings. For
details see above.</para>
<para>The notification protocol from the service manager up the stack towards a supervisor supports a
number of extension fields that allow a supervisor to learn about specific properties of the system and
track its boot progress. Specifically the following fields are sent:</para>
<itemizedlist>
<listitem><para>An <varname>X_SYSTEMD_HOSTNAME=…</varname> message will be sent out once the initial
hostname for the system has been determined. Note that during later runtime the hostname might be
changed again programmatically, and (currently) no further notifications are sent out in that case.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
<listitem><para>An <varname>X_SYSTEMD_MACHINE_ID=…</varname> message will be sent out once the machine
ID of the system has been determined. See
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
<listitem><para>An <varname>X_SYSTEMD_SIGNALS_LEVEL=…</varname> message will be sent out once the
service manager installed the various UNIX process signal handlers described above. The field's value
is an unsigned integer formatted as decimal string, and indicates the supported UNIX process signal
feature level of the service manager. Currently, only a single feature level is defined:</para>
<itemizedlist>
<listitem><para><varname>X_SYSTEMD_SIGNALS_LEVEL=2</varname> covers the various UNIX process signals
documented above which are a superset of those supported by the historical SysV init
system.</para></listitem>
</itemizedlist>
<para>Signals sent to PID 1 before this message is sent might not be handled correctly yet. A consumer
of these messages should parse the value as an unsigned integer indication the level of support. For
now only the mentioned level 2 is defined, but later on additional levels might be defined with higher
integers, that will implement a superset of the currently defined behaviour.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
<listitem><para><varname>X_SYSTEMD_UNIT_ACTIVE=…</varname> and
<varname>X_SYSTEMD_UNIT_INACTIVE=…</varname> messages will be sent out for each target unit as it
becomes active or stops being active. This is useful to track boot progress and functionality. For
example, once the <filename>ssh-access.target</filename> unit is reported started SSH access is
typically available, see
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
details.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
</itemizedlist>
<para>Note that these extension fields are sent in addition to the regular <literal>READY=1</literal> and
<literal>RELOADING=1</literal> notifications.</para>
</refsect1>
<refsect1>

View file

@ -3282,7 +3282,8 @@ finish:
#endif
if (r < 0)
(void) sd_notifyf(0, "ERRNO=%i", -r);
(void) sd_notifyf(/* unset_environment= */ false,
"ERRNO=%i", -r);
/* Try to invoke the shutdown binary unless we already failed.
* If we failed above, we want to freeze after finishing cleanup. */
@ -3295,7 +3296,8 @@ finish:
/* This is primarily useful when running systemd in a VM, as it provides the user running the VM with
* a mechanism to pick up systemd's exit status in the VM. */
(void) sd_notifyf(0, "EXIT_STATUS=%i", retval);
(void) sd_notifyf(/* unset_environment= */ false,
"EXIT_STATUS=%i", retval);
watchdog_free_device();
arg_watchdog_device = mfree(arg_watchdog_device);

View file

@ -264,12 +264,11 @@ static void manager_print_jobs_in_progress(Manager *m) {
strempty(status_text));
}
sd_notifyf(false,
"STATUS=%sUser job %s/%s running (%s / %s)...",
job_of_n,
ident,
job_type_to_string(j->type),
time, limit);
(void) sd_notifyf(/* unset_environment= */ false,
"STATUS=%sUser job %s/%s running (%s / %s)...",
job_of_n,
ident, job_type_to_string(j->type),
time, limit);
m->status_ready = false;
}
@ -483,21 +482,19 @@ static int enable_special_signals(Manager *m) {
if (MANAGER_IS_TEST_RUN(m))
return 0;
/* Enable that we get SIGINT on control-alt-del. In containers
* this will fail with EPERM (older) or EINVAL (newer), so
* ignore that. */
/* Enable that we get SIGINT on control-alt-del. In containers this will fail with EPERM (older) or
* EINVAL (newer), so ignore that. */
if (reboot(RB_DISABLE_CAD) < 0 && !IN_SET(errno, EPERM, EINVAL))
log_warning_errno(errno, "Failed to enable ctrl-alt-del handling: %m");
log_warning_errno(errno, "Failed to enable ctrl-alt-del handling, ignoring: %m");
fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
if (fd < 0) {
/* Support systems without virtual console */
if (fd != -ENOENT)
log_warning_errno(errno, "Failed to open /dev/tty0: %m");
} else {
if (fd < 0)
/* Support systems without virtual console (ENOENT) gracefully */
log_full_errno(fd == -ENOENT ? LOG_DEBUG : LOG_WARNING, fd, "Failed to open /dev/tty0, ignoring: %m");
else {
/* Enable that we get SIGWINCH on kbrequest */
if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
log_warning_errno(errno, "Failed to enable kbrequest handling: %m");
log_warning_errno(errno, "Failed to enable kbrequest handling, ignoring: %m");
}
return 0;
@ -597,6 +594,17 @@ static int manager_setup_signals(Manager *m) {
if (r < 0)
return r;
/* Report to supervisor that we now process the above signals. We report this as level "2", to
* indicate that we support more than sysvinit's signals (of course, sysvinit never sent this
* message, but conceptually it makes sense to consider level "1" to be equivalent to sysvinit's
* signal handling). Also, by setting this to "2" people looking for this hopefully won't
* misunderstand this as a boolean concept. Signal level 2 shall refer to the signals PID 1
* understands at the time of release of systemd v256, i.e. including basic SIGRTMIN+18 handling for
* memory pressure and stuff. When more signals are hooked up (or more SIGRTMIN+18 multiplex
* operations added, this level should be increased). */
(void) sd_notify(/* unset_environment= */ false,
"X_SYSTEMD_SIGNALS_LEVEL=2");
if (MANAGER_IS_SYSTEM(m))
return enable_special_signals(m);
@ -2869,8 +2877,8 @@ static void manager_start_special(Manager *m, const char *name, JobMode mode) {
log_info("Activating special unit %s...", s);
sd_notifyf(false,
"STATUS=Activating special unit %s...", s);
(void) sd_notifyf(/* unset_environment= */ false,
"STATUS=Activating special unit %s...", s);
m->status_ready = false;
}
@ -3362,18 +3370,20 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
const char *msg;
int audit_fd, r;
assert(m);
assert(u);
if (!MANAGER_IS_SYSTEM(m))
return;
/* Don't generate audit events if the service was already started and we're just deserializing */
if (MANAGER_IS_RELOADING(m))
return;
audit_fd = get_audit_fd();
if (audit_fd < 0)
return;
/* Don't generate audit events if the service was already
* started and we're just deserializing */
if (MANAGER_IS_RELOADING(m))
return;
r = unit_name_to_prefix_and_instance(u->id, &p);
if (r < 0) {
log_warning_errno(r, "Failed to extract prefix and instance of unit name, ignoring: %m");
@ -3390,21 +3400,22 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
log_warning_errno(errno, "Failed to send audit message, ignoring: %m");
}
#endif
}
void manager_send_unit_plymouth(Manager *m, Unit *u) {
_cleanup_free_ char *message = NULL;
int c, r;
/* Don't generate plymouth events if the service was already
* started and we're just deserializing */
if (MANAGER_IS_RELOADING(m))
return;
assert(m);
assert(u);
if (!MANAGER_IS_SYSTEM(m))
return;
/* Don't generate plymouth events if the service was already started and we're just deserializing */
if (MANAGER_IS_RELOADING(m))
return;
if (detect_container() > 0)
return;
@ -3422,6 +3433,27 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
"Failed to communicate with plymouth: %m");
}
void manager_send_unit_supervisor(Manager *m, Unit *u, bool active) {
assert(m);
assert(u);
/* Notify a "supervisor" process about our progress, i.e. a container manager, hypervisor, or
* surrounding service manager. */
if (MANAGER_IS_RELOADING(m))
return;
if (!UNIT_VTABLE(u)->notify_supervisor)
return;
if (in_initrd()) /* Only send these once we left the initrd */
return;
(void) sd_notifyf(/* unset_environment= */ false,
active ? "X_SYSTEMD_UNIT_ACTIVE=%s" : "X_SYSTEMD_UNIT_INACTIVE=%s",
u->id);
}
usec_t manager_get_watchdog(Manager *m, WatchdogType t) {
assert(m);
@ -3731,7 +3763,7 @@ static void manager_notify_finished(Manager *m) {
log_taint_string(m);
}
static void user_manager_send_ready(Manager *m) {
static void manager_send_ready_user_scope(Manager *m) {
int r;
assert(m);
@ -3740,7 +3772,7 @@ static void user_manager_send_ready(Manager *m) {
if (!MANAGER_IS_USER(m) || m->ready_sent)
return;
r = sd_notify(false,
r = sd_notify(/* unset_environment= */ false,
"READY=1\n"
"STATUS=Reached " SPECIAL_BASIC_TARGET ".");
if (r < 0)
@ -3750,14 +3782,19 @@ static void user_manager_send_ready(Manager *m) {
m->status_ready = false;
}
static void manager_send_ready(Manager *m) {
static void manager_send_ready_system_scope(Manager *m) {
int r;
if (m->ready_sent && m->status_ready)
/* Skip the notification if nothing changed. */
assert(m);
if (!MANAGER_IS_SYSTEM(m))
return;
r = sd_notify(false,
/* Skip the notification if nothing changed. */
if (m->ready_sent && m->status_ready)
return;
r = sd_notify(/* unset_environment= */ false,
"READY=1\n"
"STATUS=Ready.");
if (r < 0)
@ -3781,7 +3818,7 @@ static void manager_check_basic_target(Manager *m) {
return;
/* For user managers, send out READY=1 as soon as we reach basic.target */
user_manager_send_ready(m);
manager_send_ready_user_scope(m);
/* Log the taint string as soon as we reach basic.target */
log_taint_string(m);
@ -3812,7 +3849,7 @@ void manager_check_finished(Manager *m) {
if (hashmap_buckets(m->jobs) > hashmap_size(m->units) / 10)
m->jobs = hashmap_free(m->jobs);
manager_send_ready(m);
manager_send_ready_system_scope(m);
/* Notify Type=idle units that we are done now */
manager_close_idle_pipe(m);
@ -3842,7 +3879,7 @@ void manager_send_reloading(Manager *m) {
assert(m);
/* Let whoever invoked us know that we are now reloading */
(void) sd_notifyf(/* unset= */ false,
(void) sd_notifyf(/* unset_environment= */ false,
"RELOADING=1\n"
"MONOTONIC_USEC=" USEC_FMT "\n", now(CLOCK_MONOTONIC));

View file

@ -575,6 +575,7 @@ void manager_reset_failed(Manager *m);
void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success);
void manager_send_unit_plymouth(Manager *m, Unit *u);
void manager_send_unit_supervisor(Manager *m, Unit *u, bool active);
bool manager_unit_inactive_or_pending(Manager *m, const char *name);

View file

@ -213,4 +213,6 @@ const UnitVTable target_vtable = {
[JOB_DONE] = "Stopped target %s.",
},
},
.notify_supervisor = true,
};

View file

@ -2678,12 +2678,14 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
unit_emit_audit_start(u);
manager_send_unit_plymouth(m, u);
manager_send_unit_supervisor(m, u, /* active= */ true);
}
if (UNIT_IS_INACTIVE_OR_FAILED(ns) && !UNIT_IS_INACTIVE_OR_FAILED(os)) {
/* This unit just stopped/failed. */
unit_emit_audit_stop(u, ns);
manager_send_unit_supervisor(m, u, /* active= */ false);
unit_log_resources(u);
}

View file

@ -731,6 +731,9 @@ typedef struct UnitVTable {
/* If true, we'll notify plymouth about this unit */
bool notify_plymouth;
/* If true, we'll notify a surrounding VMM/container manager about this unit becoming available */
bool notify_supervisor;
/* The audit events to generate on start + stop (or 0 if none shall be generated) */
int audit_start_message_type;
int audit_stop_message_type;

View file

@ -4408,6 +4408,17 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
if (!tags)
return log_oom();
if (DEBUG_LOGGING) {
_cleanup_free_ char *joined = strv_join(tags, " ");
if (joined) {
_cleanup_free_ char *j = cescape(joined);
free_and_replace(joined, j);
}
log_debug("Got sd_notify() message: %s", strnull(joined));
}
if (strv_contains(tags, "READY=1")) {
r = sd_notify(false, "READY=1\n");
if (r < 0)

View file

@ -6,6 +6,8 @@
#include <sys/utsname.h>
#include <unistd.h>
#include "sd-daemon.h"
#include "alloc-util.h"
#include "creds-util.h"
#include "fd-util.h"
@ -13,6 +15,7 @@
#include "fs-util.h"
#include "hostname-setup.h"
#include "hostname-util.h"
#include "initrd-util.h"
#include "log.h"
#include "macro.h"
#include "proc-cmdline.h"
@ -24,7 +27,8 @@ static int sethostname_idempotent_full(const char *s, bool really) {
assert(s);
assert_se(uname(&u) >= 0);
if (uname(&u) < 0)
return -errno;
if (streq_ptr(s, u.nodename))
return 0;
@ -41,34 +45,33 @@ int sethostname_idempotent(const char *s) {
}
int shorten_overlong(const char *s, char **ret) {
char *h, *p;
_cleanup_free_ char *h = NULL;
/* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
* whatever comes earlier. */
assert(s);
assert(ret);
h = strdup(s);
if (!h)
return -ENOMEM;
if (hostname_is_valid(h, 0)) {
*ret = h;
*ret = TAKE_PTR(h);
return 0;
}
p = strchr(h, '.');
char *p = strchr(h, '.');
if (p)
*p = 0;
strshorten(h, HOST_NAME_MAX);
if (!hostname_is_valid(h, 0)) {
free(h);
if (!hostname_is_valid(h, /* flags= */ 0))
return -EDOM;
}
*ret = h;
*ret = TAKE_PTR(h);
return 1;
}
@ -147,74 +150,64 @@ void hostname_update_source_hint(const char *hostname, HostnameSource source) {
r = write_string_file("/run/systemd/default-hostname", hostname,
WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_ATOMIC);
if (r < 0)
log_warning_errno(r, "Failed to create \"/run/systemd/default-hostname\": %m");
log_warning_errno(r, "Failed to create \"/run/systemd/default-hostname\", ignoring: %m");
} else
unlink_or_warn("/run/systemd/default-hostname");
}
int hostname_setup(bool really) {
_cleanup_free_ char *b = NULL;
const char *hn = NULL;
_cleanup_free_ char *hn = NULL;
HostnameSource source;
bool enoent = false;
int r;
r = proc_cmdline_get_key("systemd.hostname", 0, &b);
r = proc_cmdline_get_key("systemd.hostname", 0, &hn);
if (r < 0)
log_warning_errno(r, "Failed to retrieve system hostname from kernel command line, ignoring: %m");
else if (r > 0) {
if (hostname_is_valid(b, VALID_HOSTNAME_TRAILING_DOT)) {
hn = b;
if (hostname_is_valid(hn, VALID_HOSTNAME_TRAILING_DOT))
source = HOSTNAME_TRANSIENT;
} else {
log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", b);
b = mfree(b);
else {
log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", hn);
hn = mfree(hn);
}
}
if (!hn) {
r = read_etc_hostname(NULL, &b);
if (r < 0) {
if (r == -ENOENT)
enoent = true;
else
log_warning_errno(r, "Failed to read configured hostname: %m");
} else {
hn = b;
r = read_etc_hostname(NULL, &hn);
if (r == -ENOENT)
enoent = true;
else if (r < 0)
log_warning_errno(r, "Failed to read configured hostname, ignoring: %m");
else
source = HOSTNAME_STATIC;
}
}
if (!hn) {
r = acquire_hostname_from_credential(&b);
if (r >= 0) {
hn = b;
r = acquire_hostname_from_credential(&hn);
if (r >= 0)
source = HOSTNAME_TRANSIENT;
}
}
if (!hn) {
_cleanup_free_ char *buf = NULL;
/* Don't override the hostname if it is already set and not explicitly configured */
r = gethostname_full(GET_HOSTNAME_ALLOW_LOCALHOST, &buf);
r = gethostname_full(GET_HOSTNAME_ALLOW_LOCALHOST, &hn);
if (r == -ENOMEM)
return log_oom();
if (r >= 0) {
log_debug("No hostname configured, leaving existing hostname <%s> in place.", buf);
return 0;
log_debug("No hostname configured, leaving existing hostname <%s> in place.", hn);
goto finish;
}
if (enoent)
log_info("No hostname configured, using default hostname.");
hn = b = get_default_hostname();
hn = get_default_hostname();
if (!hn)
return log_oom();
source = HOSTNAME_DEFAULT;
}
r = sethostname_idempotent_full(hn, really);
@ -230,7 +223,11 @@ int hostname_setup(bool really) {
if (really)
hostname_update_source_hint(hn, source);
return r;
finish:
if (!in_initrd())
(void) sd_notifyf(/* unset_environment= */ false, "X_SYSTEMD_HOSTNAME=%s", hn);
return 0;
}
static const char* const hostname_source_table[] = {

View file

@ -5,6 +5,7 @@
#include <sys/mount.h>
#include <unistd.h>
#include "sd-daemon.h"
#include "sd-id128.h"
#include "alloc-util.h"
@ -12,6 +13,7 @@
#include "creds-util.h"
#include "fd-util.h"
#include "id128-util.h"
#include "initrd-util.h"
#include "io-util.h"
#include "log.h"
#include "machine-id-setup.h"
@ -141,8 +143,8 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_
if (sd_id128_is_null(machine_id)) {
/* Try to read any existing machine ID */
if (id128_read_fd(fd, ID128_FORMAT_PLAIN, ret) >= 0)
return 0;
if (id128_read_fd(fd, ID128_FORMAT_PLAIN, &machine_id) >= 0)
goto finish;
/* Hmm, so, the id currently stored is not useful, then let's generate one */
r = generate_machine_id(root, &machine_id);
@ -207,6 +209,9 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_
return r;
finish:
if (!in_initrd())
(void) sd_notifyf(/* unset_environment= */ false, "X_SYSTEMD_MACHINE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(machine_id));
if (ret)
*ret = machine_id;

View file

@ -128,7 +128,8 @@ static int write_socket_unit(
const char *dest,
const char *unit,
const char *listen_stream,
const char *comment) {
const char *comment,
bool with_ssh_access_target_dependency) {
int r;
@ -149,13 +150,21 @@ static int write_socket_unit(
fprintf(f,
"[Unit]\n"
"Description=OpenSSH Server Socket (systemd-ssh-generator, %s)\n"
"Documentation=man:systemd-ssh-generator(8)\n"
"Documentation=man:systemd-ssh-generator(8)\n",
comment);
/* When this is a remotely accessible socket let's mark this with a milestone: ssh-access.target */
if (with_ssh_access_target_dependency)
fputs("Wants=ssh-access.target\n"
"Before=ssh-access.target\n",
f);
fprintf(f,
"\n[Socket]\n"
"ListenStream=%s\n"
"Accept=yes\n"
"PollLimitIntervalSec=30s\n"
"PollLimitBurst=50\n",
comment,
listen_stream);
r = fflush_and_check(f);
@ -230,7 +239,8 @@ static int add_vsock_socket(
dest,
"sshd-vsock.socket",
"vsock::22",
"AF_VSOCK");
"AF_VSOCK",
/* with_ssh_access_target_dependency= */ true);
if (r < 0)
return r;
@ -264,7 +274,8 @@ static int add_local_unix_socket(
dest,
"sshd-unix-local.socket",
"/run/ssh-unix-local/socket",
"AF_UNIX Local");
"AF_UNIX Local",
/* with_ssh_access_target_dependency= */ false);
if (r < 0)
return r;
@ -320,7 +331,8 @@ static int add_export_unix_socket(
dest,
"sshd-unix-export.socket",
"/run/host/unix-export/ssh",
"AF_UNIX Export");
"AF_UNIX Export",
/* with_ssh_access_target_dependency= */ true);
if (r < 0)
return r;
@ -370,7 +382,8 @@ static int add_extra_sockets(
dest,
socket ?: "sshd-extra.socket",
*i,
*i);
*i,
/* with_ssh_access_target_dependency= */ true);
if (r < 0)
return r;

View file

@ -203,6 +203,7 @@ units = [
{ 'file' : 'sockets.target' },
{ 'file' : 'soft-reboot.target' },
{ 'file' : 'sound.target' },
{ 'file' : 'ssh-access.target' },
{
'file' : 'suspend-then-hibernate.target',
'conditions' : ['ENABLE_HIBERNATE'],

12
units/ssh-access.target Normal file
View file

@ -0,0 +1,12 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=SSH Access Available
Documentation=man:systemd.special(7)