diff --git a/.github/workflows/mkosi.yml b/.github/workflows/mkosi.yml
index 61aae020252..50b9e49cc6b 100644
--- a/.github/workflows/mkosi.yml
+++ b/.github/workflows/mkosi.yml
@@ -84,6 +84,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.default <<- EOF
[Distribution]
Distribution=${{ matrix.distro }}
@@ -124,8 +127,6 @@ jobs:
CopyFiles=/
Minimize=guess
EOF
- 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: sudo mkosi genkey
diff --git a/man/common-variables.xml b/man/common-variables.xml
index 4d2092f7489..4392ce27e55 100644
--- a/man/common-variables.xml
+++ b/man/common-variables.xml
@@ -83,17 +83,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.
@@ -150,28 +155,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 62c807925ab..fa4b3df3404 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -8077,7 +8077,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 52d08b7a923..7114ff2f2bd 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 dd3a9500cf3..6ab98a62109 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/systemctl.xml b/man/systemctl.xml
index 1625427f9f0..a701efde7bb 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -139,10 +139,9 @@ binfmt_misc /proc/sys/fs/binfmt_misc yes 0 proc-sys-fs-binfmt_mis
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
@@ -844,7 +843,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.link.xml b/man/systemd.link.xml
index aad3736c367..30514464627 100644
--- a/man/systemd.link.xml
+++ b/man/systemd.link.xml
@@ -32,6 +32,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
@@ -1018,11 +1023,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 2eef826a063..54ef5e59388 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 8287382eb68..e0b323af542 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 126382c4b0e..4bb2fe9f52d 100644
--- a/man/systemd.xml
+++ b/man/systemd.xml
@@ -976,12 +976,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/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in
index 759ffc02061..e8461ca7fd6 100644
--- a/shell-completion/zsh/_systemctl.in
+++ b/shell-completion/zsh/_systemctl.in
@@ -408,7 +408,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 84ad7a9dc18..595244dca83 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 fbfb8aa7875..ab7521d0155 100644
--- a/src/basic/log.h
+++ b/src/basic/log.h
@@ -96,8 +96,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/socket-util.c b/src/basic/socket-util.c
index 9538367e3d9..6cf0f3867a7 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -1157,6 +1158,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 1a8384ec3fb..c0ee8e0db76 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -171,6 +171,7 @@ int receive_one_fd(int transport_fd, int flags);
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/busctl/busctl.c b/src/busctl/busctl.c
index b073d5feffa..5f4ea0dc813 100644
--- a/src/busctl/busctl.c
+++ b/src/busctl/busctl.c
@@ -2152,6 +2152,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;
@@ -2221,6 +2228,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 a33fbeb667a..925aea0ca08 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -51,6 +51,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 tasks_max_resolve(const TasksMax *tasks_max) {
if (tasks_max->scale == 0)
return tasks_max->value;
@@ -2423,6 +2425,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. */
}
}
@@ -2431,8 +2437,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 556328fd221..d2cff4b944b 100644
--- a/src/core/core-varlink.c
+++ b/src/core/core-varlink.c
@@ -500,7 +500,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-manager.c b/src/core/dbus-manager.c
index cffd2ebcb16..b72cf8cdf84 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -2927,7 +2927,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, default_timer_accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 3268cc58a3a..c650e615368 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"
@@ -940,7 +939,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/main.c b/src/core/main.c
index f6c76ccdbe4..014b6f48177 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -2730,7 +2730,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;
diff --git a/src/core/manager.c b/src/core/manager.c
index ec07f3428f8..f46c73f6ceb 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -305,7 +305,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)
@@ -946,7 +946,7 @@ int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager *
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)
@@ -996,7 +996,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);
@@ -1735,6 +1734,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);
@@ -1811,11 +1813,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->unit_file_scope,
diff --git a/src/core/meson.build b/src/core/meson.build
index 981b46fc0b2..e0bab84315a 100644
--- a/src/core/meson.build
+++ b/src/core/meson.build
@@ -166,9 +166,11 @@ install_data('org.freedesktop.systemd1.conf',
install_data('org.freedesktop.systemd1.service',
install_dir : dbussystemservicedir)
+meson.add_install_script('sh', '-c', mkdir_p.format(systemenvgeneratordir))
meson.add_install_script('sh', '-c', mkdir_p.format(systemshutdowndir))
meson.add_install_script('sh', '-c', mkdir_p.format(systemsleepdir))
meson.add_install_script('sh', '-c', mkdir_p.format(systemgeneratordir))
+meson.add_install_script('sh', '-c', mkdir_p.format(userenvgeneratordir))
meson.add_install_script('sh', '-c', mkdir_p.format(usergeneratordir))
if install_sysconfdir
diff --git a/src/core/socket.c b/src/core/socket.c
index 46648dced4e..d36faaca020 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -2292,8 +2292,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/getty-generator/getty-generator.c b/src/getty-generator/getty-generator.c
index d255e90db52..16b6cc68c4c 100644
--- a/src/getty-generator/getty-generator.c
+++ b/src/getty-generator/getty-generator.c
@@ -214,17 +214,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 -ENOMEM;
if (access(p, F_OK) < 0)
diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c
index 0c8f78b7029..007d21ae2ca 100644
--- a/src/home/homed-manager.c
+++ b/src/home/homed-manager.c
@@ -543,7 +543,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 0882570a660..0a0c8ce2e9e 100644
--- a/src/initctl/initctl.c
+++ b/src/initctl/initctl.c
@@ -325,8 +325,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 39ba512d130..be5040c723a 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -1719,8 +1719,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-device/test-sd-device.c b/src/libsystemd/sd-device/test-sd-device.c
index 8c6d59e0409..030e2147016 100644
--- a/src/libsystemd/sd-device/test-sd-device.c
+++ b/src/libsystemd/sd-device/test-sd-device.c
@@ -430,6 +430,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;
sd_device *dev;
+ /* 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);
@@ -447,6 +449,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);
@@ -476,6 +481,8 @@ TEST(sd_device_enumerator_add_match_parent) {
TEST(sd_device_get_child) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
sd_device *dev;
+ /* 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);
@@ -509,6 +516,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/shared/calendarspec.c b/src/shared/calendarspec.c
index 86a6d3f6080..2a9d6811d4a 100644
--- a/src/shared/calendarspec.c
+++ b/src/shared/calendarspec.c
@@ -1239,14 +1239,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 */
@@ -1259,7 +1288,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);
@@ -1349,6 +1379,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 6ed35a3ca99..e6c6715d581 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] = PIPE_EBADF, exe_name_pipe[2] = PIPE_EBADF;
_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/test/test-calendarspec.c b/src/test/test-calendarspec.c
index 0fcf35bd658..840f1185779 100644
--- a/src/test/test-calendarspec.c
+++ b/src/test/test-calendarspec.c
@@ -48,7 +48,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);
@@ -225,6 +225,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-specifier.c b/src/test/test-specifier.c
index f5c491b9cfe..de5e9a19de7 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 (files_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/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c
index affa2f089b0..6efe78d579f 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 349213d8318..76c1331ab6a 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-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index d1d47622357..12d56413db7 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -5892,6 +5892,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 0f0dda884bd..34cb941f93c 100755
--- a/test/units/testsuite-73.sh
+++ b/test/units/testsuite-73.sh
@@ -237,11 +237,6 @@ test_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-75.sh b/test/units/testsuite-75.sh
index 7c23632db91..dbf95a9074d 100755
--- a/test/units/testsuite-75.sh
+++ b/test/units/testsuite-75.sh
@@ -16,6 +16,11 @@ set -o pipefail
: >/failed
+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() {
@@ -217,10 +222,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