diff --git a/.github/workflows/mkosi.yml b/.github/workflows/mkosi.yml
index c4908542112..f3dba761589 100644
--- a/.github/workflows/mkosi.yml
+++ b/.github/workflows/mkosi.yml
@@ -82,6 +82,9 @@ jobs:
- name: Configure
run: |
+ # mkosi GHA clones and builds from main but tools are not compatible with this branch, 24.04 ships 255 which is enough
+ sudo apt install --reinstall systemd systemd-container systemd-boot systemd-ukify
+
tee mkosi.local.conf <<- EOF
[Distribution]
Distribution=${{ matrix.distro }}
@@ -128,8 +131,6 @@ jobs:
ExecStart=false
EOF
cp mkosi.images/initrd/mkosi.extra/usr/lib/systemd/system/emergency.service.d/poweroff.conf mkosi.images/system/mkosi.extra/usr/lib/systemd/system/emergency.service.d/poweroff.conf
- sudo ln -svf "$(dirname "$(readlink /usr/bin/bootctl)")/systemd-keyutil" /usr/lib/systemd/systemd-keyutil
- /usr/lib/systemd/systemd-keyutil --version
- name: Generate secure boot key
run: mkosi --debug genkey
diff --git a/docs/MEMORY_PRESSURE.md b/docs/MEMORY_PRESSURE.md
index 38f1c645c9f..204a42e59aa 100644
--- a/docs/MEMORY_PRESSURE.md
+++ b/docs/MEMORY_PRESSURE.md
@@ -16,7 +16,7 @@ it can attempt various things to make more memory available again ("reclaim"):
pages are the many memory mapped executable files and shared libraries on
disk, among others.
-* The kernel can flush out memory packages not backed by files on disk
+* The kernel can flush out memory pages not backed by files on disk
("anonymous" memory, i.e. memory allocated via `malloc()` and similar calls,
or `tmpfs` file system contents) if there's swap to write it to.
diff --git a/man/common-variables.xml b/man/common-variables.xml
index 1aa31e1363a..37930781abd 100644
--- a/man/common-variables.xml
+++ b/man/common-variables.xml
@@ -91,17 +91,22 @@
$SYSTEMD_PAGER
+ $PAGER
- Pager to use when is not given; overrides
- $PAGER. If neither $SYSTEMD_PAGER nor $PAGER are set, a
- set of well-known pager implementations are tried in turn, including
- less1 and
- more1, until one is found. If
- no pager implementation is discovered no pager is invoked. Setting this environment variable to an empty string
- or the value cat is equivalent to passing .
+ Pager to use when is not given.
+ $SYSTEMD_PAGER is used if set; otherwise $PAGER is used.
+ If neither $SYSTEMD_PAGER nor $PAGER are set, a set of well-known
+ pager implementations is tried in turn, including
+ less1
+ and
+ more1,
+ until one is found. If no pager implementation is discovered, no pager is invoked. Setting those
+ environment variables to an empty string or the value cat is equivalent to passing
+ .Note: if $SYSTEMD_PAGERSECURE is not set, $SYSTEMD_PAGER
- (as well as $PAGER) will be silently ignored.
+ and $PAGER can only be used to disable the pager (with cat or
+ ), and are otherwise ignored.
@@ -158,28 +163,53 @@
$SYSTEMD_PAGERSECURE
- Takes a boolean argument. When true, the "secure" mode of the pager is enabled; if
- false, disabled. If $SYSTEMD_PAGERSECURE is not set at all, secure mode is enabled
- if the effective UID is not the same as the owner of the login session, see
- geteuid2
- and sd_pid_get_owner_uid3.
- In secure mode, will be set when invoking the pager, and the pager shall
- disable commands that open or create new files or start new subprocesses. When
- $SYSTEMD_PAGERSECURE is not set at all, pagers which are not known to implement
- secure mode will not be used. (Currently only
- less1
- implements secure mode.)
-
- Note: when commands are invoked with elevated privileges, for example under
+ Common pager commands like less1, in
+ addition to "paging", i.e. scrolling through the output, support opening of or writing to other files
+ and running arbitrary shell commands. When commands are invoked with elevated privileges, for example
+ under sudo8 or
pkexec1, care
- must be taken to ensure that unintended interactive features are not enabled. "Secure" mode for the
- pager may be enabled automatically as describe above. Setting SYSTEMD_PAGERSECURE=0
- or not removing it from the inherited environment allows the user to invoke arbitrary commands. Note
- that if the $SYSTEMD_PAGER or $PAGER variables are to be
- honoured, $SYSTEMD_PAGERSECURE must be set too. It might be reasonable to completely
- disable the pager using instead.
+ project='die-net'>pkexec1, the
+ pager becomes a security boundary. Care must be taken that only programs with strictly limited
+ functionality are used as pagers, and unintended interactive features like opening or creation of new
+ files or starting of subprocesses are not allowed. "Secure mode" for the pager may be enabled as
+ described below, if the pager supports that (most pagers are not written in a way
+ that takes this into consideration). It is recommended to either explicitly enable "secure mode" or to
+ completely disable the pager using or PAGER=cat when
+ allowing untrusted users to execute commands with elevated privileges.
+
+ This option takes a boolean argument. When set to true, the "secure mode" of the pager is
+ enabled. In "secure mode", will be set when invoking the pager, which
+ instructs the pager to disable commands that open or create new files or start new subprocesses.
+ Currently only less1 is known
+ to understand this variable and implement "secure mode".
+
+ When set to false, no limitation is placed on the pager. Setting
+ SYSTEMD_PAGERSECURE=0 or not removing it from the inherited environment may allow
+ the user to invoke arbitrary commands.
+
+ When $SYSTEMD_PAGERSECURE is not set, systemd tools attempt to automatically
+ figure out if "secure mode" should be enabled and whether the pager supports it. "Secure mode" is
+ enabled if the effective UID is not the same as the owner of the login session, see
+ geteuid2
+ and
+ sd_pid_get_owner_uid3,
+ or when running under
+ sudo8 or similar
+ tools ($SUDO_UID is set
+ It is recommended for other tools to set and check $SUDO_UID as appropriate,
+ treating it is a common interface.). In those cases,
+ SYSTEMD_PAGERSECURE=1 will be set and pagers which are not known to implement
+ "secure mode" will not be used at all. Note that this autodetection only covers the most common
+ mechanisms to elevate privileges and is intended as convenience. It is recommended to explicitly set
+ $SYSTEMD_PAGERSECURE or disable the pager.
+
+ Note that if the $SYSTEMD_PAGER or $PAGER variables are to
+ be honoured, other than to disable the pager, $SYSTEMD_PAGERSECURE must be set
+ too.
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index e1aee5a6a13..19bf7a4d600 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -8658,7 +8658,7 @@ node /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer {
elapsation point on the CLOCK_REALTIME clock, relative to its epoch.
NextElapseUSecRealtime contains the next elapsation point on the
- CLOCK_REALTIME clock in miscroseconds since the epoch, or 0 if this timer event
+ CLOCK_REALTIME clock in microseconds since the epoch, or 0 if this timer event
does not include at least one calendar event.Similarly, NextElapseUSecMonotonic contains the next elapsation point on the
diff --git a/man/sd_bus_emit_signal.xml b/man/sd_bus_emit_signal.xml
index 7444e1249c6..10c1af165d9 100644
--- a/man/sd_bus_emit_signal.xml
+++ b/man/sd_bus_emit_signal.xml
@@ -91,7 +91,7 @@
int sd_bus_emit_interfaces_added_strvsd_bus *busconst char *path
- const char **interfaces
+ char **interfaces
@@ -106,7 +106,7 @@
int sd_bus_emit_interfaces_removed_strvsd_bus *busconst char *path
- const char **interfaces
+ char **interfaces
@@ -123,7 +123,7 @@
sd_bus *busconst char *pathconst char *interface
- const char **names
+ char **names
diff --git a/man/sd_bus_slot_set_floating.xml b/man/sd_bus_slot_set_floating.xml
index df2cbc6fba2..bf0d089ef9d 100644
--- a/man/sd_bus_slot_set_floating.xml
+++ b/man/sd_bus_slot_set_floating.xml
@@ -51,8 +51,8 @@
referenced bus slot object around. The floating state hence controls the direction of referencing between the bus
object and the bus slot objects: if floating the bus pins the bus slot, and otherwise the bus slot pins the bus
objects. Use sd_bus_slot_set_floating() to switch between both modes: if the
- b parameter is zero, the slot object is considered floating, otherwise it is made a regular
- (non-floating) slot object.
+ b parameter is zero, the slot object is made into a regular (non-floating) slot object,
+ otherwise it is made into a floating slot object.
Bus slot objects may be allocated with calls such as
sd_bus_add_match3. If the
diff --git a/man/sd_notify.xml b/man/sd_notify.xml
index aa07599fd8e..0afd30a23c3 100644
--- a/man/sd_notify.xml
+++ b/man/sd_notify.xml
@@ -466,6 +466,26 @@
successfully. Specifically, no error is returned when a file descriptor is attempted to be stored using
FDSTORE=1 but the service is not actually configured to permit storing of file
descriptors (see above).
+
+
+ Errors
+
+ Returned errors may indicate the following problems:
+
+
+
+ -E2BIG
+
+ More file descriptors passed at once than the system allows. On Linux the number of
+ file descriptors that may be passed across AF_UNIX sockets at once is 253, see
+ unix7 for
+ details.
+
+
+
+
+
diff --git a/man/systemctl.xml b/man/systemctl.xml
index 9d212e17e3a..cedd3f9b630 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -163,10 +163,9 @@ PATH CONDITION UNIT
shown. Produces output similar to
LISTEN UNIT ACTIVATES
-/dev/initctl systemd-initctl.socket systemd-initctl.service
-…
-[::]:22 sshd.socket sshd.service
kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
+/dev/rfkill systemd-rfkill.socket systemd-rfkill.service
+…
5 sockets listed.
Note: because the addresses might contains spaces, this output
@@ -555,7 +554,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
clean PATTERN…
- Remove the configuration, state, cache, logs or runtime data of the specified units. Use
+ Remove the configuration, state, cache, logs, runtime or file descriptor store data of the specified units. Use
to select which kind of resource to remove. For service units this may
be used to remove the directories configured with ConfigurationDirectory=,
StateDirectory=, CacheDirectory=,
@@ -570,7 +569,8 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
command only applies to units that use either of these settings. If is
not specified, the cache and runtime data as well as the file descriptor store are removed (as
these three types of resources are generally redundant and reproducible on the next invocation of
- the unit). Note that the specified units must be stopped to invoke this operation.
+ the unit). Multiple values can be seperated by commas. Note that the specified units must be stopped
+ to invoke this operation.
@@ -939,7 +939,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
preset UNIT…
- Reset the enable/disable status one or more unit files, as specified on
+ Reset the enable/disable status of one or more unit files, as specified on
the command line, to the defaults configured in the preset policy files. This
has the same effect as disable or
enable, depending how the unit is listed in the preset
diff --git a/man/systemd-networkd.service.xml b/man/systemd-networkd.service.xml
index 12cd4c331bd..ed886c8aa7c 100644
--- a/man/systemd-networkd.service.xml
+++ b/man/systemd-networkd.service.xml
@@ -33,12 +33,16 @@
manages networks. It detects and configures network devices as
they appear, as well as creating virtual network devices.
- To configure low-level link settings independently of
- networks, see
- systemd.link5.
-
- systemd-networkd will create network devices based
- on the configuration in
+ Certain low-level settings of physical network devices (e.g. device
+ names and altnames) as well as the creation of SR-IOV virtual functions on
+ physical network interfaces may be managed by
+ systemd-udevd8
+ according to the contents of
+ systemd.link5
+ files.
+
+ systemd-networkd will create "virtual" network
+ devices (e.g. bridges and tunnels) based on the configuration in
systemd.netdev5
files, respecting the [Match] sections in those files.
@@ -47,10 +51,10 @@
with an appropriate [Match] section, see
systemd.network5.
For those links, it will flush existing network addresses and routes when
- bringing up the device. Any links not matched by one of the
- .network files will be ignored. It is also possible to
- explicitly tell systemd-networkd to ignore a link by
- using Unmanaged=yes option, see
+ bringing up the device (except when directed not to). Any links not matched
+ by one of the .network files will be ignored. It is
+ also possible to explicitly tell systemd-networkd to
+ ignore a link by using the Unmanaged=yes option, see
systemd.network5.
diff --git a/man/systemd-remount-fs.service.xml b/man/systemd-remount-fs.service.xml
index 266db884614..4c772fb0346 100644
--- a/man/systemd-remount-fs.service.xml
+++ b/man/systemd-remount-fs.service.xml
@@ -51,7 +51,7 @@
Note: systemd-remount-fs.service is usually pulled in by
systemd-fstab-generator8,
hence it is also affected by the kernel command line option fstab=, which may be used
- to disable the generator. It may also pulled in by
+ to disable the generator. It may also be pulled in by
systemd-gpt-auto-generator8,
which is affected by systemd.gpt_auto and other options.
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index b75626f1d8f..7971951514a 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -2094,28 +2094,36 @@ BindReadOnlyPaths=/var/lib/systemd
allow-list, such as AF_UNIX, AF_INET or
AF_INET6. When none is specified, then all address
families will be denied. When prefixed with ~ the listed address
- families will be applied as deny list, otherwise as allow list. Note that this restricts access
- to the
- socket2
+ families will be applied as deny list, otherwise as allow list.
+
+ By default, no restrictions apply, all address families are accessible to processes. If
+ assigned the empty string, any previous address family restriction changes are undone. This setting
+ does not affect commands prefixed with +.
+
+ Use this option to limit exposure of processes to remote access, in particular via exotic and
+ sensitive network protocols, such as AF_PACKET. Note that in most cases, the
+ local AF_UNIX address family should be included in the configured allow list as
+ it is frequently used for local communication, including for
+ syslog2
+ logging.
+
+ Note that this restricts access to the socket2
system call only. Sockets passed into the process by other means (for example, by using socket
activation with socket units, see
systemd.socket5)
are unaffected. Also, sockets created with socketpair() (which creates connected
- AF_UNIX sockets only) are unaffected. Note that this option has no effect on 32-bit x86, s390, s390x,
- mips, mips-le, ppc, ppc-le, ppc64, ppc64-le and is ignored (but works correctly on other ABIs,
- including x86-64). Note that on systems supporting multiple ABIs (such as x86/x86-64) it is
- recommended to turn off alternative ABIs for services, so that they cannot be used to circumvent the
- restrictions of this option. Specifically, it is recommended to combine this option with
- SystemCallArchitectures=native or similar. By default, no restrictions apply, all
- address families are accessible to processes. If assigned the empty string, any previous address family
- restriction changes are undone. This setting does not affect commands prefixed with +.
-
- Use this option to limit exposure of processes to remote access, in particular via exotic and sensitive
- network protocols, such as AF_PACKET. Note that in most cases, the local
- AF_UNIX address family should be included in the configured allow list as it is frequently
- used for local communication, including for
- syslog2
- logging.
+ AF_UNIX sockets) or the
+ io_uring7
+ functions, are not affected. Thus, it is recommended to combined this setting with
+ SystemCallFilter=@service, to only allow a limited subset of system calls.
+
+ Note that this option is limited to some ABIs, in particular x86-64, but currently has no
+ effect on 32-bit x86, s390, s390x, mips, mips-le, ppc, ppc-le, ppc64, or ppc64-le, and is ignored. On
+ systems supporting multiple ABIs (such as x86/x86-64) it is recommended to turn off alternative ABIs
+ for services, so that they cannot be used to circumvent the restrictions of this option.
+ Specifically, it is recommended to combine this option with
+ SystemCallArchitectures=native or similar.
@@ -2424,40 +2432,42 @@ RestrictNamespaces=~cgroup net
SystemCallFilter=
- Takes a space-separated list of system call names. If this setting is used, all
- system calls executed by the unit processes except for the listed ones will result in immediate
- process termination with the SIGSYS signal (allow-listing). (See
- SystemCallErrorNumber= below for changing the default action). If the first
- character of the list is ~, the effect is inverted: only the listed system calls
- will result in immediate process termination (deny-listing). Deny-listed system calls and system call
- groups may optionally be suffixed with a colon (:) and errno
- error number (between 0 and 4095) or errno name such as EPERM,
- EACCES or EUCLEAN (see errno3 for a
- full list). This value will be returned when a deny-listed system call is triggered, instead of
- terminating the processes immediately. Special setting kill can be used to
- explicitly specify killing. This value takes precedence over the one given in
- SystemCallErrorNumber=, see below. This feature makes use of the Secure Computing Mode 2
- interfaces of the kernel ('seccomp filtering') and is useful for enforcing a minimal sandboxing environment.
- Note that the execve(), exit(), exit_group(),
- getrlimit(), rt_sigreturn(), sigreturn()
- system calls and the system calls for querying time and sleeping are implicitly allow-listed and do not
- need to be listed explicitly. This option may be specified more than once, in which case the filter masks are
+ Takes a space-separated list of system call names or system call groups. If this
+ setting is used, system calls executed by the unit processes except for the listed ones will result
+ in the system call being denied (allow-listing). If the first character of the list is
+ ~, the effect is inverted: only the listed system calls will be denied
+ (deny-listing). This option may be specified more than once, in which case the filter masks are
merged. If the empty string is assigned, the filter is reset, all prior assignments will have no
- effect. This does not affect commands prefixed with +.
-
- Note that on systems supporting multiple ABIs (such as x86/x86-64) it is recommended to turn off
- alternative ABIs for services, so that they cannot be used to circumvent the restrictions of this
+ effect.
+
+ Commands prefixed with + are not subject to filtering. The
+ execve(), exit(), exit_group(),
+ getrlimit(), rt_sigreturn(),
+ sigreturn() system calls and the system calls for querying time and sleeping are
+ implicitly allow-listed and do not need to be listed explicitly.
+
+ The default action when a system call is denied is to terminate the processes with a
+ SIGSYS signal. This can changed using SystemCallErrorNumber=,
+ see below. In addition, deny-listed system calls and system call groups may optionally be suffixed
+ with a colon (:) and an argument in the same format as
+ SystemCallErrorNumber=, to take this action when the matching system call is made.
+ This takes precedence over the action specified in SystemCallErrorNumber=.
+
+ This feature makes use of the Secure Computing Mode 2 interfaces of the kernel ('seccomp
+ filtering') and is useful for enforcing a minimal sandboxing environment.
+
+ Note that on systems supporting multiple ABIs (such as x86/x86-64) it is recommended to turn
+ off alternative ABIs for services, so that they cannot be used to circumvent the restrictions of this
option. Specifically, it is recommended to combine this option with
SystemCallArchitectures=native or similar.
- Note that strict system call filters may impact execution and error handling code paths of the service
- invocation. Specifically, access to the execve() system call is required for the execution
- of the service binary — if it is blocked service invocation will necessarily fail. Also, if execution of the
- service binary fails for some reason (for example: missing service executable), the error handling logic might
- require access to an additional set of system calls in order to process and log this failure correctly. It
- might be necessary to temporarily disable system call filters in order to simplify debugging of such
- failures.
+ Note that strict system call filters may impact execution and error handling code paths of the
+ service invocation. Specifically, access to the execve() system call is required
+ for the execution of the service binary — if it is blocked service invocation will necessarily fail.
+ Also, if execution of the service binary fails for some reason (for example: missing service
+ executable), the error handling logic might require access to an additional set of system calls in
+ order to process and log this failure correctly. It might be necessary to temporarily disable system
+ call filters in order to allow debugging of such failures.If you specify both types of this option (i.e. allow-listing and deny-listing), the first
encountered will take precedence and will dictate the default action (termination or approval of a
@@ -2467,8 +2477,8 @@ RestrictNamespaces=~cgroup net
write(), and right after it add a deny list rule for write(),
then write() will be removed from the set.)
- As the number of possible system calls is large, predefined sets of system calls are provided. A set
- starts with @ character, followed by name of the set.
+ As the number of possible system calls is large, predefined groups of system calls are
+ provided. A group starts with @ character, followed by name of the set.
Currently predefined system call sets
diff --git a/man/systemd.link.xml b/man/systemd.link.xml
index 063f8e3566f..30f69bee6c3 100644
--- a/man/systemd.link.xml
+++ b/man/systemd.link.xml
@@ -33,6 +33,11 @@
systemd.syntax7 for a
general description of the syntax.
+ Note that some distributions may incorporate .link files in their early boot
+ facilities (e.g. by including copies of the .link files in initramfs). As such it
+ may be necessary to take manual steps to ensure that any local changes are consistent with early-boot
+ storage facilities. The relevant distribution-specific documentation should be consulted.
+
The .link files are read from the files located in the system network
directory /usr/lib/systemd/network and
/usr/local/lib/systemd/network, the volatile runtime network directory
@@ -1155,11 +1160,18 @@
[SR-IOV] Section Options
- The [SR-IOV] section accepts the following keys. Specify several [SR-IOV] sections to
- configure several SR-IOVs. SR-IOV provides the ability to partition a single physical PCI resource
- into virtual PCI functions which can then be injected into a VM. In the case of network VFs, SR-IOV
- improves north-south network performance (that is, traffic with endpoints outside the host machine)
- by allowing traffic to bypass the host machine’s network stack.
+ SR-IOV provides the ability to partition a single physical PCI resource into virtual PCI
+ functions which can then be e.g. injected into a VM. In the case of network VFs, SR-IOV reduces
+ latency and CPU utilisation for north-south network traffic (that is, traffic with endpoints
+ outside the host machine), by allowing traffic to bypass the host machine’s network stack.
+
+
+ The presence of an [SR-IOV] section in a .link file will cause the creation and
+ configuration of the specified virtual function. Within a .network file, the specified virtual
+ function will be configured, but must already exist. Specify several [SR-IOV] sections to
+ configure several SR-IOVs.
+
+ The [SR-IOV] section accepts the following keys.
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 7b72a1eba10..b529988635a 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -37,6 +37,14 @@
The main network file must have the extension .network; other
extensions are ignored. Networks are applied to links whenever the links appear.
+ Note that not all settings and configurations can be made with .network
+ files, and that it may be necessary to use
+ systemd.link5)
+ or
+ systemd.netdev5)
+ files in conjuction with .network files when working with physical and virtual
+ network devices respectively.
+
The .network files are read from the files located in the system network
directories /usr/lib/systemd/network and
/usr/local/lib/systemd/network, the volatile runtime network directory
diff --git a/man/systemd.swap.xml b/man/systemd.swap.xml
index 1c019b26d80..edbd2dcb6a2 100644
--- a/man/systemd.swap.xml
+++ b/man/systemd.swap.xml
@@ -72,7 +72,7 @@
All swap units automatically get the
- BindsTo= and After=
+ Requires= and After=
dependencies on the device units or the mount units of the files
they are activated from.
diff --git a/man/systemd.xml b/man/systemd.xml
index 229ef0aa32c..4205c09dd1a 100644
--- a/man/systemd.xml
+++ b/man/systemd.xml
@@ -1055,12 +1055,9 @@
5Boot into the specified legacy SysV runlevel.
- These are equivalent to
- systemd.unit=runlevel2.target,
- systemd.unit=runlevel3.target,
- systemd.unit=runlevel4.target, and
- systemd.unit=runlevel5.target,
- respectively, and provided for compatibility reasons and to be
+ 2, 3, and 4 are equivalent to
+ systemd.unit=multi-user.target; and 5 is equivalent to
+ systemd.unit=graphical.target, and provided for compatibility reasons and to be
easier to type.
diff --git a/man/timedatectl.xml b/man/timedatectl.xml
index f06441bfbe3..df9719cb238 100644
--- a/man/timedatectl.xml
+++ b/man/timedatectl.xml
@@ -78,10 +78,10 @@
set-time [TIME]
- Set the system clock to the specified time.
- This will also update the RTC time accordingly. The time may
- be specified in the format "2012-10-30
- 18:17:16".
+ Set the system clock to the specified timestamp. This will also update the RTC time
+ accordingly. The timestamp may be specified in the format 2012-10-30 18:17:16. See
+ systemd.time7
+ for more details about acceptable timestamp format.
diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in
index 54e34a1781e..2924dd229d0 100644
--- a/shell-completion/zsh/_systemctl.in
+++ b/shell-completion/zsh/_systemctl.in
@@ -412,7 +412,7 @@ for fun in set-environment unset-environment ; do
suf='-S='
fi
_wanted systemd-environment expl 'environment variable' \
- compadd "$@" ${suf} - ${${(f)"$(systemctl show-environment)"}%%=*}
+ compadd "$@" ${suf} - ${${(f)"$(systemctl "$_sys_service_mgr" show-environment)"}%%=*}
}
done
diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c
index d3fef01febf..833cc183403 100644
--- a/src/basic/locale-util.c
+++ b/src/basic/locale-util.c
@@ -97,7 +97,6 @@ static int add_locales_from_archive(Set *locales) {
const struct namehashent *e;
const void *p = MAP_FAILED;
_cleanup_close_ int fd = -EBADF;
- size_t sz = 0;
struct stat st;
int r;
@@ -154,9 +153,9 @@ static int add_locales_from_archive(Set *locales) {
r = 0;
- finish:
+finish:
if (p != MAP_FAILED)
- munmap((void*) p, sz);
+ munmap((void*) p, st.st_size);
return r;
}
diff --git a/src/basic/log.h b/src/basic/log.h
index 76c188dcd37..115fbec3027 100644
--- a/src/basic/log.h
+++ b/src/basic/log.h
@@ -97,8 +97,8 @@ int log_dispatch_internal(
const char *func,
const char *object_field,
const char *object,
- const char *extra,
const char *extra_field,
+ const char *extra,
char *buffer);
int log_internal(
diff --git a/src/basic/missing_socket.h b/src/basic/missing_socket.h
index 30ac297e171..c4b124c8dd9 100644
--- a/src/basic/missing_socket.h
+++ b/src/basic/missing_socket.h
@@ -79,3 +79,10 @@ struct sockaddr_vm {
#ifndef SIOCGSKNS
#define SIOCGSKNS 0x894C
#endif
+
+/* The maximum number of fds that SCM_RIGHTS accepts. This is an internal kernel constant, but very much
+ * useful for userspace too. It's documented in unix(7) these days, hence should be fairly reliable to define
+ * here. */
+#ifndef SCM_MAX_FD
+#define SCM_MAX_FD 253U
+#endif
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index beb64d8e6c7..ad75b3708b7 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -1281,6 +1282,54 @@ int flush_accept(int fd) {
}
}
+ssize_t flush_mqueue(int fd) {
+ _cleanup_free_ char *buf = NULL;
+ struct mq_attr attr;
+ ssize_t count = 0;
+ int r;
+
+ assert(fd >= 0);
+
+ /* Similar to flush_fd() but flushes all messages from a POSIX message queue. */
+
+ for (;;) {
+ ssize_t l;
+
+ r = fd_wait_for_event(fd, POLLIN, /* timeout= */ 0);
+ if (r < 0) {
+ if (r == -EINTR)
+ continue;
+
+ return r;
+ }
+ if (r == 0)
+ return count;
+
+ if (!buf) {
+ /* Buffer must be at least as large as mq_msgsize. */
+ if (mq_getattr(fd, &attr) < 0)
+ return -errno;
+
+ buf = malloc(attr.mq_msgsize);
+ if (!buf)
+ return -ENOMEM;
+ }
+
+ l = mq_receive(fd, buf, attr.mq_msgsize, /* msg_prio = */ NULL);
+ if (l < 0) {
+ if (errno == EINTR)
+ continue;
+
+ if (errno == EAGAIN)
+ return count;
+
+ return -errno;
+ }
+
+ count += l;
+ }
+}
+
struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length) {
struct cmsghdr *cmsg;
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
index 9a11df834d1..b3f2e3641ae 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -195,6 +195,7 @@ int receive_many_fds(int transport_fd, int **ret_fds_array, size_t *ret_n_fds_ar
ssize_t next_datagram_size_fd(int fd);
int flush_accept(int fd);
+ssize_t flush_mqueue(int fd);
#define CMSG_FOREACH(cmsg, mh) \
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
diff --git a/src/basic/time-util.h b/src/basic/time-util.h
index ed4c1aabd48..14f8e904a87 100644
--- a/src/basic/time-util.h
+++ b/src/basic/time-util.h
@@ -219,8 +219,8 @@ static inline int usleep_safe(usec_t usec) {
* ⚠️ Note we are not using plain nanosleep() here, since that operates on CLOCK_REALTIME, not
* CLOCK_MONOTONIC! */
- // FIXME: use RET_NERRNO() macro here. Currently, this header cannot include errno-util.h.
- return clock_nanosleep(CLOCK_MONOTONIC, 0, TIMESPEC_STORE(usec), NULL) < 0 ? -errno : 0;
+ /* `clock_nanosleep()` does not use `errno`, but returns positive error codes. */
+ return -clock_nanosleep(CLOCK_MONOTONIC, 0, TIMESPEC_STORE(usec), NULL);
}
/* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit
diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c
index 01cb896a442..794ef45f36b 100644
--- a/src/busctl/busctl.c
+++ b/src/busctl/busctl.c
@@ -2161,6 +2161,13 @@ static int get_property(int argc, char **argv, void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
+ if (!service_name_is_valid(argv[1]))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name: %s", argv[1]);
+ if (!object_path_is_valid(argv[2]))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid object path: %s", argv[2]);
+ if (!interface_name_is_valid(argv[3]))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name: %s", argv[3]);
+
r = acquire_bus(false, &bus);
if (r < 0)
return r;
@@ -2230,6 +2237,13 @@ static int set_property(int argc, char **argv, void *userdata) {
char **p;
int r;
+ if (!service_name_is_valid(argv[1]))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name: %s", argv[1]);
+ if (!object_path_is_valid(argv[2]))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid object path: %s", argv[2]);
+ if (!interface_name_is_valid(argv[3]))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name: %s", argv[3]);
+
r = acquire_bus(false, &bus);
if (r < 0)
return r;
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 61539afdbfc..d398655b0a6 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -52,6 +52,8 @@
* out specific attributes from us. */
#define LOG_LEVEL_CGROUP_WRITE(r) (IN_SET(abs(r), ENOENT, EROFS, EACCES, EPERM) ? LOG_DEBUG : LOG_WARNING)
+static void unit_remove_from_cgroup_empty_queue(Unit *u);
+
uint64_t cgroup_tasks_max_resolve(const CGroupTasksMax *tasks_max) {
if (tasks_max->scale == 0)
return tasks_max->value;
@@ -2674,6 +2676,10 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) {
else {
if (ret >= 0)
ret++; /* Count successful additions */
+
+ /* the cgroup is definitely not empty now, in case the unit was in
+ * the cgroup empty queue, drop it from there */
+ unit_remove_from_cgroup_empty_queue(u);
continue; /* When the bus thing worked via the bus we are fully done for this PID. */
}
}
@@ -2682,8 +2688,10 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) {
ret = r; /* Remember first error */
continue;
- } else if (ret >= 0)
+ } else if (ret >= 0) {
+ unit_remove_from_cgroup_empty_queue(u);
ret++; /* Count successful additions */
+ }
r = cg_all_unified();
if (r < 0)
diff --git a/src/core/core-varlink.c b/src/core/core-varlink.c
index 5cac0e2b068..a6789524323 100644
--- a/src/core/core-varlink.c
+++ b/src/core/core-varlink.c
@@ -506,7 +506,7 @@ static int manager_varlink_init_system(Manager *m) {
bool fresh = r > 0;
if (!MANAGER_IS_TEST_RUN(m)) {
- (void) mkdir_p_label("/run/systemd/userdb", 0755);
+ (void) mkdir_label("/run/systemd/userdb", 0755);
FOREACH_STRING(address, "/run/systemd/userdb/io.systemd.DynamicUser", VARLINK_ADDR_PATH_MANAGED_OOM_SYSTEM) {
if (!fresh) {
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 2d05ba7e1d2..71b07a6ec19 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -942,6 +942,23 @@ static int property_get_image_policy(
return sd_bus_message_append(reply, "s", s);
}
+static int property_get_unsigned_as_uint16(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ unsigned *value = ASSERT_PTR(userdata);
+
+ /* Returns an unsigned as a D-Bus "q" type, i.e. as 16-bit value, even if unsigned is 32-bit. We'll saturate if it doesn't fit. */
+
+ uint16_t q = *value >= UINT16_MAX ? UINT16_MAX : (uint16_t) *value;
+ return sd_bus_message_append_basic(reply, 'q', &q);
+}
+
const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1019,8 +1036,8 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("TTYReset", "b", bus_property_get_bool, offsetof(ExecContext, tty_reset), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TTYVHangup", "b", bus_property_get_bool, offsetof(ExecContext, tty_vhangup), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TTYVTDisallocate", "b", bus_property_get_bool, offsetof(ExecContext, tty_vt_disallocate), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TTYRows", "q", bus_property_get_unsigned, offsetof(ExecContext, tty_rows), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TTYColumns", "q", bus_property_get_unsigned, offsetof(ExecContext, tty_cols), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("TTYRows", "q", property_get_unsigned_as_uint16, offsetof(ExecContext, tty_rows), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("TTYColumns", "q", property_get_unsigned_as_uint16, offsetof(ExecContext, tty_cols), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 12d54351f8d..c7372ca0336 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -3016,7 +3016,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_WRITABLE_PROPERTY("ServiceWatchdogs", "b", bus_property_get_bool, bus_property_set_bool, offsetof(Manager, service_watchdogs), 0),
SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0),
SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0),
- SD_BUS_PROPERTY("ExitCode", "y", bus_property_get_unsigned, offsetof(Manager, return_value), 0),
+ SD_BUS_PROPERTY("ExitCode", "y", NULL, offsetof(Manager, return_value), 0),
SD_BUS_PROPERTY("DefaultTimerAccuracyUSec", "t", bus_property_get_usec, offsetof(Manager, defaults.timer_accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, defaults.timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, defaults.timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
diff --git a/src/core/dbus.c b/src/core/dbus.c
index b08e97f2e04..216526b8da4 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -33,7 +33,6 @@
#include "fd-util.h"
#include "fs-util.h"
#include "log.h"
-#include "mkdir-label.h"
#include "process-util.h"
#include "selinux-access.h"
#include "serialize.h"
@@ -966,7 +965,6 @@ int bus_init_private(Manager *m) {
return log_error_errno(r, "Can't set path for AF_UNIX socket to bind to: %m");
sa_len = r;
- (void) mkdir_parents_label(sa.un.sun_path, 0755);
(void) sockaddr_un_unlink(&sa.un);
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c
index 22bc8d10c1d..9d27280ed07 100644
--- a/src/core/exec-invoke.c
+++ b/src/core/exec-invoke.c
@@ -1900,7 +1900,9 @@ static int build_environment(
* could cause problem for e.g. getty, since login doesn't override $HOME, and $LOGNAME and $SHELL don't
* really make much sense since we're not logged in. Hence we conditionalize the three based on
* SetLoginEnvironment= switch. */
- if (!c->user && !c->dynamic_user && p->runtime_scope == RUNTIME_SCOPE_SYSTEM) {
+ if (!username && !c->dynamic_user && p->runtime_scope == RUNTIME_SCOPE_SYSTEM) {
+ assert(!c->user);
+
r = get_fixed_user("root", &username, NULL, NULL, &home, &shell);
if (r < 0)
return log_exec_debug_errno(c,
diff --git a/src/core/main.c b/src/core/main.c
index 8373a156cbe..364dc895d11 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1798,37 +1798,10 @@ static int do_reexecute(
assert(saved_rlimit_memlock);
assert(ret_error_message);
- if (switch_root_init) {
- r = chase(switch_root_init, switch_root_dir, CHASE_PREFIX_ROOT, NULL, NULL);
- if (r < 0)
- log_warning_errno(r, "Failed to chase configured init %s/%s: %m",
- strempty(switch_root_dir), switch_root_init);
- } else {
- r = chase(SYSTEMD_BINARY_PATH, switch_root_dir, CHASE_PREFIX_ROOT, NULL, NULL);
- if (r < 0)
- log_debug_errno(r, "Failed to chase our own binary %s/%s: %m",
- strempty(switch_root_dir), SYSTEMD_BINARY_PATH);
- }
-
- if (r < 0) {
- r = chase("/sbin/init", switch_root_dir, CHASE_PREFIX_ROOT, NULL, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to chase %s/sbin/init", strempty(switch_root_dir));
- }
-
/* Close and disarm the watchdog, so that the new instance can reinitialize it, but doesn't get
* rebooted while we do that */
watchdog_close(true);
- /* Reset RLIMIT_NOFILE + RLIMIT_MEMLOCK back to the kernel defaults, so that the new systemd can pass
- * the kernel default to its child processes */
- if (saved_rlimit_nofile->rlim_cur != 0)
- (void) setrlimit(RLIMIT_NOFILE, saved_rlimit_nofile);
- if (saved_rlimit_memlock->rlim_cur != RLIM_INFINITY)
- (void) setrlimit(RLIMIT_MEMLOCK, saved_rlimit_memlock);
-
- finish_remaining_processes(objective);
-
if (!switch_root_dir && objective == MANAGER_SOFT_REBOOT) {
/* If no switch root dir is specified, then check if /run/nextroot/ qualifies and use that */
r = path_is_os_tree("/run/nextroot");
@@ -1838,6 +1811,39 @@ static int do_reexecute(
switch_root_dir = "/run/nextroot";
}
+ if (switch_root_dir) {
+ /* If we're supposed to switch root, preemptively check the existence of a usable init.
+ * Otherwise the system might end up in a completely undebuggable state afterwards. */
+ if (switch_root_init) {
+ r = chase_and_access(switch_root_init, switch_root_dir, CHASE_PREFIX_ROOT, X_OK, /* ret_path = */ NULL);
+ if (r < 0)
+ log_warning_errno(r, "Failed to chase configured init %s/%s: %m",
+ switch_root_dir, switch_root_init);
+ } else {
+ r = chase_and_access(SYSTEMD_BINARY_PATH, switch_root_dir, CHASE_PREFIX_ROOT, X_OK, /* ret_path = */ NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to chase our own binary %s/%s: %m",
+ switch_root_dir, SYSTEMD_BINARY_PATH);
+ }
+
+ if (r < 0) {
+ r = chase_and_access("/sbin/init", switch_root_dir, CHASE_PREFIX_ROOT, X_OK, /* ret_path = */ NULL);
+ if (r < 0) {
+ *ret_error_message = "Switch root target contains no usable init";
+ return log_error_errno(r, "Failed to chase %s/sbin/init", switch_root_dir);
+ }
+ }
+ }
+
+ /* Reset RLIMIT_NOFILE + RLIMIT_MEMLOCK back to the kernel defaults, so that the new systemd can pass
+ * the kernel default to its child processes */
+ if (saved_rlimit_nofile->rlim_cur != 0)
+ (void) setrlimit(RLIMIT_NOFILE, saved_rlimit_nofile);
+ if (saved_rlimit_memlock->rlim_cur != RLIM_INFINITY)
+ (void) setrlimit(RLIMIT_MEMLOCK, saved_rlimit_memlock);
+
+ finish_remaining_processes(objective);
+
if (switch_root_dir) {
r = switch_root(/* new_root= */ switch_root_dir,
/* old_root_after= */ NULL,
@@ -1929,16 +1935,17 @@ static int do_reexecute(
ANSI_HIGHLIGHT_RED " !! " ANSI_NORMAL,
"Failed to execute /sbin/init");
- *ret_error_message = "Failed to execute fallback shell";
if (r == -ENOENT) {
- log_warning("No /sbin/init, trying fallback");
+ log_warning_errno(r, "No /sbin/init, trying fallback shell");
args[0] = "/bin/sh";
args[1] = NULL;
(void) execve(args[0], (char* const*) args, saved_env);
- return log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m");
- } else
- return log_error_errno(r, "Failed to execute /sbin/init, giving up: %m");
+ r = -errno;
+ }
+
+ *ret_error_message = "Failed to execute fallback shell";
+ return log_error_errno(r, "Failed to execute /bin/sh, giving up: %m");
}
static int invoke_main_loop(
@@ -2024,7 +2031,7 @@ static int invoke_main_loop(
log_notice("Reexecuting.");
- *ret_retval = EXIT_SUCCESS;
+ *ret_retval = EXIT_FAILURE;
*ret_switch_root_dir = *ret_switch_root_init = NULL;
return objective;
@@ -2047,7 +2054,7 @@ static int invoke_main_loop(
log_notice("Switching root.");
- *ret_retval = EXIT_SUCCESS;
+ *ret_retval = EXIT_FAILURE;
/* Steal the switch root parameters */
*ret_switch_root_dir = TAKE_PTR(m->switch_root);
@@ -2067,7 +2074,7 @@ static int invoke_main_loop(
log_notice("Soft-rebooting.");
- *ret_retval = EXIT_SUCCESS;
+ *ret_retval = EXIT_FAILURE;
*ret_switch_root_dir = TAKE_PTR(m->switch_root);
*ret_switch_root_init = NULL;
@@ -2788,7 +2795,7 @@ static int save_env(void) {
l = strv_copy(environ);
if (!l)
- return -ENOMEM;
+ return log_oom();
strv_free_and_replace(saved_env, l);
return 0;
@@ -2902,7 +2909,8 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (mac_init() < 0) {
+ r = mac_init();
+ if (r < 0) {
error_message = "Failed to initialize MAC support";
goto finish;
}
@@ -2977,7 +2985,8 @@ int main(int argc, char *argv[]) {
* operate. */
capability_ambient_set_apply(0, /* also_inherit= */ false);
- if (mac_init() < 0) {
+ r = mac_init();
+ if (r < 0) {
error_message = "Failed to initialize MAC support";
goto finish;
}
diff --git a/src/core/manager.c b/src/core/manager.c
index 3874586ebdc..9448cde3726 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -320,7 +320,7 @@ static int manager_check_ask_password(Manager *m) {
if (!m->ask_password_event_source) {
assert(m->ask_password_inotify_fd < 0);
- (void) mkdir_p_label("/run/systemd/ask-password", 0755);
+ (void) mkdir_label("/run/systemd/ask-password", 0755);
m->ask_password_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
if (m->ask_password_inotify_fd < 0)
@@ -1008,7 +1008,7 @@ int manager_new(RuntimeScope runtime_scope, ManagerTestRunFlags test_run_flags,
r = xdg_user_runtime_dir(&units_path, "/systemd/units");
if (r < 0)
return r;
- r = mkdir_p_label(units_path, 0755);
+ r = mkdir_label(units_path, 0755);
}
if (r < 0 && r != -EEXIST)
@@ -1090,7 +1090,6 @@ static int manager_setup_notify(Manager *m) {
m->notify_socket);
sa_len = r;
- (void) mkdir_parents_label(m->notify_socket, 0755);
(void) sockaddr_un_unlink(&sa.un);
r = mac_selinux_bind(fd, &sa.sa, sa_len);
@@ -1846,6 +1845,9 @@ static bool manager_dbus_is_running(Manager *m, bool deserialized) {
static void manager_setup_bus(Manager *m) {
assert(m);
+ if (MANAGER_IS_TEST_RUN(m))
+ return;
+
/* Let's set up our private bus connection now, unconditionally */
(void) bus_init_private(m);
@@ -1922,11 +1924,31 @@ void manager_reloading_stopp(Manager **m) {
}
}
+static int manager_make_runtime_dir(Manager *m) {
+ int r;
+
+ assert(m);
+
+ _cleanup_free_ char *d = path_join(m->prefix[EXEC_DIRECTORY_RUNTIME], "systemd");
+ if (!d)
+ return log_oom();
+
+ r = mkdir_label(d, 0755);
+ if (r < 0 && r != -EEXIST)
+ return log_error_errno(r, "Failed to create directory '%s/': %m", d);
+
+ return 0;
+}
+
int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *root) {
int r;
assert(m);
+ r = manager_make_runtime_dir(m);
+ if (r < 0)
+ return r;
+
/* If we are running in test mode, we still want to run the generators,
* but we should not touch the real generator directories. */
r = lookup_paths_init_or_warn(&m->lookup_paths, m->runtime_scope,
diff --git a/src/core/meson.build b/src/core/meson.build
index 439a88c5b2b..cc47ae056af 100644
--- a/src/core/meson.build
+++ b/src/core/meson.build
@@ -246,9 +246,11 @@ install_data('org.freedesktop.systemd1.conf',
install_data('org.freedesktop.systemd1.service',
install_dir : dbussystemservicedir)
+install_emptydir(systemenvgeneratordir)
install_emptydir(systemshutdowndir)
install_emptydir(systemsleepdir)
install_emptydir(systemgeneratordir)
+install_emptydir(userenvgeneratordir)
install_emptydir(usergeneratordir)
if install_sysconfdir
diff --git a/src/core/socket.c b/src/core/socket.c
index 9adae16b00f..23bc8ceb71f 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -2269,8 +2269,12 @@ static void flush_ports(Socket *s) {
if (p->fd < 0)
continue;
- (void) flush_accept(p->fd);
- (void) flush_fd(p->fd);
+ if (p->type == SOCKET_MQUEUE)
+ (void) flush_mqueue(p->fd);
+ else {
+ (void) flush_accept(p->fd);
+ (void) flush_fd(p->fd);
+ }
}
}
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 016f3baa7f8..e7caf510ba9 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -108,15 +108,15 @@ static int mount_array_add_internal(
char *in_what,
char *in_where,
const char *in_fstype,
- const char *in_options) {
+ char *in_options) {
_cleanup_free_ char *what = NULL, *where = NULL, *fstype = NULL, *options = NULL;
- int r;
/* This takes what and where. */
what = ASSERT_PTR(in_what);
where = in_where;
+ options = in_options;
fstype = strdup(isempty(in_fstype) ? "auto" : in_fstype);
if (!fstype)
@@ -125,19 +125,6 @@ static int mount_array_add_internal(
if (streq(fstype, "swap"))
where = mfree(where);
- if (!isempty(in_options)) {
- _cleanup_strv_free_ char **options_strv = NULL;
-
- r = strv_split_full(&options_strv, in_options, ",", 0);
- if (r < 0)
- return r;
-
- r = strv_make_nulstr(options_strv, &options, NULL);
- } else
- r = strv_make_nulstr(STRV_MAKE("defaults"), &options, NULL);
- if (r < 0)
- return r;
-
if (!GREEDY_REALLOC(arg_mounts, arg_n_mounts + 1))
return -ENOMEM;
@@ -167,7 +154,7 @@ static int mount_array_add(bool for_initrd, const char *str) {
if (!isempty(str))
return -EINVAL;
- return mount_array_add_internal(for_initrd, TAKE_PTR(what), TAKE_PTR(where), fstype, options);
+ return mount_array_add_internal(for_initrd, TAKE_PTR(what), TAKE_PTR(where), fstype, TAKE_PTR(options));
}
static int mount_array_add_swap(bool for_initrd, const char *str) {
@@ -185,7 +172,7 @@ static int mount_array_add_swap(bool for_initrd, const char *str) {
if (!isempty(str))
return -EINVAL;
- return mount_array_add_internal(for_initrd, TAKE_PTR(what), NULL, "swap", options);
+ return mount_array_add_internal(for_initrd, TAKE_PTR(what), NULL, "swap", TAKE_PTR(options));
}
static int write_options(FILE *f, const char *options) {
@@ -476,17 +463,13 @@ static int mandatory_mount_drop_unapplicable_options(
assert(flags);
assert(where);
- assert(options);
assert(ret_options);
if (!(*flags & (MOUNT_NOAUTO|MOUNT_NOFAIL|MOUNT_AUTOMOUNT))) {
- _cleanup_free_ char *opts = NULL;
-
- opts = strdup(options);
- if (!opts)
- return -ENOMEM;
+ r = strdup_or_null(options, ret_options);
+ if (r < 0)
+ return r;
- *ret_options = TAKE_PTR(opts);
return 0;
}
@@ -522,7 +505,6 @@ static int add_mount(
assert(what);
assert(where);
- assert(opts);
assert(target_unit);
assert(source);
@@ -816,6 +798,9 @@ static int add_sysusr_sysroot_usr_bind_mount(const char *source) {
static MountPointFlags fstab_options_to_flags(const char *options, bool is_swap) {
MountPointFlags flags = 0;
+ if (isempty(options))
+ return 0;
+
if (fstab_test_option(options, "x-systemd.makefs\0"))
flags |= MOUNT_MAKEFS;
if (fstab_test_option(options, "x-systemd.growfs\0"))
@@ -891,7 +876,6 @@ static int parse_fstab_one(
assert(what_original);
assert(fstype);
- assert(options);
if (prefix_sysroot && !mount_in_initrd(where_original, options, accept_root))
return 0;
diff --git a/src/getty-generator/getty-generator.c b/src/getty-generator/getty-generator.c
index 7486118365f..6267fd7c08b 100644
--- a/src/getty-generator/getty-generator.c
+++ b/src/getty-generator/getty-generator.c
@@ -271,17 +271,17 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
return r;
}
- /* Automatically add in a serial getty on the first virtualizer console */
+ /* Automatically add a serial getty to each available virtualizer console. */
FOREACH_STRING(j,
"hvc0",
"xvc0",
"hvsi0",
"sclp_line0",
"ttysclp0",
- "3270!tty1") {
+ "3270/tty1") {
_cleanup_free_ char *p = NULL;
- p = path_join("/sys/class/tty", j);
+ p = path_join("/dev", j);
if (!p)
return log_oom();
if (access(p, F_OK) < 0)
diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c
index e37660a61b6..4f3bfee0632 100644
--- a/src/home/homed-manager.c
+++ b/src/home/homed-manager.c
@@ -555,7 +555,7 @@ static int search_quota(uid_t uid, const char *exclude_quota_path) {
if ((FLAGS_SET(req.dqb_valid, QIF_SPACE) && req.dqb_curspace > 0) ||
(FLAGS_SET(req.dqb_valid, QIF_INODES) && req.dqb_curinodes > 0)) {
- log_debug_errno(errno, "Quota reports UID " UID_FMT " occupies disk space on %s.", uid, where);
+ log_debug("Quota reports UID " UID_FMT " occupies disk space on %s.", uid, where);
return 1;
}
}
diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c
index d1b7c305624..1c86e20b3bf 100644
--- a/src/initctl/initctl.c
+++ b/src/initctl/initctl.c
@@ -318,8 +318,7 @@ static int run(int argc, char *argv[]) {
n = sd_listen_fds(true);
if (n < 0)
- return log_error_errno(errno,
- "Failed to read listening file descriptors from environment: %m");
+ return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
if (n <= 0 || n > SERVER_FD_MAX)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 8befc974609..b32cd6c6a03 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -1727,8 +1727,10 @@ _public_ int sd_bus_open_user_machine(sd_bus **ret, const char *user_and_machine
assert_return(user_and_machine, -EINVAL);
assert_return(ret, -EINVAL);
- /* Shortcut things if we'd end up on this host and as the same user. */
- if (user_and_machine_equivalent(user_and_machine))
+ /* Shortcut things if we'd end up on this host and as the same user and have one of the necessary
+ * environment variables set already. */
+ if (user_and_machine_equivalent(user_and_machine) &&
+ (secure_getenv("DBUS_SESSION_BUS_ADDRESS") || secure_getenv("XDG_RUNTIME_DIR")))
return sd_bus_open_user(ret);
r = user_and_machine_valid(user_and_machine);
diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c
index b69a7c72246..fa3ef7ba9bc 100644
--- a/src/libsystemd/sd-daemon/sd-daemon.c
+++ b/src/libsystemd/sd-daemon/sd-daemon.c
@@ -476,6 +476,12 @@ static int pid_notify_with_fds_internal(
if (n_fds > 0 && !fds)
return -EINVAL;
+ /* Let's make sure the multiplications below don't overflow, and also return a recognizable error in
+ * case the caller tries to send more fds than the kernel limit. The kernel would return EINVAL which
+ * is not too useful I'd say. */
+ if (n_fds > SCM_MAX_FD)
+ return -E2BIG;
+
e = getenv("NOTIFY_SOCKET");
if (!e)
return 0;
diff --git a/src/libsystemd/sd-device/test-sd-device.c b/src/libsystemd/sd-device/test-sd-device.c
index bce99b55186..a5212a804ef 100644
--- a/src/libsystemd/sd-device/test-sd-device.c
+++ b/src/libsystemd/sd-device/test-sd-device.c
@@ -451,6 +451,8 @@ static void check_parent_match(sd_device_enumerator *e, sd_device *dev) {
TEST(sd_device_enumerator_add_match_parent) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ /* Some devices have thousands of children. Avoid spending too much time in the double loop below. */
+ unsigned iterations = 200;
int r;
assert_se(sd_device_enumerator_new(&e) >= 0);
@@ -468,6 +470,9 @@ TEST(sd_device_enumerator_add_match_parent) {
const char *syspath;
sd_device *parent;
+ if (iterations-- == 0)
+ break;
+
assert_se(sd_device_get_syspath(dev, &syspath) >= 0);
r = sd_device_get_parent(dev, &parent);
@@ -496,6 +501,8 @@ TEST(sd_device_enumerator_add_match_parent) {
TEST(sd_device_get_child) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ /* Some devices have thousands of children. Avoid spending too much time in the double loop below. */
+ unsigned iterations = 3000;
int r;
assert_se(sd_device_enumerator_new(&e) >= 0);
@@ -529,6 +536,9 @@ TEST(sd_device_get_child) {
FOREACH_DEVICE_CHILD_WITH_SUFFIX(parent, child, suffix) {
const char *s;
+ if (iterations-- == 0)
+ return;
+
assert_se(child);
assert_se(suffix);
diff --git a/src/notify/notify.c b/src/notify/notify.c
index f63ec8b355f..8dfd2ac2850 100644
--- a/src/notify/notify.c
+++ b/src/notify/notify.c
@@ -433,6 +433,8 @@ static int run(int argc, char* argv[]) {
r = sd_pid_notify_with_fds(source_pid, /* unset_environment= */ false, n, a, k);
}
+ if (r == -E2BIG)
+ return log_error_errno(r, "Too many file descriptors passed.");
if (r < 0)
return log_error_errno(r, "Failed to notify init system: %m");
if (r == 0)
diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c
index 039080f0521..d811de13de4 100644
--- a/src/shared/calendarspec.c
+++ b/src/shared/calendarspec.c
@@ -1229,14 +1229,43 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm, bool utc) {
return (weekdays_bits & (1 << k));
}
+static int tm_compare(const struct tm *t1, const struct tm *t2) {
+ int r;
+
+ assert(t1);
+ assert(t2);
+
+ r = CMP(t1->tm_year, t2->tm_year);
+ if (r != 0)
+ return r;
+
+ r = CMP(t1->tm_mon, t2->tm_mon);
+ if (r != 0)
+ return r;
+
+ r = CMP(t1->tm_mday, t2->tm_mday);
+ if (r != 0)
+ return r;
+
+ r = CMP(t1->tm_hour, t2->tm_hour);
+ if (r != 0)
+ return r;
+
+ r = CMP(t1->tm_min, t2->tm_min);
+ if (r != 0)
+ return r;
+
+ return CMP(t1->tm_sec, t2->tm_sec);
+}
+
/* A safety valve: if we get stuck in the calculation, return an error.
* C.f. https://bugzilla.redhat.com/show_bug.cgi?id=1941335. */
#define MAX_CALENDAR_ITERATIONS 1000
static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) {
struct tm c;
- int tm_usec;
- int r;
+ int tm_usec, r;
+ bool invalidate_dst = false;
/* Returns -ENOENT if the expression is not going to elapse anymore */
@@ -1249,7 +1278,8 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) {
for (unsigned iteration = 0; iteration < MAX_CALENDAR_ITERATIONS; iteration++) {
/* Normalize the current date */
(void) mktime_or_timegm(&c, spec->utc);
- c.tm_isdst = spec->dst;
+ if (!invalidate_dst)
+ c.tm_isdst = spec->dst;
c.tm_year += 1900;
r = find_matching_component(spec, spec->year, &c, &c.tm_year);
@@ -1339,6 +1369,18 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) {
if (r == 0)
continue;
+ r = tm_compare(tm, &c);
+ if (r == 0) {
+ assert(tm_usec + 1 <= 1000000);
+ r = CMP(*usec, (usec_t) tm_usec + 1);
+ }
+ if (r >= 0) {
+ /* We're stuck - advance, let mktime determine DST transition and try again. */
+ invalidate_dst = true;
+ c.tm_hour++;
+ continue;
+ }
+
*tm = c;
*usec = tm_usec;
return 0;
diff --git a/src/shared/pager.c b/src/shared/pager.c
index 19deefab565..41dd7bffdce 100644
--- a/src/shared/pager.c
+++ b/src/shared/pager.c
@@ -82,6 +82,22 @@ static int no_quit_on_interrupt(int exe_name_fd, const char *less_opts) {
return r;
}
+static bool running_with_escalated_privileges(void) {
+ int r;
+
+ if (getenv("SUDO_UID"))
+ return true;
+
+ uid_t uid;
+ r = sd_pid_get_owner_uid(0, &uid);
+ if (r < 0) {
+ log_debug_errno(r, "sd_pid_get_owner_uid() failed, enabling pager secure mode: %m");
+ return true;
+ }
+
+ return uid != geteuid();
+}
+
void pager_open(PagerFlags flags) {
_cleanup_close_pair_ int fd[2] = EBADF_PAIR, exe_name_pipe[2] = EBADF_PAIR;
_cleanup_strv_free_ char **pager_args = NULL;
@@ -177,16 +193,9 @@ void pager_open(PagerFlags flags) {
* know to be good. */
int use_secure_mode = getenv_bool_secure("SYSTEMD_PAGERSECURE");
bool trust_pager = use_secure_mode >= 0;
- if (use_secure_mode == -ENXIO) {
- uid_t uid;
-
- r = sd_pid_get_owner_uid(0, &uid);
- if (r < 0)
- log_debug_errno(r, "sd_pid_get_owner_uid() failed, enabling pager secure mode: %m");
-
- use_secure_mode = r < 0 || uid != geteuid();
-
- } else if (use_secure_mode < 0) {
+ if (use_secure_mode == -ENXIO)
+ use_secure_mode = running_with_escalated_privileges();
+ else if (use_secure_mode < 0) {
log_warning_errno(use_secure_mode, "Unable to parse $SYSTEMD_PAGERSECURE, assuming true: %m");
use_secure_mode = true;
}
diff --git a/src/shared/varlink.c b/src/shared/varlink.c
index d3373266bcd..8a99a6c3f1a 100644
--- a/src/shared/varlink.c
+++ b/src/shared/varlink.c
@@ -2732,8 +2732,8 @@ int varlink_push_fd(Varlink *v, int fd) {
if (!v->allow_fd_passing_output)
return -EPERM;
- if (v->n_pushed_fds >= INT_MAX)
- return -ENOMEM;
+ if (v->n_pushed_fds >= SCM_MAX_FD) /* Kernel doesn't support more than 253 fds per message, refuse early hence */
+ return -ENOBUFS;
if (!GREEDY_REALLOC(v->pushed_fds, v->n_pushed_fds + 1))
return -ENOMEM;
@@ -3221,7 +3221,7 @@ int varlink_server_listen_address(VarlinkServer *s, const char *address, mode_t
int varlink_server_listen_auto(VarlinkServer *s) {
_cleanup_strv_free_ char **names = NULL;
- int r, n = 0;
+ int r, m, n = 0;
assert_return(s, -EINVAL);
@@ -3231,11 +3231,11 @@ int varlink_server_listen_auto(VarlinkServer *s) {
* See https://varlink.org/#activation for the environment variables this is backed by and the
* recommended "varlink" identifier in $LISTEN_FDNAMES. */
- r = sd_listen_fds_with_names(/* unset_environment= */ false, &names);
- if (r < 0)
- return r;
+ m = sd_listen_fds_with_names(/* unset_environment= */ false, &names);
+ if (m < 0)
+ return m;
- for (int i = 0; i < r; i++) {
+ for (int i = 0; i < m; i++) {
int b, fd;
socklen_t l = sizeof(b);
diff --git a/src/shutdown/detach-loopback.c b/src/shutdown/detach-loopback.c
index 8778a9e0c44..25288af2215 100644
--- a/src/shutdown/detach-loopback.c
+++ b/src/shutdown/detach-loopback.c
@@ -17,6 +17,7 @@
#include "blockdev-util.h"
#include "detach-loopback.h"
#include "device-util.h"
+#include "errno-util.h"
#include "fd-util.h"
#include "shutdown.h"
@@ -106,8 +107,12 @@ static int delete_loopback(const char *device) {
fd = open(device, O_RDONLY|O_CLOEXEC);
if (fd < 0) {
- log_debug_errno(errno, "Failed to open loopback device %s: %m", device);
- return errno == ENOENT ? 0 : -errno;
+ if (ERRNO_IS_DEVICE_ABSENT(errno)) {
+ log_debug_errno(errno, "Tried to open loopback device '%s', but device disappeared by now, ignoring: %m", device);
+ return 0;
+ }
+
+ return log_debug_errno(errno, "Failed to open loopback device '%s': %m", device);
}
/* Loopback block devices don't sync in-flight blocks when we clear the fd, hence sync explicitly
diff --git a/src/shutdown/detach-md.c b/src/shutdown/detach-md.c
index 513bbdcef19..d66ecfacd56 100644
--- a/src/shutdown/detach-md.c
+++ b/src/shutdown/detach-md.c
@@ -131,12 +131,21 @@ static int delete_md(RaidDevice *m) {
assert(m->path);
fd = open(m->path, O_RDONLY|O_CLOEXEC|O_EXCL);
- if (fd < 0)
- return -errno;
+ if (fd < 0) {
+ if (ERRNO_IS_DEVICE_ABSENT(errno)) {
+ log_debug_errno(errno, "Tried to open MD device '%s', but device disappeared by now, ignoring: %m", m->path);
+ return 0;
+ }
+
+ return log_debug_errno(errno, "Failed to open MD device '%s': %m", m->path);
+ }
(void) sync_with_progress(fd);
- return RET_NERRNO(ioctl(fd, STOP_ARRAY, NULL));
+ if (ioctl(fd, STOP_ARRAY, NULL) < 0)
+ return log_debug_errno(errno, "Failed to issue STOP_ARRAY on MD device '%s': %m", m->path);
+
+ return 1;
}
static int md_points_list_detach(RaidDevice **head, bool *changed, bool last_try) {
@@ -164,8 +173,9 @@ static int md_points_list_detach(RaidDevice **head, bool *changed, bool last_try
n_failed++;
continue;
}
+ if (r > 0)
+ *changed = true;
- *changed = true;
raid_device_free(head, m);
}
diff --git a/src/shutdown/detach-swap.c b/src/shutdown/detach-swap.c
index fd7dcdf943d..eafdc4341e1 100644
--- a/src/shutdown/detach-swap.c
+++ b/src/shutdown/detach-swap.c
@@ -7,6 +7,7 @@
#include "alloc-util.h"
#include "detach-swap.h"
+#include "errno-util.h"
#include "libmount-util.h"
static void swap_device_free(SwapDevice **head, SwapDevice *m) {
@@ -74,20 +75,23 @@ int swap_list_get(const char *swaps, SwapDevice **head) {
}
static int swap_points_list_off(SwapDevice **head, bool *changed) {
- int n_failed = 0;
+ int n_failed = 0, r;
assert(head);
assert(changed);
LIST_FOREACH(swap_device, m, *head) {
log_info("Deactivating swap %s.", m->path);
- if (swapoff(m->path) < 0) {
- log_warning_errno(errno, "Could not deactivate swap %s: %m", m->path);
+ r = RET_NERRNO(swapoff(m->path));
+ if (ERRNO_IS_NEG_DEVICE_ABSENT(r))
+ log_debug_errno(r, "Tried to deactivate swap '%s', but swap disappeared by now, ignoring: %m", m->path);
+ else if (r < 0) {
+ log_warning_errno(r, "Could not deactivate swap %s: %m", m->path);
n_failed++;
continue;
- }
+ } else
+ *changed = true;
- *changed = true;
swap_device_free(head, m);
}
diff --git a/src/shutdown/umount.c b/src/shutdown/umount.c
index 1a9b99d7618..08067067afb 100644
--- a/src/shutdown/umount.c
+++ b/src/shutdown/umount.c
@@ -63,7 +63,7 @@ int mount_points_list_get(const char *mountinfo, MountPoint **head) {
struct libmnt_fs *fs;
const char *path, *fstype;
unsigned long remount_flags = 0u;
- bool try_remount_ro, is_api_vfs;
+ bool try_remount_ro, is_api_vfs, is_network;
_cleanup_free_ MountPoint *m = NULL;
r = mnt_table_next_fs(table, iter, &fs);
@@ -98,6 +98,7 @@ int mount_points_list_get(const char *mountinfo, MountPoint **head) {
PATH_STARTSWITH_SET(path, "/dev", "/sys", "/proc"))
continue;
+ is_network = fstype_is_network(fstype);
is_api_vfs = fstype_is_api_vfs(fstype);
/* If we are in a container, don't attempt to read-only mount anything as that brings no real
@@ -108,7 +109,7 @@ int mount_points_list_get(const char *mountinfo, MountPoint **head) {
* leave a "dirty fs") and could hang if the network is down. Note that umount2() is more
* careful and will not hang because of the network being down. */
try_remount_ro = detect_container() <= 0 &&
- !fstype_is_network(fstype) &&
+ !is_network &&
!is_api_vfs &&
!fstype_is_ro(fstype) &&
!fstab_test_yes_no_option(options, "ro\0rw\0");
@@ -152,7 +153,11 @@ int mount_points_list_get(const char *mountinfo, MountPoint **head) {
/* Unmount sysfs/procfs/… lazily, since syncing doesn't matter there, and it's OK if
* something keeps an fd open to it. */
.umount_lazily = is_api_vfs,
- .leaf = leaf,
+
+ /* If a mount point is not a leaf, moving it would invalidate our mount table.
+ * If a mount point is on the network and the network is down, it can hang and block
+ * the shutdown. */
+ .umount_move_if_busy = leaf && !is_network,
};
m->path = strdup(path);
@@ -405,10 +410,9 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool last_
*changed = true;
/* If a mount is busy, we move it to not keep parent mount points busy.
- * If a mount point is not a leaf, moving it would invalidate our mount table.
* More moving will occur in next iteration with a fresh mount table.
*/
- if (r != -EBUSY || !m->leaf)
+ if (r != -EBUSY || !m->umount_move_if_busy)
continue;
_cleanup_free_ char *dirname = NULL;
diff --git a/src/shutdown/umount.h b/src/shutdown/umount.h
index f8f9ae80380..e76106cc05e 100644
--- a/src/shutdown/umount.h
+++ b/src/shutdown/umount.h
@@ -18,7 +18,7 @@ typedef struct MountPoint {
unsigned long remount_flags;
bool try_remount_ro;
bool umount_lazily;
- bool leaf;
+ bool umount_move_if_busy;
LIST_FIELDS(struct MountPoint, mount_point);
} MountPoint;
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index dd6f6c9873e..ddd20510c15 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -945,7 +945,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
"cache\n"
"logs\n"
"configuration\n"
- "fdstore");
+ "fdstore\n"
+ "all");
return 0;
}
diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c
index eee621f2a03..f323438bcbf 100644
--- a/src/test/test-calendarspec.c
+++ b/src/test/test-calendarspec.c
@@ -47,7 +47,7 @@ static void _test_next(int line, const char *input, const char *new_tz, usec_t a
if (old_tz)
old_tz = strdupa_safe(old_tz);
- if (!isempty(new_tz))
+ if (!isempty(new_tz) && !strchr(new_tz, ','))
new_tz = strjoina(":", new_tz);
assert_se(set_unset_env("TZ", new_tz, true) == 0);
@@ -219,6 +219,8 @@ TEST(calendar_spec_next) {
/* Check that we don't start looping if mktime() moves us backwards */
test_next("Sun *-*-* 01:00:00 Europe/Dublin", "", 1616412478000000, 1617494400000000);
test_next("Sun *-*-* 01:00:00 Europe/Dublin", "IST", 1616412478000000, 1617494400000000);
+ /* Europe/Dublin TZ that moves DST backwards */
+ test_next("hourly", "IST-1GMT-0,M10.5.0/1,M3.5.0/1", 1743292800000000, 1743296400000000);
}
TEST(calendar_spec_from_string) {
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 6fc383ca1bd..ab5aaf79db2 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -1373,9 +1373,10 @@ static void run_tests(RuntimeScope scope, char **patterns) {
start = now(CLOCK_MONOTONIC);
for (const test_entry *test = tests; test->f; test++)
- if (strv_fnmatch_or_empty(patterns, test->name, FNM_NOESCAPE))
+ if (strv_fnmatch_or_empty(patterns, test->name, FNM_NOESCAPE)) {
+ log_info("Starting %s.", test->name);
test->f(m);
- else
+ } else
log_info("Skipping %s because it does not match any pattern.", test->name);
finish = now(CLOCK_MONOTONIC);
diff --git a/src/test/test-specifier.c b/src/test/test-specifier.c
index d6a8b79aa4a..952cf34b577 100644
--- a/src/test/test-specifier.c
+++ b/src/test/test-specifier.c
@@ -3,7 +3,9 @@
#include "sd-id128.h"
#include "alloc-util.h"
+#include "format-util.h"
#include "log.h"
+#include "process-util.h"
#include "specifier.h"
#include "stat-util.h"
#include "stdio-util.h"
@@ -89,25 +91,27 @@ TEST(specifier_printf) {
TEST(specifier_real_path) {
static const Specifier table[] = {
- { 'p', specifier_string, "/dev/initctl" },
- { 'y', specifier_real_path, "/dev/initctl" },
- { 'Y', specifier_real_directory, "/dev/initctl" },
+ { 'p', specifier_string, "/dev/fd" },
+ { 'y', specifier_real_path, "/dev/fd" },
+ { 'Y', specifier_real_directory, "/dev/fd" },
{ 'w', specifier_real_path, "/dev/tty" },
{ 'W', specifier_real_directory, "/dev/tty" },
{}
};
- _cleanup_free_ char *w = NULL;
+ _cleanup_free_ char *w = NULL, *expected = NULL;
int r;
r = specifier_printf("p=%p y=%y Y=%Y w=%w W=%W", SIZE_MAX, table, NULL, NULL, &w);
- assert_se(r >= 0 || r == -ENOENT);
- assert_se(w || r == -ENOENT);
- puts(strnull(w));
+ if (r < 0) {
+ assert_se(r == -ENOENT);
+ return (void) log_tests_skipped_errno(r, "/dev/fd and/or /dev/tty do not exist");
+ }
- /* /dev/initctl should normally be a symlink to /run/initctl */
- if (inode_same("/dev/initctl", "/run/initctl", 0) > 0)
- assert_se(streq(w, "p=/dev/initctl y=/run/initctl Y=/run w=/dev/tty W=/dev"));
+ assert_se(asprintf(&expected,
+ "p=/dev/fd y=/proc/"PID_FMT"/fd Y=/proc/"PID_FMT" w=/dev/tty W=/dev",
+ getpid_cached(), getpid_cached()) >= 0);
+ assert_se(streq(w, expected));
}
TEST(specifier_real_path_missing_file) {
diff --git a/src/udev/udev-manager.c b/src/udev/udev-manager.c
index 8077e51055d..a1cbab5b999 100644
--- a/src/udev/udev-manager.c
+++ b/src/udev/udev-manager.c
@@ -302,7 +302,7 @@ static void manager_reload(Manager *manager, bool force) {
static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userdata) {
Manager *manager = ASSERT_PTR(userdata);
- log_debug("Cleanup idle workers");
+ log_debug("Cleaning up idle workers.");
manager_kill_workers(manager, false);
return 1;
@@ -1154,7 +1154,7 @@ static int on_post(sd_event_source *s, void *userdata) {
if (errno != ENOENT)
log_warning_errno(errno, "Failed to unlink /run/udev/queue, ignoring: %m");
} else
- log_debug("No events are queued, removing /run/udev/queue.");
+ log_debug("No events are queued, removed /run/udev/queue.");
if (!hashmap_isempty(manager->workers)) {
/* There are idle workers */
diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c
index 088b4da3c1a..dfea849fd05 100644
--- a/src/udev/udevadm-test-builtin.c
+++ b/src/udev/udevadm-test-builtin.c
@@ -58,16 +58,11 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached();
}
- arg_command = argv[optind++];
- if (!arg_command)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Command missing.");
-
- arg_syspath = argv[optind++];
- if (!arg_syspath)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "device is missing.");
+ if (argc != optind + 2)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected two arguments: command string and device path.");
+ arg_command = ASSERT_PTR(argv[optind]);
+ arg_syspath = ASSERT_PTR(argv[optind+1]);
return 1;
}
diff --git a/test/networkd-test.py b/test/networkd-test.py
index bf49a6da68c..62be9895ac8 100755
--- a/test/networkd-test.py
+++ b/test/networkd-test.py
@@ -47,6 +47,12 @@ def setUpModule():
global tmpmounts
"""Initialize the environment, and perform sanity checks on it."""
+
+ if shutil.which('networkctl') is None:
+ raise unittest.SkipTest('networkd not installed')
+ if shutil.which('resolvectl') is None:
+ raise unittest.SkipTest('resolved not installed')
+
if NETWORKD_WAIT_ONLINE is None:
raise OSError(errno.ENOENT, 'systemd-networkd-wait-online not found')
diff --git a/test/test-fstab-generator/test-19-mounts-from-cmdline.expected/hoge-withx20space.mount b/test/test-fstab-generator/test-19-mounts-from-cmdline.expected/hoge-withx20space.mount
index e9ffb4bbd93..d3797c97065 100644
--- a/test/test-fstab-generator/test-19-mounts-from-cmdline.expected/hoge-withx20space.mount
+++ b/test/test-fstab-generator/test-19-mounts-from-cmdline.expected/hoge-withx20space.mount
@@ -9,4 +9,4 @@ Before=remote-fs.target
What=//foobar
Where=/hoge/with space
Type=cifs
-Options=rw
+Options=rw,seclabel
diff --git a/test/test-fstab-generator/test-20-swap-from-cmdline.expected/dev-sdy3.swap b/test/test-fstab-generator/test-20-swap-from-cmdline.expected/dev-sdy3.swap
index 3b6563d2164..1b4b53c9b84 100644
--- a/test/test-fstab-generator/test-20-swap-from-cmdline.expected/dev-sdy3.swap
+++ b/test/test-fstab-generator/test-20-swap-from-cmdline.expected/dev-sdy3.swap
@@ -7,4 +7,4 @@ After=blockdev@dev-sdy3.target
[Swap]
What=/dev/sdy3
-Options=x-systemd.makefs
+Options=x-systemd.makefs,nofail
diff --git a/test/test-fstab-generator/test-20-swap-from-cmdline.expected/swap.target.requires/dev-sdy3.swap b/test/test-fstab-generator/test-20-swap-from-cmdline.expected/swap.target.wants/dev-sdy3.swap
similarity index 100%
rename from test/test-fstab-generator/test-20-swap-from-cmdline.expected/swap.target.requires/dev-sdy3.swap
rename to test/test-fstab-generator/test-20-swap-from-cmdline.expected/swap.target.wants/dev-sdy3.swap
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 9e5fd065266..ba3af61f5e0 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -6977,6 +6977,10 @@ def test_mtu_link_ipv6_mtu(self):
if not os.path.exists(os.path.join(systemd_source_dir, "meson_options.txt")):
raise RuntimeError(f"{systemd_source_dir} doesn't appear to be a systemd source tree")
+ if networkd_bin is None or resolved_bin is None or timesyncd_bin is None:
+ print("networkd tests require networkd/resolved/timesyncd to be enabled")
+ sys.exit(77)
+
use_valgrind = ns.use_valgrind
enable_debug = ns.enable_debug
asan_options = ns.asan_options
diff --git a/test/units/testsuite-73.sh b/test/units/testsuite-73.sh
index df5af4ba873..2e11ce2c511 100755
--- a/test/units/testsuite-73.sh
+++ b/test/units/testsuite-73.sh
@@ -239,11 +239,6 @@ testcase_vc_keymap() {
assert_in "VC Keymap:" "$(localectl)"
for i in $(localectl list-keymaps); do
- # clear previous conversion from VC -> X11 keymap
- systemctl stop systemd-localed.service
- wait_vconsole_setup
- rm -f /etc/vconsole.conf /etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard
-
# set VC keymap
assert_rc 0 localectl set-keymap "$i"
output=$(localectl)
diff --git a/test/units/testsuite-74.busctl.sh b/test/units/testsuite-74.busctl.sh
index aaf96d08c12..b0afcd70690 100755
--- a/test/units/testsuite-74.busctl.sh
+++ b/test/units/testsuite-74.busctl.sh
@@ -108,3 +108,12 @@ busctl get-property -j \
# Invalid argument
(! busctl set-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \
KExecWatchdogUSec t "foo")
+
+# Invalid destination
+(! busctl get-property '*' /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager Version)
+
+# Invalid object
+(! busctl get-property org.freedesktop.systemd1 '*' org.freedesktop.systemd1.Manager Version)
+
+# Invalid interface
+(! busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 '*' Version)
diff --git a/test/units/testsuite-75.sh b/test/units/testsuite-75.sh
index 86d602d6159..6829e598d73 100755
--- a/test/units/testsuite-75.sh
+++ b/test/units/testsuite-75.sh
@@ -14,6 +14,11 @@ set -o pipefail
# shellcheck source=test/units/util.sh
. "$(dirname "$0")"/util.sh
+if ! command -v resolvectl >/dev/null || ! command -v networkctl >/dev/null; then
+ echo "resolved/networkd not found, skipping..." | tee --append /skipped
+ exit 77
+fi
+
RUN_OUT="$(mktemp)"
run() {
@@ -222,10 +227,13 @@ keymgr . generate algorithm=ECDSAP256SHA256 ksk=yes zsk=yes
# Create a trust anchor for resolved with our root zone
keymgr . ds | sed 's/ DS/ IN DS/g' >/etc/dnssec-trust-anchors.d/root.positive
# Create a bind-compatible trust anchor (for delv)
-# Note: the trust-anchors directive is relatively new, so use the original
-# managed-keys one until it's widespread enough
+# Note: managed-keys was removed in version 9.21, use the newer trust-anchors directive
{
- echo 'managed-keys {'
+ if systemd-analyze compare-versions "$(delv -v | awk '{print $2}')" ge 9.21; then
+ echo 'trust-anchors {'
+ else
+ echo 'managed-keys {'
+ fi
keymgr . dnskey | sed -r 's/^\. DNSKEY ([0-9]+ [0-9]+ [0-9]+) (.+)$/. static-key \1 "\2";/g'
echo '};'
} >/etc/bind.keys
diff --git a/test/units/testsuite-84.sh b/test/units/testsuite-84.sh
index c5cb8989020..ddc107560e8 100755
--- a/test/units/testsuite-84.sh
+++ b/test/units/testsuite-84.sh
@@ -22,7 +22,7 @@ NVME_UUID="$(cat /proc/sys/kernel/random/uuid)"
systemd-run -u teststoragetm.service -p Type=notify -p "Environment=SYSTEMD_NVME_UUID=${NVME_UUID:?}" /usr/lib/systemd/systemd-storagetm /var/tmp/storagetm.test --nqn=quux
NVME_DEVICE="/dev/disk/by-id/nvme-uuid.${NVME_UUID:?}"
-nvme connect-all -t tcp -a 127.0.0.1 -s 16858 --hostid="$(cat /proc/sys/kernel/random/uuid)"
+nvme connect-all -vv -t tcp -a 127.0.0.1 -s 16858 --hostnqn="$(nvme gen-hostnqn)"
udevadm wait --settle "$NVME_DEVICE"
dd if="$NVME_DEVICE" bs=1024 | cmp /var/tmp/storagetm.test -