diff --git a/.github/workflows/mkosi.yml b/.github/workflows/mkosi.yml
index bb6e1cecde1..5c53cb8f4ae 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.conf <<- EOF
[Distribution]
Distribution=${{ matrix.distro }}
@@ -138,8 +141,6 @@ jobs:
ExecStart=false
EOF
cp mkosi.presets/10-initrd/mkosi.extra/usr/lib/systemd/system/emergency.service.d/poweroff.conf mkosi.presets/20-final/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: sudo 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 7a30647084d..742e4751f62 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -8457,7 +8457,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 ec2a7976fd0..432fec07a4d 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 3309147847e..e60dc6bacb1 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 8df94b1d7df..13fc5c94d7b 100644
--- a/man/sd_notify.xml
+++ b/man/sd_notify.xml
@@ -405,6 +405,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 4918c82d8ba..86a2e5f2f37 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -159,10 +159,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
@@ -890,7 +889,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 293aba2c88d..c81aa5b8af6 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
@@ -977,11 +982,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 d0e52cff42d..47f0921518d 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 09527de2cb4..fe7b1f479be 100644
--- a/man/systemd.xml
+++ b/man/systemd.xml
@@ -1005,12 +1005,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 2306cbf6b02..822dd339db1 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 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 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 6951c12c9b7..446ba95867c 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 9c4c95bd3a1..17ec943a92b 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 941b1efd44f..a506836d143 100644
--- a/src/busctl/busctl.c
+++ b/src/busctl/busctl.c
@@ -2157,6 +2157,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;
@@ -2226,6 +2233,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 8ce69d1ef71..8fe93059e76 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;
@@ -2502,6 +2504,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. */
}
}
@@ -2510,8 +2516,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 b4de317f304..82a6f9f547c 100644
--- a/src/core/core-varlink.c
+++ b/src/core/core-varlink.c
@@ -504,7 +504,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 a9a375290b4..e5c74913381 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -1183,6 +1183,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),
@@ -1260,8 +1277,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 dea69bb6e25..91fe54bb118 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -3007,7 +3007,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 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/main.c b/src/core/main.c
index f7d54e68b55..536654ff447 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -2073,7 +2073,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;
@@ -2096,7 +2096,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);
@@ -2116,7 +2116,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;
@@ -2844,7 +2844,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;
@@ -2958,7 +2958,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;
}
@@ -3031,7 +3032,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 185923061c6..5ba7873a62e 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -308,7 +308,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)
@@ -994,7 +994,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)
@@ -1044,7 +1044,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);
@@ -1805,6 +1804,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);
@@ -1881,11 +1883,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 91477afc9cf..43a65c01f15 100644
--- a/src/core/meson.build
+++ b/src/core/meson.build
@@ -173,9 +173,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 75034ac357e..d18bd977b73 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -2289,8 +2289,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 2bd8aad1fdd..ca778ae99cc 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,20 @@ 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;
+ if (options) {
+ _cleanup_free_ char *opts = NULL;
- opts = strdup(options);
- if (!opts)
- return -ENOMEM;
+ opts = strdup(options);
+ if (!opts)
+ return -ENOMEM;
+
+ *ret_options = TAKE_PTR(opts);
+ } else
+ *ret_options = NULL;
- *ret_options = TAKE_PTR(opts);
return 0;
}
@@ -522,7 +512,6 @@ static int add_mount(
assert(what);
assert(where);
- assert(opts);
assert(target_unit);
assert(source);
@@ -817,6 +806,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"))
@@ -892,7 +884,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 4379b4b6480..dd570e886bd 100644
--- a/src/getty-generator/getty-generator.c
+++ b/src/getty-generator/getty-generator.c
@@ -273,17 +273,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 b2179c53c7d..8e74b6ed884 100644
--- a/src/home/homed-manager.c
+++ b/src/home/homed-manager.c
@@ -553,7 +553,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 f89de1acce5..77d75655926 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 191a7e310d2..a9e6b61fe20 100644
--- a/src/libsystemd/sd-daemon/sd-daemon.c
+++ b/src/libsystemd/sd-daemon/sd-daemon.c
@@ -475,6 +475,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 43376a20360..6c93f6b4bb2 100644
--- a/src/libsystemd/sd-device/test-sd-device.c
+++ b/src/libsystemd/sd-device/test-sd-device.c
@@ -425,6 +425,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);
@@ -442,6 +444,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);
@@ -470,6 +475,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);
@@ -503,6 +510,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 26659302097..b2fca08374e 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 7bede85752f..23ff961b326 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/shared/varlink.c b/src/shared/varlink.c
index 9c27ebf2dd0..6d55d673198 100644
--- a/src/shared/varlink.c
+++ b/src/shared/varlink.c
@@ -2294,8 +2294,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;
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..7147fc34a58 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_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 1586c2e2141..967bd8b30e8 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/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 31cc7bdcef0..5a5634c5f51 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -1352,9 +1352,10 @@ static void run_tests(RuntimeScope scope, char **patterns) {
//manager_override_log_level(m, LOG_DEBUG);
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);
}
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/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 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-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 0cd48e34b68..f3a79b1f1fc 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -6160,6 +6160,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 c8cb85af564..45629c9c367 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