1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-21 13:34:21 +03:00

Compare commits

...

22 Commits

Author SHA1 Message Date
Ivan Kruglov
ece5cf0bd1
Merge 39a4935e3c into f108996319 2024-12-20 13:11:26 +01:00
Lennart Poettering
f108996319
core/device: handle ID_PROCESSING udev property (#35351)
Continuation of #35332.
2024-12-20 10:12:39 +01:00
Daan De Meyer
dec47e58a6
debug-generator: add a kernel cmdline option to pause the boot process (#35410)
Introduce the `systemd.break=` kernel command line option to allow
stopping the boot process at a certain point and spawn a debug shell.
After exiting this shell, the system will resume booting.

It accepts the following values:
- `pre-udev`: before starting to process kernel uevents (initrd and
host).
- `pre-basic`: before leaving early boot and regular services start
(initrd and host).
- `pre-mount`: before the root filesystem is mounted (initrd).
- `pre-switch-root`: before switching root (initrd).
2024-12-20 10:04:41 +01:00
Lennart Poettering
cdcb1eeeb8
[RFC] better naming for Azure MANA network devices (#34255)
The Azure MANA folks would like the PCI domain to be suppressed from
naming network interfaces. Let's introduce a somewhat generic way to do
this, without hardcoding anything to Azure.

Specifically: we'll ship a new hwdb entry that sets a new
ID_NET_NAME_INCLUDE_DOMAIN=0 property on relevant MANA devices. Then we
make net_id look for that property, and if it is set we simply suppress
the PCI domain.

(Untested as of now, needs feedback from Azure MANA folks that this
actually works and does what is requested here).
2024-12-20 09:52:40 +01:00
Matteo Croce
77d4a263c1 mkosi: move config options
Move some config option in the right section, fixes the following warning:
```
mkosi.conf: Setting Credentials should be configured in [Runtime], not [Host].
mkosi.conf: Setting RuntimeBuildSources should be configured in [Runtime], not [Host].
mkosi.conf: Setting RuntimeScratch should be configured in [Runtime], not [Host].
mkosi.conf: Setting QemuSmp should be configured in [Runtime], not [Host].
mkosi.conf: Setting QemuSwtpm should be configured in [Runtime], not [Host].
mkosi.conf: Setting QemuVsock should be configured in [Runtime], not [Host].
mkosi.conf: Setting QemuKvm should be configured in [Runtime], not [Host].
```
2024-12-20 09:38:11 +01:00
Yu Watanabe
5f29c86ace audit-util: rename output parameter
To make them consistent with in audit-util.c.

Follow-up for 7e02ee98d8.
2024-12-20 09:37:25 +01:00
Yu Watanabe
182ffb5819 TEST-71-HOSTNAME: do not start user session
The user session may trigger hostnamed, and the job of stopping
hostnamed may be cancelled, and the test may fail:
```
[ 4633.613578] TEST-71-HOSTNAME.sh[175]: + stop_hostnamed
[ 4633.613578] TEST-71-HOSTNAME.sh[175]: + systemctl stop systemd-hostnamed.service
[ 4633.664670] systemd[1]: Stopping systemd-hostnamed.service - Hostname Service...
[ 4636.022277] systemd-logind[121]: New session c2 of user root.
[ 4636.032532] systemd[1]: Created slice user-0.slice - User Slice of UID 0.
[ 4636.042675] systemd[1]: Starting user-runtime-dir@0.service - User Runtime Directory /run/user/0...
[ 4636.176140] systemd[1]: Finished user-runtime-dir@0.service - User Runtime Directory /run/user/0.
[ 4636.202951] systemd[1]: Starting user@0.service - User Manager for UID 0...
[ 4636.292204] systemd-logind[121]: New session c3 of user root.
[ 4636.300065] (systemd)[268]: pam_unix(systemd-user:session): session opened for user root(uid=0) by root(uid=0)
[ 4636.757667] systemd[268]: Queued start job for default target default.target.
[ 4636.774419] systemd[268]: Created slice app.slice - User Application Slice.
[ 4636.774579] systemd[268]: Started systemd-tmpfiles-clean.timer - Daily Cleanup of User's Temporary Directories.
[ 4636.774747] systemd[268]: Reached target paths.target - Paths.
[ 4636.776418] systemd[268]: Reached target sysinit.target - System Initialization.
[ 4636.776604] systemd[268]: Reached target timers.target - Timers.
[ 4636.784997] systemd[268]: Starting dbus.socket - D-Bus User Message Bus Socket...
[ 4636.799472] systemd[268]: Starting systemd-tmpfiles-setup.service - Create User Files and Directories...
[ 4637.027125] systemd[268]: Finished systemd-tmpfiles-setup.service - Create User Files and Directories.
[ 4637.031721] systemd[268]: Listening on dbus.socket - D-Bus User Message Bus Socket.
[ 4637.036189] systemd[268]: Reached target sockets.target - Sockets.
[ 4637.036373] systemd[268]: Reached target basic.target - Basic System.
[ 4637.036558] systemd[268]: Reached target default.target - Main User Target.
[ 4637.036646] systemd[268]: Startup finished in 702ms.
[ 4637.049075] systemd[1]: Started user@0.service - User Manager for UID 0.
[ 4637.075263] systemd[1]: Started session-c2.scope - Session c2 of User root.
[ 4637.084917] login[136]: pam_unix(login:session): session opened for user root(uid=0) by root(uid=0)
[ 4637.117348] login[136]: ROOT LOGIN ON pts/0
[ 4637.238572] systemctl[261]: Job for systemd-hostnamed.service canceled.
[ 4637.290369] systemd[1]: TEST-71-HOSTNAME.service: Main process exited, code=exited, status=1/FAILURE
```

Fixes #35643.
2024-12-20 09:36:51 +01:00
Antonio Alvarez Feijoo
e9f781a5a4
debug-generator: add a kernel cmdline option to pause the boot process
Introduce the `systemd.break=` kernel command line option to allow stopping the
boot process at a certain point and spawn a debug shell. After exiting this
shell, the system will resume booting.

It accepts the following values:
- `pre-udev`: before starting to process kernel uevents (initrd and host).
- `pre-basic`: before leaving early boot and regular services start (initrd and
host).
- `pre-mount`: before the root filesystem is mounted (initrd).
- `pre-switch-root`: before switching root (initrd).
2024-12-20 08:51:23 +01:00
Antonio Alvarez Feijoo
cb3801a4c9
man/debug-generator: add a section for kernel command line options 2024-12-20 08:48:23 +01:00
Yu Watanabe
f01132aacf TEST-17: add test case for ID_PROCESSING flag on add uevent
Also, check the state of the device units on change event.
2024-12-20 10:52:57 +09:00
Yu Watanabe
ad920b4cb3 core/device: handle ID_PROCESSING udev property
If an enumerated device has ID_PROCESSING=1 property, and the service
manager does not know if the device has been processed by udevd
previously (that is, Device.deserialized_found does not have
DEVICE_FOUND_UDEV), then drop DEVICE_FOUND_UDEV flag from the device and
make the device not enter the active state.

Follow-up for 405be62f05, which was
reverted by c4fc22c4de.
2024-12-20 10:52:57 +09:00
Yu Watanabe
a7396f8364 core/device: use path_equal() to compare sysfs path
The hashmap Manager.devices_by_sysfs uses path_hash_ops.
Let's consistent compare function.
2024-12-20 10:52:57 +09:00
Yu Watanabe
71ec342d13 core/device: rename output parameters of device_setup_units() to ret_xyz
No functional change, just refactoring.
2024-12-20 10:52:57 +09:00
Ivan Kruglov
39a4935e3c machine: move io.systemd.Machine.Map* tests into right position 2024-12-17 19:09:19 +01:00
Ivan Kruglov
f1ce905e94 machine: tests for io.systemd.Machine.{CopyFrom, CopyTo} methods 2024-12-17 19:09:19 +01:00
Ivan Kruglov
9616d7eb44 machine: introduce io.system.Machine.{CopyFrom, CopyTo} methods 2024-12-17 19:09:19 +01:00
Ivan Kruglov
9f309f9893 machine: use machine_copy_from_to() in dbus implementation 2024-12-17 18:56:28 +01:00
Ivan Kruglov
2b9c7a8bd0 machine: introduce machine_copy_from_to() helper 2024-12-17 18:56:28 +01:00
Ivan Kruglov
22cd741ff1 machine: split operation initialization into two steps 2024-12-17 18:56:28 +01:00
Ivan Kruglov
bf4066ece0 machine: adjust operation callback logic for varlink
This is to simplyfy varlink callback. There is no use of this logic atm.
So, no harm.
2024-12-17 18:56:28 +01:00
Lennart Poettering
9311c28b34 hwdb: disable inclusion of the PCI domain in MANA network interface naming 2024-12-11 16:38:25 +01:00
Lennart Poettering
19491cc90f net_id: depending on new udev prop, include/exclude PCI domain from netif names 2024-12-11 16:37:59 +01:00
29 changed files with 954 additions and 176 deletions

View File

@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: systemd/mkosi@07ef37c4c0dad5dfc6cec86c967a7600df1cd88c
- uses: systemd/mkosi@7d45366395f29fdb2b534a850c09d23d29b78fa9
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
# immediately, we remove the files in the background. However, we first move them to a different location
@ -64,7 +64,7 @@ jobs:
MESON_OPTIONS=--werror
COVERAGE=1
[Host]
[Runtime]
QemuMem=4G
EOF

View File

@ -113,7 +113,7 @@ jobs:
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: systemd/mkosi@c4bbf3b71a3e2cf947995caedf10f69da3c4957a
- uses: systemd/mkosi@7d45366395f29fdb2b534a850c09d23d29b78fa9
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
# immediately, we remove the files in the background. However, we first move them to a different location
@ -171,7 +171,7 @@ jobs:
[Content]
SELinuxRelabel=${{ matrix.relabel }}
[Host]
[Runtime]
QemuMem=4G
EOF

View File

@ -3,3 +3,7 @@
# Dell iDRAC Virtual USB NIC
usb:v413CpA102*
ID_NET_NAME_FROM_DATABASE=idrac
# Disable inclusion of PCI domain in interface names on Azure MANA
pci:v00001414d000000BA*
ID_NET_NAME_INCLUDE_DOMAIN=0

View File

@ -97,6 +97,18 @@
</listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.break=</varname></term>
<term><varname>rd.systemd.break=</varname></term>
<listitem>
<para>Parameters understood by
<citerefentry><refentrytitle>systemd-debug-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
to pause the boot process at a certain point and spawn a debug shell.</para>
<xi:include href="version-info.xml" xpointer="v258"/>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.run=</varname></term>
<term><varname>systemd.run_success_action=</varname></term>

View File

@ -31,45 +31,131 @@
<refsect1>
<title>Description</title>
<para><filename>systemd-debug-generator</filename> is a generator
that reads the kernel command line and understands three
options:</para>
<para><command>systemd-debug-generator</command> is a generator that provides some debugging
functionality.</para>
<para>If the <option>systemd.mask=</option> or <option>rd.systemd.mask=</option>
option is specified and followed by a unit name, this unit is
masked for the runtime (i.e. for this session — from boot to shutdown), similarly to the effect of
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>mask</command> command. This is useful to boot with
certain units removed from the initial boot transaction for
debugging system startup. May be specified more than once.
<option>rd.systemd.mask=</option> is honored only by initial
RAM disk (initrd) while <option>systemd.mask=</option> is
honored only in the main system.</para>
<para>If the <option>systemd.wants=</option> or
<option>rd.systemd.wants=</option> option is specified
and followed by a unit name, a start job for this unit is added to
the initial transaction. This is useful to start one or more
additional units at boot. May be specified more than once.
<option>rd.systemd.wants=</option> is honored only by initial
RAM disk (initrd) while <option>systemd.wants=</option> is
honored only in the main system.</para>
<para>If the <option>systemd.debug_shell</option> or <option>rd.systemd.debug_shell</option> option is
specified, the debug shell service <literal>debug-shell.service</literal> is pulled into the boot
transaction and a debug shell will be spawned during early boot. By default,
<filename>&DEBUGTTY;</filename> is used, but a specific tty can also be specified, either with or without
the <filename>/dev/</filename> prefix. To set the tty to use without enabling the debug shell, the
<option>systemd.default_debug_tty=</option> option can be used which also takes a tty with or without the
<filename>/dev/</filename> prefix. Note that the shell may also be turned on persistently by enabling it
with <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>enable</command> command. <option>rd.systemd.debug_shell</option> is honored only by initial
RAM disk (initrd) while <option>systemd.debug_shell</option> is honored only in the main system.</para>
<para><filename>systemd-debug-generator</filename> implements
<para><command>systemd-debug-generator</command> implements
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
<title>Kernel Command Line</title>
<para><command>systemd-debug-generator</command> understands the following kernel command line
parameters:</para>
<variablelist class='kernel-commandline-options'>
<varlistentry>
<term><varname>systemd.mask=</varname></term>
<term><varname>rd.systemd.mask=</varname></term>
<listitem><para>These options take a unit name as argument. The unit specified is masked for the
runtime (i.e. for this session — from boot to shutdown), similarly to the effect of
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>mask</command> command. This is useful to boot with certain units removed from the initial
boot transaction for debugging system startup. May be specified more than once. The option prefixed
with <literal>rd.</literal> is honored only in the initrd, while the one without prefix is only
honored in the main system.</para>
<xi:include href="version-info.xml" xpointer="v215"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.wants=</varname></term>
<term><varname>rd.systemd.wants=</varname></term>
<listitem><para>These options take a unit name as argument. A start job for this unit is added to the
initial transaction. This is useful to start one or more additional units at boot. May be specified
more than once. The option prefixed with <literal>rd.</literal> is honored only in the initrd, while
the one that is not prefixed only in the main system.</para>
<xi:include href="version-info.xml" xpointer="v215"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.debug_shell</varname></term>
<term><varname>rd.systemd.debug_shell</varname></term>
<term><varname>systemd.default_debug_tty=</varname></term>
<term><varname>rd.systemd.default_debug_tty=</varname></term>
<listitem><para>If the <option>systemd.debug_shell</option> or
<option>rd.systemd.debug_shell</option> option is specified, the debug shell service
<literal>debug-shell.service</literal> is pulled into the boot transaction and a debug shell will be
spawned during early boot. By default, <filename>&DEBUGTTY;</filename> is used, but a specific tty
can also be specified, either with or without the <filename>/dev/</filename> prefix. To set the tty
to use without enabling the debug shell, the <option>systemd.default_debug_tty=</option> option can
be used which also takes a tty with or without the <filename>/dev/</filename> prefix. Note that the
shell may also be turned on persistently by enabling it with
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>enable</command> command. The options prefixed with <literal>rd.</literal> are honored only
in the initrd, while the ones without prefix are only honored in the main system.</para>
<xi:include href="version-info.xml" xpointer="v215"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.break=</varname></term>
<term><varname>rd.systemd.break=</varname></term>
<listitem><para>Takes one of <option>pre-udev</option>, <option>pre-basic</option>,
<option>pre-mount</option>, or <option>pre-switch-root</option> (the default for the
<literal>rd.</literal> option). It also accepts multiple values separated by comma
(<literal>,</literal>). These options allow to pause the boot process at a certain point and spawn a
debug shell. After exiting this shell, the system will resume booting. The option prefixed with
<literal>rd.</literal> is honored only in the initrd, while the one without prefix is only honored in
the main system.</para>
<table>
<title>Available breakpoints</title>
<tgroup cols='4'>
<colspec colname='breakpoint' />
<colspec colname='description' />
<colspec colname='initrd' />
<colspec colname='main' />
<thead>
<row>
<entry>Breakpoints</entry>
<entry>Description</entry>
<entry>Can be used in the initrd</entry>
<entry>Can be used in the main system</entry>
</row>
</thead>
<tbody>
<row>
<entry><option>pre-udev</option></entry>
<entry>Before starting to process kernel uevents, i.e., before <filename>systemd-udevd.service</filename> starts.</entry>
<entry></entry>
<entry></entry>
</row>
<row>
<entry><option>pre-basic</option></entry>
<entry>Before leaving early boot and regular services start, i.e., before <filename>basic.target</filename> is reached.</entry>
<entry></entry>
<entry></entry>
</row>
<row>
<entry><option>pre-mount</option></entry>
<entry>Before the root filesystem is mounted, i.e., before <filename>sysroot.mount</filename> starts.</entry>
<entry></entry>
<entry></entry>
</row>
<row>
<entry><option>pre-switch-root</option></entry>
<entry>Before switching from the initrd to the real root.</entry>
<entry></entry>
<entry></entry>
</row>
</tbody>
</tgroup>
</table>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>System Credentials</title>
@ -108,6 +194,8 @@
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd.system-credentials</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>

View File

@ -130,7 +130,7 @@ Packages=
zsh
zstd
[Host]
[Runtime]
Credentials=
journal.storage=persistent
tty.serial.hvc0.agetty.autologin=root

View File

@ -9,8 +9,8 @@
#define AUDIT_SESSION_INVALID UINT32_MAX
int audit_session_from_pid(const PidRef *pid, uint32_t *id);
int audit_loginuid_from_pid(const PidRef *pid, uid_t *uid);
int audit_session_from_pid(const PidRef *pid, uint32_t *ret_id);
int audit_loginuid_from_pid(const PidRef *pid, uid_t *ret_uid);
bool use_audit(void);

View File

@ -85,7 +85,9 @@ static int device_set_sysfs(Device *d, const char *sysfs) {
Unit *u = UNIT(ASSERT_PTR(d));
int r;
if (streq_ptr(d->sysfs, sysfs))
assert(sysfs);
if (path_equal(d->sysfs, sysfs))
return 0;
Hashmap **devices = &u->manager->devices_by_sysfs;
@ -332,6 +334,20 @@ static void device_catchup(Unit *u) {
Device *d = ASSERT_PTR(DEVICE(u));
/* Second, let's update the state with the enumerated state */
/* If Device.found (set from Device.deserialized_found) does not have DEVICE_FOUND_UDEV, and the
* device has not been processed by udevd while enumeration, it indicates the unit was never active
* before reexecution, hence we can safely drop the flag from Device.enumerated_found. The device
* will be set up later when udev finishes processing (see also comment in
* device_setup_devlink_unit_one()).
*
* NB: 💣💣💣 If Device.found already contains udev, i.e. the unit was fully ready before
* reexecution, do not unset the flag. Otherwise, e.g. if systemd-udev-trigger.service is started
* just before reexec, reload, and so on, devices being reprocessed (carrying ID_PROCESSING=1
* property) on enumeration and will enter dead state. See issue #35329. */
if (!FLAGS_SET(d->found, DEVICE_FOUND_UDEV) && !d->processed)
d->enumerated_found &= ~DEVICE_FOUND_UDEV;
device_update_found_one(d, d->enumerated_found, _DEVICE_FOUND_MASK);
}
@ -777,8 +793,16 @@ static int device_setup_devlink_unit_one(Manager *m, const char *devlink, Set **
assert(ready_units);
assert(not_ready_units);
if (sd_device_new_from_devname(&dev, devlink) >= 0 && device_is_ready(dev))
if (sd_device_new_from_devname(&dev, devlink) >= 0 && device_is_ready(dev)) {
if (MANAGER_IS_RUNNING(m) && device_is_processed(dev) <= 0)
/* The device is being processed by udevd. We will receive relevant uevent for the
* device later when completed. Let's ignore the device now. */
return 0;
/* Note, even if the device is being processed by udevd, setup the unit on enumerate.
* See also the comments in device_catchup(). */
return device_setup_unit(m, dev, devlink, /* main = */ false, ready_units);
}
/* the devlink is already removed or not ready */
if (device_by_path(m, devlink, &u) < 0)
@ -874,14 +898,15 @@ static int device_setup_extra_units(Manager *m, sd_device *dev, Set **ready_unit
return 0;
}
static int device_setup_units(Manager *m, sd_device *dev, Set **ready_units, Set **not_ready_units) {
static int device_setup_units(Manager *m, sd_device *dev, Set **ret_ready_units, Set **ret_not_ready_units) {
_cleanup_set_free_ Set *ready_units = NULL, *not_ready_units = NULL;
const char *syspath, *devname = NULL;
int r;
assert(m);
assert(dev);
assert(ready_units);
assert(not_ready_units);
assert(ret_ready_units);
assert(ret_not_ready_units);
r = sd_device_get_syspath(dev, &syspath);
if (r < 0)
@ -901,13 +926,13 @@ static int device_setup_units(Manager *m, sd_device *dev, Set **ready_units, Set
/* Add the main unit named after the syspath. If this one fails, don't bother with the rest,
* as this one shall be the main device unit the others just follow. (Compare with how
* device_following() is implemented, see below, which looks for the sysfs device.) */
r = device_setup_unit(m, dev, syspath, /* main = */ true, ready_units);
r = device_setup_unit(m, dev, syspath, /* main = */ true, &ready_units);
if (r < 0)
return r;
/* Add an additional unit for the device node */
if (sd_device_get_devname(dev, &devname) >= 0)
(void) device_setup_unit(m, dev, devname, /* main = */ false, ready_units);
(void) device_setup_unit(m, dev, devname, /* main = */ false, &ready_units);
} else {
Unit *u;
@ -915,28 +940,30 @@ static int device_setup_units(Manager *m, sd_device *dev, Set **ready_units, Set
/* If the device exists but not ready, then save the units and unset udev bits later. */
if (device_by_path(m, syspath, &u) >= 0) {
r = set_ensure_put(not_ready_units, NULL, DEVICE(u));
r = set_ensure_put(&not_ready_units, NULL, DEVICE(u));
if (r < 0)
log_unit_debug_errno(u, r, "Failed to store unit, ignoring: %m");
}
if (sd_device_get_devname(dev, &devname) >= 0 &&
device_by_path(m, devname, &u) >= 0) {
r = set_ensure_put(not_ready_units, NULL, DEVICE(u));
r = set_ensure_put(&not_ready_units, NULL, DEVICE(u));
if (r < 0)
log_unit_debug_errno(u, r, "Failed to store unit, ignoring: %m");
}
}
/* Next, add/update additional .device units point to aliases and symlinks. */
(void) device_setup_extra_units(m, dev, ready_units, not_ready_units);
(void) device_setup_extra_units(m, dev, &ready_units, &not_ready_units);
/* Safety check: no unit should be in ready_units and not_ready_units simultaneously. */
Unit *u;
SET_FOREACH(u, *not_ready_units)
if (set_remove(*ready_units, u))
SET_FOREACH(u, not_ready_units)
if (set_remove(ready_units, u))
log_unit_error(u, "Cannot activate and deactivate the unit simultaneously. Deactivating.");
*ret_ready_units = TAKE_PTR(ready_units);
*ret_not_ready_units = TAKE_PTR(not_ready_units);
return 0;
}
@ -1046,13 +1073,32 @@ static void device_enumerate(Manager *m) {
FOREACH_DEVICE(e, dev) {
_cleanup_set_free_ Set *ready_units = NULL, *not_ready_units = NULL;
const char *syspath;
bool processed;
Device *d;
r = sd_device_get_syspath(dev, &syspath);
if (r < 0) {
log_device_debug_errno(dev, r, "Failed to get syspath of enumerated device, ignoring: %m");
continue;
}
r = device_is_processed(dev);
if (r < 0)
log_device_debug_errno(dev, r, "Failed to check if device is processed by udevd, assuming not: %m");
processed = r > 0;
if (device_setup_units(m, dev, &ready_units, &not_ready_units) < 0)
continue;
SET_FOREACH(d, ready_units)
SET_FOREACH(d, ready_units) {
device_update_found_one(d, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV);
/* Why we need to check the syspath here? Because the device unit may be generated by
* a devlink, and the syspath may be different from the one of the original device. */
if (path_equal(d->sysfs, syspath))
d->processed = processed;
}
SET_FOREACH(d, not_ready_units)
device_update_found_one(d, DEVICE_NOT_FOUND, DEVICE_FOUND_UDEV);
}
@ -1097,7 +1143,6 @@ static void device_remove_old_on_move(Manager *m, sd_device *dev) {
}
static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
_cleanup_set_free_ Set *ready_units = NULL, *not_ready_units = NULL;
Manager *m = ASSERT_PTR(userdata);
sd_device_action_t action;
const char *sysfs;
@ -1150,6 +1195,7 @@ static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *
* change events */
ready = device_is_ready(dev);
_cleanup_set_free_ Set *ready_units = NULL, *not_ready_units = NULL;
(void) device_setup_units(m, dev, &ready_units, &not_ready_units);
if (action == SD_DEVICE_REMOVE) {

View File

@ -29,7 +29,9 @@ struct Device {
DeviceState state, deserialized_state;
DeviceFound found, deserialized_found, enumerated_found;
bool processed; /* Whether udevd has done processing the device, i.e. the device has database and
* ID_PROCESSING=1 udev property is not set. This is used only by enumeration and
* subsequent catchup process. */
bool bind_mounts;
/* The SYSTEMD_WANTS udev property for this device the last time we saw it */

View File

@ -3,9 +3,11 @@
#include <unistd.h>
#include "alloc-util.h"
#include "bitfield.h"
#include "creds-util.h"
#include "dropin.h"
#include "errno-util.h"
#include "extract-word.h"
#include "fd-util.h"
#include "fileio.h"
#include "generator.h"
@ -27,6 +29,7 @@ static char **arg_wants = NULL;
static bool arg_debug_shell = false;
static char *arg_debug_tty = NULL;
static char *arg_default_debug_tty = NULL;
static uint32_t arg_breakpoints = 0;
STATIC_DESTRUCTOR_REGISTER(arg_default_unit, freep);
STATIC_DESTRUCTOR_REGISTER(arg_mask, strv_freep);
@ -34,6 +37,91 @@ STATIC_DESTRUCTOR_REGISTER(arg_wants, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_debug_tty, freep);
STATIC_DESTRUCTOR_REGISTER(arg_default_debug_tty, freep);
typedef enum BreakpointType {
BREAKPOINT_PRE_UDEV,
BREAKPOINT_PRE_BASIC,
BREAKPOINT_PRE_SYSROOT_MOUNT,
BREAKPOINT_PRE_SWITCH_ROOT,
_BREAKPOINT_TYPE_MAX,
_BREAKPOINT_TYPE_INVALID = -EINVAL,
} BreakpointType;
typedef enum BreakpointValidity {
BREAKPOINT_DEFAULT = 1 << 0,
BREAKPOINT_IN_INITRD = 1 << 1,
BREAKPOINT_ON_HOST = 1 << 2,
} BreakpointValidity;
typedef struct BreakpointInfo {
BreakpointType type;
const char *name;
const char *unit;
BreakpointValidity validity;
} BreakpointInfo;
static const struct BreakpointInfo breakpoint_info_table[_BREAKPOINT_TYPE_MAX] = {
{ BREAKPOINT_PRE_UDEV, "pre-udev", "breakpoint-pre-udev.service", BREAKPOINT_IN_INITRD | BREAKPOINT_ON_HOST },
{ BREAKPOINT_PRE_BASIC, "pre-basic", "breakpoint-pre-basic.service", BREAKPOINT_IN_INITRD | BREAKPOINT_ON_HOST },
{ BREAKPOINT_PRE_SYSROOT_MOUNT, "pre-mount", "breakpoint-pre-mount.service", BREAKPOINT_IN_INITRD },
{ BREAKPOINT_PRE_SWITCH_ROOT, "pre-switch-root", "breakpoint-pre-switch-root.service", BREAKPOINT_IN_INITRD | BREAKPOINT_DEFAULT },
};
static BreakpointType parse_breakpoint_from_string_one(const char *s) {
assert(s);
FOREACH_ARRAY(i, breakpoint_info_table, ELEMENTSOF(breakpoint_info_table))
if (streq(i->name, s))
return i->type;
return _BREAKPOINT_TYPE_INVALID;
}
static int parse_breakpoint_from_string(const char *s, uint32_t *ret_breakpoints) {
uint32_t breakpoints = 0;
int r;
assert(ret_breakpoints);
/* Empty value? set default breakpoint */
if (isempty(s)) {
if (in_initrd()) {
FOREACH_ARRAY(i, breakpoint_info_table, ELEMENTSOF(breakpoint_info_table))
if (i->validity & BREAKPOINT_DEFAULT) {
breakpoints |= 1 << i->type;
break;
}
} else
log_warning("No default breakpoint defined on the host, ignoring breakpoint request from kernel command line.");
} else
for (;;) {
_cleanup_free_ char *t = NULL;
BreakpointType tt;
r = extract_first_word(&s, &t, ",", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return r;
if (r == 0)
break;
tt = parse_breakpoint_from_string_one(t);
if (tt < 0) {
log_warning("Invalid breakpoint value '%s', ignoring.", t);
continue;
}
if (in_initrd() && !FLAGS_SET(breakpoint_info_table[tt].validity, BREAKPOINT_IN_INITRD))
log_warning("Breakpoint '%s' not valid in the initrd, ignoring.", t);
else if (!in_initrd() && !FLAGS_SET(breakpoint_info_table[tt].validity, BREAKPOINT_ON_HOST))
log_warning("Breakpoint '%s' not valid on the host, ignoring.", t);
else
breakpoints |= 1 << tt;
}
*ret_breakpoints = breakpoints;
return 0;
}
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
int r;
@ -88,6 +176,15 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
return free_and_strdup_warn(&arg_default_unit, value);
} else if (streq(key, "systemd.break")) {
uint32_t breakpoints = 0;
r = parse_breakpoint_from_string(value, &breakpoints);
if (r < 0)
return log_warning_errno(r, "Failed to parse breakpoint value '%s': %m", value);
arg_breakpoints |= breakpoints;
} else if (!value) {
const char *target;
@ -269,6 +366,10 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
RET_GATHER(r, install_debug_shell_dropin());
}
BIT_FOREACH(i, arg_breakpoints)
if (strv_extend(&arg_wants, breakpoint_info_table[i].unit) < 0)
return log_oom();
if (get_credentials_dir(&credentials_dir) >= 0)
RET_GATHER(r, process_unit_credentials(credentials_dir));

View File

@ -492,15 +492,11 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
}
int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *host_basename = NULL, *container_basename = NULL;
const char *src, *dest, *host_path, *container_path;
_cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR;
CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS;
_cleanup_close_ int hostfd = -EBADF;
Machine *m = ASSERT_PTR(userdata);
Manager *manager = m->manager;
bool copy_from;
pid_t child;
uid_t uid_shift;
int r;
assert(message);
@ -549,17 +545,13 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
message,
"org.freedesktop.machine1.manage-machines",
details,
&m->manager->polkit_registry,
&manager->polkit_registry,
error);
if (r < 0)
return r;
if (r == 0)
return 1; /* Will call us back */
r = machine_get_uid_shift(m, &uid_shift);
if (r < 0)
return r;
copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
if (copy_from) {
@ -570,83 +562,12 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
container_path = dest;
}
r = path_extract_filename(host_path, &host_basename);
Operation *op;
r = machine_copy_from_to(manager, m, host_path, container_path, copy_from, copy_flags, &op);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to extract file name of '%s' path: %m", host_path);
r = path_extract_filename(container_path, &container_basename);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to extract file name of '%s' path: %m", container_path);
hostfd = open_parent(host_path, O_CLOEXEC, 0);
if (hostfd < 0)
return sd_bus_error_set_errnof(error, hostfd, "Failed to open host directory %s: %m", host_path);
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
r = safe_fork("(sd-copy)", FORK_RESET_SIGNALS, &child);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
if (r == 0) {
int containerfd;
const char *q;
int mntfd;
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
q = procfs_file_alloca(m->leader.pid, "ns/mnt");
mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
if (mntfd < 0) {
r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
goto child_fail;
}
if (setns(mntfd, CLONE_NEWNS) < 0) {
r = log_error_errno(errno, "Failed to join namespace of leader: %m");
goto child_fail;
}
containerfd = open_parent(container_path, O_CLOEXEC, 0);
if (containerfd < 0) {
r = log_error_errno(containerfd, "Failed to open destination directory: %m");
goto child_fail;
}
/* Run the actual copy operation. Note that when a UID shift is set we'll either clamp the UID/GID to
* 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy
* the UID/GIDs as they are. */
if (copy_from)
r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, uid_shift == 0 ? UID_INVALID : 0, uid_shift == 0 ? GID_INVALID : 0, copy_flags, NULL, NULL);
else
r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, uid_shift == 0 ? UID_INVALID : uid_shift, uid_shift == 0 ? GID_INVALID : uid_shift, copy_flags, NULL, NULL);
hostfd = safe_close(hostfd);
containerfd = safe_close(containerfd);
if (r < 0) {
r = log_error_errno(r, "Failed to copy tree: %m");
goto child_fail;
}
_exit(EXIT_SUCCESS);
child_fail:
(void) write(errno_pipe_fd[1], &r, sizeof(r));
_exit(EXIT_FAILURE);
}
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
/* Copying might take a while, hence install a watch on the child, and return */
r = operation_new_with_bus_reply(m->manager, m, child, message, errno_pipe_fd[0], /* ret= */ NULL);
if (r < 0) {
(void) sigkill_wait(child);
return r;
}
errno_pipe_fd[0] = -EBADF;
return sd_bus_error_set_errnof(error, r, "Failed to copy from/to machine '%s': %m", m->name);
operation_with_bus_reply(op, message);
return 1;
}

View File

@ -7,6 +7,7 @@
#include "sd-varlink.h"
#include "bus-polkit.h"
#include "copy.h"
#include "fd-util.h"
#include "hostname-util.h"
#include "json-util.h"
@ -728,3 +729,102 @@ int vl_method_map_to(sd_varlink *link, sd_json_variant *parameters, sd_varlink_m
return sd_varlink_reply(link, v);
}
typedef struct MachineCopyParameters {
const char *name;
PidRef pidref;
char *src, *dest;
bool replace;
} MachineCopyParameters;
static void machine_copy_paramaters_done(MachineCopyParameters *p) {
assert(p);
pidref_done(&p->pidref);
free(p->src);
free(p->dest);
}
static int copy_done(Operation *operation, int ret, sd_bus_error *error) {
assert(operation);
assert(operation->link);
// TODO(ikruglov): maybe just leaving a plain errno in response?
if (ret == -EPERM || ret == -EACCES)
return sd_varlink_error(operation->link, SD_VARLINK_ERROR_PERMISSION_DENIED, NULL);
if (ERRNO_IS_NEG_NOT_SUPPORTED(ret))
return sd_varlink_error(operation->link, "io.systemd.Machine.NotSupported", NULL);
if (ret == -ENOENT)
return sd_varlink_error(operation->link, "io.systemd.Machine.NoSuchFile", NULL);
if (ret == -EEXIST)
return sd_varlink_error(operation->link, "io.systemd.Machine.FileExists", NULL);
if (ret < 0)
return sd_varlink_error_errno(operation->link, ret);
return sd_varlink_reply(operation->link, NULL);
}
int vl_method_copy_internal(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata, bool copy_from) {
static const sd_json_dispatch_field dispatch_table[] = {
VARLINK_DISPATCH_MACHINE_LOOKUP_FIELDS(MachineCopyParameters),
{ "source", SD_JSON_VARIANT_STRING, json_dispatch_path, offsetof(MachineCopyParameters, src), SD_JSON_MANDATORY },
{ "destination", SD_JSON_VARIANT_STRING, json_dispatch_path, offsetof(MachineCopyParameters, dest), 0 },
{ "replace", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(MachineCopyParameters, replace), 0 },
VARLINK_DISPATCH_POLKIT_FIELD,
{}
};
int r;
Manager *manager = ASSERT_PTR(userdata);
_cleanup_(machine_copy_paramaters_done) MachineCopyParameters p = {
.pidref = PIDREF_NULL
};
assert(link);
assert(parameters);
if (manager->n_operations >= OPERATIONS_MAX)
return sd_varlink_error(link, "io.systemd.MachineImage.TooManyOperations", NULL);
r = sd_varlink_dispatch(link, parameters, dispatch_table, &p);
if (r != 0)
return r;
/* There is no need for extra validation since path_is_absolute() does path_is_valid() and path_is_absolute().*/
const char *dest = p.dest ?: p.src;
const char *container_path = copy_from ? p.src : dest;
const char *host_path = copy_from ? dest : p.src;
CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS;
copy_flags |= p.replace ? COPY_REPLACE : 0;
Machine *machine;
r = lookup_machine_by_name_or_pidref(link, manager, p.name, &p.pidref, &machine);
if (r == -ESRCH)
return sd_varlink_error(link, "io.systemd.Machine.NoSuchMachine", NULL);
if (r != 0)
return r;
if (machine->class != MACHINE_CONTAINER)
return sd_varlink_error(link, "io.systemd.Machine.NotSupported", NULL);
r = varlink_verify_polkit_async(
link,
manager->bus,
"org.freedesktop.machine1.manage-machines",
(const char**) STRV_MAKE("name", machine->name,
"verb", "copy",
"src", p.src,
"dest", dest),
&manager->polkit_registry);
if (r <= 0)
return r;
Operation *op;
r = machine_copy_from_to(manager, machine, host_path, container_path, copy_from, copy_flags, &op);
if (r < 0)
return log_debug_errno(r, "Failed to copy from/to machine '%s': %m", machine->name);
operation_with_varlink_reply(op, link);
op->done = copy_done;
return 1;
}

View File

@ -27,3 +27,4 @@ int vl_method_kill(sd_varlink *link, sd_json_variant *parameters, sd_varlink_met
int vl_method_open(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int vl_method_map_from(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int vl_method_map_to(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int vl_method_copy_internal(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata, bool copy_from);

View File

@ -973,6 +973,115 @@ char** machine_default_shell_args(const char *user) {
return TAKE_PTR(args);
}
int machine_copy_from_to(Manager *manager, Machine *machine, const char *host_path, const char *container_path, bool copy_from, CopyFlags copy_flags, Operation **ret) {
_cleanup_close_ int hostfd = -EBADF, mntns_fd = -EBADF;
_cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR;
_cleanup_free_ char *host_basename = NULL, *container_basename = NULL;
uid_t uid_shift;
pid_t child;
int r;
assert(manager);
assert(machine);
assert(ret);
if (isempty(host_path) || isempty(container_path))
return -EINVAL;
r = path_extract_filename(host_path, &host_basename);
if (r < 0)
return log_debug_errno(r, "Failed to extract file name of '%s' path: %m", host_path);
r = path_extract_filename(container_path, &container_basename);
if (r < 0)
return log_debug_errno(r, "Failed to extract file name of '%s' path: %m", container_path);
hostfd = open_parent(host_path, O_CLOEXEC, 0);
if (hostfd < 0)
return log_debug_errno(hostfd, "Failed to open host directory %s: %m", host_path);
r = machine_get_uid_shift(machine, &uid_shift);
if (r < 0)
return log_debug_errno(r, "Failed to get machine '%s' UID shift: %m", machine->name);
r = pidref_namespace_open(&machine->leader,
/* ret_pidns_fd = */ NULL,
&mntns_fd,
/* ret_netns_fd = */ NULL,
/* ret_userns_fd = */ NULL,
/* ret_root_fd = */ NULL);
if (r < 0)
return log_debug_errno(r, "Failed to open namespace for machine '%s': %m", machine->name);
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
return log_debug_errno(errno, "Failed to create pipe: %m");
r = namespace_fork("(sd-copyns)",
"(sd-copy)",
/* except_fds = */ NULL,
/* n_except_fds = */ 0,
FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL,
/* pidns_fd = */ -1,
mntns_fd,
/* netns_fd = */ -1,
/* userns_fd = */ -1,
/* root_fd = */ -1,
&child);
if (r < 0)
return log_debug_errno(r, "Failed to fork() for machine '%s': %m", machine->name);
if (r == 0) {
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
_cleanup_close_ int containerfd = -EBADF;
containerfd = open_parent(container_path, O_CLOEXEC, 0);
if (containerfd < 0) {
log_error_errno(containerfd, "Failed to open destination directory: %m");
report_errno_and_exit(errno_pipe_fd[1], containerfd);
}
/* Run the actual copy operation. Note that when a UID shift is set we'll either clamp the UID/GID to */
/* 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy */
/* the UID/GIDs as they are. */
r = copy_from ? copy_tree_at(
containerfd,
container_basename,
hostfd,
host_basename,
uid_shift == 0 ? UID_INVALID : 0,
uid_shift == 0 ? GID_INVALID : 0,
copy_flags,
/* denylist = */ NULL,
/* subvolumes = */ NULL)
: copy_tree_at(
hostfd,
host_basename,
containerfd,
container_basename,
uid_shift == 0 ? UID_INVALID : uid_shift,
uid_shift == 0 ? GID_INVALID : uid_shift,
copy_flags,
/* denylist = */ NULL,
/* subvolumes = */ NULL);
if (r < 0)
log_error_errno(r, "Failed to copy tree: %m");
report_errno_and_exit(errno_pipe_fd[1], r);
}
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
Operation *operation;
r = operation_new(manager, machine, child, errno_pipe_fd[0], &operation);
if (r < 0) {
sigkill_wait(child);
return r;
}
TAKE_FD(errno_pipe_fd[0]);
*ret = operation;
return 0;
}
void machine_release_unit(Machine *m) {
assert(m);

View File

@ -4,6 +4,7 @@
typedef struct Machine Machine;
typedef enum KillWhom KillWhom;
#include "copy.h"
#include "list.h"
#include "machined.h"
#include "operation.h"
@ -107,6 +108,7 @@ int machine_start_shell(Machine *m, int ptmx_fd, const char *ptmx_name, const ch
#define machine_default_shell_path() ("/bin/sh")
char** machine_default_shell_args(const char *user);
int machine_copy_from_to(Manager *manager, Machine *machine, const char *host_path, const char *container_path, bool copy_from, CopyFlags copy_flags, Operation **ret);
int machine_get_uid_shift(Machine *m, uid_t *ret);
int machine_owns_uid(Machine *m, uid_t host_uid, uid_t *ret_internal_uid);

View File

@ -591,6 +591,13 @@ static int vl_method_terminate(sd_varlink *link, sd_json_variant *parameters, sd
return lookup_machine_and_call_method(link, parameters, flags, userdata, vl_method_terminate_internal);
}
static int vl_method_copy_from(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return vl_method_copy_internal(link, parameters, flags, userdata, /* copy_from = */ true);
}
static int vl_method_copy_to(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return vl_method_copy_internal(link, parameters, flags, userdata, /* copy_from = */ false);
}
static int list_image_one_and_maybe_read_metadata(sd_varlink *link, Image *image, bool more, AcquireMetadata am) {
int r;
@ -773,6 +780,8 @@ static int manager_varlink_init_machine(Manager *m) {
"io.systemd.Machine.Open", vl_method_open,
"io.systemd.Machine.MapFrom", vl_method_map_from,
"io.systemd.Machine.MapTo", vl_method_map_to,
"io.systemd.Machine.CopyFrom", vl_method_copy_from,
"io.systemd.Machine.CopyTo", vl_method_copy_to,
"io.systemd.MachineImage.List", vl_method_list_images,
"io.systemd.MachineImage.Update", vl_method_update_image,
"io.systemd.MachineImage.Clone", vl_method_clone_image,

View File

@ -46,10 +46,12 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
if (r < 0)
log_debug_errno(r, "Operation failed: %m");
/* If a completion routine (o->done) is set for this operation, call it. It sends a response, but can return an error in which case it expect us to reply.
* Otherwise, the default action is to simply return an error on failure or an empty success message on success. */
if (o->message) {
/* If o->done set, call it. It sends a response, but can return
* an error in which case it expect this code to reply.
* If o->done is not set, the default action is to simply return
* an error on failure or an empty success message on success.*/
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
if (o->done)
r = o->done(o, r, &error);
@ -68,13 +70,16 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
log_error_errno(r, "Failed to reply to dbus message: %m");
}
} else if (o->link) {
if (o->done)
r = o->done(o, r, /* error = */ NULL);
/* If o->done set, call it. Unlike o->message case above, this
* code expect o->done to reply in all cases.
* If o->done is not set, the default action is to simply return
* an error on failure or an empty success message on success.*/
if (r < 0)
if (o->done)
(void) o->done(o, r, /* error = */ NULL);
else if (r < 0)
(void) sd_varlink_error_errno(o->link, r);
else if (!o->done)
/* when o->done set it's responsible for sending reply in a happy-path case */
else
(void) sd_varlink_reply(o->link, NULL);
} else
assert_not_reached();
@ -83,15 +88,14 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
return 0;
}
int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, sd_varlink *link, int errno_fd, Operation **ret) {
int operation_new(Manager *manager, Machine *machine, pid_t child, int errno_fd, Operation **ret) {
Operation *o;
int r;
assert(manager);
assert(child > 1);
assert(errno_fd >= 0);
assert(message || link);
assert(!(message && link));
assert(ret);
o = new0(Operation, 1);
if (!o)
@ -106,8 +110,8 @@ int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_messag
}
o->pid = child;
o->message = sd_bus_message_ref(message);
o->link = sd_varlink_ref(link);
o->message = NULL;
o->link = NULL;
o->errno_fd = errno_fd;
LIST_PREPEND(operations, manager->operations, o);
@ -123,9 +127,7 @@ int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_messag
/* At this point we took ownership of both the child and the errno file descriptor! */
if (ret)
*ret = o;
*ret = o;
return 0;
}

View File

@ -31,11 +31,53 @@ struct Operation {
LIST_FIELDS(Operation, operations_by_machine);
};
int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, sd_varlink *link, int errno_fd, Operation **ret);
int operation_new(Manager *manager, Machine *machine, pid_t child, int errno_fd, Operation **ret);
Operation *operation_free(Operation *o);
static inline void operation_with_bus_reply(Operation *op, sd_bus_message *message) {
assert(op);
assert(!op->message);
assert(!op->link);
assert(message);
op->message = sd_bus_message_ref(message);
}
static inline void operation_with_varlink_reply(Operation *op, sd_varlink *link) {
assert(op);
assert(!op->message);
assert(!op->link);
assert(link);
op->link = sd_varlink_ref(link);
}
static inline int operation_new_with_bus_reply(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd, Operation **ret) {
return operation_new(manager, machine, child, message, /* link = */ NULL, errno_fd, ret);
Operation *op;
int r;
r = operation_new(manager, machine, child, errno_fd, &op);
if (r < 0)
return r;
operation_with_bus_reply(op, message);
if (ret)
*ret = op;
return 0;
}
static inline int operation_new_with_varlink_reply(Manager *manager, Machine *machine, pid_t child, sd_varlink *link, int errno_fd, Operation **ret) {
return operation_new(manager, machine, child, /* message = */ NULL, link, errno_fd, ret);
Operation *op;
int r;
r = operation_new(manager, machine, child, errno_fd, &op);
if (r < 0)
return r;
operation_with_varlink_reply(op, link);
if (ret)
*ret = op;
return 0;
}

View File

@ -121,6 +121,25 @@ static SD_VARLINK_DEFINE_METHOD(
SD_VARLINK_DEFINE_OUTPUT(ptyFileDescriptor, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Path to the allocated pseudo TTY"),
SD_VARLINK_DEFINE_OUTPUT(ptyPath, SD_VARLINK_STRING, 0));
static SD_VARLINK_DEFINE_METHOD(
CopyFrom,
VARLINK_DEFINE_MACHINE_LOOKUP_AND_POLKIT_INPUT_FIELDS,
SD_VARLINK_FIELD_COMMENT("A source directory/file in the container"),
SD_VARLINK_DEFINE_INPUT(source, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("A destination directory/file in the container. If null, it's equal to 'source'"),
SD_VARLINK_DEFINE_INPUT(destination, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("If true the destination will be replaced"),
SD_VARLINK_DEFINE_INPUT(replace, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD(
CopyTo,
VARLINK_DEFINE_MACHINE_LOOKUP_AND_POLKIT_INPUT_FIELDS,
SD_VARLINK_FIELD_COMMENT("A source directory/file on the host"),
SD_VARLINK_DEFINE_INPUT(source, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("A destination directory/file in the container. If null, it's equal to 'source'"),
SD_VARLINK_DEFINE_INPUT(destination, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("If true the destination will be replaced"),
SD_VARLINK_DEFINE_INPUT(replace, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD(
MapFrom,
@ -149,6 +168,8 @@ static SD_VARLINK_DEFINE_METHOD(
static SD_VARLINK_DEFINE_ERROR(NoSuchMachine);
static SD_VARLINK_DEFINE_ERROR(MachineExists);
static SD_VARLINK_DEFINE_ERROR(NoSuchFile);
static SD_VARLINK_DEFINE_ERROR(FileExists);
static SD_VARLINK_DEFINE_ERROR(NoPrivateNetworking);
static SD_VARLINK_DEFINE_ERROR(NoOSReleaseInformation);
static SD_VARLINK_DEFINE_ERROR(NoUIDShift);
@ -187,9 +208,17 @@ SD_VARLINK_DEFINE_INTERFACE(
&vl_method_MapFrom,
SD_VARLINK_SYMBOL_COMMENT("Maps given host's UID/GID to a machine and corresponding UID/GID"),
&vl_method_MapTo,
SD_VARLINK_SYMBOL_COMMENT("Copy files or directories from a container into the host"),
&vl_method_CopyFrom,
SD_VARLINK_SYMBOL_COMMENT("Copy files or directories from the host into a container"),
&vl_method_CopyTo,
SD_VARLINK_SYMBOL_COMMENT("No matching machine currently running"),
&vl_error_NoSuchMachine,
&vl_error_MachineExists,
SD_VARLINK_SYMBOL_COMMENT("No such file"),
&vl_error_NoSuchFile,
SD_VARLINK_SYMBOL_COMMENT("File exists"),
&vl_error_FileExists,
SD_VARLINK_SYMBOL_COMMENT("Machine does not use private networking"),
&vl_error_NoPrivateNetworking,
SD_VARLINK_SYMBOL_COMMENT("Machine does not contain OS release information"),

View File

@ -650,7 +650,16 @@ static int get_pci_slot_specifiers(
* where the slot makes up the upper 5 bits. */
func += slot * 8;
if (domain > 0 && asprintf(&domain_spec, "P%u", domain) < 0)
/* Include the PCI domain in the name if the ID_NET_NAME_INCLUDE_DOMAIN property says so, if it is
* set. If it is not set, include it if the domain is non-zero. */
r = device_get_property_bool(dev, "ID_NET_NAME_INCLUDE_DOMAIN");
if (r < 0) {
if (r != -ENOENT)
log_device_warning_errno(dev, r, "Failed to read property \"ID_NET_NAME_INCLUDE_DOMAIN\", ignoring: %m");
r = domain > 0;
}
if (r > 0 && asprintf(&domain_spec, "P%u", domain) < 0)
return log_oom_debug();
if (asprintf(&bus_and_slot_spec, "p%us%u", bus, slot) < 0)

View File

@ -3,5 +3,11 @@
integration_tests += [
integration_test_template + {
'name' : fs.name(meson.current_source_dir()),
'configuration' : integration_test_template['configuration'] + {
# Do not request user session, as it may trigger to start
# hostnamed in an unexpected timing, and the test may fail.
'wants' : 'multi-user.target',
'after' : 'multi-user.target',
},
},
]

View File

@ -259,7 +259,7 @@ done
####################
# varlinkctl tests #
# ##################
####################
long_running_machine_start
@ -387,6 +387,11 @@ varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Open
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Open '{"name": ".host", "mode": "login"}'
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Open '{"name": ".host", "mode": "shell"}'
rm -f /tmp/none-existent-file
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Open '{"name": ".host", "mode": "shell", "user": "root", "path": "/bin/sh", "args": ["/bin/sh", "-c", "echo $FOO > /tmp/none-existent-file"], "environment": ["FOO=BAR"]}'
timeout 30 bash -c "until test -e /tmp/none-existent-file; do sleep .5; done"
grep -q "BAR" /tmp/none-existent-file
# test io.systemd.Machine.MapFrom
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.MapFrom '{"name": "long-running", "uid":0, "gid": 0}'
container_uid=$(varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.MapFrom '{"name": "long-running", "uid":0}' | jq '.uid')
@ -396,12 +401,26 @@ varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.MapTo
(! varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.MapTo '{"uid": 0}')
(! varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.MapTo '{"gid": 0}')
rm -f /tmp/none-existent-file
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Open '{"name": ".host", "mode": "shell", "user": "root", "path": "/bin/sh", "args": ["/bin/sh", "-c", "echo $FOO > /tmp/none-existent-file"], "environment": ["FOO=BAR"]}'
timeout 30 bash -c "until test -e /tmp/none-existent-file; do sleep .5; done"
grep -q "BAR" /tmp/none-existent-file
# test io.systemd.Machine.CopyTo
rm -f /tmp/foo /var/lib/machines/long-running/root/foo
cp /etc/machine-id /tmp/foo
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.CopyTo '{"name": "long-running", "source": "/tmp/foo", "destination": "/root/foo"}'
diff /tmp/foo /var/lib/machines/long-running/root/foo
(! varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.CopyTo '{"name": "long-running", "source": "/tmp/foo", "destination": "/root/foo"}') 2>&1 | grep "FileExists"
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.CopyTo '{"name": "long-running", "source": "/tmp/foo", "destination": "/root/foo", "replace": true}'
# terminate machines
echo "sample-test-output" > /tmp/foo
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.CopyTo '{"name": "long-running", "source": "/tmp/foo", "destination": "/root/foo", "replace": true}'
diff /tmp/foo /var/lib/machines/long-running/root/foo
rm -f /tmp/foo /var/lib/machines/long-running/root/foo
# test io.systemd.Machine.CopyFrom
cp /etc/machine-id /var/lib/machines/long-running/foo
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.CopyFrom '{"name": "long-running", "source": "/foo"}'
diff /var/lib/machines/long-running/foo /foo
rm -f /var/lib/machines/long-running/root/foo /foo
# Terminating machine, otherwise acquiring image metadata by io.systemd.MachineImage.List may fail in the below.
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"

View File

@ -31,18 +31,50 @@ cat >/run/udev/udev.conf.d/timeout.conf <<EOF
event_timeout=1h
EOF
# First, test 'add' event.
mkdir -p /run/udev/rules.d/
cat >/run/udev/rules.d/99-testsuite.rules <<EOF
SUBSYSTEM=="net", ACTION=="change", KERNEL=="${IFNAME}", OPTIONS="log_level=debug", RUN+="/usr/bin/sleep 1000"
SUBSYSTEM=="net", ACTION=="add", KERNEL=="${IFNAME}", OPTIONS="log_level=debug", RUN+="/usr/bin/sleep 1000"
EOF
udevadm control --reload
ip link add "$IFNAME" type dummy
IFINDEX=$(ip -json link show "$IFNAME" | jq '.[].ifindex')
udevadm wait --timeout 10 "/sys/class/net/${IFNAME}"
# Check if the database file is created.
[[ -e "/run/udev/data/n${IFINDEX}" ]]
timeout 30 bash -c "until [[ -e /run/udev/data/n${IFINDEX} ]] && grep -q -F 'ID_PROCESSING=1' /run/udev/data/n${IFINDEX}; do sleep .5; done"
(! systemctl is-active "sys-devices-virtual-net-${IFNAME}.device")
(! systemctl is-active "sys-subsystem-net-devices-${IFNAME}.device")
for _ in {1..3}; do
systemctl daemon-reexec
(! systemctl is-active "sys-devices-virtual-net-${IFNAME}.device")
(! systemctl is-active "sys-subsystem-net-devices-${IFNAME}.device")
done
for _ in {1..3}; do
systemctl daemon-reload
(! systemctl is-active "sys-devices-virtual-net-${IFNAME}.device")
(! systemctl is-active "sys-subsystem-net-devices-${IFNAME}.device")
done
# Check if the reexec and reload have finished during processing the event.
grep -q -F 'ID_PROCESSING=1' "/run/udev/data/n${IFINDEX}"
# Forcibly kill sleep command ivoked by the udev rule to finish processing the add event.
killall sleep
udevadm settle --timeout=20
# Check if ID_PROCESSING flag is unset, and the device units are active.
(! grep -q -F 'ID_PROCESSING=1' "/run/udev/data/n${IFINDEX}")
systemctl is-active "sys-devices-virtual-net-${IFNAME}.device"
systemctl is-active "sys-subsystem-net-devices-${IFNAME}.device"
# Next, test 'change' event.
cat >/run/udev/rules.d/99-testsuite.rules <<EOF
SUBSYSTEM=="net", ACTION=="change", KERNEL=="${IFNAME}", OPTIONS="log_level=debug", RUN+="/usr/bin/sleep 1000"
EOF
udevadm control --reload
systemd-run \
-p After="sys-subsystem-net-devices-${IFNAME}.device" \
@ -50,22 +82,29 @@ systemd-run \
-u testsleep.service \
sleep 1h
timeout 10 bash -c 'until systemctl is-active testsleep.service; do sleep .5; done'
udevadm trigger "/sys/class/net/${IFNAME}"
timeout 30 bash -c "until grep -F 'ID_PROCESSING=1' /run/udev/data/n${IFINDEX}; do sleep .5; done"
timeout 30 bash -c "until grep -q -F 'ID_PROCESSING=1' /run/udev/data/n${IFINDEX}; do sleep .5; done"
# Check if the service and device units are still active even ID_PROCESSING flag is set.
systemctl is-active testsleep.service
systemctl is-active "sys-devices-virtual-net-${IFNAME}.device"
systemctl is-active "sys-subsystem-net-devices-${IFNAME}.device"
for _ in {1..3}; do
systemctl daemon-reexec
systemctl is-active testsleep.service
systemctl is-active "sys-devices-virtual-net-${IFNAME}.device"
systemctl is-active "sys-subsystem-net-devices-${IFNAME}.device"
done
for _ in {1..3}; do
systemctl daemon-reload
systemctl is-active testsleep.service
systemctl is-active "sys-devices-virtual-net-${IFNAME}.device"
systemctl is-active "sys-subsystem-net-devices-${IFNAME}.device"
done
# Check if the reexec and reload have finished during processing the event.
grep -F 'ID_PROCESSING=1' "/run/udev/data/n${IFINDEX}"
grep -q -F 'ID_PROCESSING=1' "/run/udev/data/n${IFINDEX}"
exit 0

View File

@ -69,6 +69,51 @@ SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/default.target.wants/debug-shell.service" /lib/systemd/system/debug-shell.service
grep -F "/dev/tty666" "$OUT_DIR/early/debug-shell.service.d/50-tty.conf"
# systemd.break (default)
: "debug-shell: regular + systemd.break"
CMDLINE="$CMDLINE systemd.break"
SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-udev.service"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-mount.service"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-switch-root.service"
# systemd.break=pre-switch-root
: "debug-shell: regular + systemd.break=pre-switch-root"
CMDLINE="$CMDLINE systemd.break=pre-switch-root"
SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-udev.service"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-mount.service"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-switch-root.service"
# systemd.break=pre-mount
: "debug-shell: regular + systemd.break=pre-mount"
CMDLINE="$CMDLINE systemd.break=pre-mount"
SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-udev.service"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-mount.service"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-switch-root.service"
# systemd.break=pre-basic
: "debug-shell: regular + systemd.break=pre-basic"
CMDLINE="$CMDLINE systemd.break=pre-basic"
SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/default.target.wants/breakpoint-pre-basic.service" /lib/systemd/system/breakpoint-pre-basic.service
# systemd.break=pre-udev
: "debug-shell: regular + systemd.break=pre-udev"
CMDLINE="$CMDLINE systemd.break=pre-udev"
SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/default.target.wants/breakpoint-pre-udev.service" /lib/systemd/system/breakpoint-pre-udev.service
# systemd.break=pre-udev,pre-basic,pre-mount,pre-switch-root
: "debug-shell: regular + systemd.break=pre-udev,pre-basic,pre-mount,pre-switch-root"
rm -f "$OUT_DIR/early/default.target.wants/breakpoint-pre-udev.service"
rm -f "$OUT_DIR/early/default.target.wants/breakpoint-pre-basic.service"
CMDLINE="$CMDLINE systemd.break=pre-udev,pre-basic,pre-mount,pre-switch-root"
SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/default.target.wants/breakpoint-pre-udev.service" /lib/systemd/system/breakpoint-pre-udev.service
link_endswith "$OUT_DIR/early/default.target.wants/breakpoint-pre-basic.service" /lib/systemd/system/breakpoint-pre-basic.service
# Now override the default target via systemd.unit=
: "debug-shell: regular + systemd.unit="
CMDLINE="$CMDLINE systemd.unit=my-fancy.target"
@ -103,6 +148,50 @@ CMDLINE="$CMDLINE rd.systemd.debug_shell"
SYSTEMD_IN_INITRD=1 SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/initrd.target.wants/debug-shell.service" /lib/systemd/system/debug-shell.service
# rd.systemd.break (default)
: "debug-shell: initrd + rd.systemd.break"
CMDLINE="$CMDLINE rd.systemd.break"
SYSTEMD_IN_INITRD=1 SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-switch-root.service" /lib/systemd/system/breakpoint-pre-switch-root.service
# rd.systemd.break=pre-udev
: "debug-shell: initrd + rd.systemd.break=pre-udev"
CMDLINE="$CMDLINE rd.systemd.break=pre-udev"
SYSTEMD_IN_INITRD=1 SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-udev.service" /lib/systemd/system/breakpoint-pre-udev.service
# rd.systemd.break=pre-basic
: "debug-shell: initrd + rd.systemd.break=pre-basic"
CMDLINE="$CMDLINE rd.systemd.break=pre-basic"
SYSTEMD_IN_INITRD=1 SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-basic.service" /lib/systemd/system/breakpoint-pre-basic.service
# rd.systemd.break=pre-mount
: "debug-shell: initrd + rd.systemd.break=pre-mount"
CMDLINE="$CMDLINE rd.systemd.break=pre-mount"
SYSTEMD_IN_INITRD=1 SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-mount.service" /lib/systemd/system/breakpoint-pre-mount.service
# rd.systemd.break=pre-switch-root
: "debug-shell: initrd + rd.systemd.break=pre-switch-root"
rm -f "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-switch-root.service"
CMDLINE="$CMDLINE rd.systemd.break=pre-switch-root"
SYSTEMD_IN_INITRD=1 SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-switch-root.service" /lib/systemd/system/breakpoint-pre-switch-root.service
# rd.systemd.break=pre-udev,pre-basic,pre-mount,pre-switch-root
: "debug-shell: initrd + rd.systemd.break=pre-udev,pre-mount,pre-switch-root"
rm -f "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-udev.service"
rm -f "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-basic.service"
rm -f "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-mount.service"
rm -f "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-switch-root.service"
CMDLINE="$CMDLINE rd.systemd.break=pre-udev,pre-basic,pre-mount,pre-switch-root"
SYSTEMD_IN_INITRD=1 SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-udev.service" /lib/systemd/system/breakpoint-pre-udev.service
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-basic.service" /lib/systemd/system/breakpoint-pre-basic.service
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-mount.service" /lib/systemd/system/breakpoint-pre-mount.service
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-switch-root.service" /lib/systemd/system/breakpoint-pre-switch-root.service
# Override the default target
: "debug-shell: initrd + rd.systemd.unit"
CMDLINE="$CMDLINE rd.systemd.unit=my-fancy-initrd.target"

View File

@ -0,0 +1,35 @@
# 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=Breakpoint Before Basic System
Documentation=man:systemd-debug-generator(8)
DefaultDependencies=no
Conflicts=shutdown.target emergency.target
After=sysinit.target sockets.target paths.target slices.target tmp.mount systemd-vconsole-setup.service
Before=basic.target
[Service]
Environment=SHELL_PROMPT_PREFIX="pre-basic "
Type=oneshot
ExecStartPre=-plymouth --wait quit
# Execute shell with "-" prefix to not consider the unit failed if it exits with
# a non-zero value
ExecStart=-{{SUSHELL}}
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
KillMode=process
IgnoreSIGPIPE=no
# bash ignores SIGTERM
KillSignal=SIGHUP
# Unset locale for the console getty since the console has problems
# displaying some internationalized messages.
UnsetEnvironment=LANG LANGUAGE LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION

View File

@ -0,0 +1,36 @@
# 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=Breakpoint Before Mounting the Root Filesystem on /sysroot
Documentation=man:systemd-debug-generator(8)
AssertPathExists=/etc/initrd-release
DefaultDependencies=no
Conflicts=shutdown.target emergency.target
After=basic.target systemd-vconsole-setup.service
Before=initrd-root-fs.target sysroot.mount systemd-fsck-root.service
[Service]
Environment=SHELL_PROMPT_PREFIX="pre-mount "
Type=oneshot
ExecStartPre=-plymouth --wait quit
# Execute shell with "-" prefix to not consider the unit failed if it exits with
# a non-zero value
ExecStart=-{{SUSHELL}}
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
KillMode=process
IgnoreSIGPIPE=no
# bash ignores SIGTERM
KillSignal=SIGHUP
# Unset locale for the console getty since the console has problems
# displaying some internationalized messages.
UnsetEnvironment=LANG LANGUAGE LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION

View File

@ -0,0 +1,37 @@
# 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=Breakpoint Before Switching Root
Documentation=man:systemd-debug-generator(8)
AssertPathExists=/etc/initrd-release
DefaultDependencies=no
Conflicts=shutdown.target emergency.target
Wants=remote-fs.target
After=initrd.target initrd-parse-etc.service sysroot.mount remote-fs.target systemd-vconsole-setup.service
Before=initrd-cleanup.service
[Service]
Environment=SHELL_PROMPT_PREFIX="pre-switch-root "
Type=oneshot
ExecStartPre=-plymouth --wait quit
# Execute shell with "-" prefix to not consider the unit failed if it exits with
# a non-zero value
ExecStart=-{{SUSHELL}}
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
KillMode=process
IgnoreSIGPIPE=no
# bash ignores SIGTERM
KillSignal=SIGHUP
# Unset locale for the console getty since the console has problems
# displaying some internationalized messages.
UnsetEnvironment=LANG LANGUAGE LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION

View File

@ -0,0 +1,36 @@
# 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=Breakpoint Before Starting to Process Kernel uevents
Documentation=man:systemd-debug-generator(8)
DefaultDependencies=no
Conflicts=shutdown.target emergency.target
Wants=systemd-journald.socket
After=systemd-journald.socket systemd-vconsole-setup.service
Before=systemd-udevd.service systemd-udev-trigger.service
[Service]
Environment=SHELL_PROMPT_PREFIX="pre-udev "
Type=oneshot
ExecStartPre=-plymouth --wait quit
# Execute shell with "-" prefix to not consider the unit failed if it exits with
# a non-zero value
ExecStart=-{{SUSHELL}}
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
KillMode=process
IgnoreSIGPIPE=no
# bash ignores SIGTERM
KillSignal=SIGHUP
# Unset locale for the console getty since the console has problems
# displaying some internationalized messages.
UnsetEnvironment=LANG LANGUAGE LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION

View File

@ -7,6 +7,10 @@ units = [
{ 'file' : 'blockdev@.target' },
{ 'file' : 'bluetooth.target' },
{ 'file' : 'boot-complete.target' },
{ 'file' : 'breakpoint-pre-basic.service.in' },
{ 'file' : 'breakpoint-pre-mount.service.in' },
{ 'file' : 'breakpoint-pre-switch-root.service.in' },
{ 'file' : 'breakpoint-pre-udev.service.in' },
{ 'file' : 'capsule@.service.in' },
{ 'file' : 'capsule.slice' },
{ 'file' : 'console-getty.service.in' },