diff --git a/.github/workflows/mkosi.yml b/.github/workflows/mkosi.yml
index 0c210d1ed9e..458308aeab0 100644
--- a/.github/workflows/mkosi.yml
+++ b/.github/workflows/mkosi.yml
@@ -60,6 +60,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 }}
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 155d94dbbc6..1cf8168794d 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -8007,7 +8007,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 08d5be400ed..3b74993df02 100644
--- a/man/sd_bus_emit_signal.xml
+++ b/man/sd_bus_emit_signal.xml
@@ -67,7 +67,7 @@
int sd_bus_emit_interfaces_added_strvsd_bus *busconst char *path
- const char **interfaces
+ char **interfaces
@@ -82,7 +82,7 @@
int sd_bus_emit_interfaces_removed_strvsd_bus *busconst char *path
- const char **interfaces
+ char **interfaces
@@ -99,7 +99,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 cfaf8a8cb59..373307cce4b 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
@@ -837,7 +836,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 cc55b02b182..10f469bb90c 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 c2104742e51..0c2eb4a468e 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 48c0bf289be..1327c199adf 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 60f3d211e3c..6f5d633d8d7 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 = -1;
- 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 d6e1126df8b..9c638c103c0 100644
--- a/src/basic/log.h
+++ b/src/basic/log.h
@@ -94,8 +94,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 cefbbcd9ab5..67ce4b69a1a 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 78031682e7d..bdf1a1956e9 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 afd5d8d6c7f..97476b80021 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 570b39fc80e..89087a276d3 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;
@@ -2366,6 +2368,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. */
}
}
@@ -2374,8 +2380,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 b01c06b61dc..9df3153b9d2 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -2829,7 +2829,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 9e99972c0f5..6a3fa1d97e2 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 e13e90830b2..86856789aba 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -2684,7 +2684,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 7446444add4..23f1a25bfcf 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -302,7 +302,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)
@@ -941,7 +941,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)
@@ -991,7 +991,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);
@@ -1726,6 +1725,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);
@@ -1802,11 +1804,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 6fc90895830..cfbc1c03ad2 100644
--- a/src/core/meson.build
+++ b/src/core/meson.build
@@ -234,9 +234,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 e86e9c85b81..0dd32d52409 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 4e8162a3198..002814bb37c 100644
--- a/src/getty-generator/getty-generator.c
+++ b/src/getty-generator/getty-generator.c
@@ -215,17 +215,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 5084afbe97b..b96bde46b89 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 52b1ba199a1..1fe3d96c1bd 100644
--- a/src/initctl/initctl.c
+++ b/src/initctl/initctl.c
@@ -324,8 +324,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 37fb88864d3..bedba942967 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -1717,8 +1717,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 24bc32f172d..8c7a45e379b 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 dc717cd1fe8..41a0b097cd6 100644
--- a/src/shared/pager.c
+++ b/src/shared/pager.c
@@ -83,6 +83,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] = { -1, -1 }, exe_name_pipe[2] = { -1, -1 };
_cleanup_strv_free_ char **pager_args = NULL;
@@ -178,16 +194,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 ebb555325fc..f30f51ac2db 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 fbb3dfe8c37..1c7dedc2090 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -5767,6 +5767,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-75.sh b/test/units/testsuite-75.sh
index 4e49143c2cd..212890a7085 100755
--- a/test/units/testsuite-75.sh
+++ b/test/units/testsuite-75.sh
@@ -10,6 +10,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() {
@@ -102,10 +107,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